diff --git a/.coderabbit.yaml b/.coderabbit.yaml deleted file mode 100644 index 46a4f0b9..00000000 --- a/.coderabbit.yaml +++ /dev/null @@ -1,5 +0,0 @@ -reviews: - auto_review: - enabled: true - auto_incremental_review: true - drafts: false diff --git a/.gemini/config.yaml b/.gemini/config.yaml deleted file mode 100644 index 3b5e413e..00000000 --- a/.gemini/config.yaml +++ /dev/null @@ -1,23 +0,0 @@ -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 deleted file mode 100644 index 7185a625..00000000 --- a/.gemini/styleguide.md +++ /dev/null @@ -1,110 +0,0 @@ -# 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 2482712d..1530cb1c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @kvaps @lllamnyp @lexfrei @androndo @IvanHunters @sircthulhu @myasnikovdaniil +* @kvaps @lllamnyp @nbykov0 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index fefdab82..1a119259 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,7 +1,7 @@ --- name: Bug report about: Create a report to help us improve -labels: 'kind/bug' +labels: 'bug' assignees: '' --- diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 044dd6a0..9a52457c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,11 +1,8 @@ - ### Release note ```release-note - +[] ``` \ No newline at end of file diff --git a/.github/labels.yml b/.github/labels.yml deleted file mode 100644 index 2ce04130..00000000 --- a/.github/labels.yml +++ /dev/null @@ -1,371 +0,0 @@ -# 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 index 44ca8ca6..19d4b460 100644 --- a/.github/workflows/auto-release.yaml +++ b/.github/workflows/auto-release.yaml @@ -20,14 +20,6 @@ jobs: 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: @@ -36,27 +28,27 @@ jobs: - name: Configure git env: - APP_TOKEN: ${{ steps.app-token.outputs.token }} + GH_PAT: ${{ secrets.GH_PAT }} 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 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 --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 }} + GH_PAT: ${{ secrets.GH_PAT }} with: - github-token: ${{ steps.app-token.outputs.token }} + github-token: ${{ secrets.GH_PAT }} 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) + // Configure git to use PAT for authentication + execSync('git config user.name "cozystack-bot"', { encoding: 'utf8' }); + execSync('git config user.email "217169706+cozystack-bot@users.noreply.github.com"', { encoding: 'utf8' }); + execSync(`git remote set-url origin https://cozystack-bot:${process.env.GH_PAT}@github.com/${process.env.GITHUB_REPOSITORY}`, { encoding: 'utf8' }); + // Remove GITHUB_TOKEN extraheader to ensure PAT 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 diff --git a/.github/workflows/codegen-drift.yml b/.github/workflows/codegen-drift.yml deleted file mode 100644 index a26caf5e..00000000 --- a/.github/workflows/codegen-drift.yml +++ /dev/null @@ -1,61 +0,0 @@ -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 deleted file mode 100644 index 69c18329..00000000 --- a/.github/workflows/labels.yaml +++ /dev/null @@ -1,84 +0,0 @@ -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 deleted file mode 100644 index 6e6f3017..00000000 --- a/.github/workflows/pr-labeler.yaml +++ /dev/null @@ -1,206 +0,0 @@ -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 b2d82ff3..ef1ce088 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -28,7 +28,7 @@ jobs: - name: Install generate run: | - 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 + curl -sSL https://github.com/cozystack/cozyvalues-gen/releases/download/v1.0.6/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 bb7f5da5..1e13fa88 100644 --- a/.github/workflows/pull-requests-release.yaml +++ b/.github/workflows/pull-requests-release.yaml @@ -23,14 +23,6 @@ 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 @@ -55,11 +47,11 @@ jobs: - name: Create tag on merge commit env: - APP_TOKEN: ${{ steps.app-token.outputs.token }} + GH_PAT: ${{ secrets.GH_PAT }} 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 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 tag -f ${{ steps.get_tag.outputs.tag }} ${{ github.sha }} git push -f origin ${{ steps.get_tag.outputs.tag }} @@ -67,7 +59,7 @@ jobs: - name: Ensure maintenance branch release-X.Y uses: actions/github-script@v7 with: - github-token: ${{ steps.app-token.outputs.token }} + github-token: ${{ secrets.GH_PAT }} script: | const tag = '${{ steps.get_tag.outputs.tag }}'; // e.g. v0.1.3 or v0.1.3-rc3 const match = tag.match(/^v(\d+)\.(\d+)\.\d+(?:[-\w\.]+)?$/); @@ -118,95 +110,67 @@ jobs: } } - # Publish draft release and ensure correct latest flag - - name: Publish draft release + # Get the latest published release + - name: Get the latest published release + id: latest_release uses: actions/github-script@v7 with: script: | - const tag = '${{ steps.get_tag.outputs.tag }}'; + 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 isRc = Boolean(m[2]); + 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'); - // 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 + # Publish draft release with correct flags + - name: Publish draft release + uses: actions/github-script@v7 + with: + script: | + const tag = '${{ steps.get_tag.outputs.tag }}'; const releases = await github.rest.repos.listReleases({ owner: context.repo.owner, - repo: context.repo.repo, - per_page: 100 + repo: context.repo.repo }); - - // 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 + 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 }}' }); - 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`); - } + console.log(`🚀 Published release for ${tag}`); diff --git a/.github/workflows/pull-requests.yaml b/.github/workflows/pull-requests.yaml index d9898616..2de01160 100644 --- a/.github/workflows/pull-requests.yaml +++ b/.github/workflows/pull-requests.yaml @@ -6,6 +6,8 @@ env: on: pull_request: types: [opened, synchronize, reopened] + paths-ignore: + - 'docs/**/*' # Cancel in‑flight runs for the same PR when a new push arrives. concurrency: @@ -13,32 +15,16 @@ 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 - needs: ["detect-changes"] - # Never run when the PR carries the "release" label or only docs changed. + # Never run when the PR carries the "release" label. if: | - needs.detect-changes.outputs.code == 'true' - && !contains(github.event.pull_request.labels.*.name, 'release') + !contains(github.event.pull_request.labels.*.name, 'release') steps: - name: Checkout code @@ -85,6 +71,12 @@ 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: @@ -96,17 +88,10 @@ jobs: runs-on: ubuntu-latest if: contains(github.event.pull_request.labels.*.name, 'release') outputs: - disk_id: ${{ steps.fetch_assets.outputs.disk_id }} + installer_id: ${{ steps.fetch_assets.outputs.installer_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 @@ -133,7 +118,7 @@ jobs: id: fetch_assets uses: actions/github-script@v7 with: - github-token: ${{ steps.app-token.outputs.token }} + github-token: ${{ secrets.GH_PAT }} script: | const tag = '${{ steps.get_tag.outputs.tag }}'; const releases = await github.rest.repos.listReleases({ @@ -147,19 +132,19 @@ jobs: return; } const find = (n) => draft.assets.find(a => a.name === n)?.id; - const diskId = find('nocloud-amd64.raw.xz'); - if (!diskId) { + const installerId = find('cozystack-installer.yaml'); + const diskId = find('nocloud-amd64.raw.xz'); + if (!installerId || !diskId) { core.setFailed('Required assets missing in draft release'); return; } - core.setOutput('disk_id', diskId); + core.setOutput('installer_id', installerId); + core.setOutput('disk_id', diskId); - 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 + prepare_env: + name: "Prepare environment" + runs-on: [self-hosted] permissions: contents: read packages: read @@ -167,15 +152,6 @@ 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 @@ -205,16 +181,16 @@ jobs: if: contains(github.event.pull_request.labels.*.name, 'release') run: | mkdir -p _out/assets - curl -sSL -H "Authorization: token ${APP_TOKEN}" -H "Accept: application/octet-stream" \ + curl -sSL -H "Authorization: token ${GH_PAT}" -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: - APP_TOKEN: ${{ steps.app-token.outputs.token }} + GH_PAT: ${{ secrets.GH_PAT }} - name: Set sandbox ID run: echo "SANDBOX_NAME=cozy-e2e-sandbox-$(echo "${GITHUB_REPOSITORY}:${GITHUB_WORKFLOW}:${GITHUB_REF}" | sha256sum | cut -c1-10)" >> $GITHUB_ENV - # ▸ Prepare environment + # ▸ Start actual job steps - name: Prepare workspace run: | rm -rf /tmp/$SANDBOX_NAME @@ -234,7 +210,47 @@ jobs: done echo "✅ The task completed successfully after $attempt attempts" - # ▸ Install Cozystack + 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/ + - name: Install Cozystack into sandbox run: | cd /tmp/$SANDBOX_NAME @@ -247,77 +263,107 @@ jobs: fi echo "❌ Attempt $attempt failed, retrying..." done - echo "✅ The task completed successfully after $attempt attempts" + echo "✅ The task completed successfully after $attempt attempts." - name: Run OpenAPI tests run: | cd /tmp/$SANDBOX_NAME 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" + detect_test_matrix: + name: "Detect e2e test matrix" + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set.outputs.matrix }} - # ▸ Collect debug information (always runs) - - name: Collect report - if: always() + steps: + - uses: actions/checkout@v4 + - id: set + run: | + apps=$(ls hack/e2e-apps/*.bats | cut -f3 -d/ | cut -f1 -d. | jq -R | jq -cs) + echo "matrix={\"app\":$apps}" >> "$GITHUB_OUTPUT" + + test_apps: + strategy: + fail-fast: false + 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 - make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME collect-report || true + 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 + run: | + cd /tmp/$SANDBOX_NAME + make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME collect-report - 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 || true + make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME collect-images - name: Upload image list - if: always() uses: actions/upload-artifact@v4 with: name: image-list path: /tmp/${{ env.SANDBOX_NAME }}/_out/images.txt - # ▸ Tear down environment (always runs) + 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 + - name: Tear down sandbox - if: always() - run: make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME delete || true + run: make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME delete - name: Remove workspace - if: always() run: rm -rf /tmp/$SANDBOX_NAME + + diff --git a/.github/workflows/tags.yaml b/.github/workflows/tags.yaml index 1b68ee32..80100f23 100644 --- a/.github/workflows/tags.yaml +++ b/.github/workflows/tags.yaml @@ -16,8 +16,6 @@ jobs: prepare-release: name: Prepare Release runs-on: [self-hosted] - outputs: - skip: ${{ steps.check_release.outputs.skip }} permissions: contents: write packages: write @@ -25,14 +23,6 @@ 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 @@ -123,29 +113,41 @@ jobs: - name: Commit release artifacts if: steps.check_release.outputs.skip == 'false' env: - APP_TOKEN: ${{ steps.app-token.outputs.token }} + GH_PAT: ${{ secrets.GH_PAT }} 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 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 --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 - # Tag the api/apps/v1alpha1 submodule for pkg.go.dev - - name: Tag API submodule + # Get `latest_version` from latest published release + - name: Get latest published release if: steps.check_release.outputs.skip == 'false' - 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}" + 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 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 release - name: Create / reuse draft release @@ -191,11 +193,11 @@ jobs: - name: Create release branch if: steps.check_release.outputs.skip == 'false' env: - APP_TOKEN: ${{ steps.app-token.outputs.token }} + GH_PAT: ${{ secrets.GH_PAT }} 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 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} BRANCH="release-${GITHUB_REF#refs/tags/v}" git branch -f "$BRANCH" git push -f origin "$BRANCH" @@ -205,7 +207,7 @@ jobs: if: steps.check_release.outputs.skip == 'false' uses: actions/github-script@v7 with: - github-token: ${{ steps.app-token.outputs.token }} + github-token: ${{ secrets.GH_PAT }} script: | const version = context.ref.replace('refs/tags/v', ''); const base = '${{ steps.get_base.outputs.branch }}'; @@ -223,7 +225,7 @@ jobs: repo: context.repo.repo, head, base, - title: `chore(release): cut v${version}`, + title: `Release v${version}`, body: `This PR prepares the release \`v${version}\`.`, draft: false }); @@ -237,312 +239,3 @@ 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/.gitignore b/.gitignore index 61003de5..0ecfa223 100644 --- a/.gitignore +++ b/.gitignore @@ -80,7 +80,3 @@ fabric.properties **/.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 6492b92d..ac0f7e30 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,17 +1,6 @@ repos: - repo: local hooks: - - 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 - 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 - id: run-make-generate name: Run 'make generate' in all app directories entry: | diff --git a/AGENTS.md b/AGENTS.md index 1e9c4d15..eb1febf7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -27,12 +27,6 @@ working with the **Cozystack** project. - 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) @@ -59,7 +53,7 @@ working with the **Cozystack** project. ### 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` +- **Git Commits**: `[component] Description` format with `--signoff` ### What NOT to Do - ❌ Edit `/vendor/`, `zz_generated.*.go`, upstream charts directly diff --git a/MAINTAINERS.md b/MAINTAINERS.md index d7061941..9c44daab 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -10,5 +10,3 @@ | 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 acc9b6f6..9aff5ac6 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,4 @@ -.PHONY: manifests assets unit-tests helm-unit-tests bats-unit-tests preflight - -include hack/common-envs.mk +.PHONY: manifests repos assets unit-tests helm-unit-tests build-deps: @command -V find docker skopeo jq gh helm > /dev/null @@ -11,118 +9,50 @@ build-deps: build: build-deps make -C packages/apps/http-cache image - make -C packages/apps/mariadb image + make -C packages/apps/mysql image make -C packages/apps/clickhouse image make -C packages/apps/kubernetes image - make -C packages/system/monitoring image + make -C packages/extra/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/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/system repo + make -C packages/apps repo + make -C packages/extra repo + manifests: mkdir -p _out/assets - 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 + (cd packages/core/installer/; helm template -n cozy-installer installer .) > _out/assets/cozystack-installer.yaml -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: +assets: 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 +unit-tests: helm-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 5bc8d7be..b81af2a7 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,11 @@ [![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) -[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/10177/badge)](https://www.bestpractices.dev/projects/10177) +[![GitHub Commit](https://img.shields.io/github/commit-activity/y/cozystack/cozystack)](https://github.com/cozystack/cozystack/graphs/contributors) # Cozystack -**Cozystack** is a free platform and framework for building clouds. +**Cozystack** is a free PaaS 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/). diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index b64e533b..00000000 --- a/SECURITY.md +++ /dev/null @@ -1,102 +0,0 @@ -# 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/apps/v1alpha1/bucket/types.go b/api/apps/v1alpha1/bucket/types.go deleted file mode 100644 index 96082a67..00000000 --- a/api/apps/v1alpha1/bucket/types.go +++ /dev/null @@ -1,33 +0,0 @@ -// 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 deleted file mode 100644 index 26f925cd..00000000 --- a/api/apps/v1alpha1/bucket/zz_generated.deepcopy.go +++ /dev/null @@ -1,88 +0,0 @@ -//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 deleted file mode 100644 index 153ff5e0..00000000 --- a/api/apps/v1alpha1/clickhouse/types.go +++ /dev/null @@ -1,112 +0,0 @@ -// 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 deleted file mode 100644 index 2c3a6ed8..00000000 --- a/api/apps/v1alpha1/clickhouse/zz_generated.deepcopy.go +++ /dev/null @@ -1,141 +0,0 @@ -//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 deleted file mode 100644 index 5b0e5920..00000000 --- a/api/apps/v1alpha1/foundationdb/types.go +++ /dev/null @@ -1,162 +0,0 @@ -// 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 deleted file mode 100644 index 92d80421..00000000 --- a/api/apps/v1alpha1/foundationdb/zz_generated.deepcopy.go +++ /dev/null @@ -1,234 +0,0 @@ -//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 deleted file mode 100644 index d5d57383..00000000 --- a/api/apps/v1alpha1/go.mod +++ /dev/null @@ -1,24 +0,0 @@ -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 deleted file mode 100644 index d9b1cf31..00000000 --- a/api/apps/v1alpha1/go.sum +++ /dev/null @@ -1,56 +0,0 @@ -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 deleted file mode 100644 index 974576b3..00000000 --- a/api/apps/v1alpha1/harbor/types.go +++ /dev/null @@ -1,114 +0,0 @@ -// 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 deleted file mode 100644 index 3e7338ad..00000000 --- a/api/apps/v1alpha1/harbor/zz_generated.deepcopy.go +++ /dev/null @@ -1,186 +0,0 @@ -//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 deleted file mode 100644 index 30bb10ba..00000000 --- a/api/apps/v1alpha1/httpcache/types.go +++ /dev/null @@ -1,72 +0,0 @@ -// 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 deleted file mode 100644 index 47da2baa..00000000 --- a/api/apps/v1alpha1/httpcache/zz_generated.deepcopy.go +++ /dev/null @@ -1,123 +0,0 @@ -//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 deleted file mode 100644 index 485f34ee..00000000 --- a/api/apps/v1alpha1/kafka/types.go +++ /dev/null @@ -1,90 +0,0 @@ -// 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 deleted file mode 100644 index c2d39077..00000000 --- a/api/apps/v1alpha1/kafka/zz_generated.deepcopy.go +++ /dev/null @@ -1,142 +0,0 @@ -//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 deleted file mode 100644 index 88a3c97e..00000000 --- a/api/apps/v1alpha1/kubernetes/types.go +++ /dev/null @@ -1,279 +0,0 @@ -// 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 deleted file mode 100644 index e021fbaa..00000000 --- a/api/apps/v1alpha1/kubernetes/zz_generated.deepcopy.go +++ /dev/null @@ -1,455 +0,0 @@ -//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 deleted file mode 100644 index b3b6c414..00000000 --- a/api/apps/v1alpha1/mariadb/types.go +++ /dev/null @@ -1,109 +0,0 @@ -// 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 deleted file mode 100644 index 4cc5a94f..00000000 --- a/api/apps/v1alpha1/mariadb/zz_generated.deepcopy.go +++ /dev/null @@ -1,171 +0,0 @@ -//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 deleted file mode 100644 index 886b716c..00000000 --- a/api/apps/v1alpha1/mongodb/types.go +++ /dev/null @@ -1,149 +0,0 @@ -// 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 deleted file mode 100644 index 694009f4..00000000 --- a/api/apps/v1alpha1/mongodb/zz_generated.deepcopy.go +++ /dev/null @@ -1,227 +0,0 @@ -//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 deleted file mode 100644 index 5437355d..00000000 --- a/api/apps/v1alpha1/nats/types.go +++ /dev/null @@ -1,78 +0,0 @@ -// 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 deleted file mode 100644 index f6c23cb1..00000000 --- a/api/apps/v1alpha1/nats/zz_generated.deepcopy.go +++ /dev/null @@ -1,149 +0,0 @@ -//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 deleted file mode 100644 index bb5d12d9..00000000 --- a/api/apps/v1alpha1/openbao/types.go +++ /dev/null @@ -1,51 +0,0 @@ -// 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 deleted file mode 100644 index baa1258b..00000000 --- a/api/apps/v1alpha1/openbao/zz_generated.deepcopy.go +++ /dev/null @@ -1,85 +0,0 @@ -//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 deleted file mode 100644 index b188cdfa..00000000 --- a/api/apps/v1alpha1/opensearch/types.go +++ /dev/null @@ -1,115 +0,0 @@ -// 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 deleted file mode 100644 index f7f2daef..00000000 --- a/api/apps/v1alpha1/opensearch/zz_generated.deepcopy.go +++ /dev/null @@ -1,161 +0,0 @@ -//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 deleted file mode 100644 index a2ff77a8..00000000 --- a/api/apps/v1alpha1/postgresql/types.go +++ /dev/null @@ -1,153 +0,0 @@ -// 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 deleted file mode 100644 index 5fba855e..00000000 --- a/api/apps/v1alpha1/postgresql/zz_generated.deepcopy.go +++ /dev/null @@ -1,240 +0,0 @@ -//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 deleted file mode 100644 index 203e9a97..00000000 --- a/api/apps/v1alpha1/qdrant/types.go +++ /dev/null @@ -1,48 +0,0 @@ -// 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 deleted file mode 100644 index 2abfd37e..00000000 --- a/api/apps/v1alpha1/qdrant/zz_generated.deepcopy.go +++ /dev/null @@ -1,85 +0,0 @@ -//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 deleted file mode 100644 index f67c4402..00000000 --- a/api/apps/v1alpha1/rabbitmq/types.go +++ /dev/null @@ -1,77 +0,0 @@ -// 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 deleted file mode 100644 index a1d55f89..00000000 --- a/api/apps/v1alpha1/rabbitmq/zz_generated.deepcopy.go +++ /dev/null @@ -1,155 +0,0 @@ -//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 deleted file mode 100644 index e9a02c72..00000000 --- a/api/apps/v1alpha1/redis/types.go +++ /dev/null @@ -1,57 +0,0 @@ -// 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 deleted file mode 100644 index 6390200c..00000000 --- a/api/apps/v1alpha1/redis/zz_generated.deepcopy.go +++ /dev/null @@ -1,85 +0,0 @@ -//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 deleted file mode 100644 index aa99cd6d..00000000 --- a/api/apps/v1alpha1/tcpbalancer/types.go +++ /dev/null @@ -1,75 +0,0 @@ -// 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 deleted file mode 100644 index 1c63eafc..00000000 --- a/api/apps/v1alpha1/tcpbalancer/zz_generated.deepcopy.go +++ /dev/null @@ -1,126 +0,0 @@ -//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 deleted file mode 100644 index 60f8bb22..00000000 --- a/api/apps/v1alpha1/tenant/types.go +++ /dev/null @@ -1,41 +0,0 @@ -// 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 deleted file mode 100644 index 784a8f25..00000000 --- a/api/apps/v1alpha1/tenant/zz_generated.deepcopy.go +++ /dev/null @@ -1,74 +0,0 @@ -//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 deleted file mode 100644 index c493f49c..00000000 --- a/api/apps/v1alpha1/vmdisk/types.go +++ /dev/null @@ -1,61 +0,0 @@ -// 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 deleted file mode 100644 index 301bb1d9..00000000 --- a/api/apps/v1alpha1/vmdisk/zz_generated.deepcopy.go +++ /dev/null @@ -1,163 +0,0 @@ -//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 deleted file mode 100644 index 9c48724a..00000000 --- a/api/apps/v1alpha1/vminstance/types.go +++ /dev/null @@ -1,100 +0,0 @@ -// 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 deleted file mode 100644 index 86d5ddfc..00000000 --- a/api/apps/v1alpha1/vminstance/zz_generated.deepcopy.go +++ /dev/null @@ -1,160 +0,0 @@ -//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 deleted file mode 100644 index fed72f58..00000000 --- a/api/apps/v1alpha1/vpc/types.go +++ /dev/null @@ -1,49 +0,0 @@ -// 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 deleted file mode 100644 index 3cda29c4..00000000 --- a/api/apps/v1alpha1/vpc/zz_generated.deepcopy.go +++ /dev/null @@ -1,126 +0,0 @@ -//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 deleted file mode 100644 index 7ec0b0e3..00000000 --- a/api/apps/v1alpha1/vpn/types.go +++ /dev/null @@ -1,56 +0,0 @@ -// 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 deleted file mode 100644 index a3595bb0..00000000 --- a/api/apps/v1alpha1/vpn/zz_generated.deepcopy.go +++ /dev/null @@ -1,111 +0,0 @@ -//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/velero_types.go b/api/backups/strategy/v1alpha1/velero_types.go index 2bfeabb7..ea61d421 100644 --- a/api/backups/strategy/v1alpha1/velero_types.go +++ b/api/backups/strategy/v1alpha1/velero_types.go @@ -6,7 +6,6 @@ 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" ) @@ -48,17 +47,7 @@ type VeleroList struct { } // 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 VeleroSpec struct{} 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 index 7f109878..50ee19a4 100644 --- a/api/backups/strategy/v1alpha1/zz_generated.deepcopy.go +++ b/api/backups/strategy/v1alpha1/zz_generated.deepcopy.go @@ -21,7 +21,6 @@ limitations under the License. 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" ) @@ -128,7 +127,7 @@ func (in *Velero) DeepCopyInto(out *Velero) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) + out.Spec = in.Spec in.Status.DeepCopyInto(&out.Status) } @@ -185,7 +184,6 @@ func (in *VeleroList) DeepCopyObject() runtime.Object { // 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. @@ -219,24 +217,3 @@ func (in *VeleroStatus) DeepCopy() *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 index 7ba06fae..455dab59 100644 --- a/api/backups/v1alpha1/DESIGN.md +++ b/api/backups/v1alpha1/DESIGN.md @@ -100,13 +100,13 @@ Describe **when**, **how**, and **where** to back up a specific managed applicat ```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"` + // Where backups should be stored. + StorageRef corev1.TypedLocalObjectReference `json:"storageRef"` + + // Driver-specific BackupStrategy to use. + StrategyRef corev1.TypedLocalObjectReference `json:"strategyRef"` // When backups should run. Schedule PlanSchedule `json:"schedule"` @@ -145,12 +145,12 @@ Core Plan controller: * 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` + * `spec.applicationRef = plan.spec.applicationRef` + * `spec.storageRef = plan.spec.storageRef` + * `spec.strategyRef = plan.spec.strategyRef` + * `spec.triggeredBy = "Plan"` * 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. @@ -159,64 +159,17 @@ The Plan controller does **not**: --- -### 4.2 BackupClass +### 4.2 Storage -**Group/Kind** -`backups.cozystack.io/v1alpha1, Kind=BackupClass` +**API Shape** -**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. +TBD -**Key fields (spec)** +**Storage usage** -```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). +* `Plan` and `BackupJob` reference `Storage` via `TypedLocalObjectReference`. +* Drivers read `Storage` to know how/where to store or read artifacts. +* Core treats `Storage` spec as opaque; it does not directly talk to S3 or buckets. --- @@ -236,13 +189,16 @@ type BackupJobSpec struct { 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"` + // Storage to use. + StorageRef corev1.TypedLocalObjectReference `json:"storageRef"` + + // Driver-specific BackupStrategy to use. + StrategyRef corev1.TypedLocalObjectReference `json:"strategyRef"` + + // Informational: what triggered this run ("Plan", "Manual", etc.). + TriggeredBy string `json:"triggeredBy,omitempty"` } ``` @@ -267,9 +223,7 @@ type BackupJobStatus struct { * 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)**. + * Reconciles runs where `spec.strategyRef.apiGroup/kind` matches its **strategy type(s)**. * Driver responsibilities: 1. On first reconcile: @@ -278,12 +232,7 @@ type BackupJobStatus struct { * 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`. + * Read `Strategy` (driver-owned CRD), `Storage`, `Application`, optionally `Plan`. 3. Execute backup logic (implementation-specific). 4. On success: @@ -315,14 +264,13 @@ Represent a single **backup artifact** for a given application, decoupled from a type BackupSpec struct { ApplicationRef corev1.TypedLocalObjectReference `json:"applicationRef"` PlanRef *corev1.LocalObjectReference `json:"planRef,omitempty"` + StorageRef corev1.TypedLocalObjectReference `json:"storageRef"` 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 @@ -342,8 +290,7 @@ type BackupStatus struct { * 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). + * The application, storage, strategy references. * `takenAt`. * Optional `driverMetadata`. * Sets `status` with: @@ -359,8 +306,6 @@ type BackupStatus struct { * 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 @@ -408,13 +353,13 @@ type RestoreJobStatus struct { * 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`). + * **Storage**: `backup.spec.storageRef`. * **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. + * Resolve `Backup`, `Storage`, `Strategy`, target application. * Execute restore logic (implementation-specific). * On success: @@ -469,10 +414,8 @@ 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. + * **When & where** (Plan + Storage) – core-owned. * **What backup artifacts exist** (Backup) – driver-created but cluster-visible. - * **Restore lifecycle** (RestoreJob) – shared contract boundary. + * **Execution lifecycle** (BackupJob, 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 index e46212f6..2f18b34f 100644 --- a/api/backups/v1alpha1/backup_types.go +++ b/api/backups/v1alpha1/backup_types.go @@ -57,6 +57,10 @@ type BackupSpec struct { // +optional PlanRef *corev1.LocalObjectReference `json:"planRef,omitempty"` + // StorageRef refers to the Storage object that describes where the backup + // artifact is stored. + StorageRef corev1.TypedLocalObjectReference `json:"storageRef"` + // 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"` @@ -72,15 +76,6 @@ type BackupSpec struct { 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. @@ -92,15 +87,6 @@ type BackupStatus struct { // +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"` diff --git a/api/backups/v1alpha1/backupclass_types.go b/api/backups/v1alpha1/backupclass_types.go deleted file mode 100644 index 2b2dc7ff..00000000 --- a/api/backups/v1alpha1/backupclass_types.go +++ /dev/null @@ -1,85 +0,0 @@ -// 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 index 111b5f1d..1230b209 100644 --- a/api/backups/v1alpha1/backupjob_types.go +++ b/api/backups/v1alpha1/backupjob_types.go @@ -21,15 +21,6 @@ func init() { }) } -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 @@ -50,16 +41,15 @@ type BackupJobSpec struct { // 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"` + // StorageRef holds a reference to the Storage object that describes where + // the backup will be stored. + StorageRef corev1.TypedLocalObjectReference `json:"storageRef"` + + // StrategyRef holds a reference to the driver-specific BackupStrategy object + // that describes how the backup should be created. + StrategyRef corev1.TypedLocalObjectReference `json:"strategyRef"` } // BackupJobStatus represents the observed state of a BackupJob. @@ -95,8 +85,6 @@ type BackupJobStatus struct { // 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` @@ -119,13 +107,3 @@ type BackupJobList struct { 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 index 87ad6f38..8cdd663a 100644 --- a/api/backups/v1alpha1/groupversion_info.go +++ b/api/backups/v1alpha1/groupversion_info.go @@ -25,13 +25,8 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" ) -const ( - thisGroup = "backups.cozystack.io" - thisVersion = "v1alpha1" -) - var ( - GroupVersion = schema.GroupVersion{Group: thisGroup, Version: thisVersion} + GroupVersion = schema.GroupVersion{Group: "backups.cozystack.io", Version: "v1alpha1"} SchemeBuilder = runtime.NewSchemeBuilder(addGroupVersion) AddToScheme = SchemeBuilder.AddToScheme ) diff --git a/api/backups/v1alpha1/plan_types.go b/api/backups/v1alpha1/plan_types.go index df807eb5..c59d5eab 100644 --- a/api/backups/v1alpha1/plan_types.go +++ b/api/backups/v1alpha1/plan_types.go @@ -65,13 +65,15 @@ type PlanList struct { 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"` + // StorageRef holds a reference to the Storage object that + // describes the location where the backup will be stored. + StorageRef corev1.TypedLocalObjectReference `json:"storageRef"` + + // StrategyRef holds a reference to the Strategy object that + // describes, how a backup copy is to be created. + StrategyRef corev1.TypedLocalObjectReference `json:"strategyRef"` // Schedule specifies when backup copies are created. Schedule PlanSchedule `json:"schedule"` diff --git a/api/backups/v1alpha1/restorejob_types.go b/api/backups/v1alpha1/restorejob_types.go index 9817e8c1..0a64b7cf 100644 --- a/api/backups/v1alpha1/restorejob_types.go +++ b/api/backups/v1alpha1/restorejob_types.go @@ -42,12 +42,6 @@ type RestoreJobSpec struct { // 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. @@ -77,8 +71,6 @@ type RestoreJobStatus struct { } // +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 { diff --git a/api/backups/v1alpha1/zz_generated.deepcopy.go b/api/backups/v1alpha1/zz_generated.deepcopy.go index 61b8f839..fe825947 100644 --- a/api/backups/v1alpha1/zz_generated.deepcopy.go +++ b/api/backups/v1alpha1/zz_generated.deepcopy.go @@ -26,26 +26,6 @@ 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 *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 @@ -88,133 +68,6 @@ func (in *BackupArtifact) DeepCopy() *BackupArtifact { 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 @@ -283,6 +136,8 @@ func (in *BackupJobSpec) DeepCopyInto(out *BackupJobSpec) { **out = **in } in.ApplicationRef.DeepCopyInto(&out.ApplicationRef) + in.StorageRef.DeepCopyInto(&out.StorageRef) + in.StrategyRef.DeepCopyInto(&out.StrategyRef) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupJobSpec. @@ -371,6 +226,7 @@ func (in *BackupSpec) DeepCopyInto(out *BackupSpec) { *out = new(v1.LocalObjectReference) **out = **in } + in.StorageRef.DeepCopyInto(&out.StorageRef) in.StrategyRef.DeepCopyInto(&out.StrategyRef) in.TakenAt.DeepCopyInto(&out.TakenAt) if in.DriverMetadata != nil { @@ -400,11 +256,6 @@ func (in *BackupStatus) DeepCopyInto(out *BackupStatus) { *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)) @@ -424,21 +275,6 @@ func (in *BackupStatus) DeepCopy() *BackupStatus { 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 @@ -517,6 +353,8 @@ func (in *PlanSchedule) DeepCopy() *PlanSchedule { func (in *PlanSpec) DeepCopyInto(out *PlanSpec) { *out = *in in.ApplicationRef.DeepCopyInto(&out.ApplicationRef) + in.StorageRef.DeepCopyInto(&out.StorageRef) + in.StrategyRef.DeepCopyInto(&out.StrategyRef) out.Schedule = in.Schedule } @@ -620,11 +458,6 @@ func (in *RestoreJobSpec) DeepCopyInto(out *RestoreJobSpec) { *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. diff --git a/api/dashboard/v1alpha1/dashboard_resources.go b/api/dashboard/v1alpha1/dashboard_resources.go index afac0b05..5af3b359 100644 --- a/api/dashboard/v1alpha1/dashboard_resources.go +++ b/api/dashboard/v1alpha1/dashboard_resources.go @@ -253,25 +253,3 @@ type FactoryList struct { 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 index 659401a7..b3c38e00 100644 --- a/api/dashboard/v1alpha1/groupversion_info.go +++ b/api/dashboard/v1alpha1/groupversion_info.go @@ -69,9 +69,6 @@ func addKnownTypes(scheme *runtime.Scheme) error { &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 index 25d97a79..45b1d9d7 100644 --- a/api/dashboard/v1alpha1/zz_generated.deepcopy.go +++ b/api/dashboard/v1alpha1/zz_generated.deepcopy.go @@ -159,65 +159,6 @@ func (in *BreadcrumbList) DeepCopyObject() runtime.Object { 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 diff --git a/api/v1alpha1/applicationdefinitions_types.go b/api/v1alpha1/cozystackresourcedefinitions_types.go similarity index 69% rename from api/v1alpha1/applicationdefinitions_types.go rename to api/v1alpha1/cozystackresourcedefinitions_types.go index 4a4cd226..2f25fb2d 100644 --- a/api/v1alpha1/applicationdefinitions_types.go +++ b/api/v1alpha1/cozystackresourcedefinitions_types.go @@ -17,52 +17,69 @@ 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 { +// CozystackResourceDefinition is the Schema for the cozystackresourcedefinitions API +type CozystackResourceDefinition struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec ApplicationDefinitionSpec `json:"spec,omitempty"` + Spec CozystackResourceDefinitionSpec `json:"spec,omitempty"` } // +kubebuilder:object:root=true -// ApplicationDefinitionList contains a list of ApplicationDefinitions -type ApplicationDefinitionList struct { +// CozystackResourceDefinitionList contains a list of CozystackResourceDefinitions +type CozystackResourceDefinitionList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []ApplicationDefinition `json:"items"` + Items []CozystackResourceDefinition `json:"items"` } func init() { - SchemeBuilder.Register(&ApplicationDefinition{}, &ApplicationDefinitionList{}) + SchemeBuilder.Register(&CozystackResourceDefinition{}, &CozystackResourceDefinitionList{}) } -type ApplicationDefinitionSpec struct { +type CozystackResourceDefinitionSpec struct { // Application configuration - Application ApplicationDefinitionApplication `json:"application"` + Application CozystackResourceDefinitionApplication `json:"application"` // Release configuration - Release ApplicationDefinitionRelease `json:"release"` + Release CozystackResourceDefinitionRelease `json:"release"` // Secret selectors - Secrets ApplicationDefinitionResources `json:"secrets,omitempty"` + Secrets CozystackResourceDefinitionResources `json:"secrets,omitempty"` // Service selectors - Services ApplicationDefinitionResources `json:"services,omitempty"` + Services CozystackResourceDefinitionResources `json:"services,omitempty"` // Ingress selectors - Ingresses ApplicationDefinitionResources `json:"ingresses,omitempty"` + Ingresses CozystackResourceDefinitionResources `json:"ingresses,omitempty"` // Dashboard configuration for this resource - Dashboard *ApplicationDefinitionDashboard `json:"dashboard,omitempty"` + Dashboard *CozystackResourceDefinitionDashboard `json:"dashboard,omitempty"` } -type ApplicationDefinitionApplication struct { +type CozystackResourceDefinitionChart struct { + // Name of the Helm chart + Name string `json:"name"` + // Source reference for the Helm chart + SourceRef SourceRef `json:"sourceRef"` +} + +type SourceRef struct { + // Kind of the source reference + // +kubebuilder:default:="HelmRepository" + Kind string `json:"kind"` + // Name of the source reference + Name string `json:"name"` + // Namespace of the source reference + // +kubebuilder:default:="cozy-public" + Namespace string `json:"namespace"` +} + +type CozystackResourceDefinitionApplication struct { // Kind of the application, used for UI and API Kind string `json:"kind"` // OpenAPI schema for the application, used for API validation @@ -73,16 +90,17 @@ type ApplicationDefinitionApplication struct { Singular string `json:"singular"` } -type ApplicationDefinitionRelease struct { - // Reference to the chart source - ChartRef *helmv2.CrossNamespaceSourceReference `json:"chartRef"` +type CozystackResourceDefinitionRelease struct { + // Helm chart configuration + // +optional + Chart CozystackResourceDefinitionChart `json:"chart,omitempty"` // 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. +// CozystackResourceDefinitionResourceSelector 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) @@ -105,7 +123,7 @@ type ApplicationDefinitionRelease struct { // - "{{ .name }}-secret" // - "{{ .kind }}-{{ .name }}-tls" // - "specificname" -type ApplicationDefinitionResourceSelector struct { +type CozystackResourceDefinitionResourceSelector 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 @@ -113,16 +131,16 @@ type ApplicationDefinitionResourceSelector struct { ResourceNames []string `json:"resourceNames,omitempty"` } -type ApplicationDefinitionResources struct { +type CozystackResourceDefinitionResources 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"` + Exclude []*CozystackResourceDefinitionResourceSelector `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"` + Include []*CozystackResourceDefinitionResourceSelector `json:"include,omitempty"` } // ---- Dashboard types ---- @@ -139,8 +157,8 @@ const ( DashboardTabYAML DashboardTab = "yaml" ) -// ApplicationDefinitionDashboard describes how this resource appears in the UI. -type ApplicationDefinitionDashboard struct { +// CozystackResourceDefinitionDashboard describes how this resource appears in the UI. +type CozystackResourceDefinitionDashboard struct { // Human-readable name shown in the UI (e.g., "Bucket") Singular string `json:"singular"` // Plural human-readable name (e.g., "Buckets") diff --git a/api/v1alpha1/packagesource_types.go b/api/v1alpha1/packagesource_types.go index 75bf217b..c0b943e8 100644 --- a/api/v1alpha1/packagesource_types.go +++ b/api/v1alpha1/packagesource_types.go @@ -132,16 +132,6 @@ type ComponentInstall struct { // 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 diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index c1adf95c..7fe4f3e2 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -21,232 +21,12 @@ 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 @@ -297,6 +77,237 @@ func (in *ComponentInstall) DeepCopy() *ComponentInstall { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CozystackResourceDefinition) DeepCopyInto(out *CozystackResourceDefinition) { + *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 CozystackResourceDefinition. +func (in *CozystackResourceDefinition) DeepCopy() *CozystackResourceDefinition { + if in == nil { + return nil + } + out := new(CozystackResourceDefinition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CozystackResourceDefinition) 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 *CozystackResourceDefinitionApplication) DeepCopyInto(out *CozystackResourceDefinitionApplication) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionApplication. +func (in *CozystackResourceDefinitionApplication) DeepCopy() *CozystackResourceDefinitionApplication { + if in == nil { + return nil + } + out := new(CozystackResourceDefinitionApplication) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CozystackResourceDefinitionChart) DeepCopyInto(out *CozystackResourceDefinitionChart) { + *out = *in + out.SourceRef = in.SourceRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionChart. +func (in *CozystackResourceDefinitionChart) DeepCopy() *CozystackResourceDefinitionChart { + if in == nil { + return nil + } + out := new(CozystackResourceDefinitionChart) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CozystackResourceDefinitionDashboard) DeepCopyInto(out *CozystackResourceDefinitionDashboard) { + *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 CozystackResourceDefinitionDashboard. +func (in *CozystackResourceDefinitionDashboard) DeepCopy() *CozystackResourceDefinitionDashboard { + if in == nil { + return nil + } + out := new(CozystackResourceDefinitionDashboard) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CozystackResourceDefinitionList) DeepCopyInto(out *CozystackResourceDefinitionList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CozystackResourceDefinition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionList. +func (in *CozystackResourceDefinitionList) DeepCopy() *CozystackResourceDefinitionList { + if in == nil { + return nil + } + out := new(CozystackResourceDefinitionList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CozystackResourceDefinitionList) 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 *CozystackResourceDefinitionRelease) DeepCopyInto(out *CozystackResourceDefinitionRelease) { + *out = *in + out.Chart = in.Chart + 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 CozystackResourceDefinitionRelease. +func (in *CozystackResourceDefinitionRelease) DeepCopy() *CozystackResourceDefinitionRelease { + if in == nil { + return nil + } + out := new(CozystackResourceDefinitionRelease) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CozystackResourceDefinitionResourceSelector) DeepCopyInto(out *CozystackResourceDefinitionResourceSelector) { + *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 CozystackResourceDefinitionResourceSelector. +func (in *CozystackResourceDefinitionResourceSelector) DeepCopy() *CozystackResourceDefinitionResourceSelector { + if in == nil { + return nil + } + out := new(CozystackResourceDefinitionResourceSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CozystackResourceDefinitionResources) DeepCopyInto(out *CozystackResourceDefinitionResources) { + *out = *in + if in.Exclude != nil { + in, out := &in.Exclude, &out.Exclude + *out = make([]*CozystackResourceDefinitionResourceSelector, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(CozystackResourceDefinitionResourceSelector) + (*in).DeepCopyInto(*out) + } + } + } + if in.Include != nil { + in, out := &in.Include, &out.Include + *out = make([]*CozystackResourceDefinitionResourceSelector, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(CozystackResourceDefinitionResourceSelector) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionResources. +func (in *CozystackResourceDefinitionResources) DeepCopy() *CozystackResourceDefinitionResources { + if in == nil { + return nil + } + out := new(CozystackResourceDefinitionResources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CozystackResourceDefinitionSpec) DeepCopyInto(out *CozystackResourceDefinitionSpec) { + *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(CozystackResourceDefinitionDashboard) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CozystackResourceDefinitionSpec. +func (in *CozystackResourceDefinitionSpec) DeepCopy() *CozystackResourceDefinitionSpec { + if in == nil { + return nil + } + out := new(CozystackResourceDefinitionSpec) + 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 @@ -611,6 +622,21 @@ 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 *SourceRef) DeepCopyInto(out *SourceRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceRef. +func (in *SourceRef) DeepCopy() *SourceRef { + if in == nil { + return nil + } + out := new(SourceRef) + in.DeepCopyInto(out) + 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 diff --git a/cmd/backup-controller/main.go b/cmd/backup-controller/main.go index 16dfc44c..d8436659 100644 --- a/cmd/backup-controller/main.go +++ b/cmd/backup-controller/main.go @@ -29,8 +29,6 @@ import ( 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" @@ -132,11 +130,6 @@ func main() { 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 diff --git a/cmd/backupstrategy-controller/main.go b/cmd/backupstrategy-controller/main.go index 03396979..61edc40a 100644 --- a/cmd/backupstrategy-controller/main.go +++ b/cmd/backupstrategy-controller/main.go @@ -29,18 +29,14 @@ import ( 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 ) @@ -53,8 +49,6 @@ 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 } @@ -136,11 +130,6 @@ func main() { 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 @@ -159,29 +148,10 @@ func main() { } if err = (&backupcontroller.BackupJobReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - Recorder: mgr.GetEventRecorderFor("backup-controller"), + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), }).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") + setupLog.Error(err, "unable to create controller", "controller", "Job") os.Exit(1) } diff --git a/cmd/cozypkg/cmd/root.go b/cmd/cozypkg/cmd/root.go index 69b0ea6d..62bd54aa 100644 --- a/cmd/cozypkg/cmd/root.go +++ b/cmd/cozypkg/cmd/root.go @@ -23,9 +23,6 @@ import ( "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", @@ -47,6 +44,6 @@ func Execute() error { } func init() { - rootCmd.Version = Version + // Commands are registered in their respective init() functions } diff --git a/cmd/cozystack-assets-server/main.go b/cmd/cozystack-assets-server/main.go new file mode 100644 index 00000000..75563712 --- /dev/null +++ b/cmd/cozystack-assets-server/main.go @@ -0,0 +1,29 @@ +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 bcaca9c9..0e7199d3 100644 --- a/cmd/cozystack-controller/main.go +++ b/cmd/cozystack-controller/main.go @@ -42,7 +42,6 @@ import ( "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 ) @@ -57,7 +56,6 @@ func init() { utilruntime.Must(cozystackiov1alpha1.AddToScheme(scheme)) utilruntime.Must(dashboard.AddToScheme(scheme)) utilruntime.Must(helmv2.AddToScheme(scheme)) - utilruntime.Must(cosiv1alpha1.AddToScheme(scheme)) // +kubebuilder:scaffold:scheme } @@ -70,6 +68,8 @@ func main() { var disableTelemetry bool var telemetryEndpoint string var telemetryInterval string + var cozystackVersion string + var reconcileDeployment 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.") @@ -87,6 +87,10 @@ 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") + flag.BoolVar(&reconcileDeployment, "reconcile-deployment", false, + "If set, the Cozystack API server is assumed to run as a Deployment, else as a DaemonSet.") opts := zap.Options{ Development: false, } @@ -102,9 +106,10 @@ func main() { // Configure telemetry telemetryConfig := telemetry.Config{ - Disabled: disableTelemetry, - Endpoint: telemetryEndpoint, - Interval: interval, + Disabled: disableTelemetry, + Endpoint: telemetryEndpoint, + Interval: interval, + CozystackVersion: cozystackVersion, } ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) @@ -195,19 +200,24 @@ func main() { os.Exit(1) } - if err = (&controller.ApplicationDefinitionReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), + cozyAPIKind := "DaemonSet" + if reconcileDeployment { + cozyAPIKind = "Deployment" + } + if err = (&controller.CozystackResourceDefinitionReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + CozystackAPIKind: cozyAPIKind, }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "ApplicationDefinitionReconciler") + setupLog.Error(err, "unable to create controller", "controller", "CozystackResourceDefinitionReconciler") os.Exit(1) } - if err = (&controller.ApplicationDefinitionHelmReconciler{ + if err = (&controller.CozystackResourceDefinitionHelmReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "ApplicationDefinitionHelmReconciler") + setupLog.Error(err, "unable to create controller", "controller", "CozystackResourceDefinitionHelmReconciler") os.Exit(1) } diff --git a/cmd/cozystack-operator/main.go b/cmd/cozystack-operator/main.go index e215b779..d9c79057 100644 --- a/cmd/cozystack-operator/main.go +++ b/cmd/cozystack-operator/main.go @@ -32,16 +32,12 @@ import ( 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" @@ -49,11 +45,8 @@ import ( 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 ) @@ -78,14 +71,8 @@ func main() { 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 cozystackVersion string var platformSourceURL string var platformSourceName string var platformSourceRef string @@ -99,20 +86,12 @@ func main() { "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(&cozystackVersion, "cozystack-version", "unknown", + "Version of Cozystack") 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(&platformSourceName, "platform-source-name", "cozystack-packages", "Name for the generated platform source resource (default: cozystack-packages)") 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, @@ -131,28 +110,10 @@ func main() { 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 + // Start the controller manager + setupLog.Info("Starting 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, @@ -179,26 +140,10 @@ func main() { 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) + installCtx, installCancel := context.WithTimeout(context.Background(), 5*time.Minute) defer installCancel() // Use direct client for pre-start operations (cache is not ready yet) @@ -212,7 +157,7 @@ func main() { // 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) + installCtx, installCancel := context.WithTimeout(context.Background(), 2*time.Minute) defer installCancel() // Use direct client for pre-start operations (cache is not ready yet) @@ -224,29 +169,6 @@ func main() { } } - // 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(), @@ -265,18 +187,6 @@ func main() { 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 { @@ -288,35 +198,8 @@ func main() { 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") + mgrCtx := ctrl.SetupSignalHandler() if err := mgr.Start(mgrCtx); err != nil { setupLog.Error(err, "problem running manager") os.Exit(1) @@ -575,79 +458,3 @@ func generateGitRepository(name, repoURL string, refMap map[string]string) (*sou 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 deleted file mode 100644 index a69bc9b5..00000000 --- a/cmd/cozystack-operator/main_test.go +++ /dev/null @@ -1,574 +0,0 @@ -/* -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 deleted file mode 100644 index 13fe88cd..00000000 --- a/cmd/flux-plunger/main.go +++ /dev/null @@ -1,151 +0,0 @@ -/* -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 index 611d030b..210405ce 100644 --- a/cmd/kubeovn-plunger/main.go +++ b/cmd/kubeovn-plunger/main.go @@ -29,7 +29,6 @@ import ( 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" @@ -132,11 +131,6 @@ func main() { 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 diff --git a/dashboards/gpu/gpu-efficiency.json b/dashboards/gpu/gpu-efficiency.json deleted file mode 100644 index 28a24568..00000000 --- a/dashboards/gpu/gpu-efficiency.json +++ /dev/null @@ -1,819 +0,0 @@ -{ - "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 deleted file mode 100644 index 60c12bfb..00000000 --- a/dashboards/gpu/gpu-fleet.json +++ /dev/null @@ -1,1157 +0,0 @@ -{ - "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 deleted file mode 100644 index aed9c69a..00000000 --- a/dashboards/gpu/gpu-performance.json +++ /dev/null @@ -1,957 +0,0 @@ -{ - "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 deleted file mode 100644 index 865fb95c..00000000 --- a/dashboards/gpu/gpu-quotas.json +++ /dev/null @@ -1,637 +0,0 @@ -{ - "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 deleted file mode 100644 index 7fef321d..00000000 --- a/dashboards/gpu/gpu-tenants.json +++ /dev/null @@ -1,1098 +0,0 @@ -{ - "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 deleted file mode 100644 index 57f804cf..00000000 --- a/dashboards/hubble/dns-namespace.json +++ /dev/null @@ -1,602 +0,0 @@ -{ - "__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 deleted file mode 100644 index b21004a6..00000000 --- a/dashboards/hubble/l7-http-metrics.json +++ /dev/null @@ -1,1394 +0,0 @@ -{ - "__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 deleted file mode 100644 index cddb473d..00000000 --- a/dashboards/hubble/network-overview.json +++ /dev/null @@ -1,1001 +0,0 @@ -{ - "__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 deleted file mode 100644 index 783aa131..00000000 --- a/dashboards/hubble/overview.json +++ /dev/null @@ -1,3357 +0,0 @@ -{ - "__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 deleted file mode 100644 index c774a314..00000000 --- a/dashboards/mongodb/mongodb-inmemory.json +++ /dev/null @@ -1,1640 +0,0 @@ -{ - "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 deleted file mode 100644 index 558c8490..00000000 --- a/dashboards/mongodb/mongodb-overview.json +++ /dev/null @@ -1,1460 +0,0 @@ -{ - "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 deleted file mode 100644 index d2312e7e..00000000 --- a/dashboards/nats/nats-jetstream.json +++ /dev/null @@ -1,1541 +0,0 @@ -{ - "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 deleted file mode 100644 index 02aa39b2..00000000 --- a/dashboards/nats/nats-server.json +++ /dev/null @@ -1,1463 +0,0 @@ -{ - "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/docs/agents/changelog.md b/docs/agents/changelog.md index 2fde1224..feb70597 100644 --- a/docs/agents/changelog.md +++ b/docs/agents/changelog.md @@ -6,20 +6,6 @@ This file contains detailed instructions for AI-powered IDE on how to generate c 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. @@ -36,7 +22,7 @@ When the user asks to generate a changelog, follow these steps in the specified - [ ] 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**: Check ALL optional repositories (talm, boot-to-talos, cozyhr, cozy-proxy) 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) @@ -162,8 +148,6 @@ Cozystack release may include changes from related repositories. Check and inclu - [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. @@ -211,7 +195,7 @@ Cozystack release may include changes from related repositories. Check and inclu 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!** + **⚠️ MANDATORY: You MUST check ALL optional repositories (talm, boot-to-talos, cozyhr, cozy-proxy). Do NOT skip any repository!** **Use the helper script:** ```bash @@ -224,7 +208,7 @@ Cozystack release may include changes from related repositories. Check and inclu ``` The script will: - - Check ALL optional repositories (talm, boot-to-talos, cozyhr, cozy-proxy, external-apps-example, ansible-cozystack) + - Check ALL optional repositories (talm, boot-to-talos, cozyhr, cozy-proxy) - 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 @@ -585,7 +569,7 @@ Create a new changelog file in the format matching previous versions: - [ ] 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: **ALL** optional repositories (talm, boot-to-talos, cozyhr, cozy-proxy) 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 @@ -622,8 +606,6 @@ Create a new changelog file in the format matching previous versions: **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 @@ -646,7 +628,7 @@ Save the changelog to file `docs/changelogs/v.md` according to the vers - **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**: You MUST check ALL optional repositories (talm, boot-to-talos, cozyhr, cozy-proxy) 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) @@ -655,7 +637,7 @@ Save the changelog to file `docs/changelogs/v.md` according to the vers - **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. + - For **optional repositories** (talm, boot-to-talos, cozyhr, cozy-proxy), 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 diff --git a/docs/agents/contributing.md b/docs/agents/contributing.md index 88b062ea..4a2a7ef9 100644 --- a/docs/agents/contributing.md +++ b/docs/agents/contributing.md @@ -1,140 +1,167 @@ -# Contributing Conventions for AI Agents +# Instructions for AI Agents -Project-side conventions for commits, branches, and pull requests in Cozystack. +Guidelines for AI agents contributing to Cozystack. ## Checklist for Creating a Pull Request -- [ ] Commit message follows Conventional Commits format +- [ ] Changes are made and tested +- [ ] Commit message uses correct `[component]` prefix - [ ] 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 +- [ ] PR is pushed and created with `gh pr create` -## Regenerate Artifacts Before Committing +## How to Commit and Create Pull Requests -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: +### 1. Make Your Changes -- `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. +Edit the necessary files in the codebase. -**Before committing edits to any of those sources**, run `make generate` inside the package and stage the full diff: +### 2. Commit with Proper Format + +Use the `[component]` prefix and `--signoff` flag: ```bash -make -C packages// generate -git add packages/// packages/system/-rd/ +git commit --signoff -m "[component] Brief description of changes" ``` -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. +**Component prefixes:** +- System: `[dashboard]`, `[platform]`, `[cilium]`, `[kube-ovn]`, `[linstor]`, `[fluxcd]`, `[cluster-api]` +- Apps: `[postgres]`, `[mysql]`, `[redis]`, `[kafka]`, `[clickhouse]`, `[virtual-machine]`, `[kubernetes]` +- Other: `[tests]`, `[ci]`, `[docs]`, `[maintenance]` **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" +git commit --signoff -m "[dashboard] Add config hash annotations to restart pods on config changes" +git commit --signoff -m "[postgres] Update operator to version 1.2.3" +git commit --signoff -m "[docs] Add installation guide" ``` -## PR Title Auto-Labeling +### 3. Rebase on upstream/main (if needed) -`.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: +If your branch has extra commits, clean it up: ```bash +# Fetch latest git fetch upstream + +# Create clean branch from upstream/main git checkout -b my-feature upstream/main + +# Cherry-pick only your commit git cherry-pick -git push -f origin my-feature + +# Force push to your branch +git push -f origin my-feature:my-branch-name ``` -## Pull Request Body +### 4. Push Your Branch -Fill in the template at [`.github/PULL_REQUEST_TEMPLATE.md`](../../.github/PULL_REQUEST_TEMPLATE.md). It includes the required `release-note` block. +```bash +git push origin +``` -Create the PR with `gh pr create --title "type(scope): brief description" --body-file `. +### 5. Create Pull Request -## Fetching Unresolved Review Comments +Write the PR body to a temporary file: -Cozystack uses GitHub review threads with resolution status. Only unresolved threads are actionable — resolved threads are already handled. +```bash +cat > /tmp/pr_body.md << 'EOF' +## What this PR does -The REST endpoint `/pulls/{pr}/reviews` returns review summaries, not individual review comments. Use the GraphQL API to access `reviewThreads` with `isResolved` status: +Brief description of the changes. + +Changes: +- Change 1 +- Change 2 + +### Release note + +```release-note +[component] Description for changelog +``` +EOF +``` + +Create the PR: + +```bash +gh pr create --title "[component] Brief description" --body-file /tmp/pr_body.md +``` + +Clean up: + +```bash +rm /tmp/pr_body.md +``` + +## Addressing AI Bot Reviewer Comments + +When the user asks to fix comments from AI bot reviewers (like Qodo, Copilot, etc.): + +### 1. Get PR Comments + +View all comments on the pull request: + +```bash +gh pr view --comments +``` + +Or for the current branch: + +```bash +gh pr view --comments +``` + +### 2. Review Each Comment Carefully + +**Important**: Do NOT blindly apply all suggestions. Each comment should be evaluated: + +- **Consider context** - Does the suggestion make sense for this specific case? +- **Check project conventions** - Does it align with Cozystack patterns? +- **Evaluate impact** - Will this improve code quality or introduce issues? +- **Question validity** - AI bots can be wrong or miss context + +**When to apply:** +- ✅ Legitimate bugs or security issues +- ✅ Clear improvements to code quality +- ✅ Better error handling or edge cases +- ✅ Conformance to project conventions + +**When to skip:** +- ❌ Stylistic preferences that don't match project style +- ❌ Over-engineering simple code +- ❌ Changes that break existing patterns +- ❌ Suggestions that show misunderstanding of the code + +### 3. Apply Valid Fixes + +Make changes addressing the valid comments. Use your judgment. + +### 4. Leave Changes Uncommitted + +**Critical**: Do NOT commit or push the changes automatically. + +Leave the changes in the working directory so the user can: +- Review the fixes +- Decide whether to commit them +- Make additional adjustments if needed + +```bash +# After making changes, show status but DON'T commit +git status +git diff +``` + +The user will commit and push when ready. + +## Code Review Comments + +When asked to fix code review comments, **always work only with unresolved (open) comments**. Resolved comments should be ignored as they have already been addressed. + +### Getting Unresolved Review Comments + +Use GitHub GraphQL API to fetch only unresolved review comments from a pull request: ```bash gh api graphql -F owner=cozystack -F repo=cozystack -F pr= -f query=' @@ -162,7 +189,27 @@ query($owner: String!, $repo: String!, $pr: Int!) { }' --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | .comments.nodes[]' ``` -Compact one-line variant: +### Filtering for Unresolved Comments + +The key filter is `select(.isResolved == false)` which ensures only unresolved review threads are processed. Each thread can contain multiple comments, but if the thread is resolved, all its comments should be ignored. + +### Working with Review Comments + +1. **Fetch unresolved comments** using the GraphQL query above +2. **Parse the results** to identify: + - File path (`path`) + - Line number (`line` or `originalLine`) + - Comment text (`bodyText`) + - Author (`author.login`) +3. **Address each unresolved comment** by: + - Locating the relevant code section + - Making the requested changes + - Ensuring the fix addresses the concern raised +4. **Do NOT process resolved comments** - they have already been handled + +### Example: Compact List of Unresolved Comments + +For a quick overview of unresolved comments: ```bash gh api graphql -F owner=cozystack -F repo=cozystack -F pr= -f query=' @@ -186,3 +233,43 @@ query($owner: String!, $repo: String!, $pr: Int!) { } }' --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | .comments.nodes[] | "\(.path):\(.line // "N/A") - \(.author.login): \(.bodyText[:150])"' ``` + +### Important Notes + +- **REST API limitation**: The REST endpoint `/pulls/{pr}/reviews` returns review summaries, not individual review comments. Use GraphQL API for accessing `reviewThreads` with `isResolved` status. +- **Thread-based resolution**: Comments are organized in threads. If a thread is resolved (`isResolved: true`), ignore all comments in that thread. +- **Always filter**: Never process comments from resolved threads, even if they appear in the results. + +### Example Workflow + +```bash +# Get PR comments +gh pr view 1234 --comments + +# Review comments and identify valid ones +# Make necessary changes to address valid comments +# ... edit files ... + +# Show what was changed (but don't commit) +git status +git diff + +# Tell the user what was fixed and what was skipped +``` + +## Git Permissions + +Request these permissions when needed: +- `git_write` - For commit, rebase, cherry-pick, branch operations +- `network` - For push, fetch, pull operations + +## Common Issues + +**PR has extra commits?** +→ Rebase on `upstream/main` and cherry-pick only your commits + +**Wrong commit message?** +→ `git commit --amend --signoff -m "[correct] message"` then `git push -f` + +**Need to update PR?** +→ `gh pr edit --body "new description"` diff --git a/docs/agents/overview.md b/docs/agents/overview.md index ae0fd1c4..b6d69e68 100644 --- a/docs/agents/overview.md +++ b/docs/agents/overview.md @@ -78,18 +78,11 @@ packages/// - Add proper error handling and structured logging ### Git Commits -- Follow [Conventional Commits](https://www.conventionalcommits.org/) format: `type(scope): description` +- Use format: `[component] 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. +- Follow conventional commit format for changelogs ### Documentation diff --git a/docs/changelogs/v0.37.10.md b/docs/changelogs/v0.37.10.md deleted file mode 100644 index 18f0dd8b..00000000 --- a/docs/changelogs/v0.37.10.md +++ /dev/null @@ -1,16 +0,0 @@ - - -## 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.38.5.md b/docs/changelogs/v0.38.5.md deleted file mode 100644 index 0cae8b2a..00000000 --- a/docs/changelogs/v0.38.5.md +++ /dev/null @@ -1,18 +0,0 @@ - - -## 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 deleted file mode 100644 index 9c39b66d..00000000 --- a/docs/changelogs/v0.38.6.md +++ /dev/null @@ -1,12 +0,0 @@ - - -## 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 deleted file mode 100644 index 3edfd94c..00000000 --- a/docs/changelogs/v0.38.7.md +++ /dev/null @@ -1,13 +0,0 @@ - - -## 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 deleted file mode 100644 index 0dbfe7b8..00000000 --- a/docs/changelogs/v0.38.8.md +++ /dev/null @@ -1,12 +0,0 @@ - - -## 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.2.md b/docs/changelogs/v0.39.2.md deleted file mode 100644 index dacb094f..00000000 --- a/docs/changelogs/v0.39.2.md +++ /dev/null @@ -1,19 +0,0 @@ - - -## 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 deleted file mode 100644 index f493795b..00000000 --- a/docs/changelogs/v0.39.3.md +++ /dev/null @@ -1,36 +0,0 @@ - - -## 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 deleted file mode 100644 index 36d9f016..00000000 --- a/docs/changelogs/v0.39.4.md +++ /dev/null @@ -1,12 +0,0 @@ - - -## 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 deleted file mode 100644 index de352b1c..00000000 --- a/docs/changelogs/v0.39.5.md +++ /dev/null @@ -1,11 +0,0 @@ - - -## 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 deleted file mode 100644 index caaa08f6..00000000 --- a/docs/changelogs/v0.40.0.md +++ /dev/null @@ -1,206 +0,0 @@ -# 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 deleted file mode 100644 index ee718b47..00000000 --- a/docs/changelogs/v0.40.1.md +++ /dev/null @@ -1,11 +0,0 @@ - - -## 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 deleted file mode 100644 index 5c686b92..00000000 --- a/docs/changelogs/v0.40.2.md +++ /dev/null @@ -1,15 +0,0 @@ - - -## 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 deleted file mode 100644 index a62a70bc..00000000 --- a/docs/changelogs/v0.40.3.md +++ /dev/null @@ -1,15 +0,0 @@ - - -## 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 deleted file mode 100644 index ec175486..00000000 --- a/docs/changelogs/v0.40.4.md +++ /dev/null @@ -1,23 +0,0 @@ - - -## 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 deleted file mode 100644 index 40ebd107..00000000 --- a/docs/changelogs/v0.40.5.md +++ /dev/null @@ -1,15 +0,0 @@ - - -## 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 deleted file mode 100644 index 40e499f5..00000000 --- a/docs/changelogs/v0.40.6.md +++ /dev/null @@ -1,11 +0,0 @@ - - -## 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 deleted file mode 100644 index f1b7a52e..00000000 --- a/docs/changelogs/v0.40.7.md +++ /dev/null @@ -1,11 +0,0 @@ - - -## 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 deleted file mode 100644 index 3084e493..00000000 --- a/docs/changelogs/v0.41.0.md +++ /dev/null @@ -1,63 +0,0 @@ - - -# 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 deleted file mode 100644 index d084d644..00000000 --- a/docs/changelogs/v0.41.1.md +++ /dev/null @@ -1,11 +0,0 @@ - - -## 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 deleted file mode 100644 index 8b3a8261..00000000 --- a/docs/changelogs/v0.41.2.md +++ /dev/null @@ -1,13 +0,0 @@ - - -## 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 deleted file mode 100644 index 6d04dad3..00000000 --- a/docs/changelogs/v0.41.3.md +++ /dev/null @@ -1,15 +0,0 @@ - - -## 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 deleted file mode 100644 index 70f1daeb..00000000 --- a/docs/changelogs/v0.41.4.md +++ /dev/null @@ -1,11 +0,0 @@ - - -## 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 deleted file mode 100644 index fb96fcf4..00000000 --- a/docs/changelogs/v0.41.5.md +++ /dev/null @@ -1,21 +0,0 @@ - - -## 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 deleted file mode 100644 index 8e7783df..00000000 --- a/docs/changelogs/v0.41.6.md +++ /dev/null @@ -1,17 +0,0 @@ - - -## 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 deleted file mode 100644 index 5a77664d..00000000 --- a/docs/changelogs/v0.41.7.md +++ /dev/null @@ -1,15 +0,0 @@ - - -## 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 deleted file mode 100644 index 9984c87d..00000000 --- a/docs/changelogs/v0.41.8.md +++ /dev/null @@ -1,17 +0,0 @@ - - -## 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 deleted file mode 100644 index d0cd3ff9..00000000 --- a/docs/changelogs/v0.41.9.md +++ /dev/null @@ -1,15 +0,0 @@ - - -## 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 deleted file mode 100644 index 4411b35f..00000000 --- a/docs/changelogs/v1.0.0-alpha.1.md +++ /dev/null @@ -1,134 +0,0 @@ -# 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 deleted file mode 100644 index 14bd89a2..00000000 --- a/docs/changelogs/v1.0.0-alpha.2.md +++ /dev/null @@ -1,71 +0,0 @@ - - -> **⚠️ 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 deleted file mode 100644 index 45d654a7..00000000 --- a/docs/changelogs/v1.0.0-beta.3.md +++ /dev/null @@ -1,144 +0,0 @@ - - -> **⚠️ 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 deleted file mode 100644 index c5694a73..00000000 --- a/docs/changelogs/v1.0.0-beta.4.md +++ /dev/null @@ -1,96 +0,0 @@ - - -> **⚠️ 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 deleted file mode 100644 index b8bc306c..00000000 --- a/docs/changelogs/v1.0.0-beta.5.md +++ /dev/null @@ -1,36 +0,0 @@ - - -> **⚠️ 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 deleted file mode 100644 index 99e565d7..00000000 --- a/docs/changelogs/v1.0.0-beta.6.md +++ /dev/null @@ -1,46 +0,0 @@ - - -> **⚠️ 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 deleted file mode 100644 index 0fabe1b6..00000000 --- a/docs/changelogs/v1.0.0-rc.1.md +++ /dev/null @@ -1,65 +0,0 @@ - - -> **⚠️ 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 deleted file mode 100644 index a056ff8f..00000000 --- a/docs/changelogs/v1.0.0-rc.2.md +++ /dev/null @@ -1,57 +0,0 @@ - - -> **⚠️ 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 deleted file mode 100644 index 469ea1db..00000000 --- a/docs/changelogs/v1.0.0.md +++ /dev/null @@ -1,289 +0,0 @@ - - -# 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 deleted file mode 100644 index 2faf2755..00000000 --- a/docs/changelogs/v1.0.1.md +++ /dev/null @@ -1,21 +0,0 @@ - - -## 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 deleted file mode 100644 index fad9275e..00000000 --- a/docs/changelogs/v1.0.2.md +++ /dev/null @@ -1,19 +0,0 @@ - - -## 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 deleted file mode 100644 index 27ae6720..00000000 --- a/docs/changelogs/v1.0.3.md +++ /dev/null @@ -1,17 +0,0 @@ - - -## 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 deleted file mode 100644 index 4c55e2f3..00000000 --- a/docs/changelogs/v1.0.4.md +++ /dev/null @@ -1,25 +0,0 @@ - - -## 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 deleted file mode 100644 index 51f01143..00000000 --- a/docs/changelogs/v1.0.5.md +++ /dev/null @@ -1,29 +0,0 @@ - - -## 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 deleted file mode 100644 index c65c5fd5..00000000 --- a/docs/changelogs/v1.0.6.md +++ /dev/null @@ -1,21 +0,0 @@ - - -## 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 deleted file mode 100644 index 942115bf..00000000 --- a/docs/changelogs/v1.0.7.md +++ /dev/null @@ -1,27 +0,0 @@ - - -## 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 deleted file mode 100644 index ad61c1a6..00000000 --- a/docs/changelogs/v1.1.0.md +++ /dev/null @@ -1,126 +0,0 @@ - - -# 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 deleted file mode 100644 index 18bb6814..00000000 --- a/docs/changelogs/v1.1.1.md +++ /dev/null @@ -1,23 +0,0 @@ - - -## 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 deleted file mode 100644 index 29dba321..00000000 --- a/docs/changelogs/v1.1.2.md +++ /dev/null @@ -1,25 +0,0 @@ - - -## 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 deleted file mode 100644 index f589476e..00000000 --- a/docs/changelogs/v1.1.3.md +++ /dev/null @@ -1,19 +0,0 @@ - - -## 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 deleted file mode 100644 index f1e4ede9..00000000 --- a/docs/changelogs/v1.1.4.md +++ /dev/null @@ -1,41 +0,0 @@ - - -## 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 deleted file mode 100644 index e756bdd9..00000000 --- a/docs/changelogs/v1.1.5.md +++ /dev/null @@ -1,13 +0,0 @@ - - -## 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 deleted file mode 100644 index 77c49475..00000000 --- a/docs/changelogs/v1.1.6.md +++ /dev/null @@ -1,19 +0,0 @@ - - -## 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 deleted file mode 100644 index 7c5b5e24..00000000 --- a/docs/changelogs/v1.2.0.md +++ /dev/null @@ -1,204 +0,0 @@ - - -# 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 deleted file mode 100644 index 29e3fdf6..00000000 --- a/docs/changelogs/v1.2.1.md +++ /dev/null @@ -1,31 +0,0 @@ - - -## 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 deleted file mode 100644 index 2b6a1ae5..00000000 --- a/docs/changelogs/v1.2.2.md +++ /dev/null @@ -1,63 +0,0 @@ - - -## 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 deleted file mode 100644 index 6d1b3b74..00000000 --- a/docs/changelogs/v1.2.3.md +++ /dev/null @@ -1,58 +0,0 @@ - - -# 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 deleted file mode 100644 index 9b63c106..00000000 --- a/docs/changelogs/v1.3.0-rc.1.md +++ /dev/null @@ -1,173 +0,0 @@ - - -# 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 deleted file mode 100644 index 60c800a8..00000000 --- a/docs/changelogs/v1.3.0.md +++ /dev/null @@ -1,238 +0,0 @@ - - -# 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 deleted file mode 100644 index 0f149d0d..00000000 --- a/docs/changelogs/v1.3.1.md +++ /dev/null @@ -1,37 +0,0 @@ - - -# 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 deleted file mode 100644 index 33597eec..00000000 --- a/docs/hubble-observability.md +++ /dev/null @@ -1,99 +0,0 @@ -# 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 deleted file mode 100755 index 38405495..00000000 --- a/examples/backups/vmi/00-helpers.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/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 deleted file mode 100755 index 78aa34d3..00000000 --- a/examples/backups/vmi/01-create-strategies.sh +++ /dev/null @@ -1,145 +0,0 @@ -#!/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 deleted file mode 100755 index 08c29fc1..00000000 --- a/examples/backups/vmi/02-create-backupclass.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/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 deleted file mode 100755 index 581490a4..00000000 --- a/examples/backups/vmi/05-create-backupjob.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/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 deleted file mode 100755 index 9b84ce55..00000000 --- a/examples/backups/vmi/07-restore-to-copy.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/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 deleted file mode 100755 index 5965c3f0..00000000 --- a/examples/backups/vmi/cleanup.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/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 deleted file mode 100755 index b58f4b9d..00000000 --- a/examples/backups/vmi/run-all.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/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 deleted file mode 100644 index edfca5d1..00000000 --- a/examples/backups/vmi/scenario-admin-prepare.md +++ /dev/null @@ -1,73 +0,0 @@ -# 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 deleted file mode 100644 index 31241fd9..00000000 --- a/examples/backups/vmi/scenario-user-backup.md +++ /dev/null @@ -1,91 +0,0 @@ -# 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 deleted file mode 100644 index 1d35b22b..00000000 --- a/examples/backups/vmi/scenario-user-restore.md +++ /dev/null @@ -1,101 +0,0 @@ -# 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 7b7d5bc4..8a2156cb 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ module github.com/cozystack/cozystack go 1.25.0 require ( - 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 @@ -18,8 +17,8 @@ require ( 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 + gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.34.1 k8s.io/apiextensions-apiserver v0.34.1 k8s.io/apimachinery v0.34.2 @@ -29,10 +28,8 @@ require ( k8s.io/klog/v2 v2.130.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 + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 ) require ( @@ -47,6 +44,7 @@ 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.12.2 // indirect + github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fluxcd/pkg/apis/acl v0.9.0 // indirect @@ -82,8 +80,8 @@ require ( 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_model v0.6.2 // indirect - github.com/prometheus/common v0.65.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/spf13/pflag v1.0.7 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect @@ -92,14 +90,14 @@ require ( 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/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect + go.opentelemetry.io/otel v1.35.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/otel/metric v1.35.0 // indirect + go.opentelemetry.io/otel/sdk v1.34.0 // indirect + go.opentelemetry.io/otel/trace v1.35.0 // indirect go.opentelemetry.io/proto/otlp v1.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect @@ -107,18 +105,18 @@ require ( golang.org/x/crypto v0.42.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/net v0.45.0 // indirect - golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/oauth2 v0.29.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/time v0.11.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-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 + google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect + google.golang.org/grpc v1.72.1 // indirect + google.golang.org/protobuf v1.36.5 // 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 @@ -127,6 +125,8 @@ require ( 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 + sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect ) // See: issues.k8s.io/135537 diff --git a/go.sum b/go.sum index 81e1779f..11aad32d 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,6 @@ github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8 github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 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= @@ -83,6 +81,7 @@ 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.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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= @@ -145,10 +144,10 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/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.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= 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/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= @@ -180,8 +179,6 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu 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-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk= @@ -204,24 +201,24 @@ 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/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= 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/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= 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= @@ -249,8 +246,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 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/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98= +golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= 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= @@ -267,8 +264,8 @@ 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.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/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= +golang.org/x/time v0.11.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= @@ -281,14 +278,14 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T 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/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= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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= @@ -298,6 +295,8 @@ 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.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= @@ -321,15 +320,17 @@ k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d h1:wAhiDyZ4Tdtt7e46e9M5ZSAJ/MnPG 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 v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= 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/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= 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.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= 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 deleted file mode 100644 index a4b98b00..00000000 --- a/hack/admin-kubeconfig-invariant.bats +++ /dev/null @@ -1,145 +0,0 @@ -#!/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 f19f9970..be1558d0 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 deleted file mode 100644 index b121b31b..00000000 --- a/hack/check-host-runtime.bats +++ /dev/null @@ -1,415 +0,0 @@ -#!/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 deleted file mode 100755 index 917453d2..00000000 --- a/hack/check-host-runtime.sh +++ /dev/null @@ -1,161 +0,0 @@ -#!/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-readiness.sh b/hack/check-readiness.sh deleted file mode 100755 index bd3a3ffc..00000000 --- a/hack/check-readiness.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/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/cozyreport.sh b/hack/cozyreport.sh index 565fd435..3174ed50 100755 --- a/hack/cozyreport.sh +++ b/hack/cozyreport.sh @@ -56,33 +56,13 @@ kubectl get hr -A --no-headers | 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} {.spec.initContainers[*].name}' -n $NAMESPACE $NAME) + CONTAINERS=$(kubectl get pod -o jsonpath='{.spec.containers[*].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 diff --git a/hack/cozytest.sh b/hack/cozytest.sh index a3955fd1..ff476e08 100755 --- a/hack/cozytest.sh +++ b/hack/cozytest.sh @@ -10,11 +10,7 @@ PATTERN=${2:-*} LINE='----------------------------------------------------------------' cols() { stty size 2>/dev/null | awk '{print $2}' || echo 80; } -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 +MAXW=$(( $(cols) - 12 )); [ "$MAXW" -lt 40 ] && MAXW=70 BEGIN=$(date +%s) timestamp() { s=$(( $(date +%s) - BEGIN )); printf '[%02d:%02d]' $((s/60)) $((s%60)); } @@ -49,7 +45,7 @@ run_one() { *) out=$line ;; esac now=$(( $(date +%s) - START )) - [ "$MAXW" -gt 0 ] && [ ${#out} -gt "$MAXW" ] && out="$(printf '%.*s…' "$MAXW" "$out")" + [ ${#out} -gt "$MAXW" ] && out="$(printf '%.*s…' "$MAXW" "$out")" printf '┊[%02d:%02d] %s\n' $((now/60)) $((now%60)) "$out" done @@ -65,7 +61,6 @@ run_one() { echo "----- captured output -----------------------------------------" grep -v '^__RC__' "$log" echo "$LINE" - rm -rf "$tmp" exit "$rc" fi diff --git a/hack/dcgm-default-counters.csv b/hack/dcgm-default-counters.csv deleted file mode 100644 index b5e94540..00000000 --- a/hack/dcgm-default-counters.csv +++ /dev/null @@ -1,104 +0,0 @@ -# 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 d761f71c..a1a6082a 100755 --- a/hack/download-dashboards.sh +++ b/hack/download-dashboards.sh @@ -83,8 +83,6 @@ modules/340-monitoring-kubernetes/monitoring/grafana-dashboards//flux/flux-stats 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 deleted file mode 100755 index 0a5c13d9..00000000 --- a/hack/e2e-apps/backup.bats.disabled +++ /dev/null @@ -1,226 +0,0 @@ -#!/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 index 31e7efb0..2621812a 100644 --- a/hack/e2e-apps/bucket.bats +++ b/hack/e2e-apps/bucket.bats @@ -1,39 +1,29 @@ #!/usr/bin/env bats @test "Create and Verify Seeweedfs Bucket" { - # Create the bucket resource with readwrite and readonly users + # Create the bucket resource 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 and decode credentials + kubectl -n tenant-test get secret bucket-${name} -ojsonpath='{.data.BucketInfo}' | base64 -d > bucket-test-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) + # Get credentials from the secret + ACCESS_KEY=$(jq -r '.spec.secretS3.accessKeyID' bucket-test-credentials.json) + SECRET_KEY=$(jq -r '.spec.secretS3.accessSecretKey' bucket-test-credentials.json) + BUCKET_NAME=$(jq -r '.spec.bucketName' bucket-test-credentials.json) # Start port-forwarding bash -c 'timeout 100s kubectl port-forward service/seaweedfs-s3 -n tenant-root 8333:8333 > /dev/null 2>&1 &' @@ -41,33 +31,17 @@ EOF # 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 + # Set up MinIO alias with error handling + mc alias set local https://localhost:8333 $ACCESS_KEY $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 + # Upload file to bucket + mc cp bucket-test-credentials.json $BUCKET_NAME/bucket-test-credentials.json - # Admin can list - mc ls --insecure rw-user/$BUCKET_NAME/rw-test.txt + # Verify file was uploaded + mc ls $BUCKET_NAME/bucket-test-credentials.json - # Admin can download - mc cp --insecure rw-user/$BUCKET_NAME/rw-test.txt /tmp/rw-test-download.txt + # Clean up uploaded file + mc rm $BUCKET_NAME/bucket-test-credentials.json - # --- 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 fbc9f906..1684c0c4 100644 --- a/hack/e2e-apps/clickhouse.bats +++ b/hack/e2e-apps/clickhouse.bats @@ -2,7 +2,6 @@ @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 - <" + s3SecretKey: "" + schedule: "0 2 * * * *" + bootstrap: + enabled: false + external: false + quorum: + maxSyncReplicas: 0 + minSyncReplicas: 0 + replicas: 2 + resources: {} + resourcesPreset: "micro" + size: "10Gi" + users: + testuser: + password: xai7Wepo +EOF + sleep 5 + kubectl -n tenant-test wait hr ferretdb-$name --timeout=100s --for=condition=ready + timeout 40 sh -ec "until kubectl -n tenant-test get svc ferretdb-$name-postgres-r -o jsonpath='{.spec.ports[0].port}' | grep -q '5432'; do sleep 10; done" + timeout 40 sh -ec "until kubectl -n tenant-test get svc ferretdb-$name-postgres-ro -o jsonpath='{.spec.ports[0].port}' | grep -q '5432'; do sleep 10; done" + timeout 40 sh -ec "until kubectl -n tenant-test get svc ferretdb-$name-postgres-rw -o jsonpath='{.spec.ports[0].port}' | grep -q '5432'; do sleep 10; done" + timeout 120 sh -ec "until kubectl -n tenant-test get endpoints ferretdb-$name-postgres-r -o jsonpath='{.subsets[*].addresses[*].ip}' | grep -q '[0-9]'; do sleep 10; done" + # for some reason it takes longer for the read-only endpoint to be ready + #timeout 120 sh -ec "until kubectl -n tenant-test get endpoints ferretdb-$name-postgres-ro -o jsonpath='{.subsets[*].addresses[*].ip}' | grep -q '[0-9]'; do sleep 10; done" + timeout 120 sh -ec "until kubectl -n tenant-test get endpoints ferretdb-$name-postgres-rw -o jsonpath='{.subsets[*].addresses[*].ip}' | grep -q '[0-9]'; do sleep 10; done" + kubectl -n tenant-test delete ferretdb.apps.cozystack.io $name +} diff --git a/hack/e2e-apps/foundationdb.bats b/hack/e2e-apps/foundationdb.bats index 199bda11..4c8d1b53 100644 --- a/hack/e2e-apps/foundationdb.bats +++ b/hack/e2e-apps/foundationdb.bats @@ -2,7 +2,6 @@ @test "Create DB FoundationDB" { name='test' - kubectl -n tenant-test delete foundationdb.apps.cozystack.io $name --ignore-not-found --timeout=2m || true kubectl apply -f - </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 d85837bd..ceaf2cde 100644 --- a/hack/e2e-apps/kafka.bats +++ b/hack/e2e-apps/kafka.bats @@ -2,8 +2,6 @@ @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 b86bc664..024ce086 100644 --- a/hack/e2e-apps/postgres.bats +++ b/hack/e2e-apps/postgres.bats @@ -2,7 +2,6 @@ @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}" + kubectl get secret kubernetes-${test_name}-admin-kubeconfig -ojsonpath='{.data.super-admin\.conf}' -n tenant-test | base64 -d > 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}" + 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' + # Set up port forwarding to the Kubernetes API server for a 200 second timeout + bash -c 'timeout 500s kubectl port-forward service/kubernetes-'"${test_name}"' -n tenant-test '"${port}"':6443 > /dev/null 2>&1 &' # 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' + timeout 20 sh -ec 'until kubectl --kubeconfig tenantkubeconfig-'"${test_name}"' version 2>/dev/null | grep -Fq "Server Version: ${k8s_version}"; do sleep 5; 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 + # Wait for the nodes to be ready (timeout after 2 minutes) + timeout 3m bash -c ' + until [ "$(kubectl --kubeconfig tenantkubeconfig-'"${test_name}"' get nodes -o jsonpath="{.items[*].metadata.name}" | wc -w)" -eq 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 + kubectl --kubeconfig tenantkubeconfig-${test_name} wait node --all --timeout=2m --for=condition=Ready + 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}"-*) @@ -143,21 +125,15 @@ EOF fi - kubectl --kubeconfig "tenantkubeconfig-${test_name}" apply -f - <&2 - exit 1 - fi +if [ -z "$LB_ADDR" ]; then + echo "LoadBalancer address is empty" >&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 + curl --silent --fail "http://${LB_ADDR}" && break sleep 3 done - if [ "$lb_ok" != true ]; then + if [ "$i" -eq 20 ]; 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 + 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 # 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 + for component in cilium coredns csi ingress-nginx 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 + # Clean up by deleting the Kubernetes resource + kubectl -n tenant-test delete kuberneteses.apps.cozystack.io $test_name } diff --git a/hack/e2e-apps/virtualmachine.bats b/hack/e2e-apps/virtualmachine.bats new file mode 100644 index 00000000..33e87b53 --- /dev/null +++ b/hack/e2e-apps/virtualmachine.bats @@ -0,0 +1,45 @@ +#!/usr/bin/env bats + +@test "Create a Virtual Machine" { + name='test' + kubectl apply -f - <&2 +@test "Required installer assets exist" { + if [ ! -f _out/assets/cozystack-installer.yaml ]; then + echo "Missing: _out/assets/cozystack-installer.yaml" >&2 exit 1 fi } @test "Install Cozystack" { - # 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 + # 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 - - # Verify the operator deployment is available - kubectl wait deployment/cozystack-operator -n cozy-system --timeout=1m --for=condition=Available + # Apply installer manifests from file + kubectl apply -f _out/assets/cozystack-installer.yaml - # 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' + timeout 60 sh -ec 'until kubectl get hr -A -l cozystack.io/system-app=true | grep -q cozys; do sleep 1; done' sleep 5 - kubectl get hr -A | awk 'NR>1 {print "kubectl wait --timeout=15m --for=condition=ready -n "$1" hr/"$2" &"} END {print "wait"}' | sh -ex + 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 # Fail the test if any HelmRelease is not Ready if kubectl get hr -A | grep -v " True " | grep -v NAME; then @@ -65,8 +40,8 @@ EOF @test "Wait for Cluster‑API provider deployments" { # Wait for Cluster‑API provider deployments - 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 + timeout 60 sh -ec 'until kubectl get deploy -n cozy-cluster-api capi-controller-manager capi-kamaji-controller-manager capi-kubeadm-bootstrap-controller-manager capi-operator-cluster-api-operator capk-controller-manager >/dev/null 2>&1; do sleep 1; done' + kubectl wait deployment/capi-controller-manager deployment/capi-kamaji-controller-manager deployment/capi-kubeadm-bootstrap-controller-manager deployment/capi-operator-cluster-api-operator deployment/capk-controller-manager -n cozy-cluster-api --timeout=1m --for=condition=available } @test "Wait for LINSTOR and configure storage" { @@ -167,7 +142,7 @@ EOF # Expose Cozystack services through ingress - kubectl patch package cozystack.cozystack-platform --type merge -p '{"spec":{"components":{"platform":{"values":{"publishing":{"exposedServices":["api","dashboard","cdi-uploadproxy","vm-exportproxy","keycloak"]}}}}}}' + kubectl patch configmap/cozystack -n cozy-system --type merge -p '{"data":{"expose-services":"api,dashboard,cdi-uploadproxy,vm-exportproxy,keycloak"}}' # NGINX ingress controller timeout 60 sh -ec 'until kubectl get deploy root-ingress-controller -n tenant-root >/dev/null 2>&1; do sleep 1; done' @@ -178,8 +153,8 @@ EOF # VictoriaMetrics components 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 + kubectl wait vlogs/generic -n tenant-root --for=jsonpath='{.status.updateStatus}'=operational --timeout=5m + kubectl wait vmcluster/shortterm vmcluster/longterm -n tenant-root --for=jsonpath='{.status.clusterStatus}'=operational --timeout=5m # Grafana kubectl wait clusters.postgresql.cnpg.io/grafana-db -n tenant-root --for=condition=ready --timeout=5m @@ -194,66 +169,14 @@ EOF } @test "Keycloak OIDC stack is healthy" { - kubectl patch package cozystack.cozystack-platform --type merge -p '{"spec":{"components":{"platform":{"values":{"authentication":{"oidc":{"enabled":true}}}}}}}' + kubectl patch configmap/cozystack -n cozy-system --type merge -p '{"data":{"oidc-enabled":"true"}}' timeout 120 sh -ec 'until kubectl get hr -n cozy-keycloak keycloak keycloak-configure keycloak-operator >/dev/null 2>&1; do sleep 1; done' kubectl wait hr/keycloak hr/keycloak-configure hr/keycloak-operator -n cozy-keycloak --timeout=10m --for=condition=ready } -@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 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 180 sh -ec 'until talosctl etcd members -n 192.168.123.11,192.168.123.12,192.168.123.13 -e 192.168.123.10 >/dev/null 2>&1; do sleep 1; done' timeout 60 sh -ec 'while talosctl etcd members -n 192.168.123.11,192.168.123.12,192.168.123.13 -e 192.168.123.10 2>&1 | grep -q "rpc error"; do sleep 1; done' # Retrieve kubeconfig diff --git a/hack/migrate-to-version-1.0.sh b/hack/migrate-to-version-1.0.sh deleted file mode 100755 index a7c3f9b4..00000000 --- a/hack/migrate-to-version-1.0.sh +++ /dev/null @@ -1,263 +0,0 @@ -#!/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 -} - -@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 f3a47e78..3b2af7d9 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -19,14 +19,14 @@ set -o nounset set -o pipefail SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -CODEGEN_PKG=${CODEGEN_PKG:-~/go/pkg/mod/k8s.io/code-generator@v0.34.1} +CODEGEN_PKG=${CODEGEN_PKG:-$(cd "${SCRIPT_ROOT}"; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)} 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 +OPERATOR_CRDDIR=packages/core/installer/definitions COZY_CONTROLLER_CRDDIR=packages/system/cozystack-controller/definitions -COZY_RD_CRDDIR=packages/system/application-definition-crd/definition +COZY_RD_CRDDIR=packages/system/cozystack-resource-definition-crd/definition BACKUPS_CORE_CRDDIR=packages/system/backup-controller/definitions BACKUPSTRATEGY_CRDDIR=packages/system/backupstrategy-controller/definitions @@ -34,7 +34,7 @@ trap 'rm -rf ${TMPDIR}' EXIT source "${CODEGEN_PKG}/kube_codegen.sh" -THIS_PKG="github.com/cozystack/cozystack" +THIS_PKG="k8s.io/sample-apiserver" kube::codegen::gen_helpers \ --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \ @@ -60,32 +60,16 @@ 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/v1alpha1/..." paths="./api/backups/..." paths="./api/dashboard/..." output:crd:artifacts:config=${TMPDIR} +$CONTROLLER_GEN rbac:roleName=manager-role crd paths="./api/..." 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}/cozystack.io_cozystackresourcedefinitions.yaml \ + ${COZY_RD_CRDDIR}/cozystack.io_cozystackresourcedefinitions.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 index 81172406..b619b220 100755 --- a/hack/update-crd.sh +++ b/hack/update-crd.sh @@ -65,21 +65,12 @@ case "$PWD" in *"/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" <-" or "" for extra -# - chartRef points to ExternalArtifact created by Package controller +# - labels ensure cozystack.io/ui: "true" +# - prefix = "-" +# - sourceRef derived from directory (apps|extra) yq -i ' .apiVersion = (.apiVersion // "cozystack.io/v1alpha1") | - .kind = (.kind // "ApplicationDefinition") | + .kind = (.kind // "CozystackResourceDefinition") | .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.release.labels."cozystack.io/ui" = "true" | + .spec.release.chart.name = strenv(RES_NAME) | + .spec.release.chart.sourceRef.kind = "HelmRepository" | + .spec.release.chart.sourceRef.name = strenv(SOURCE_NAME) | + .spec.release.chart.sourceRef.namespace = "cozy-public" | .spec.dashboard.description = strenv(DESCRIPTION) | .spec.dashboard.icon = strenv(ICON_B64) | .spec.dashboard.keysOrder = env(KEYS_ORDER) diff --git a/hack/upload-assets.sh b/hack/upload-assets.sh index 2f7f9813..9788c04f 100755 --- a/hack/upload-assets.sh +++ b/hack/upload-assets.sh @@ -3,15 +3,9 @@ set -xe version=${VERSION:-$(git describe --tags)} -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/cozystack-installer.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/internal/backupcontroller/backup_controller.go b/internal/backupcontroller/backup_controller.go deleted file mode 100644 index 486a24ae..00000000 --- a/internal/backupcontroller/backup_controller.go +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index a1449c49..00000000 --- a/internal/backupcontroller/backupclass_resolver.go +++ /dev/null @@ -1,75 +0,0 @@ -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 deleted file mode 100644 index cd65f22a..00000000 --- a/internal/backupcontroller/backupclass_resolver_test.go +++ /dev/null @@ -1,371 +0,0 @@ -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 index b926722f..c16a0ec1 100644 --- a/internal/backupcontroller/backupjob_controller.go +++ b/internal/backupcontroller/backupjob_controller.go @@ -2,141 +2,52 @@ 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. +// BackupVeleroStrategyReconciler reconciles BackupJob with a strategy referencing +// Velero.strategy.backups.cozystack.io objects. type BackupJobReconciler struct { client.Client - dynamic.Interface - meta.RESTMapper - Scheme *runtime.Scheme - Recorder record.EventRecorder + Scheme *runtime.Scheme } 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) - + _ = log.FromContext(ctx) 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) + if j.Spec.StrategyRef.APIGroup == nil || *j.Spec.StrategyRef.APIGroup != strategyv1alpha1.GroupVersion.Group { 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 { + switch j.Spec.StrategyRef.Kind { case strategyv1alpha1.JobStrategyKind: - return r.reconcileJob(ctx, j, resolved) + return r.reconcileJob(ctx, j) case strategyv1alpha1.VeleroStrategyKind: - return r.reconcileVelero(ctx, j, resolved) + return r.reconcileVelero(ctx, j) 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 index 1c51d434..722e5d99 100644 --- a/internal/backupcontroller/factory/backupjob.go +++ b/internal/backupcontroller/factory/backupjob.go @@ -10,9 +10,6 @@ import ( ) 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), @@ -22,8 +19,9 @@ func BackupJob(p *backupsv1alpha1.Plan, scheduledFor time.Time) *backupsv1alpha1 PlanRef: &corev1.LocalObjectReference{ Name: p.Name, }, - ApplicationRef: appRef, - BackupClassName: p.Spec.BackupClassName, + ApplicationRef: *p.Spec.ApplicationRef.DeepCopy(), + StorageRef: *p.Spec.StorageRef.DeepCopy(), + StrategyRef: *p.Spec.StrategyRef.DeepCopy(), }, } return job diff --git a/internal/backupcontroller/factory/backupjob_test.go b/internal/backupcontroller/factory/backupjob_test.go deleted file mode 100644 index afe1f155..00000000 --- a/internal/backupcontroller/factory/backupjob_test.go +++ /dev/null @@ -1,167 +0,0 @@ -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 index aaa54c19..e52e38f2 100644 --- a/internal/backupcontroller/jobstrategy_controller.go +++ b/internal/backupcontroller/jobstrategy_controller.go @@ -9,13 +9,7 @@ import ( 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) { +func (r *BackupJobReconciler) reconcileJob(ctx context.Context, j *backupsv1alpha1.BackupJob) (ctrl.Result, error) { _ = log.FromContext(ctx) return ctrl.Result{}, nil } diff --git a/internal/backupcontroller/plan_controller.go b/internal/backupcontroller/plan_controller.go index 4945802d..046fdce4 100644 --- a/internal/backupcontroller/plan_controller.go +++ b/internal/backupcontroller/plan_controller.go @@ -20,8 +20,8 @@ import ( ) const ( - minRequeueDelay = 30 * time.Second - startingDeadline = 300 * time.Second + minRequeueDelay = 30 * time.Second + startingDeadlineSeconds = 300 * time.Second ) // PlanReconciler reconciles a Plan object @@ -45,7 +45,7 @@ func (r *PlanReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl. return ctrl.Result{}, err } - tCheck := time.Now().Add(-startingDeadline) + tCheck := time.Now().Add(-startingDeadlineSeconds) 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) @@ -78,7 +78,7 @@ func (r *PlanReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl. tNext := sch.Next(tCheck) if time.Now().Before(tNext) { - return ctrl.Result{RequeueAfter: time.Until(tNext)}, nil + return ctrl.Result{RequeueAfter: tNext.Sub(time.Now())}, nil } job := factory.BackupJob(p, tNext) @@ -88,12 +88,12 @@ func (r *PlanReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl. if err := r.Create(ctx, job); err != nil { if apierrors.IsAlreadyExists(err) { - return ctrl.Result{RequeueAfter: startingDeadline}, nil + return ctrl.Result{RequeueAfter: startingDeadlineSeconds}, nil } return ctrl.Result{}, err } - return ctrl.Result{RequeueAfter: startingDeadline}, nil + return ctrl.Result{RequeueAfter: startingDeadlineSeconds}, nil } // SetupWithManager registers our controller with the Manager and sets up watches. diff --git a/internal/backupcontroller/restorejob_controller.go b/internal/backupcontroller/restorejob_controller.go deleted file mode 100644 index f0062064..00000000 --- a/internal/backupcontroller/restorejob_controller.go +++ /dev/null @@ -1,194 +0,0 @@ -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 index 8b063519..85049b7b 100644 --- a/internal/backupcontroller/velerostrategy_controller.go +++ b/internal/backupcontroller/velerostrategy_controller.go @@ -2,1480 +2,14 @@ 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() +func (r *BackupJobReconciler) reconcileVelero(ctx context.Context, j *backupsv1alpha1.BackupJob) (ctrl.Result, error) { + _ = log.FromContext(ctx) + return ctrl.Result{}, nil } diff --git a/internal/backupcontroller/velerostrategy_controller_test.go b/internal/backupcontroller/velerostrategy_controller_test.go deleted file mode 100644 index 7b085dbf..00000000 --- a/internal/backupcontroller/velerostrategy_controller_test.go +++ /dev/null @@ -1,1213 +0,0 @@ -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_helmreconciler.go b/internal/controller/applicationdefinition_helmreconciler.go deleted file mode 100644 index 5f4f63bd..00000000 --- a/internal/controller/applicationdefinition_helmreconciler.go +++ /dev/null @@ -1,188 +0,0 @@ -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/applicationdefinition_controller.go b/internal/controller/cozystackresource_controller.go similarity index 64% rename from internal/controller/applicationdefinition_controller.go rename to internal/controller/cozystackresource_controller.go index 6ce25249..5492a4a8 100644 --- a/internal/controller/applicationdefinition_controller.go +++ b/internal/controller/cozystackresource_controller.go @@ -23,7 +23,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" ) -type ApplicationDefinitionReconciler struct { +type CozystackResourceDefinitionReconciler struct { client.Client Scheme *runtime.Scheme @@ -32,23 +32,25 @@ type ApplicationDefinitionReconciler struct { mu sync.Mutex lastEvent time.Time lastHandled time.Time + + CozystackAPIKind string } -func (r *ApplicationDefinitionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { +func (r *CozystackResourceDefinitionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { // Only handle debounced restart logic - // HelmRelease reconciliation is handled by ApplicationDefinitionHelmReconciler + // HelmRelease reconciliation is handled by CozystackResourceDefinitionHelmReconciler return r.debouncedRestart(ctx) } -func (r *ApplicationDefinitionReconciler) SetupWithManager(mgr ctrl.Manager) error { +func (r *CozystackResourceDefinitionReconciler) SetupWithManager(mgr ctrl.Manager) error { if r.Debounce == 0 { r.Debounce = 5 * time.Second } return ctrl.NewControllerManagedBy(mgr). - Named("applicationdefinition-controller"). + Named("cozystackresource-controller"). Watches( - &cozyv1alpha1.ApplicationDefinition{}, + &cozyv1alpha1.CozystackResourceDefinition{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request { r.mu.Lock() r.lastEvent = time.Now() @@ -64,22 +66,22 @@ func (r *ApplicationDefinitionReconciler) SetupWithManager(mgr ctrl.Manager) err Complete(r) } -type appDefHashView struct { - Name string `json:"name"` - Spec cozyv1alpha1.ApplicationDefinitionSpec `json:"spec"` +type crdHashView struct { + Name string `json:"name"` + Spec cozyv1alpha1.CozystackResourceDefinitionSpec `json:"spec"` } -func (r *ApplicationDefinitionReconciler) computeConfigHash(ctx context.Context) (string, error) { - list := &cozyv1alpha1.ApplicationDefinitionList{} +func (r *CozystackResourceDefinitionReconciler) computeConfigHash(ctx context.Context) (string, error) { + list := &cozyv1alpha1.CozystackResourceDefinitionList{} if err := r.List(ctx, list); err != nil { return "", err } - slices.SortFunc(list.Items, sortAppDefs) + slices.SortFunc(list.Items, sortCozyRDs) - views := make([]appDefHashView, 0, len(list.Items)) + views := make([]crdHashView, 0, len(list.Items)) for i := range list.Items { - views = append(views, appDefHashView{ + views = append(views, crdHashView{ Name: list.Items[i].Name, Spec: list.Items[i].Spec, }) @@ -92,7 +94,7 @@ func (r *ApplicationDefinitionReconciler) computeConfigHash(ctx context.Context) return hex.EncodeToString(sum[:]), nil } -func (r *ApplicationDefinitionReconciler) debouncedRestart(ctx context.Context) (ctrl.Result, error) { +func (r *CozystackResourceDefinitionReconciler) debouncedRestart(ctx context.Context) (ctrl.Result, error) { logger := log.FromContext(ctx) r.mu.Lock() @@ -130,7 +132,7 @@ func (r *ApplicationDefinitionReconciler) debouncedRestart(ctx context.Context) r.mu.Lock() r.lastHandled = le r.mu.Unlock() - logger.Info("No changes in ApplicationDefinition config; skipping restart", "hash", newHash) + logger.Info("No changes in CRD config; skipping restart", "hash", newHash) return ctrl.Result{}, nil } @@ -149,24 +151,34 @@ func (r *ApplicationDefinitionReconciler) debouncedRestart(ctx context.Context) return ctrl.Result{}, nil } -func (r *ApplicationDefinitionReconciler) getWorkload( +func (r *CozystackResourceDefinitionReconciler) 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 + if r.CozystackAPIKind == "Deployment" { + 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()) + } else { + ds := &appsv1.DaemonSet{} + if err := r.Get(ctx, key, ds); err != nil { + return nil, nil, nil, err + } + obj = ds + tpl = &ds.Spec.Template + patch = client.MergeFrom(ds.DeepCopy()) } - 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 { +func sortCozyRDs(a, b cozyv1alpha1.CozystackResourceDefinition) int { if a.Name == b.Name { return 0 } diff --git a/internal/controller/cozystackresourcedefinition_helmreconciler.go b/internal/controller/cozystackresourcedefinition_helmreconciler.go new file mode 100644 index 00000000..57c8141f --- /dev/null +++ b/internal/controller/cozystackresourcedefinition_helmreconciler.go @@ -0,0 +1,211 @@ +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=cozystackresourcedefinitions,verbs=get;list;watch +// +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases,verbs=get;list;watch;update;patch + +// CozystackResourceDefinitionHelmReconciler reconciles CozystackResourceDefinitions +// and updates related HelmReleases when a CozyRD changes. +// This controller does NOT watch HelmReleases to avoid mutual reconciliation storms +// with Flux's helm-controller. +type CozystackResourceDefinitionHelmReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +func (r *CozystackResourceDefinitionHelmReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + + // Get the CozystackResourceDefinition that triggered this reconciliation + crd := &cozyv1alpha1.CozystackResourceDefinition{} + if err := r.Get(ctx, req.NamespacedName, crd); err != nil { + logger.Error(err, "failed to get CozystackResourceDefinition", "name", req.Name) + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + // Update HelmReleases related to this specific CozyRD + if err := r.updateHelmReleasesForCRD(ctx, crd); err != nil { + logger.Error(err, "failed to update HelmReleases for CRD", "crd", crd.Name) + return ctrl.Result{}, err + } + + return ctrl.Result{}, nil +} + +func (r *CozystackResourceDefinitionHelmReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + Named("cozystackresourcedefinition-helm-reconciler"). + For(&cozyv1alpha1.CozystackResourceDefinition{}). + Complete(r) +} + +// updateHelmReleasesForCRD updates all HelmReleases that match the application labels from CozystackResourceDefinition +func (r *CozystackResourceDefinitionHelmReconciler) updateHelmReleasesForCRD(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error { + logger := log.FromContext(ctx) + + // Use application labels to find HelmReleases + // Labels: apps.cozystack.io/application.kind and apps.cozystack.io/application.group + applicationKind := crd.Spec.Application.Kind + + // Validate that applicationKind is non-empty + if applicationKind == "" { + logger.V(4).Info("Skipping HelmRelease update: Application.Kind is empty", "crd", crd.Name) + return nil + } + + applicationGroup := "apps.cozystack.io" // All applications use this group + + // Build label selector for HelmReleases + // Only reconcile HelmReleases with cozystack.io/ui=true label + labelSelector := client.MatchingLabels{ + "apps.cozystack.io/application.kind": applicationKind, + "apps.cozystack.io/application.group": applicationGroup, + "cozystack.io/ui": "true", + } + + // 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", "crd", crd.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, crd); 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", + ValuesKey: "_namespace", + TargetPath: "_namespace", + Optional: false, + }, + { + Kind: "Secret", + Name: "cozystack-values", + ValuesKey: "_cluster", + TargetPath: "_cluster", + Optional: false, + }, + } +} + +// 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 CozystackResourceDefinition +func (r *CozystackResourceDefinitionHelmReconciler) updateHelmReleaseChart(ctx context.Context, hr *helmv2.HelmRelease, crd *cozyv1alpha1.CozystackResourceDefinition) error { + logger := log.FromContext(ctx) + hrCopy := hr.DeepCopy() + updated := false + + // Validate Chart configuration exists + if crd.Spec.Release.Chart.Name == "" { + logger.V(4).Info("Skipping HelmRelease chart update: Chart.Name is empty", "crd", crd.Name) + return nil + } + + // Validate SourceRef fields + if crd.Spec.Release.Chart.SourceRef.Kind == "" || + crd.Spec.Release.Chart.SourceRef.Name == "" || + crd.Spec.Release.Chart.SourceRef.Namespace == "" { + logger.Error(fmt.Errorf("invalid SourceRef in CRD"), "Skipping HelmRelease chart update: SourceRef fields are incomplete", + "crd", crd.Name, + "kind", crd.Spec.Release.Chart.SourceRef.Kind, + "name", crd.Spec.Release.Chart.SourceRef.Name, + "namespace", crd.Spec.Release.Chart.SourceRef.Namespace) + return nil + } + + // Get version and reconcileStrategy from CRD or use defaults + version := ">= 0.0.0-0" + reconcileStrategy := "Revision" + // TODO: Add Version and ReconcileStrategy fields to CozystackResourceDefinitionChart if needed + + // Build expected SourceRef + expectedSourceRef := helmv2.CrossNamespaceObjectReference{ + Kind: crd.Spec.Release.Chart.SourceRef.Kind, + Name: crd.Spec.Release.Chart.SourceRef.Name, + Namespace: crd.Spec.Release.Chart.SourceRef.Namespace, + } + + if hrCopy.Spec.Chart == nil { + // Need to create Chart spec + hrCopy.Spec.Chart = &helmv2.HelmChartTemplate{ + Spec: helmv2.HelmChartTemplateSpec{ + Chart: crd.Spec.Release.Chart.Name, + Version: version, + ReconcileStrategy: reconcileStrategy, + SourceRef: expectedSourceRef, + }, + } + updated = true + } else { + // Update existing Chart spec + if hrCopy.Spec.Chart.Spec.Chart != crd.Spec.Release.Chart.Name || + hrCopy.Spec.Chart.Spec.SourceRef != expectedSourceRef { + hrCopy.Spec.Chart.Spec.Chart = crd.Spec.Release.Chart.Name + hrCopy.Spec.Chart.Spec.SourceRef = expectedSourceRef + 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 + } + + if updated { + logger.V(4).Info("Updating HelmRelease chart", "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 deleted file mode 100644 index 2efe9f45..00000000 --- a/internal/controller/dashboard/README.md +++ /dev/null @@ -1,355 +0,0 @@ -# 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 index 6d65f2db..5122f605 100644 --- a/internal/controller/dashboard/breadcrumb.go +++ b/internal/controller/dashboard/breadcrumb.go @@ -14,7 +14,7 @@ import ( ) // ensureBreadcrumb creates or updates a Breadcrumb resource for the given CRD -func (m *Manager) ensureBreadcrumb(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error { +func (m *Manager) ensureBreadcrumb(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error { group, version, kind := pickGVK(crd) lowerKind := strings.ToLower(kind) @@ -33,12 +33,12 @@ func (m *Manager) ensureBreadcrumb(ctx context.Context, crd *cozyv1alpha1.Applic 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) + link := fmt.Sprintf("/openapi-ui/{clusterName}/{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" + link = "/openapi-ui/{clusterName}/{namespace}/api-table/core.cozystack.io/v1alpha1/tenantmodules" } items := []any{ diff --git a/internal/controller/dashboard/customcolumns.go b/internal/controller/dashboard/customcolumns.go index 19a5a16a..6c23d68b 100644 --- a/internal/controller/dashboard/customcolumns.go +++ b/internal/controller/dashboard/customcolumns.go @@ -21,7 +21,7 @@ import ( // // metadata.name: stock-namespace-.. // spec.id: stock-namespace-/// -func (m *Manager) ensureCustomColumnsOverride(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) (controllerutil.OperationResult, error) { +func (m *Manager) ensureCustomColumnsOverride(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) (controllerutil.OperationResult, error) { g, v, kind := pickGVK(crd) plural := pickPlural(kind, crd) // Details page segment uses lowercase kind, mirroring your example @@ -34,6 +34,9 @@ func (m *Manager) ensureCustomColumnsOverride(ctx context.Context, crd *cozyv1al obj.SetName(name) href := fmt.Sprintf("/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/%s/{reqsJsonPath[0]['.metadata.name']['-']}", detailsSegment) + if g == "apps.cozystack.io" && kind == "Tenant" && plural == "tenants" { + href = "/openapi-ui/{2}/{reqsJsonPath[0]['.status.namespace']['-']}/api-table/core.cozystack.io/v1alpha1/tenantmodules" + } desired := map[string]any{ "spec": map[string]any{ diff --git a/internal/controller/dashboard/customformsoverride.go b/internal/controller/dashboard/customformsoverride.go index 0a20ae71..2b0daa08 100644 --- a/internal/controller/dashboard/customformsoverride.go +++ b/internal/controller/dashboard/customformsoverride.go @@ -15,7 +15,7 @@ import ( ) // ensureCustomFormsOverride creates or updates a CustomFormsOverride resource for the given CRD -func (m *Manager) ensureCustomFormsOverride(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error { +func (m *Manager) ensureCustomFormsOverride(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error { g, v, kind := pickGVK(crd) plural := pickPlural(kind, crd) @@ -46,11 +46,8 @@ func (m *Manager) ensureCustomFormsOverride(ctx context.Context, crd *cozyv1alph } } - // 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 + l := log.FromContext(ctx) schema, err := buildMultilineStringSchema(crd.Spec.Application.OpenAPISchema) if err != nil { // If schema parsing fails, log the error and use an empty schema @@ -58,12 +55,6 @@ func (m *Manager) ensureCustomFormsOverride(ctx context.Context, crd *cozyv1alph 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, @@ -93,58 +84,8 @@ func (m *Manager) ensureCustomFormsOverride(ctx context.Context, crd *cozyv1alph 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) +// for all string fields inside spec that don't have enum func buildMultilineStringSchema(openAPISchema string) (map[string]any, error) { if openAPISchema == "" { return map[string]any{}, nil @@ -164,25 +105,15 @@ func buildMultilineStringSchema(openAPISchema string) (map[string]any, error) { "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) + // Check if there's a spec property + specProp, ok := props["spec"].(map[string]any) + if !ok { + return map[string]any{}, nil } - // 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 + specProps, ok := specProp["properties"].(map[string]any) + if !ok { + return map[string]any{}, nil } // Create spec.properties structure in schema @@ -198,206 +129,6 @@ func buildMultilineStringSchema(openAPISchema string) (map[string]any, error) { 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) { diff --git a/internal/controller/dashboard/customformsoverride_test.go b/internal/controller/dashboard/customformsoverride_test.go index 6a83d62e..9f7babe9 100644 --- a/internal/controller/dashboard/customformsoverride_test.go +++ b/internal/controller/dashboard/customformsoverride_test.go @@ -169,453 +169,3 @@ func TestBuildMultilineStringSchemaInvalidJSON(t *testing.T) { 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 index 35d22ff1..d2761873 100644 --- a/internal/controller/dashboard/customformsprefill.go +++ b/internal/controller/dashboard/customformsprefill.go @@ -16,7 +16,7 @@ import ( ) // ensureCustomFormsPrefill creates or updates a CustomFormsPrefill resource for the given CRD -func (m *Manager) ensureCustomFormsPrefill(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) (reconcile.Result, error) { +func (m *Manager) ensureCustomFormsPrefill(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) (reconcile.Result, error) { logger := log.FromContext(ctx) app := crd.Spec.Application diff --git a/internal/controller/dashboard/factory.go b/internal/controller/dashboard/factory.go index fe0cadfd..53d771d0 100644 --- a/internal/controller/dashboard/factory.go +++ b/internal/controller/dashboard/factory.go @@ -15,7 +15,7 @@ import ( ) // ensureFactory creates or updates a Factory resource for the given CRD -func (m *Manager) ensureFactory(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error { +func (m *Manager) ensureFactory(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error { g, v, kind := pickGVK(crd) plural := pickPlural(kind, crd) @@ -47,8 +47,7 @@ func (m *Manager) ensureFactory(ctx context.Context, crd *cozyv1alpha1.Applicati if prefix, ok := vncTabPrefix(kind); ok { tabs = append(tabs, vncTab(prefix)) } - tabs = append(tabs, eventsTab(kind)) - tabs = append(tabs, yamlTab(g, v, plural)) + tabs = append(tabs, yamlTab(plural)) // Use unified factory creation config := UnifiedResourceConfig{ @@ -161,11 +160,11 @@ func detailsTab(kind, endpoint, schemaJSON string, keysOrder [][]string) map[str 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", + "id": "vpc-subnets-table", + "baseprefix": "/openapi-ui", + "clusterNamePartOfUrl": "{2}", + "customizationId": "virtualprivatecloud-subnets", + "fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/configmaps", "fieldSelector": map[string]any{ "metadata.name": "virtualprivatecloud-{6}-subnets", }, @@ -175,31 +174,6 @@ func detailsTab(kind, endpoint, schemaJSON string, keysOrder [][]string) map[str }), ) } - 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", @@ -243,13 +217,13 @@ func detailsTab(kind, endpoint, schemaJSON string, keysOrder [][]string) map[str 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"}, + "id": "conditions-table", + "fetchUrl": endpoint, + "clusterNamePartOfUrl": "{2}", + "customizationId": "factory-status-conditions", + "baseprefix": "/openapi-ui", + "withoutControls": true, + "pathToItems": []any{"status", "conditions"}, }, }, }), @@ -265,12 +239,12 @@ func workloadsTab(kind string) map[string]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"}, + "id": "workloads-table", + "fetchUrl": "/api/clusters/{2}/k8s/apis/cozystack.io/v1alpha1/namespaces/{3}/workloadmonitors", + "clusterNamePartOfUrl": "{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, @@ -290,12 +264,12 @@ func servicesTab(kind string) map[string]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"}, + "id": "services-table", + "fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/services", + "clusterNamePartOfUrl": "{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, @@ -316,12 +290,12 @@ func ingressesTab(kind string) map[string]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"}, + "id": "ingresses-table", + "fetchUrl": "/api/clusters/{2}/k8s/apis/networking.k8s.io/v1/namespaces/{3}/ingresses", + "clusterNamePartOfUrl": "{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, @@ -342,12 +316,12 @@ func secretsTab(kind string) map[string]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"}, + "id": "secrets-table", + "fetchUrl": "/api/clusters/{2}/k8s/apis/core.cozystack.io/v1alpha1/namespaces/{3}/tenantsecrets", + "clusterNamePartOfUrl": "{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, @@ -359,38 +333,7 @@ func secretsTab(kind string) map[string]any { } } -// 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 { +func yamlTab(plural string) map[string]any { return map[string]any{ "key": "yaml", "label": "YAML", @@ -401,10 +344,8 @@ func yamlTab(group, version, plural string) map[string]any { "id": "yaml-editor", "cluster": "{2}", "isNameSpaced": true, - "type": "apis", - "apiGroup": group, - "apiVersion": version, - "plural": plural, + "type": "builtin", + "typeName": plural, "prefillValuesRequestIndex": float64(0), "readOnly": true, "substractHeight": float64(400), @@ -614,14 +555,15 @@ type factoryFlags struct { 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, - } +// factoryFeatureFlags tries several conventional locations so you can evolve the API +// without breaking the controller. Defaults are false (hidden). +func factoryFeatureFlags(crd *cozyv1alpha1.CozystackResourceDefinition) factoryFlags { + var f factoryFlags + + f.Workloads = true + f.Ingresses = true + f.Services = true + f.Secrets = true + + return f } diff --git a/internal/controller/dashboard/factory_test.go b/internal/controller/dashboard/factory_test.go deleted file mode 100644 index b3742564..00000000 --- a/internal/controller/dashboard/factory_test.go +++ /dev/null @@ -1,60 +0,0 @@ -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 index 2a35bbff..a0023a05 100644 --- a/internal/controller/dashboard/helpers.go +++ b/internal/controller/dashboard/helpers.go @@ -23,7 +23,7 @@ type fieldInfo struct { // 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) { +func pickGVK(crd *cozyv1alpha1.CozystackResourceDefinition) (group, version, kind string) { // Best guess based on your examples: if crd.Spec.Application.Kind != "" { kind = crd.Spec.Application.Kind @@ -41,7 +41,7 @@ func pickGVK(crd *cozyv1alpha1.ApplicationDefinition) (group, version, kind stri } // 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 { +func pickPlural(kind string, crd *cozyv1alpha1.CozystackResourceDefinition) string { // If you have crd.Spec.Application.Plural, prefer it. Example: if crd.Spec.Application.Plural != "" { return crd.Spec.Application.Plural diff --git a/internal/controller/dashboard/manager.go b/internal/controller/dashboard/manager.go index 42c641ad..12e50fbc 100644 --- a/internal/controller/dashboard/manager.go +++ b/internal/controller/dashboard/manager.go @@ -41,7 +41,7 @@ func AddToScheme(s *runtime.Scheme) error { } // 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. +// It’s easy to extend: add new ensure* methods and wire them into EnsureForCRD. type Manager struct { client.Client Scheme *runtime.Scheme @@ -56,7 +56,7 @@ func NewManager(c client.Client, scheme *runtime.Scheme) *Manager { func (m *Manager) SetupWithManager(mgr ctrl.Manager) error { if err := ctrl.NewControllerManagedBy(mgr). Named("dashboard-reconciler"). - For(&cozyv1alpha1.ApplicationDefinition{}). + For(&cozyv1alpha1.CozystackResourceDefinition{}). Complete(m); err != nil { return err } @@ -72,7 +72,7 @@ func (m *Manager) SetupWithManager(mgr ctrl.Manager) error { func (m *Manager) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { l := log.FromContext(ctx) - crd := &cozyv1alpha1.ApplicationDefinition{} + crd := &cozyv1alpha1.CozystackResourceDefinition{} err := m.Get(ctx, types.NamespacedName{Name: req.Name}, crd) if err != nil { @@ -85,10 +85,10 @@ func (m *Manager) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, return ctrl.Result{}, err } - return m.EnsureForAppDef(ctx, crd) + return m.EnsureForCRD(ctx, crd) } -// EnsureForAppDef is the single entry-point used by the controller. +// EnsureForCRD is the single entry-point used by the controller. // Add more ensure* calls here as you implement support for other resources: // // - ensureBreadcrumb (implemented) @@ -99,7 +99,7 @@ func (m *Manager) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, // - ensureMarketplacePanel (implemented) // - ensureSidebar (implemented) // - ensureTableUriMapping (implemented) -func (m *Manager) EnsureForAppDef(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) (reconcile.Result, error) { +func (m *Manager) EnsureForCRD(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) (reconcile.Result, error) { // Early return if crd.Spec.Dashboard is nil to prevent oscillation if crd.Spec.Dashboard == nil { return reconcile.Result{}, nil @@ -132,10 +132,6 @@ func (m *Manager) EnsureForAppDef(ctx context.Context, crd *cozyv1alpha1.Applica 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 } @@ -143,10 +139,6 @@ func (m *Manager) EnsureForAppDef(ctx context.Context, crd *cozyv1alpha1.Applica 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 } @@ -156,7 +148,7 @@ func (m *Manager) InitializeStaticResources(ctx context.Context) error { } // addDashboardLabels adds standard dashboard management labels to a resource -func (m *Manager) addDashboardLabels(obj client.Object, crd *cozyv1alpha1.ApplicationDefinition, resourceType string) { +func (m *Manager) addDashboardLabels(obj client.Object, crd *cozyv1alpha1.CozystackResourceDefinition, resourceType string) { labels := obj.GetLabels() if labels == nil { labels = make(map[string]string) @@ -205,7 +197,7 @@ func (m *Manager) getStaticResourceSelector() client.MatchingLabels { // 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 + var crdList cozyv1alpha1.CozystackResourceDefinitionList if err := m.List(ctx, &crdList, &client.ListOptions{}); err != nil { return err } @@ -236,7 +228,7 @@ func (m *Manager) CleanupOrphanedResources(ctx context.Context) error { } // buildExpectedResourceSet creates a map of expected resource names by type -func (m *Manager) buildExpectedResourceSet(crds []cozyv1alpha1.ApplicationDefinition) map[string]map[string]bool { +func (m *Manager) buildExpectedResourceSet(crds []cozyv1alpha1.CozystackResourceDefinition) map[string]map[string]bool { expected := make(map[string]map[string]bool) // Initialize maps for each resource type @@ -299,6 +291,10 @@ func (m *Manager) buildExpectedResourceSet(crds []cozyv1alpha1.ApplicationDefini // Add other stock sidebars that are created for each CRD stockSidebars := []string{ + "stock-instance-api-form", + "stock-instance-api-table", + "stock-instance-builtin-form", + "stock-instance-builtin-table", "stock-project-factory-marketplace", "stock-project-factory-workloadmonitor-details", "stock-project-api-form", @@ -307,10 +303,6 @@ func (m *Manager) buildExpectedResourceSet(crds []cozyv1alpha1.ApplicationDefini "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 diff --git a/internal/controller/dashboard/marketplacepanel.go b/internal/controller/dashboard/marketplacepanel.go index 14684afc..82a8f336 100644 --- a/internal/controller/dashboard/marketplacepanel.go +++ b/internal/controller/dashboard/marketplacepanel.go @@ -16,7 +16,7 @@ import ( ) // ensureMarketplacePanel creates or updates a MarketplacePanel resource for the given CRD -func (m *Manager) ensureMarketplacePanel(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) (reconcile.Result, error) { +func (m *Manager) ensureMarketplacePanel(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) (reconcile.Result, error) { logger := log.FromContext(ctx) mp := &dashv1alpha1.MarketplacePanel{} @@ -68,46 +68,31 @@ func (m *Manager) ensureMarketplacePanel(ctx context.Context, crd *cozyv1alpha1. tags[i] = t } - _, err := controllerutil.CreateOrUpdate(ctx, m.Client, mp, func() error { + specMap := map[string]any{ + "description": d.Description, + "name": displayName, + "type": "nonCrd", + "apiGroup": "apps.cozystack.io", + "apiVersion": "v1alpha1", + "typeName": app.Plural, // e.g., "buckets" + "disabled": false, + "hidden": false, + "tags": tags, + "icon": d.Icon, + } + + specBytes, err := json.Marshal(specMap) + if err != nil { + return reconcile.Result{}, err + } + + _, 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}, diff --git a/internal/controller/dashboard/navigation.go b/internal/controller/dashboard/navigation.go deleted file mode 100644 index 5e4bad2e..00000000 --- a/internal/controller/dashboard/navigation.go +++ /dev/null @@ -1,69 +0,0 @@ -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 index 69c933fb..97937921 100644 --- a/internal/controller/dashboard/sidebar.go +++ b/internal/controller/dashboard/sidebar.go @@ -17,44 +17,28 @@ import ( // 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 +// - The stock-instance sidebars: api-form, api-table, builtin-form, builtin-table +// - 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) +// - Marketplace (/openapi-ui/{clusterName}/{namespace}/factory/marketplace) +// - Tenant Info (/openapi-ui/{clusterName}/{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 +// Marketplace, IaaS, PaaS, NaaS, , Resources, Administration // - Items within each category: sort by Weight (desc), then Label (A→Z). -func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error { +func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) error { // Build the full menu once. // 1) Fetch all CRDs - var all []cozyv1alpha1.ApplicationDefinition - var crdList cozyv1alpha1.ApplicationDefinitionList + var all []cozyv1alpha1.CozystackResourceDefinition + var crdList cozyv1alpha1.CozystackResourceDefinitionList 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 @@ -80,11 +64,6 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Applicati 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 @@ -112,7 +91,7 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Applicati // Weight (default 0) weight := def.Spec.Dashboard.Weight - link := fmt.Sprintf("/openapi-ui/{cluster}/{namespace}/api-table/%s/%s/%s", g, v, plural) + link := fmt.Sprintf("/openapi-ui/{clusterName}/{namespace}/api-table/%s/%s/%s", g, v, plural) categories[cat] = append(categories[cat], item{ Key: plural, @@ -132,20 +111,6 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Applicati 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 { @@ -158,10 +123,10 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Applicati } // 4) Order categories strictly: - // Marketplace (hardcoded), IaaS, PaaS, NaaS, , Resources, Backups (hardcoded), Administration (hardcoded) + // Marketplace (hardcoded), IaaS, PaaS, NaaS, , Resources, Administration orderedCats := orderCategoryLabels(categories) - // 5) Build menuItems (hardcode "Marketplace"; then dynamic categories; then hardcode "Backups" and "Administration") + // 5) Build menuItems (hardcode "Marketplace"; then dynamic categories; then hardcode "Administration") menuItems := []any{ map[string]any{ "key": "marketplace", @@ -170,15 +135,15 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Applicati map[string]any{ "key": "marketplace", "label": "Marketplace", - "link": "/openapi-ui/{cluster}/{namespace}/factory/marketplace", + "link": "/openapi-ui/{clusterName}/{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") { + // Skip "Marketplace" and "Administration" here since they're hardcoded + if strings.EqualFold(cat, "Marketplace") || strings.EqualFold(cat, "Administration") { continue } children := []any{} @@ -198,34 +163,6 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Applicati } } - // 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", @@ -234,22 +171,17 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Applicati map[string]any{ "key": "info", "label": "Info", - "link": "/openapi-ui/{cluster}/{namespace}/factory/info-details/info", + "link": "/openapi-ui/{clusterName}/{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", + "link": "/openapi-ui/{clusterName}/{namespace}/api-table/core.cozystack.io/v1alpha1/tenantmodules", }, map[string]any{ "key": "tenants", "label": "Tenants", - "link": "/openapi-ui/{cluster}/{namespace}/api-table/apps.cozystack.io/v1alpha1/tenants", + "link": "/openapi-ui/{clusterName}/{namespace}/api-table/apps.cozystack.io/v1alpha1/tenants", }, }, }) @@ -257,36 +189,27 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Applicati // 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-instance sidebars + "stock-instance-api-form", + "stock-instance-api-table", + "stock-instance-builtin-form", + "stock-instance-builtin-table", + + // stock-project sidebars "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{} + // Add details sidebars for all CRDs with dashboard config for i := range all { def := &all[i] if def.Spec.Dashboard == nil { @@ -296,22 +219,17 @@ func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.Applicati 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) + return m.upsertMultipleSidebars(ctx, crd, targetIDs, 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, + crd *cozyv1alpha1.CozystackResourceDefinition, ids []string, - dynamicDetailsIDs map[string]bool, keysAndTags map[string]any, menuItems []any, ) error { @@ -327,10 +245,8 @@ func (m *Manager) upsertMultipleSidebars( 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] { + // Static sidebars (stock-instance-*, stock-project-*) should not have owner references + if strings.HasPrefix(id, "stock-project-factory-") && strings.HasSuffix(id, "-details") { // This is a dynamic sidebar, set owner reference only if it matches the current CRD _, _, kind := pickGVK(crd) lowerKind := strings.ToLower(kind) @@ -419,7 +335,7 @@ func orderCategoryLabels[T any](cats map[string][]T) []string { } // safeCategory returns spec.dashboard.category or "Resources" if not set. -func safeCategory(def *cozyv1alpha1.ApplicationDefinition) string { +func safeCategory(def *cozyv1alpha1.CozystackResourceDefinition) string { if def == nil || def.Spec.Dashboard == nil { return "Resources" } diff --git a/internal/controller/dashboard/static_helpers.go b/internal/controller/dashboard/static_helpers.go index db37e05b..4c8aae30 100644 --- a/internal/controller/dashboard/static_helpers.go +++ b/internal/controller/dashboard/static_helpers.go @@ -650,31 +650,12 @@ func createStringColumn(name, jsonPath string) map[string]any { } } -// 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] + "']['-']}\"]}" - } - +// createTimestampColumn creates a timestamp column with custom formatting +func createTimestampColumn(name, jsonPath string) map[string]any { return map[string]any{ "name": name, "type": "factory", - "jsonPath": jsonPaths[0], + "jsonPath": jsonPath, "customProps": map[string]any{ "disableEventBubbling": true, "items": []any{ @@ -692,7 +673,7 @@ func createTimestampColumn(name string, jsonPaths ...string) map[string]any { "data": map[string]any{ "formatter": "timestamp", "id": "time-value", - "text": text, + "text": "{reqsJsonPath[0]['" + jsonPath + "']['-']}", }, }, }, @@ -1042,27 +1023,6 @@ func createReadyColumn() map[string]any { } } -// 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{ @@ -1153,7 +1113,7 @@ func yamlEditor(id, cluster string, isNameSpaced bool, typeName string, prefillV "cluster": cluster, "isNameSpaced": isNameSpaced, "type": "builtin", - "plural": typeName, + "typeName": typeName, "prefillValuesRequestIndex": prefillValuesRequestIndex, "substractHeight": float64(400), }, diff --git a/internal/controller/dashboard/static_processor.go b/internal/controller/dashboard/static_processor.go index d4b270f4..902e3818 100644 --- a/internal/controller/dashboard/static_processor.go +++ b/internal/controller/dashboard/static_processor.go @@ -49,8 +49,6 @@ func (m *Manager) ensureStaticResource(ctx context.Context, obj client.Object) e 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) diff --git a/internal/controller/dashboard/static_refactored.go b/internal/controller/dashboard/static_refactored.go index 9f28c0fb..619d36f5 100644 --- a/internal/controller/dashboard/static_refactored.go +++ b/internal/controller/dashboard/static_refactored.go @@ -17,111 +17,111 @@ 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("configmaps", "v1/configmaps", "/openapi-ui/{clusterName}/{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("namespaces", "v1/namespaces", "/openapi-ui/{clusterName}/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", "v1/nodes", "/openapi-ui/{clusterName}/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("pods", "v1/pods", "/openapi-ui/{clusterName}/{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("secrets", "v1/secrets", "/openapi-ui/{clusterName}/{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("services", "v1/services", "/openapi-ui/{clusterName}/{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("ingresses", "networking.k8s.io/v1/ingresses", "/openapi-ui/{clusterName}/{namespace}/builtin-table/ingresses"), createBreadcrumbItem("ingress", "{6}"), }), // Stock cluster api table createBreadcrumb("stock-cluster-api-table", []map[string]any{ - createBreadcrumbItem("api", "{apiGroup}/{apiVersion}/{plural}"), + createBreadcrumbItem("api", "{apiGroup}/{apiVersion}/{typeName}"), }), // 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-table", "{apiGroup}/{apiVersion}/{typeName}", "/openapi-ui/{clusterName}/api-table/{apiGroup}/{apiVersion}/{typeName}"), 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-table", "{apiGroup}/{apiVersion}/{typeName}", "/openapi-ui/{clusterName}/api-table/{apiGroup}/{apiVersion}/{typeName}"), createBreadcrumbItem("create-api-res-namespaced-typename", "Update"), }), // Stock cluster builtin table createBreadcrumb("stock-cluster-builtin-table", []map[string]any{ - createBreadcrumbItem("api", "v1/{plural}"), + createBreadcrumbItem("api", "v1/{typeName}"), }), // 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-table", "v1/{typeName}", "/openapi-ui/{clusterName}/builtin-table/{typeName}"), 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-table", "v1/{typeName}", "/openapi-ui/{clusterName}/builtin-table/{typeName}"), createBreadcrumbItem("create-api-res-namespaced-typename", "Update"), }), // Stock project api table createBreadcrumb("stock-project-api-table", []map[string]any{ - createBreadcrumbItem("api", "{apiGroup}/{apiVersion}/{plural}"), + createBreadcrumbItem("api", "{apiGroup}/{apiVersion}/{typeName}"), }), // 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-table", "{apiGroup}/{apiVersion}/{typeName}", "/openapi-ui/{clusterName}/{namespace}/api-table/{apiGroup}/{apiVersion}/{typeName}"), 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-table", "{apiGroup}/{apiVersion}/{typeName}", "/openapi-ui/{clusterName}/{namespace}/api-table/{apiGroup}/{apiVersion}/{typeName}"), createBreadcrumbItem("create-api-res-namespaced-typename", "Update"), }), // Stock project builtin table createBreadcrumb("stock-project-builtin-table", []map[string]any{ - createBreadcrumbItem("api", "v1/{plural}"), + createBreadcrumbItem("api", "v1/{typeName}"), }), // 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-table", "v1/{typeName}", "/openapi-ui/{clusterName}/{namespace}/builtin-table/{typeName}"), 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-table", "v1/{typeName}", "/openapi-ui/{clusterName}/{namespace}/builtin-table/{typeName}"), createBreadcrumbItem("create-api-res-namespaced-typename", "Update"), }), } @@ -134,7 +134,7 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid 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"), + createStringColumn("LoadbalancerIP", ".spec.loadBalancerIP"), createTimestampColumn("Created", ".metadata.creationTimestamp"), }), @@ -154,14 +154,6 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid 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"), @@ -197,14 +189,6 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid 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"), @@ -224,20 +208,6 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid 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"), @@ -401,38 +371,6 @@ func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverrid 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"), - }), } } @@ -525,61 +463,6 @@ func CreateAllCustomFormsOverrides() []*dashboardv1alpha1.CustomFormsOverride { 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(), - }, - }, - }), - }), } } @@ -599,14 +482,14 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { }, []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", + "baseApiVersion": "v1alpha1", + "baseprefix": "openapi-ui", + "clusterNamePartOfUrl": "{2}", + "id": 311, + "mpResourceKind": "MarketplacePanel", + "mpResourceName": "marketplacepanels", + "namespacePartOfUrl": "{3}", + "baseApiGroup": "dashboard.cozystack.io", }, "type": "MarketplaceCard", }, @@ -919,7 +802,7 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { "prefillValuesRequestIndex": 0, "substractHeight": float64(400), "type": "builtin", - "plural": "secrets", + "typeName": "secrets", "readOnly": true, }, }, @@ -1149,13 +1032,13 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { 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, + "id": "service-port-mapping-table", + "baseprefix": "/openapi-ui", + "clusterNamePartOfUrl": "{2}", + "customizationId": "factory-kube-service-details-port-mapping", + "fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/services/{6}", + "pathToItems": ".spec.ports", + "withoutControls": true, }, }, }), @@ -1175,11 +1058,11 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { 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", + "id": "service-pod-serving-table", + "baseprefix": "/openapi-ui", + "clusterNamePartOfUrl": "{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']['-']}", }, @@ -1209,7 +1092,7 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { "prefillValuesRequestIndex": 0, "substractHeight": float64(400), "type": "builtin", - "plural": "services", + "typeName": "services", }, }, }, @@ -1232,12 +1115,12 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { 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{ + "id": "pods-table", + "baseprefix": "/openapi-ui", + "clusterNamePartOfUrl": "{2}", + "customizationId": "factory-node-details-/v1/pods", + "fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/pods", + "labelsSelectorFull": map[string]any{ "pathToLabels": ".spec.selector", "reqIndex": 0, }, @@ -1364,13 +1247,13 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { 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"}, + "id": "rules-table", + "fetchUrl": "/api/clusters/{2}/k8s/apis/networking.k8s.io/v1/namespaces/{3}/ingresses/{6}", + "clusterNamePartOfUrl": "{2}", + "customizationId": "factory-kube-ingress-details-rules", + "baseprefix": "/openapi-ui", + "withoutControls": true, + "pathToItems": []any{"spec", "rules"}, }, }, }), @@ -1386,10 +1269,8 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { "id": "yaml-editor", "cluster": "{2}", "isNameSpaced": true, - "type": "apis", - "apiGroup": "networking.k8s.io", - "apiVersion": "v1", - "plural": "ingresses", + "type": "builtin", + "typeName": "ingresses", "prefillValuesRequestIndex": float64(0), "substractHeight": float64(400), }, @@ -1518,11 +1399,11 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { 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", + "id": "workloads-table", + "baseprefix": "/openapi-ui", + "clusterNamePartOfUrl": "{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']}", }, @@ -1543,10 +1424,8 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { "isNameSpaced": true, "prefillValuesRequestIndex": 0, "substractHeight": float64(400), - "type": "apis", - "apiGroup": "cozystack.io", - "apiVersion": "v1alpha1", - "plural": "workloadmonitors", + "type": "builtin", + "typeName": "workloadmonitors", }, }, }, @@ -1554,633 +1433,6 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { } 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), @@ -2190,42 +1442,17 @@ func CreateAllFactories() []*dashboardv1alpha1.Factory { 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, }), } } @@ -2283,9 +1510,9 @@ func createCustomFormsOverride(customizationId string, spec map[string]any) *das "strategy": "merge", } - // Merge into newSpec caller-provided fields without: customizationId, hidden, strategy + // Merge caller-provided fields (like formItems) into newSpec for key, value := range spec { - if key != "customizationId" && key != "hidden" && key != "strategy" { + if key != "customizationId" && key != "hidden" && key != "schema" && key != "strategy" { newSpec[key] = value } } @@ -2330,41 +1557,6 @@ func createNavigation(name string, spec map[string]any) *dashboardv1alpha1.Navig } } -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{ @@ -2374,20 +1566,6 @@ func createFormItem(path, label, fieldType string) map[string]any { } } -// 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 @@ -2637,51 +1815,6 @@ func createWorkloadmonitorHeader() map[string]any { } } -// 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 @@ -2718,8 +1851,5 @@ func CreateAllStaticResources() []client.Object { 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 index e9a4849c..6e8a395d 100644 --- a/internal/controller/dashboard/tableurimapping.go +++ b/internal/controller/dashboard/tableurimapping.go @@ -7,7 +7,7 @@ import ( ) // ensureTableUriMapping creates or updates a TableUriMapping resource for the given CRD -func (m *Manager) ensureTableUriMapping(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error { +func (m *Manager) ensureTableUriMapping(ctx context.Context, crd *cozyv1alpha1.CozystackResourceDefinition) 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 index 6c7e3000..fb29a608 100644 --- a/internal/controller/dashboard/ui_helpers.go +++ b/internal/controller/dashboard/ui_helpers.go @@ -102,22 +102,6 @@ func antdFlex(id string, gap float64, children []any) map[string]any { } } -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 == "" { diff --git a/internal/controller/dashboard/unified_helpers.go b/internal/controller/dashboard/unified_helpers.go index d5edf207..b25d5b65 100644 --- a/internal/controller/dashboard/unified_helpers.go +++ b/internal/controller/dashboard/unified_helpers.go @@ -237,16 +237,9 @@ func createUnifiedFactory(config UnifiedResourceConfig, tabs []any, urlsToFetch "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), - ), + header := antdFlex(generateContainerID("header", "row"), float64(6), []any{ + badge, + nameText, }) // Add marginBottom style to header diff --git a/internal/controller/fluxplunger/flux_plunger.go b/internal/controller/fluxplunger/flux_plunger.go deleted file mode 100644 index 44886a2c..00000000 --- a/internal/controller/fluxplunger/flux_plunger.go +++ /dev/null @@ -1,333 +0,0 @@ -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/workload_controller_test.go b/internal/controller/workload_controller_test.go index 194a20d3..b454adc3 100644 --- a/internal/controller/workload_controller_test.go +++ b/internal/controller/workload_controller_test.go @@ -43,7 +43,7 @@ func TestWorkloadReconciler_DeletesOnMissingMonitor(t *testing.T) { Name: "pod-foo", Namespace: "default", Labels: map[string]string{ - "workloads.cozystack.io/monitor": "missing-monitor", + "workloadmonitor.cozystack.io/name": "missing-monitor", }, }, } @@ -89,7 +89,7 @@ func TestWorkloadReconciler_KeepsWhenAllExist(t *testing.T) { Name: "pod-foo", Namespace: "default", Labels: map[string]string{ - "workloads.cozystack.io/monitor": "mon", + "workloadmonitor.cozystack.io/name": "mon", }, }, } diff --git a/internal/controller/workloadmonitor_controller.go b/internal/controller/workloadmonitor_controller.go index 35906a87..d4d86b97 100644 --- a/internal/controller/workloadmonitor_controller.go +++ b/internal/controller/workloadmonitor_controller.go @@ -4,13 +4,7 @@ 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" @@ -28,29 +22,8 @@ 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 @@ -63,13 +36,6 @@ 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 { @@ -135,190 +101,6 @@ 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, @@ -355,22 +137,14 @@ 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(), &svc) - // 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 + workload.Labels["workloads.cozystack.io/monitor"] = monitor.Name // Fill Workload status fields: workload.Status.Kind = monitor.Spec.Kind @@ -414,22 +188,14 @@ 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(), &pvc) - // 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 + workload.Labels["workloads.cozystack.io/monitor"] = monitor.Name // Fill Workload status fields: workload.Status.Kind = monitor.Spec.Kind @@ -496,22 +262,14 @@ func (r *WorkloadMonitorReconciler) reconcilePodForMonitor( } 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(), &pod) - // 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 + workload.Labels["workloads.cozystack.io/monitor"] = monitor.Name // Add workload meta to labels for k, v := range metaLabels { @@ -617,34 +375,6 @@ 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 @@ -658,12 +388,10 @@ func (r *WorkloadMonitorReconciler) Reconcile(ctx context.Context, req ctrl.Requ 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) + // 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) } return r.Status().Update(ctx, fresh) }) @@ -672,12 +400,7 @@ func (r *WorkloadMonitorReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, err } - // 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 without requeue if we want purely event-driven reconciliations return ctrl.Result{}, nil } @@ -696,11 +419,6 @@ 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) @@ -749,26 +467,5 @@ 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 deleted file mode 100644 index 355b0379..00000000 --- a/internal/controller/workloadmonitor_controller_test.go +++ /dev/null @@ -1,846 +0,0 @@ -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 deleted file mode 100644 index 5f6215a7..00000000 --- a/internal/cozyvaluesreplicator/cozyvaluesreplicator.go +++ /dev/null @@ -1,272 +0,0 @@ -/* -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 deleted file mode 100644 index 5143f2e6..00000000 --- a/internal/crdinstall/install.go +++ /dev/null @@ -1,112 +0,0 @@ -/* -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 deleted file mode 100644 index 870a146c..00000000 --- a/internal/crdinstall/install_test.go +++ /dev/null @@ -1,302 +0,0 @@ -/* -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 deleted file mode 100644 index 7464e54e..00000000 --- a/internal/crdinstall/manifests.embed.go +++ /dev/null @@ -1,51 +0,0 @@ -/* -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/fluxinstall/install.go b/internal/fluxinstall/install.go index 4ae6f4cb..aa834404 100644 --- a/internal/fluxinstall/install.go +++ b/internal/fluxinstall/install.go @@ -17,15 +17,18 @@ limitations under the License. package fluxinstall import ( + "bufio" + "bytes" "context" "fmt" + "io" "os" "path/filepath" "strings" - - "github.com/cozystack/cozystack/internal/manifestutil" + "time" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + k8syaml "k8s.io/apimachinery/pkg/util/yaml" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" ) @@ -53,31 +56,26 @@ func Install(ctx context.Context, k8sClient client.Client, writeEmbeddedManifest 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) + // Find the manifest file (should be fluxcd.yaml from cozypkg) + manifestPath := filepath.Join(manifestsDir, "fluxcd.yaml") + if _, err := os.Stat(manifestPath); err != nil { + // Try to find any YAML file if fluxcd.yaml doesn't exist + entries, err := os.ReadDir(manifestsDir) if err != nil { - return fmt.Errorf("failed to parse manifests from %s: %w", manifestPath, err) + return fmt.Errorf("failed to read manifests directory: %w", err) } - objects = append(objects, objs...) + for _, entry := range entries { + if strings.HasSuffix(entry.Name(), ".yaml") { + manifestPath = filepath.Join(manifestsDir, entry.Name()) + break + } + } + } + + // Parse and apply manifests + objects, err := parseManifests(manifestPath) + if err != nil { + return fmt.Errorf("failed to parse manifests: %w", err) } if len(objects) == 0 { @@ -98,7 +96,7 @@ func Install(ctx context.Context, k8sClient client.Client, writeEmbeddedManifest 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) + logger.Info("Applying Flux manifests", "count", len(objects), "manifest", manifestPath, "namespace", namespace) if err := applyManifests(ctx, k8sClient, objects); err != nil { return fmt.Errorf("failed to apply manifests: %w", err) } @@ -107,6 +105,56 @@ func Install(ctx context.Context, k8sClient client.Client, writeEmbeddedManifest return nil } +// parseManifests parses YAML manifests into unstructured objects. +func parseManifests(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 into unstructured objects. +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) + } + + // Skip empty documents + 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 { + // Skip documents that can't be decoded (might be comments or empty) + if err == io.EOF { + continue + } + return nil, fmt.Errorf("failed to decode YAML document: %w", err) + } + + // Skip empty objects (no kind) + if obj.GetKind() == "" { + continue + } + + objects = append(objects, obj) + } + + return objects, 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) @@ -130,11 +178,8 @@ func applyManifests(ctx context.Context, k8sClient client.Client, objects []*uns 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) - } + // Wait a bit for CRDs to be registered + time.Sleep(2 * time.Second) } // Apply stage two (everything else) @@ -165,6 +210,7 @@ func applyObjects(ctx context.Context, k8sClient client.Client, objects []*unstr 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 { @@ -205,17 +251,11 @@ func injectKubernetesServiceEnv(objects []*unstructured.Unstructured) error { continue } - // Navigate to spec.template.spec + // Navigate to spec.template.spec.containers 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) @@ -335,3 +375,4 @@ func setEnvVar(env []interface{}, name, value string) []interface{} { return env } + diff --git a/internal/fluxinstall/manifests.embed.go b/internal/fluxinstall/manifests.embed.go index 6ff48d2d..e6a13a99 100644 --- a/internal/fluxinstall/manifests.embed.go +++ b/internal/fluxinstall/manifests.embed.go @@ -22,7 +22,6 @@ import ( "io/fs" "os" "path" - "path/filepath" ) //go:embed manifests/*.yaml @@ -41,8 +40,8 @@ func WriteEmbeddedManifests(dir string) error { 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 { + outputPath := path.Join(dir, manifest.Name()) + if err := os.WriteFile(outputPath, data, 0666); err != nil { return fmt.Errorf("failed to write file %s: %w", outputPath, err) } } diff --git a/internal/fluxinstall/manifests/fluxcd-service.yaml b/internal/fluxinstall/manifests/fluxcd-service.yaml deleted file mode 100644 index 87feaec4..00000000 --- a/internal/fluxinstall/manifests/fluxcd-service.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -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 deleted file mode 100644 index 077cf34c..00000000 --- a/internal/fluxinstall/manifests/fluxcd-tenants.yaml +++ /dev/null @@ -1,102 +0,0 @@ ---- -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 index 803f52bb..237db089 100644 --- a/internal/fluxinstall/manifests/fluxcd.yaml +++ b/internal/fluxinstall/manifests/fluxcd.yaml @@ -11871,7 +11871,7 @@ spec: - --health-addr=:9693 - --storage-addr=:9691 - --storage-path=/data - - --storage-adv-addr=flux.$(RUNTIME_NAMESPACE).svc + - --storage-adv-addr=source-watcher.$(RUNTIME_NAMESPACE).svc - --events-addr=http://localhost:9690 env: - name: SOURCE_CONTROLLER_LOCALHOST @@ -11940,12 +11940,10 @@ spec: 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 + - effect: NoExecute + key: node.kubernetes.io/unreachable operator: Exists + tolerationSeconds: 300 volumes: - emptyDir: {} name: data diff --git a/internal/lineagecontrollerwebhook/config.go b/internal/lineagecontrollerwebhook/config.go index ce4b6898..7204ab66 100644 --- a/internal/lineagecontrollerwebhook/config.go +++ b/internal/lineagecontrollerwebhook/config.go @@ -14,14 +14,14 @@ type appRef struct { } type runtimeConfig struct { - appCRDMap map[appRef]*cozyv1alpha1.ApplicationDefinition + appCRDMap map[appRef]*cozyv1alpha1.CozystackResourceDefinition } func (l *LineageControllerWebhook) initConfig() { l.initOnce.Do(func() { if l.config.Load() == nil { l.config.Store(&runtimeConfig{ - appCRDMap: make(map[appRef]*cozyv1alpha1.ApplicationDefinition), + appCRDMap: make(map[appRef]*cozyv1alpha1.CozystackResourceDefinition), }) } }) diff --git a/internal/lineagecontrollerwebhook/controller.go b/internal/lineagecontrollerwebhook/controller.go index 42bdb396..092d16e7 100644 --- a/internal/lineagecontrollerwebhook/controller.go +++ b/internal/lineagecontrollerwebhook/controller.go @@ -8,23 +8,23 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" ) -// +kubebuilder:rbac:groups=cozystack.io,resources=applicationdefinitions,verbs=list;watch;get +// +kubebuilder:rbac:groups=cozystack.io,resources=cozystackresourcedefinitions,verbs=list;watch;get func (c *LineageControllerWebhook) SetupWithManagerAsController(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - For(&cozyv1alpha1.ApplicationDefinition{}). + For(&cozyv1alpha1.CozystackResourceDefinition{}). Complete(c) } func (c *LineageControllerWebhook) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { l := log.FromContext(ctx) - crds := &cozyv1alpha1.ApplicationDefinitionList{} + crds := &cozyv1alpha1.CozystackResourceDefinitionList{} if err := c.List(ctx, crds); err != nil { - l.Error(err, "failed reading ApplicationDefinitions") + l.Error(err, "failed reading CozystackResourceDefinitions") return ctrl.Result{}, err } cfg := &runtimeConfig{ - appCRDMap: make(map[appRef]*cozyv1alpha1.ApplicationDefinition), + appCRDMap: make(map[appRef]*cozyv1alpha1.CozystackResourceDefinition), } for _, crd := range crds.Items { appRef := appRef{ diff --git a/internal/lineagecontrollerwebhook/matcher.go b/internal/lineagecontrollerwebhook/matcher.go index 6e7bd318..7c756a49 100644 --- a/internal/lineagecontrollerwebhook/matcher.go +++ b/internal/lineagecontrollerwebhook/matcher.go @@ -42,7 +42,7 @@ func matchName(ctx context.Context, name string, templateContext map[string]stri return false } -func matchResourceToSelector(ctx context.Context, name string, templateContext, l map[string]string, s *cozyv1alpha1.ApplicationDefinitionResourceSelector) bool { +func matchResourceToSelector(ctx context.Context, name string, templateContext, l map[string]string, s *cozyv1alpha1.CozystackResourceDefinitionResourceSelector) bool { sel, err := metav1.LabelSelectorAsSelector(&s.LabelSelector) if err != nil { log.FromContext(ctx).Error(err, "failed to convert label selector to selector") @@ -53,7 +53,7 @@ func matchResourceToSelector(ctx context.Context, name string, templateContext, return labelMatches && nameMatches } -func matchResourceToSelectorArray(ctx context.Context, name string, templateContext, l map[string]string, ss []*cozyv1alpha1.ApplicationDefinitionResourceSelector) bool { +func matchResourceToSelectorArray(ctx context.Context, name string, templateContext, l map[string]string, ss []*cozyv1alpha1.CozystackResourceDefinitionResourceSelector) bool { for _, s := range ss { if matchResourceToSelector(ctx, name, templateContext, l, s) { return true @@ -62,7 +62,7 @@ func matchResourceToSelectorArray(ctx context.Context, name string, templateCont return false } -func matchResourceToExcludeInclude(ctx context.Context, name string, templateContext, l map[string]string, resources *cozyv1alpha1.ApplicationDefinitionResources) bool { +func matchResourceToExcludeInclude(ctx context.Context, name string, templateContext, l map[string]string, resources *cozyv1alpha1.CozystackResourceDefinitionResources) bool { if resources == nil { return false } diff --git a/internal/lineagecontrollerwebhook/webhook.go b/internal/lineagecontrollerwebhook/webhook.go index cf871fb0..0841c891 100644 --- a/internal/lineagecontrollerwebhook/webhook.go +++ b/internal/lineagecontrollerwebhook/webhook.go @@ -8,28 +8,22 @@ import ( "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") + NoAncestors = fmt.Errorf("no managed apps found in lineage") + AncestryAmbiguous = fmt.Errorf("object ancestry is ambiguous") ) const ( @@ -39,8 +33,8 @@ const ( 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 { +// getResourceSelectors returns the appropriate CozystackResourceDefinitionResources for a given GroupKind +func (h *LineageControllerWebhook) getResourceSelectors(gk schema.GroupKind, crd *cozyv1alpha1.CozystackResourceDefinition) *cozyv1alpha1.CozystackResourceDefinitionResources { switch { case gk.Group == "" && gk.Kind == "Secret": return &crd.Spec.Secrets @@ -101,29 +95,26 @@ func (h *LineageControllerWebhook) Handle(ctx context.Context, req admission.Req 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)) + labels, err := h.computeLabels(ctx, obj) + for { + if err != nil && errors.Is(err, NoAncestors) { + break // not a problem, mark object as unmanaged + } + if err != nil && errors.Is(err, AncestryAmbiguous) { + warn = append(warn, "object ancestry ambiguous, using first ancestor found") + break + } + if err != nil { + logger.Error(err, "error computing lineage labels") + return admission.Errored(500, fmt.Errorf("error computing lineage labels: %w", err)) + } + if err == nil { + break + } } 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)) @@ -132,29 +123,22 @@ func (h *LineageControllerWebhook) Handle(ctx context.Context, req admission.Req return admission.PatchResponseFromRaw(req.Object.Raw, mutated).WithWarnings(warn...) } -func (h *LineageControllerWebhook) getOwner(ctx context.Context, o *unstructured.Unstructured) (*unstructured.Unstructured, error) { +func (h *LineageControllerWebhook) computeLabels(ctx context.Context, o *unstructured.Unstructured) (map[string]string, error) { owners := lineage.WalkOwnershipGraph(ctx, h.dynClient, h.mapper, h, o) if len(owners) == 0 { - return nil, NoAncestors + return map[string]string{ManagedObjectKey: "false"}, 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()) + gv, err := schema.ParseGroupVersion(obj.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) + return nil, fmt.Errorf("could not parse APIVersion %s to a group and version: %w", obj.GetAPIVersion(), err) + } + if len(owners) > 1 { + err = AncestryAmbiguous } labels := map[string]string{ // truncate apigroup to first 63 chars @@ -169,25 +153,25 @@ func (h *LineageControllerWebhook) computeLabels(ctx context.Context, obj *unstr } return s }(gv.Group), - ManagerKindKey: owner.GetKind(), - ManagerNameKey: owner.GetName(), + ManagerKindKey: obj.GetKind(), + ManagerNameKey: obj.GetName(), } templateLabels := map[string]string{ - "kind": strings.ToLower(owner.GetKind()), - "name": owner.GetName(), - "namespace": obj.GetNamespace(), + "kind": strings.ToLower(obj.GetKind()), + "name": obj.GetName(), + "namespace": o.GetNamespace(), } cfg := h.config.Load().(*runtimeConfig) - crd := cfg.appCRDMap[appRef{gv.Group, owner.GetKind()}] - resourceSelectors := h.getResourceSelectors(obj.GroupVersionKind().GroupKind(), crd) + crd := cfg.appCRDMap[appRef{gv.Group, obj.GetKind()}] + resourceSelectors := h.getResourceSelectors(o.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 + }(matchResourceToExcludeInclude(ctx, o.GetName(), templateLabels, o.GetLabels(), resourceSelectors)) + return labels, err } func (h *LineageControllerWebhook) applyLabels(o *unstructured.Unstructured, labels map[string]string) { @@ -201,68 +185,6 @@ func (h *LineageControllerWebhook) applyLabels(o *unstructured.Unstructured, lab 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 { diff --git a/internal/manifestutil/crd.go b/internal/manifestutil/crd.go deleted file mode 100644 index 08468d1b..00000000 --- a/internal/manifestutil/crd.go +++ /dev/null @@ -1,118 +0,0 @@ -/* -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 deleted file mode 100644 index 5d046353..00000000 --- a/internal/manifestutil/crd_test.go +++ /dev/null @@ -1,202 +0,0 @@ -/* -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 deleted file mode 100644 index 009e4a96..00000000 --- a/internal/manifestutil/parse.go +++ /dev/null @@ -1,76 +0,0 @@ -/* -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 deleted file mode 100644 index 860405c7..00000000 --- a/internal/manifestutil/parse_test.go +++ /dev/null @@ -1,161 +0,0 @@ -/* -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 index 0e724e49..879fe3d9 100644 --- a/internal/operator/package_reconciler.go +++ b/internal/operator/package_reconciler.go @@ -37,24 +37,6 @@ import ( "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 @@ -221,31 +203,18 @@ func (r *PackageReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct 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 { @@ -398,7 +367,6 @@ func (r *PackageReconciler) createOrUpdateHelmRelease(ctx context.Context, hr *h } hr.SetAnnotations(annotations) - hr.Spec.Suspend = existing.Spec.Suspend // Update Spec existing.Spec = hr.Spec existing.SetLabels(hr.GetLabels()) @@ -747,39 +715,53 @@ func (r *PackageReconciler) updateDependentPackagesDependencies(ctx context.Cont 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. +// reconcileNamespaces creates or updates namespaces based on components in the variant 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{}) + // Collect namespaces from components + // Map: namespace -> {isPrivileged} + type namespaceInfo struct { + privileged bool + } + namespacesMap := make(map[string]namespaceInfo) + 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 { continue } } + + // Namespace must be set 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) + info, exists := namespacesMap[namespace] + if !exists { + info = namespaceInfo{ + privileged: false, + } + } + + // If component is privileged, mark namespace as privileged + if component.Install.Privileged { + info.privileged = true + } + + namespacesMap[namespace] = info } // Create or update all namespaces - for nsName := range targetNamespaces { + for nsName, info := range namespacesMap { namespace := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: nsName, @@ -790,89 +772,36 @@ func (r *PackageReconciler) reconcileNamespaces(ctx context.Context, pkg *cozyv1 }, } + // Add system label only for non-tenant namespaces if !strings.HasPrefix(nsName, "tenant-") { namespace.Labels["cozystack.io/system"] = "true" } - if privileged[nsName] { + // Add privileged label if needed + if info.privileged { 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]) + logger.Error(err, "failed to reconcile namespace", "name", nsName, "privileged", info.privileged) return fmt.Errorf("failed to reconcile namespace %s: %w", nsName, err) } - logger.Info("reconciled namespace", "name", nsName, "privileged", privileged[nsName]) + logger.Info("reconciled namespace", "name", nsName, "privileged", info.privileged) } 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. +// createOrUpdateNamespace creates or updates a namespace using server-side apply func (r *PackageReconciler) createOrUpdateNamespace(ctx context.Context, namespace *corev1.Namespace) error { + // Ensure TypeMeta is set for server-side apply namespace.SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("Namespace")) - return r.Patch(ctx, namespace, client.Apply, client.FieldOwner("cozystack-package-controller"), client.ForceOwnership) + + // Use server-side apply with field manager + // This is atomic and avoids race conditions from Get/Create/Update pattern + // Labels and annotations will be merged automatically by the server + // Each label/annotation key is treated as a separate field, so existing ones are preserved + return r.Patch(ctx, namespace, client.Apply, client.FieldOwner("cozystack-package-controller")) } // cleanupOrphanedHelmReleases removes HelmReleases that are no longer needed @@ -940,7 +869,6 @@ 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 { diff --git a/internal/operator/package_reconciler_test.go b/internal/operator/package_reconciler_test.go deleted file mode 100644 index f0ee2c19..00000000 --- a/internal/operator/package_reconciler_test.go +++ /dev/null @@ -1,138 +0,0 @@ -/* -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 index e79370bd..dfbc096d 100644 --- a/internal/operator/packagesource_reconciler.go +++ b/internal/operator/packagesource_reconciler.go @@ -31,7 +31,9 @@ import ( 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" ) // PackageSourceReconciler reconciles PackageSource resources @@ -407,7 +409,26 @@ func (r *PackageSourceReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). Named("cozystack-packagesource"). For(&cozyv1alpha1.PackageSource{}). - Owns(&sourcewatcherv1beta1.ArtifactGenerator{}). + Watches( + &sourcewatcherv1beta1.ArtifactGenerator{}, + handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request { + ag, ok := obj.(*sourcewatcherv1beta1.ArtifactGenerator) + if !ok { + return nil + } + // Find the PackageSource that owns this ArtifactGenerator by ownerReference + for _, ownerRef := range ag.OwnerReferences { + if ownerRef.Kind == "PackageSource" { + return []reconcile.Request{{ + NamespacedName: types.NamespacedName{ + Name: ownerRef.Name, + }, + }} + } + } + return nil + }), + ). Complete(r) } diff --git a/internal/shared/crdmem/memory.go b/internal/shared/crdmem/memory.go index f0446627..fbfbeeea 100644 --- a/internal/shared/crdmem/memory.go +++ b/internal/shared/crdmem/memory.go @@ -11,13 +11,13 @@ import ( type Memory struct { mu sync.RWMutex - data map[string]cozyv1alpha1.ApplicationDefinition + data map[string]cozyv1alpha1.CozystackResourceDefinition primed bool primeOnce sync.Once } func New() *Memory { - return &Memory{data: make(map[string]cozyv1alpha1.ApplicationDefinition)} + return &Memory{data: make(map[string]cozyv1alpha1.CozystackResourceDefinition)} } var ( @@ -30,7 +30,7 @@ func Global() *Memory { return global } -func (m *Memory) Upsert(obj *cozyv1alpha1.ApplicationDefinition) { +func (m *Memory) Upsert(obj *cozyv1alpha1.CozystackResourceDefinition) { if obj == nil { return } @@ -45,10 +45,10 @@ func (m *Memory) Delete(name string) { m.mu.Unlock() } -func (m *Memory) Snapshot() []cozyv1alpha1.ApplicationDefinition { +func (m *Memory) Snapshot() []cozyv1alpha1.CozystackResourceDefinition { m.mu.RLock() defer m.mu.RUnlock() - out := make([]cozyv1alpha1.ApplicationDefinition, 0, len(m.data)) + out := make([]cozyv1alpha1.CozystackResourceDefinition, 0, len(m.data)) for _, v := range m.data { out = append(out, v) } @@ -72,7 +72,7 @@ func (m *Memory) EnsurePrimingWithManager(mgr ctrl.Manager) error { if ok := mgr.GetCache().WaitForCacheSync(ctx); !ok { return nil } - var list cozyv1alpha1.ApplicationDefinitionList + var list cozyv1alpha1.CozystackResourceDefinitionList if err := mgr.GetClient().List(ctx, &list); err == nil { for i := range list.Items { m.Upsert(&list.Items[i]) @@ -87,11 +87,11 @@ func (m *Memory) EnsurePrimingWithManager(mgr ctrl.Manager) error { return errOut } -func (m *Memory) ListFromCacheOrAPI(ctx context.Context, c client.Client) ([]cozyv1alpha1.ApplicationDefinition, error) { +func (m *Memory) ListFromCacheOrAPI(ctx context.Context, c client.Client) ([]cozyv1alpha1.CozystackResourceDefinition, error) { if m.IsPrimed() { return m.Snapshot(), nil } - var list cozyv1alpha1.ApplicationDefinitionList + var list cozyv1alpha1.CozystackResourceDefinitionList if err := c.List(ctx, &list); err != nil { return nil, err } diff --git a/internal/telemetry/collector.go b/internal/telemetry/collector.go index f4bb8dd8..04d05d3a 100644 --- a/internal/telemetry/collector.go +++ b/internal/telemetry/collector.go @@ -9,34 +9,35 @@ 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" ) -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 +// Collector handles telemetry data collection and sending type Collector struct { - client client.Client - config *Config - ticker *time.Ticker - stopCh chan struct{} + client client.Client + discoveryClient discovery.DiscoveryInterface + config *Config + ticker *time.Ticker + stopCh chan struct{} } -// NewCollector creates a new telemetry collector for cozystack-controller -func NewCollector(c client.Client, config *Config, _ *rest.Config) (*Collector, error) { +// 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) + } return &Collector{ - client: c, - config: config, + client: client, + discoveryClient: discoveryClient, + config: config, }, nil } @@ -66,9 +67,46 @@ 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) @@ -82,54 +120,151 @@ func (c *Collector) collect(ctx context.Context) { clusterID := string(kubeSystemNS.UID) - // 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)) + 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)) return } - // 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 - } - } + oidcEnabled := cozystackCM.Data["oidc-enabled"] + bundle := cozystackCM.Data["bundle-name"] + bundleEnable := cozystackCM.Data["bundle-enable"] + bundleDisable := cozystackCM.Data["bundle-disable"] - // 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)) + // 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)) 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 - // Write application count metrics - for kind, count := range appKindCounts { + // Add Cozystack info metric + if len(nodeList.Items) > 0 { + k8sVersion, _ := c.discoveryClient.ServerVersion() metrics.WriteString(fmt.Sprintf( - "cozy_application_count{kind=\"%s\"} %d\n", - kind, + "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, count, )) } - // 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)) + // 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++ + } } + 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 d2d3dcc0..b4c9b4d1 100644 --- a/internal/telemetry/config.go +++ b/internal/telemetry/config.go @@ -12,13 +12,16 @@ 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, + Disabled: false, + Endpoint: "https://telemetry.cozystack.io", + Interval: 15 * time.Minute, + CozystackVersion: "unknown", } } diff --git a/internal/telemetry/operator_collector.go b/internal/telemetry/operator_collector.go deleted file mode 100644 index 8b4ec302..00000000 --- a/internal/telemetry/operator_collector.go +++ /dev/null @@ -1,282 +0,0 @@ -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 deleted file mode 100644 index c206bb3d..00000000 --- a/internal/template/template.go +++ /dev/null @@ -1,68 +0,0 @@ -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 deleted file mode 100644 index 94ea2210..00000000 --- a/internal/template/template_test.go +++ /dev/null @@ -1,68 +0,0 @@ -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 50502f2b..b3917f20 100644 --- a/packages/apps/Makefile +++ b/packages/apps/Makefile @@ -1,7 +1,7 @@ OUT=../../_out/repos/apps CHARTS := $(shell find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}') -include ../../hack/common-envs.mk +include ../../scripts/common-envs.mk repo: rm -rf "$(OUT)" diff --git a/packages/apps/bucket/Makefile b/packages/apps/bucket/Makefile index 1e35bd53..d448d0c0 100644 --- a/packages/apps/bucket/Makefile +++ b/packages/apps/bucket/Makefile @@ -1,5 +1,6 @@ -include ../../../hack/package.mk +include ../../../scripts/package.mk generate: - cozyvalues-gen -m 'bucket' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/bucket/types.go + 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/apps/bucket/README.md b/packages/apps/bucket/README.md index 982225ce..89749b1d 100644 --- a/packages/apps/bucket/README.md +++ b/packages/apps/bucket/README.md @@ -1,13 +1,3 @@ # 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 0639916f..5cfdc1c1 100644 --- a/packages/apps/bucket/templates/bucketclaim.yaml +++ b/packages/apps/bucket/templates/bucketclaim.yaml @@ -1,24 +1,19 @@ {{- $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 }}{{- if $pool }}-{{ $pool }}{{- end }}{{- if .Values.locking }}-lock{{- end }} + bucketClassName: {{ $seaweedfs }} protocols: - s3 -{{- range $name, $user := .Values.users }} --- apiVersion: objectstorage.k8s.io/v1alpha1 kind: BucketAccess metadata: - name: {{ $.Release.Name }}-{{ $name }} + name: {{ .Release.Name }} spec: - bucketAccessClassName: {{ $seaweedfs }}{{- if $pool }}-{{ $pool }}{{- end }}{{- if $user.readonly }}-readonly{{- end }} - bucketClaimName: {{ $.Release.Name }} - credentialsSecretName: {{ $.Release.Name }}-{{ $name }} + bucketAccessClassName: {{ $seaweedfs }} + bucketClaimName: {{ .Release.Name }} + credentialsSecretName: {{ .Release.Name }} protocol: s3 -{{- end }} diff --git a/packages/apps/bucket/templates/dashboard-resourcemap.yaml b/packages/apps/bucket/templates/dashboard-resourcemap.yaml index 82a51e16..5edc8b7a 100644 --- a/packages/apps/bucket/templates/dashboard-resourcemap.yaml +++ b/packages/apps/bucket/templates/dashboard-resourcemap.yaml @@ -8,9 +8,8 @@ rules: resources: - secrets resourceNames: - {{- range $name, $user := .Values.users }} - - {{ $.Release.Name }}-{{ $name }}-credentials - {{- end }} + - {{ .Release.Name }} + - {{ .Release.Name }}-credentials 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 d3290512..8a57760e 100644 --- a/packages/apps/bucket/templates/helmrelease.yaml +++ b/packages/apps/bucket/templates/helmrelease.yaml @@ -2,13 +2,16 @@ 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-bucket-application-default-bucket-system - namespace: cozy-system + chart: + spec: + chart: cozy-bucket + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' interval: 5m timeout: 10m install: @@ -21,6 +24,11 @@ spec: valuesFrom: - kind: Secret name: cozystack-values + valuesKey: _cluster + targetPath: _cluster + - kind: Secret + name: cozystack-values + valuesKey: _namespace + targetPath: _namespace values: bucketName: {{ .Release.Name }} - users: {{ .Values.users | toJson }} diff --git a/packages/apps/bucket/values.schema.json b/packages/apps/bucket/values.schema.json index d302842c..167bc53e 100644 --- a/packages/apps/bucket/values.schema.json +++ b/packages/apps/bucket/values.schema.json @@ -1,30 +1,5 @@ { "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" - } - } - } - } - } + "properties": {} } diff --git a/packages/apps/bucket/values.yaml b/packages/apps/bucket/values.yaml index df284df7..0967ef42 100644 --- a/packages/apps/bucket/values.yaml +++ b/packages/apps/bucket/values.yaml @@ -1,11 +1 @@ -## @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/Makefile b/packages/apps/clickhouse/Makefile index 2d671d1d..44ac851f 100644 --- a/packages/apps/clickhouse/Makefile +++ b/packages/apps/clickhouse/Makefile @@ -1,10 +1,10 @@ CLICKHOUSE_BACKUP_TAG = $(shell awk '$$0 ~ /^version:/ {print $$2}' Chart.yaml) -include ../../../hack/common-envs.mk -include ../../../hack/package.mk +include ../../../scripts/common-envs.mk +include ../../../scripts/package.mk generate: - cozyvalues-gen -m 'clickhouse' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/clickhouse/types.go + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md ../../../hack/update-crd.sh image: diff --git a/packages/apps/clickhouse/templates/workloadmonitor.yaml b/packages/apps/clickhouse/templates/workloadmonitor.yaml index 62c951c2..9020ad41 100644 --- a/packages/apps/clickhouse/templates/workloadmonitor.yaml +++ b/packages/apps/clickhouse/templates/workloadmonitor.yaml @@ -3,8 +3,6 @@ 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 @@ -19,8 +17,6 @@ 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 diff --git a/packages/apps/clickhouse/values.schema.json b/packages/apps/clickhouse/values.schema.json index e4e1df7d..abb3aeb1 100644 --- a/packages/apps/clickhouse/values.schema.json +++ b/packages/apps/clickhouse/values.schema.json @@ -2,119 +2,6 @@ "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", @@ -216,6 +103,119 @@ "x-kubernetes-int-or-string": true } } + }, + "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 + }, + "replicas": { + "description": "Number of ClickHouse replicas.", + "type": "integer", + "default": 2 + }, + "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" + ] + }, + "shards": { + "description": "Number of ClickHouse shards.", + "type": "integer", + "default": 1 + }, + "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": "" + }, + "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" + } + } + } } } -} +} \ No newline at end of file diff --git a/packages/apps/openbao/.helmignore b/packages/apps/ferretdb/.helmignore similarity index 100% rename from packages/apps/openbao/.helmignore rename to packages/apps/ferretdb/.helmignore diff --git a/packages/apps/mongodb/Chart.yaml b/packages/apps/ferretdb/Chart.yaml similarity index 57% rename from packages/apps/mongodb/Chart.yaml rename to packages/apps/ferretdb/Chart.yaml index ffa97e9c..3044103a 100644 --- a/packages/apps/mongodb/Chart.yaml +++ b/packages/apps/ferretdb/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 -name: mongodb -description: Managed MongoDB service -icon: /logos/mongodb.svg +name: ferretdb +description: Managed FerretDB service +icon: /logos/ferretdb.svg type: application version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process -appVersion: "8.0" +appVersion: 2.4.0 diff --git a/packages/apps/ferretdb/Makefile b/packages/apps/ferretdb/Makefile new file mode 100644 index 00000000..bd52fb05 --- /dev/null +++ b/packages/apps/ferretdb/Makefile @@ -0,0 +1,12 @@ +include ../../../scripts/package.mk + +generate: + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md + ../../../hack/update-crd.sh + +update: + tag=$$(git ls-remote --tags --sort="v:refname" https://github.com/FerretDB/FerretDB | awk -F'[/^]' '{sub("^v", "", $$3)} END{print $$3}') && \ + pgtag=$$(skopeo list-tags docker://ghcr.io/ferretdb/postgres-documentdb | jq -r --arg tag "$$tag" '.Tags[] | select(endswith("ferretdb-" + $$tag))' | sort -V | tail -n1) && \ + sed -i "s|\(imageName: ghcr.io/ferretdb/postgres-documentdb:\).*|\1$$pgtag|" templates/postgres.yaml && \ + sed -i "s|\(image: ghcr.io/ferretdb/ferretdb:\).*|\1$$tag|" templates/ferretdb.yaml && \ + sed -i "s|\(appVersion: \).*|\1$$tag|" Chart.yaml diff --git a/packages/apps/ferretdb/README.md b/packages/apps/ferretdb/README.md new file mode 100644 index 00000000..91fc078e --- /dev/null +++ b/packages/apps/ferretdb/README.md @@ -0,0 +1,82 @@ +# 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 | Type | Value | +| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------- | +| `replicas` | Number of replicas. | `int` | `2` | +| `resources` | Explicit CPU and memory configuration for each FerretDB 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` | + + +### Application-specific parameters + +| Name | Description | Type | Value | +| ------------------------ | ---------------------------------------------------------------------------------- | ------------------- | ----- | +| `quorum` | Configuration for quorum-based 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` | Users configuration map. | `map[string]object` | `{}` | +| `users[name].password` | Password for the user. | `string` | `""` | + + +### Backup parameters + +| Name | Description | Type | Value | +| ------------------------ | ------------------------------------------------------------ | -------- | ----------------------------------- | +| `backup` | Backup configuration. | `object` | `{}` | +| `backup.enabled` | Enable regular backups (default: false). | `bool` | `false` | +| `backup.schedule` | Cron schedule for automated backups. | `string` | `0 2 * * * *` | +| `backup.retentionPolicy` | Retention policy. | `string` | `30d` | +| `backup.endpointURL` | S3 endpoint URL for uploads. | `string` | `http://minio-gateway-service:9000` | +| `backup.destinationPath` | Path to store the backup (e.g. s3://bucket/path/to/folder/). | `string` | `s3://bucket/path/to/folder/` | +| `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` | Restore database cluster from a backup. | `bool` | `false` | +| `bootstrap.recoveryTime` | Timestamp (RFC3339) for point-in-time recovery; empty means latest. | `string` | `""` | +| `bootstrap.oldName` | Name of database cluster before deletion. | `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` | diff --git a/packages/apps/harbor/charts/cozy-lib b/packages/apps/ferretdb/charts/cozy-lib similarity index 100% rename from packages/apps/harbor/charts/cozy-lib rename to packages/apps/ferretdb/charts/cozy-lib diff --git a/packages/apps/ferretdb/logos/ferretdb.svg b/packages/apps/ferretdb/logos/ferretdb.svg new file mode 100644 index 00000000..7d5c8b40 --- /dev/null +++ b/packages/apps/ferretdb/logos/ferretdb.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/packages/apps/mariadb/templates/.gitkeep b/packages/apps/ferretdb/templates/.gitkeep similarity index 100% rename from packages/apps/mariadb/templates/.gitkeep rename to packages/apps/ferretdb/templates/.gitkeep diff --git a/packages/apps/mariadb/templates/_resources.tpl b/packages/apps/ferretdb/templates/_resources.tpl similarity index 100% rename from packages/apps/mariadb/templates/_resources.tpl rename to packages/apps/ferretdb/templates/_resources.tpl diff --git a/packages/apps/ferretdb/templates/backup.yaml b/packages/apps/ferretdb/templates/backup.yaml new file mode 100644 index 00000000..96dea599 --- /dev/null +++ b/packages/apps/ferretdb/templates/backup.yaml @@ -0,0 +1,12 @@ +{{- if .Values.backup.enabled }} +--- +apiVersion: postgresql.cnpg.io/v1 +kind: ScheduledBackup +metadata: + name: {{ .Release.Name }}-postgres +spec: + schedule: {{ .Values.backup.schedule | quote }} + backupOwnerReference: self + cluster: + name: {{ .Release.Name }}-postgres +{{- end }} diff --git a/packages/apps/mongodb/templates/dashboard-resourcemap.yaml b/packages/apps/ferretdb/templates/dashboard-resourcemap.yaml similarity index 89% rename from packages/apps/mongodb/templates/dashboard-resourcemap.yaml rename to packages/apps/ferretdb/templates/dashboard-resourcemap.yaml index 33a6a4ef..af40a6fa 100644 --- a/packages/apps/mongodb/templates/dashboard-resourcemap.yaml +++ b/packages/apps/ferretdb/templates/dashboard-resourcemap.yaml @@ -8,9 +8,7 @@ rules: resources: - services resourceNames: - - {{ .Release.Name }}-rs0 - - {{ .Release.Name }}-mongos - - {{ .Release.Name }}-external + - {{ .Release.Name }} verbs: ["get", "list", "watch"] - apiGroups: - "" diff --git a/packages/apps/ferretdb/templates/external-svc.yaml b/packages/apps/ferretdb/templates/external-svc.yaml new file mode 100644 index 00000000..b4550cce --- /dev/null +++ b/packages/apps/ferretdb/templates/external-svc.yaml @@ -0,0 +1,19 @@ +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 + {{- if (include "cozy-lib.network.disableLoadBalancerNodePorts" $ | fromYaml) }} + allocateLoadBalancerNodePorts: false + {{- end }} + {{- 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 new file mode 100644 index 00000000..e73d42a3 --- /dev/null +++ b/packages/apps/ferretdb/templates/ferretdb.yaml @@ -0,0 +1,29 @@ +--- +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:2.4.0 + ports: + - containerPort: 27017 + env: + - name: POSTGRESQL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-postgres-superuser + key: password + - name: FERRETDB_POSTGRESQL_URL + value: "postgresql://postgres:$(POSTGRESQL_PASSWORD)@{{ .Release.Name }}-postgres-rw:5432/postgres" diff --git a/packages/apps/ferretdb/templates/postgres.yaml b/packages/apps/ferretdb/templates/postgres.yaml new file mode 100644 index 00000000..f1b1ce2c --- /dev/null +++ b/packages/apps/ferretdb/templates/postgres.yaml @@ -0,0 +1,114 @@ +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: {{ .Release.Name }}-postgres +spec: + instances: {{ .Values.replicas }} + {{- if .Values.backup.enabled }} + backup: + barmanObjectStore: + destinationPath: {{ .Values.backup.destinationPath }} + endpointURL: {{ .Values.backup.endpointURL }} + s3Credentials: + accessKeyId: + name: {{ .Release.Name }}-s3-creds + key: AWS_ACCESS_KEY_ID + secretAccessKey: + name: {{ .Release.Name }}-s3-creds + key: AWS_SECRET_ACCESS_KEY + retentionPolicy: {{ .Values.backup.retentionPolicy }} + {{- end }} + + bootstrap: + initdb: + postInitSQL: + - 'CREATE EXTENSION IF NOT EXISTS documentdb CASCADE;' + {{- if .Values.bootstrap.enabled }} + recovery: + source: {{ .Values.bootstrap.oldName }} + {{- if .Values.bootstrap.recoveryTime }} + recoveryTarget: + targetTime: {{ .Values.bootstrap.recoveryTime }} + {{- end }} + {{- end }} + {{- if .Values.bootstrap.enabled }} + externalClusters: + - name: {{ .Values.bootstrap.oldName }} + barmanObjectStore: + destinationPath: {{ .Values.backup.destinationPath }} + endpointURL: {{ .Values.backup.endpointURL }} + s3Credentials: + accessKeyId: + name: {{ .Release.Name }}-s3-creds + key: AWS_ACCESS_KEY_ID + secretAccessKey: + name: {{ .Release.Name }}-s3-creds + key: AWS_SECRET_ACCESS_KEY + {{- end }} + imageName: ghcr.io/ferretdb/postgres-documentdb:17-0.105.0-ferretdb-2.4.0 + postgresUID: 999 + postgresGID: 999 + enableSuperuserAccess: true + {{- if .Values._cluster.scheduling }} + {{- $rawConstraints := get .Values._cluster.scheduling "globalAppTopologySpreadConstraints" }} + {{- if $rawConstraints }} + {{- $rawConstraints | fromYaml | toYaml | nindent 2 }} + labelSelector: + matchLabels: + cnpg.io/cluster: {{ .Release.Name }}-postgres + {{- end }} + {{- end }} + minSyncReplicas: {{ .Values.quorum.minSyncReplicas }} + maxSyncReplicas: {{ .Values.quorum.maxSyncReplicas }} + resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 4 }} + monitoring: + enablePodMonitor: true + + postgresql: + shared_preload_libraries: + - pg_cron + - pg_documentdb_core + - pg_documentdb + parameters: + cron.database_name: 'postgres' + pg_hba: + - host postgres postgres 127.0.0.1/32 trust + - host postgres postgres ::1/128 trust + + storage: + size: {{ required ".Values.size is required" .Values.size }} + {{- with .Values.storageClass }} + storageClass: {{ . }} + {{- end }} + + inheritedMetadata: + labels: + policy.cozystack.io/allow-to-apiserver: "true" + app.kubernetes.io/instance: {{ .Release.Name }} + + {{- if .Values.users }} + managed: + roles: + {{- range $user, $config := .Values.users }} + - name: {{ $user }} + ensure: present + passwordSecret: + name: {{ printf "%s-user-%s" $.Release.Name $user }} + login: true + {{- end }} + {{- end }} + +{{- range $user, $config := .Values.users }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ printf "%s-user-%s" $.Release.Name $user }} + labels: + cnpg.io/reload: "true" +type: kubernetes.io/basic-auth +data: + username: {{ $user | b64enc }} + password: {{ $config.password | b64enc }} +{{- end }} diff --git a/packages/apps/mariadb/templates/workloadmonitor.yaml b/packages/apps/ferretdb/templates/workloadmonitor.yaml similarity index 67% rename from packages/apps/mariadb/templates/workloadmonitor.yaml rename to packages/apps/ferretdb/templates/workloadmonitor.yaml index 36cb59f0..a1b364d0 100644 --- a/packages/apps/mariadb/templates/workloadmonitor.yaml +++ b/packages/apps/ferretdb/templates/workloadmonitor.yaml @@ -3,13 +3,11 @@ 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: mariadb - type: mariadb + kind: ferretdb + type: ferretdb selector: app.kubernetes.io/instance: {{ $.Release.Name }} version: {{ $.Chart.Version }} diff --git a/packages/apps/ferretdb/values.schema.json b/packages/apps/ferretdb/values.schema.json new file mode 100644 index 00000000..f22a2340 --- /dev/null +++ b/packages/apps/ferretdb/values.schema.json @@ -0,0 +1,190 @@ +{ + "title": "Chart Values", + "type": "object", + "properties": { + "backup": { + "description": "Backup configuration.", + "type": "object", + "default": {}, + "required": [ + "destinationPath", + "enabled", + "endpointURL", + "retentionPolicy", + "s3AccessKey", + "s3SecretKey", + "schedule" + ], + "properties": { + "destinationPath": { + "description": "Path to store the backup (e.g. s3://bucket/path/to/folder/).", + "type": "string", + "default": "s3://bucket/path/to/folder/" + }, + "enabled": { + "description": "Enable regular backups (default: false).", + "type": "boolean", + "default": false + }, + "endpointURL": { + "description": "S3 endpoint URL for uploads.", + "type": "string", + "default": "http://minio-gateway-service:9000" + }, + "retentionPolicy": { + "description": "Retention policy.", + "type": "string", + "default": "30d" + }, + "s3AccessKey": { + "description": "Access key for S3 authentication.", + "type": "string", + "default": "\u003cyour-access-key\u003e" + }, + "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 * * * *" + } + } + }, + "bootstrap": { + "description": "Bootstrap configuration.", + "type": "object", + "default": {}, + "properties": { + "enabled": { + "description": "Restore database cluster from a backup.", + "type": "boolean", + "default": false + }, + "oldName": { + "description": "Name of database cluster before deletion.", + "type": "string", + "default": "" + }, + "recoveryTime": { + "description": "Timestamp (RFC3339) for point-in-time recovery; empty means latest.", + "type": "string", + "default": "" + } + } + }, + "external": { + "description": "Enable external access from outside the cluster.", + "type": "boolean", + "default": false + }, + "quorum": { + "description": "Configuration for quorum-based 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 + } + } + }, + "replicas": { + "description": "Number of replicas.", + "type": "integer", + "default": 2 + }, + "resources": { + "description": "Explicit CPU and memory configuration for each FerretDB 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": "" + }, + "users": { + "description": "Users configuration map.", + "type": "object", + "default": {}, + "additionalProperties": { + "type": "object", + "properties": { + "password": { + "description": "Password for the user.", + "type": "string" + } + } + } + } + } +} \ No newline at end of file diff --git a/packages/apps/ferretdb/values.yaml b/packages/apps/ferretdb/values.yaml new file mode 100644 index 00000000..fc905466 --- /dev/null +++ b/packages/apps/ferretdb/values.yaml @@ -0,0 +1,98 @@ +## +## @section Common parameters +## + +## @typedef {struct} Resources - Explicit CPU and memory configuration for each FerretDB 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 FerretDB replica. When omitted, the preset defined in `resourcesPreset` is applied. +resources: {} + +## @param {ResourcesPreset} resourcesPreset="micro" - Default sizing preset used when `resources` is omitted. +resourcesPreset: "micro" + +## @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 + +## +## @section Application-specific parameters +## + +## @typedef {struct} Quorum - Configuration for quorum-based synchronous replication. +## @field {int} minSyncReplicas - Minimum number of synchronous replicas required for commit. +## @field {int} maxSyncReplicas - Maximum number of synchronous replicas allowed (must be less than total replicas). + +## @param {Quorum} quorum - Configuration for quorum-based synchronous replication. +quorum: + minSyncReplicas: 0 + maxSyncReplicas: 0 + +## @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: +## password: hackme +## + +## +## @section Backup parameters +## + +## @typedef {struct} Backup - Backup configuration. +## @field {bool} enabled - Enable regular backups (default: false). +## @field {string} schedule - Cron schedule for automated backups. +## @field {string} retentionPolicy - Retention policy. +## @field {string} endpointURL - S3 endpoint URL for uploads. +## @field {string} destinationPath - Path to store the backup (e.g. s3://bucket/path/to/folder/). +## @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 + endpointURL: http://minio-gateway-service:9000 + destinationPath: s3://bucket/path/to/folder/ + s3AccessKey: "" + s3SecretKey: "" + +## +## @section Bootstrap (recovery) parameters +## + +## @typedef {struct} Bootstrap - Bootstrap configuration for restoring a database cluster from a backup. +## @field {bool} [enabled] - Restore database cluster from a backup. +## @field {string} [recoveryTime] - Timestamp (RFC3339) for point-in-time recovery; empty means latest. +## @field {string} [oldName] - Name of database cluster before deletion. + +## @param {Bootstrap} bootstrap - Bootstrap configuration. +bootstrap: + enabled: false + recoveryTime: "" + oldName: "" diff --git a/packages/apps/foundationdb/Makefile b/packages/apps/foundationdb/Makefile index 1a07cd5b..b885e4b1 100644 --- a/packages/apps/foundationdb/Makefile +++ b/packages/apps/foundationdb/Makefile @@ -1,4 +1,4 @@ -include ../../../hack/package.mk +include ../../../scripts/package.mk generate: - cozyvalues-gen -m 'foundationdb' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/foundationdb/types.go \ No newline at end of file + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md \ No newline at end of file diff --git a/packages/apps/foundationdb/README.md b/packages/apps/foundationdb/README.md index 30f5714e..4f7b6878 100644 --- a/packages/apps/foundationdb/README.md +++ b/packages/apps/foundationdb/README.md @@ -1,4 +1,4 @@ -# Managed FoundationDB Service +# FoundationDB A managed FoundationDB service for Cozystack. diff --git a/packages/apps/foundationdb/templates/workloadmonitor.yaml b/packages/apps/foundationdb/templates/workloadmonitor.yaml index 2e2a3d19..306797f3 100644 --- a/packages/apps/foundationdb/templates/workloadmonitor.yaml +++ b/packages/apps/foundationdb/templates/workloadmonitor.yaml @@ -8,7 +8,6 @@ metadata: 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" . }} diff --git a/packages/apps/foundationdb/values.schema.json b/packages/apps/foundationdb/values.schema.json index 1fc77d59..7b3a1ba5 100644 --- a/packages/apps/foundationdb/values.schema.json +++ b/packages/apps/foundationdb/values.schema.json @@ -2,6 +2,82 @@ "title": "Chart Values", "type": "object", "properties": { + "automaticReplacements": { + "description": "Enable automatic pod replacements.", + "type": "boolean", + "default": true + }, + "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" + } + } + } + } + }, "cluster": { "description": "Cluster configuration.", "type": "object", @@ -79,33 +155,35 @@ } } }, - "storage": { - "description": "Storage configuration.", + "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": {}, "required": [ - "size", - "storageClass" + "enabled" ], "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": "" + "enabled": { + "description": "Enable WorkloadMonitor integration.", + "type": "boolean", + "default": true } } }, @@ -154,109 +232,6 @@ "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", @@ -278,10 +253,35 @@ } } }, - "automaticReplacements": { - "description": "Enable automatic pod replacements.", - "type": "boolean", - "default": true + "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": "" + } + } } } -} +} \ No newline at end of file diff --git a/packages/apps/harbor/Chart.yaml b/packages/apps/harbor/Chart.yaml deleted file mode 100644 index 8b6f59da..00000000 --- a/packages/apps/harbor/Chart.yaml +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 43c25998..00000000 --- a/packages/apps/harbor/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 7789d9fe..00000000 --- a/packages/apps/harbor/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# 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/harbor/logos/harbor.svg b/packages/apps/harbor/logos/harbor.svg deleted file mode 100644 index 682254c3..00000000 --- a/packages/apps/harbor/logos/harbor.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/apps/harbor/templates/bucket.yaml b/packages/apps/harbor/templates/bucket.yaml deleted file mode 100644 index a9e60988..00000000 --- a/packages/apps/harbor/templates/bucket.yaml +++ /dev/null @@ -1,19 +0,0 @@ -{{- $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 deleted file mode 100644 index f8d91a61..00000000 --- a/packages/apps/harbor/templates/dashboard-resourcemap.yaml +++ /dev/null @@ -1,46 +0,0 @@ -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 deleted file mode 100644 index bf780967..00000000 --- a/packages/apps/harbor/templates/harbor.yaml +++ /dev/null @@ -1,205 +0,0 @@ -{{- $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 deleted file mode 100644 index 70933f5f..00000000 --- a/packages/apps/harbor/templates/ingress.yaml +++ /dev/null @@ -1,37 +0,0 @@ -{{- $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 deleted file mode 100644 index 23860ca3..00000000 --- a/packages/apps/harbor/values.schema.json +++ /dev/null @@ -1,315 +0,0 @@ -{ - "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 deleted file mode 100644 index de44eaff..00000000 --- a/packages/apps/harbor/values.yaml +++ /dev/null @@ -1,84 +0,0 @@ -## -## @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/Makefile b/packages/apps/http-cache/Makefile index 899f0288..3237f634 100644 --- a/packages/apps/http-cache/Makefile +++ b/packages/apps/http-cache/Makefile @@ -1,7 +1,7 @@ NGINX_CACHE_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml) -include ../../../hack/common-envs.mk -include ../../../hack/package.mk +include ../../../scripts/common-envs.mk +include ../../../scripts/package.mk image: image-nginx @@ -17,7 +17,7 @@ image-nginx: rm -f images/nginx-cache.json generate: - cozyvalues-gen -m 'httpcache' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/httpcache/types.go + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md ../../../hack/update-crd.sh update: diff --git a/packages/apps/http-cache/images/nginx-cache.tag b/packages/apps/http-cache/images/nginx-cache.tag index b08a374e..185dcc66 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.0.0@sha256:d397781152ab9123b11b8191d92eba7a0d2faa376aa2c15ddeb67842a9b59bab +ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:e0a07082bb6fc6aeaae2315f335386f1705a646c72f9e0af512aebbca5cb2b15 diff --git a/packages/apps/http-cache/templates/workloadmonitor.yaml b/packages/apps/http-cache/templates/workloadmonitor.yaml index a38a395a..150d8bbe 100644 --- a/packages/apps/http-cache/templates/workloadmonitor.yaml +++ b/packages/apps/http-cache/templates/workloadmonitor.yaml @@ -3,8 +3,6 @@ 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 @@ -18,8 +16,6 @@ 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 14609cc3..7fd1a37a 100644 --- a/packages/apps/http-cache/values.schema.json +++ b/packages/apps/http-cache/values.schema.json @@ -2,30 +2,6 @@ "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 \u003cip:port\u003e.", "type": "array", @@ -34,6 +10,11 @@ "type": "string" } }, + "external": { + "description": "Enable external access from outside the cluster.", + "type": "boolean", + "default": false + }, "haproxy": { "description": "HAProxy configuration.", "type": "object", @@ -159,6 +140,25 @@ ] } } + }, + "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": "" } } -} +} \ No newline at end of file diff --git a/packages/apps/kafka/Makefile b/packages/apps/kafka/Makefile index c1084e86..0d71076e 100644 --- a/packages/apps/kafka/Makefile +++ b/packages/apps/kafka/Makefile @@ -1,6 +1,6 @@ -include ../../../hack/package.mk +include ../../../scripts/package.mk PRESET_ENUM := ["nano","micro","small","medium","large","xlarge","2xlarge"] generate: - cozyvalues-gen -m 'kafka' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/kafka/types.go + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md ../../../hack/update-crd.sh diff --git a/packages/apps/kafka/templates/workloadmonitor.yaml b/packages/apps/kafka/templates/workloadmonitor.yaml index c31eb425..4b161b04 100644 --- a/packages/apps/kafka/templates/workloadmonitor.yaml +++ b/packages/apps/kafka/templates/workloadmonitor.yaml @@ -3,8 +3,6 @@ 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 @@ -21,8 +19,6 @@ 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 e3b6db12..4b375b63 100644 --- a/packages/apps/kafka/values.schema.json +++ b/packages/apps/kafka/values.schema.json @@ -7,39 +7,6 @@ "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", @@ -124,6 +91,39 @@ } } }, + "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" + } + } + } + }, "zookeeper": { "description": "ZooKeeper configuration.", "type": "object", @@ -209,4 +209,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/apps/kubernetes/.helmignore b/packages/apps/kubernetes/.helmignore index cdada667..3de7d4a5 100644 --- a/packages/apps/kubernetes/.helmignore +++ b/packages/apps/kubernetes/.helmignore @@ -2,4 +2,3 @@ /logos /Makefile /hack -/images/*/* diff --git a/packages/apps/kubernetes/Makefile b/packages/apps/kubernetes/Makefile index 4fea42ef..ae6dd757 100644 --- a/packages/apps/kubernetes/Makefile +++ b/packages/apps/kubernetes/Makefile @@ -1,14 +1,11 @@ -KUBERNETES_VERSIONS = $(shell awk -F'"' '{print $$2}' files/versions.yaml) +KUBERNETES_VERSION = v1.33 KUBERNETES_PKG_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml) -include ../../../hack/common-envs.mk -include ../../../hack/package.mk - -test: - helm unittest . +include ../../../scripts/common-envs.mk +include ../../../scripts/package.mk generate: - cozyvalues-gen -m 'kubernetes' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/kubernetes/types.go + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md ../../../hack/update-crd.sh update: @@ -18,19 +15,17 @@ update: image: image-ubuntu-container-disk image-kubevirt-cloud-provider image-kubevirt-csi-driver image-cluster-autoscaler image-ubuntu-container-disk: - $(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; \ - ) + docker buildx build images/ubuntu-container-disk \ + --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 \ + $(BUILDX_ARGS) + echo "$(REGISTRY)/ubuntu-container-disk:$(call settag,$(KUBERNETES_VERSION))@$$(yq e '."containerimage.digest"' images/ubuntu-container-disk.json -o json -r)" \ + > images/ubuntu-container-disk.tag + rm -f images/ubuntu-container-disk.json image-kubevirt-cloud-provider: docker buildx build images/kubevirt-cloud-provider \ @@ -70,4 +65,3 @@ image-cluster-autoscaler: 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 bed1117a..8bff49aa 100644 --- a/packages/apps/kubernetes/README.md +++ b/packages/apps/kubernetes/README.md @@ -104,7 +104,7 @@ See the reference for components utilized in this service: | `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` | +| `version` | Kubernetes major.minor version to deploy | `string` | `v1.33` | | `host` | External hostname for Kubernetes cluster. Defaults to `.` if empty. | `string` | `""` | @@ -128,9 +128,6 @@ See the reference for components utilized in this service: | `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` | `{}` | @@ -148,33 +145,31 @@ See the reference for components utilized in this service: ### Kubernetes Control Plane Configuration -| 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` | `""` | +| 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` | `medium` | +| `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` | ## Parameter examples and reference diff --git a/packages/apps/kubernetes/files/konnectivity-versions.yaml b/packages/apps/kubernetes/files/konnectivity-versions.yaml deleted file mode 100644 index 09ef4fa7..00000000 --- a/packages/apps/kubernetes/files/konnectivity-versions.yaml +++ /dev/null @@ -1,4 +0,0 @@ -# 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 index 58942b97..51a36034 100644 --- a/packages/apps/kubernetes/files/versions.yaml +++ b/packages/apps/kubernetes/files/versions.yaml @@ -1,6 +1,6 @@ -"v1.35": "v1.35.1" -"v1.34": "v1.34.4" -"v1.33": "v1.33.8" -"v1.32": "v1.32.12" +"v1.33": "v1.33.0" +"v1.32": "v1.32.10" "v1.31": "v1.31.14" "v1.30": "v1.30.14" +"v1.29": "v1.29.15" +"v1.28": "v1.28.15" diff --git a/packages/apps/kubernetes/images/busybox.tag b/packages/apps/kubernetes/images/busybox.tag deleted file mode 100644 index 39de220a..00000000 --- a/packages/apps/kubernetes/images/busybox.tag +++ /dev/null @@ -1 +0,0 @@ -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 d9fd9a52..d5ab33d1 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.0.0@sha256:e9d0aa7e651b03a6713b380101a61832818a91b5f989da9754f58693898c4056 +ghcr.io/cozystack/cozystack/cluster-autoscaler:0.0.0@sha256:2d39989846c3579dd020b9f6c77e6e314cc81aa344eaac0f6d633e723c17196d diff --git a/packages/apps/kubernetes/images/kubevirt-cloud-provider.tag b/packages/apps/kubernetes/images/kubevirt-cloud-provider.tag index ca661f3a..8120dd48 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.0.0@sha256:dee69d15fa8616aa6a1e5a67fc76370e7698a7f58b25e30650eb39c9fb826de8 +ghcr.io/cozystack/cozystack/kubevirt-cloud-provider:0.0.0@sha256:5335c044313b69ee13b30ca4941687e509005e55f4ae25723861edbf2fbd6dd2 diff --git a/packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/379.diff b/packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/354.diff similarity index 63% rename from packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/379.diff rename to packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/354.diff index ad1ec9c5..3410ea93 100644 --- a/packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/379.diff +++ b/packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/354.diff @@ -1,5 +1,5 @@ diff --git a/pkg/controller/kubevirteps/kubevirteps_controller.go b/pkg/controller/kubevirteps/kubevirteps_controller.go -index 53388eb8e..873060251 100644 +index 53388eb8e..28644236f 100644 --- a/pkg/controller/kubevirteps/kubevirteps_controller.go +++ b/pkg/controller/kubevirteps/kubevirteps_controller.go @@ -12,7 +12,6 @@ import ( @@ -10,17 +10,12 @@ index 53388eb8e..873060251 100644 "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" utilruntime "k8s.io/apimachinery/pkg/util/runtime" -@@ -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 +@@ -669,35 +668,50 @@ func (c *Controller) getDesiredEndpoints(service *v1.Service, tenantSlices []*di 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) @@ -28,13 +23,6 @@ index 53388eb8e..873060251 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) { @@ -80,7 +68,7 @@ index 53388eb8e..873060251 100644 desiredEndpoints = append(desiredEndpoints, &discovery.Endpoint{ Addresses: []string{i.IP}, Conditions: discovery.EndpointConditions{ -@@ -705,9 +728,9 @@ func (c *Controller) getDesiredEndpoints(service *v1.Service, tenantSlices []*di +@@ -705,9 +719,9 @@ func (c *Controller) getDesiredEndpoints(service *v1.Service, tenantSlices []*di Serving: &serving, Terminating: &terminating, }, @@ -92,71 +80,6 @@ index 53388eb8e..873060251 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 00aa2caa..80d3d2e6 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.0.0@sha256:72154a97054e16cdf3dea6129d962b8d7e86b55cf9386095e8ac2ce7c8b69172 +ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:d5c836ba33cf5dbed7e6f866784f668f80ffe69179e7c75847b680111984eefb diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver/Dockerfile b/packages/apps/kubernetes/images/kubevirt-csi-driver/Dockerfile index b156d08e..5ae5817f 100644 --- a/packages/apps/kubernetes/images/kubevirt-csi-driver/Dockerfile +++ b/packages/apps/kubernetes/images/kubevirt-csi-driver/Dockerfile @@ -1,23 +1,31 @@ +# 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 +WORKDIR /src/kubevirt-csi-driver -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 . +RUN make build FROM quay.io/centos/centos:stream9 +ARG git_url=https://github.com/kubevirt/csi-driver.git -RUN dnf install -y e2fsprogs xfsprogs nfs-utils && dnf clean all - -COPY --from=builder /src/kubevirt-csi-driver . +LABEL maintainers="The KubeVirt Project " \ + description="KubeVirt CSI Driver" \ + multi.GIT_URL=${git_url} 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 deleted file mode 100644 index edddec09..00000000 --- a/packages/apps/kubernetes/images/kubevirt-csi-driver/controller.go +++ /dev/null @@ -1,577 +0,0 @@ -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 deleted file mode 100644 index 96a96107..00000000 --- a/packages/apps/kubernetes/images/kubevirt-csi-driver/go.mod +++ /dev/null @@ -1,101 +0,0 @@ -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 deleted file mode 100644 index a0c4ac81..00000000 --- a/packages/apps/kubernetes/images/kubevirt-csi-driver/go.sum +++ /dev/null @@ -1,543 +0,0 @@ -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 deleted file mode 100644 index 396cee42..00000000 --- a/packages/apps/kubernetes/images/kubevirt-csi-driver/main.go +++ /dev/null @@ -1,219 +0,0 @@ -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 deleted file mode 100644 index a367f27f..00000000 --- a/packages/apps/kubernetes/images/kubevirt-csi-driver/node.go +++ /dev/null @@ -1,161 +0,0 @@ -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-v1.30.tag b/packages/apps/kubernetes/images/ubuntu-container-disk-v1.30.tag deleted file mode 100644 index f49fffe6..00000000 --- a/packages/apps/kubernetes/images/ubuntu-container-disk-v1.30.tag +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index b5bdc79a..00000000 --- a/packages/apps/kubernetes/images/ubuntu-container-disk-v1.31.tag +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index ca285644..00000000 --- a/packages/apps/kubernetes/images/ubuntu-container-disk-v1.32.tag +++ /dev/null @@ -1 +0,0 @@ -ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.32@sha256:7acb4728ef6b9c0ff3344bf486bb00f2a083f2098452344a362242235013db01 diff --git a/packages/apps/kubernetes/images/ubuntu-container-disk-v1.34.tag b/packages/apps/kubernetes/images/ubuntu-container-disk-v1.34.tag deleted file mode 100644 index 36eed7a7..00000000 --- a/packages/apps/kubernetes/images/ubuntu-container-disk-v1.34.tag +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index faae83d2..00000000 --- a/packages/apps/kubernetes/images/ubuntu-container-disk-v1.35.tag +++ /dev/null @@ -1 +0,0 @@ -ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.35@sha256:364c6d454891f1eb1a598fddb69cf328a14dbc451a8ac65812b038a7756da60a diff --git a/packages/apps/kubernetes/images/ubuntu-container-disk-v1.33.tag b/packages/apps/kubernetes/images/ubuntu-container-disk.tag similarity index 50% rename from packages/apps/kubernetes/images/ubuntu-container-disk-v1.33.tag rename to packages/apps/kubernetes/images/ubuntu-container-disk.tag index bb58690a..a35d1278 100644 --- a/packages/apps/kubernetes/images/ubuntu-container-disk-v1.33.tag +++ b/packages/apps/kubernetes/images/ubuntu-container-disk.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.33@sha256:a2024339ab9edb980a96b43ad2744b7aa31afaef0983ddbc6a546068b4cfa87a +ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.33@sha256:a09724a7f95283f9130b3da2a89d81c4c6051c6edf0392a81b6fc90f404b76b6 diff --git a/packages/apps/kubernetes/templates/_helpers.tpl b/packages/apps/kubernetes/templates/_helpers.tpl index 40a8ae7a..36c06b64 100644 --- a/packages/apps/kubernetes/templates/_helpers.tpl +++ b/packages/apps/kubernetes/templates/_helpers.tpl @@ -49,52 +49,3 @@ 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 index 403caff1..fcd4cee1 100644 --- a/packages/apps/kubernetes/templates/_versions.tpl +++ b/packages/apps/kubernetes/templates/_versions.tpl @@ -5,10 +5,3 @@ {{- 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 a4b7f2c9..b1399b11 100644 --- a/packages/apps/kubernetes/templates/cloud-config.yaml +++ b/packages/apps/kubernetes/templates/cloud-config.yaml @@ -10,8 +10,3 @@ 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 298d86db..a00e0155 100644 --- a/packages/apps/kubernetes/templates/cluster-autoscaler/deployment.yaml +++ b/packages/apps/kubernetes/templates/cluster-autoscaler/deployment.yaml @@ -1,14 +1,3 @@ -{{- /* - 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 @@ -34,8 +23,6 @@ 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 @@ -69,7 +56,6 @@ spec: name: cloud-config - secret: secretName: {{ .Release.Name }}-admin-kubeconfig - optional: true name: kubeconfig serviceAccountName: {{ .Release.Name }}-cluster-autoscaler terminationGracePeriodSeconds: 10 @@ -119,4 +105,3 @@ rules: - list - update - watch -{{- end }} diff --git a/packages/apps/kubernetes/templates/cluster.yaml b/packages/apps/kubernetes/templates/cluster.yaml index e1494e64..6acfb107 100644 --- a/packages/apps/kubernetes/templates/cluster.yaml +++ b/packages/apps/kubernetes/templates/cluster.yaml @@ -1,15 +1,4 @@ {{- $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 }} @@ -81,13 +70,11 @@ 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 (printf "images/ubuntu-container-disk-%s.tag" $.Values.version) | trim }}" + image: "{{ $.Files.Get "images/ubuntu-container-disk.tag" | trim }}" - name: ephemeral emptyDisk: capacity: {{ .group.ephemeralStorage | default "20Gi" }} @@ -95,26 +82,6 @@ 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 @@ -159,16 +126,8 @@ spec: dataStoreName: "{{ $etcd }}" addons: 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 @@ -282,9 +241,6 @@ spec: joinConfiguration: nodeRegistration: kubeletExtraArgs: {} - # Ignore this for 1.31 - ignorePreflightErrors: - - FileExisting-conntrack discovery: bootstrapToken: apiServerEndpoint: {{ $.Release.Name }}.{{ $.Release.Namespace }}.svc:6443 @@ -336,12 +292,6 @@ 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 }} @@ -376,7 +326,6 @@ metadata: namespace: {{ $.Release.Namespace }} spec: clusterName: {{ $.Release.Name }} - maxUnhealthy: 0 nodeStartupTimeout: 10m selector: matchLabels: @@ -435,4 +384,3 @@ 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 de62104c..b79a6d64 100644 --- a/packages/apps/kubernetes/templates/csi/deploy.yaml +++ b/packages/apps/kubernetes/templates/csi/deploy.yaml @@ -1,4 +1,3 @@ -{{- if .Values._namespace.etcd }} kind: Deployment apiVersion: apps/v1 metadata: @@ -25,8 +24,6 @@ spec: - key: node-role.kubernetes.io/control-plane operator: Exists effect: "NoSchedule" - initContainers: - {{- include "kubernetes.waitForAdminKubeconfig" $ | nindent 6 }} containers: - name: csi-driver imagePullPolicy: Always @@ -35,7 +32,6 @@ spec: - "--endpoint=$(CSI_ENDPOINT)" - "--infra-cluster-namespace=$(INFRACLUSTER_NAMESPACE)" - "--infra-cluster-labels=$(INFRACLUSTER_LABELS)" - - "--run-node-service=false" - "--v=5" ports: - name: healthz @@ -237,6 +233,4 @@ spec: 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 fb11ab25..793871d2 100644 --- a/packages/apps/kubernetes/templates/csi/infra-cluster-service-account.yaml +++ b/packages/apps/kubernetes/templates/csi/infra-cluster-service-account.yaml @@ -24,9 +24,6 @@ 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 diff --git a/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml index fd9dac7e..73954e12 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 and .Values.addons.certManager.enabled .Values._namespace.etcd }} +{{- if .Values.addons.certManager.enabled }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -6,13 +6,17 @@ metadata: labels: cozystack.io/repository: system cozystack.io/target-cluster-name: {{ .Release.Name }} - sharding.fluxcd.io/key: tenants spec: releaseName: cert-manager-crds - chartRef: - kind: ExternalArtifact - name: cozystack-kubernetes-application-kubevirt-kubernetes-cert-manager-crds - namespace: cozy-system + chart: + spec: + chart: cozy-cert-manager-crds + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml b/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml index 700b666e..e0caf4cb 100644 --- a/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml @@ -1,14 +1,4 @@ -{{- 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 }} +{{- if .Values.addons.certManager.enabled }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -16,13 +6,17 @@ metadata: labels: cozystack.io/repository: system cozystack.io/target-cluster-name: {{ .Release.Name }} - sharding.fluxcd.io/key: tenants spec: releaseName: cert-manager - chartRef: - kind: ExternalArtifact - name: cozystack-kubernetes-application-kubevirt-kubernetes-cert-manager - namespace: cozy-system + chart: + spec: + chart: cozy-cert-manager + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig @@ -39,8 +33,11 @@ spec: force: true remediation: retries: -1 + {{- with .Values.addons.certManager.valuesOverride }} values: - {{- toYaml (deepCopy .Values.addons.certManager.valuesOverride | mergeOverwrite (fromYaml (include "cozystack.defaultCertManagerValues" .))) | nindent 4 }} + {{- toYaml . | nindent 4 }} + {{- end }} + 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 d8c90cbf..c356dc79 100644 --- a/packages/apps/kubernetes/templates/helmreleases/cilium.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/cilium.yaml @@ -3,7 +3,6 @@ cilium: k8sServiceHost: {{ .Release.Name }}.{{ .Release.Namespace }}.svc k8sServicePort: 6443 routingMode: tunnel - MTU: 1350 enableIPv4Masquerade: true ipv4NativeRoutingCIDR: "" {{- if $.Values.addons.gatewayAPI.enabled }} @@ -14,7 +13,6 @@ cilium: {{- end }} {{- end }} -{{- if .Values._namespace.etcd }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -22,13 +20,17 @@ metadata: labels: cozystack.io/repository: system cozystack.io/target-cluster-name: {{ .Release.Name }} - sharding.fluxcd.io/key: tenants spec: releaseName: cilium - chartRef: - kind: ExternalArtifact - name: cozystack-kubernetes-application-kubevirt-kubernetes-cilium - namespace: cozy-system + chart: + spec: + chart: cozy-cilium + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig @@ -56,4 +58,3 @@ 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 index 0711a51d..37a09a0b 100644 --- a/packages/apps/kubernetes/templates/helmreleases/coredns.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/coredns.yaml @@ -4,7 +4,6 @@ coredns: clusterIP: "10.95.0.10" {{- end }} -{{- if .Values._namespace.etcd }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -12,13 +11,17 @@ metadata: 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 + chart: + spec: + chart: cozy-coredns + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig @@ -43,4 +46,3 @@ spec: {{- 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 109d78e1..3ecbf1eb 100644 --- a/packages/apps/kubernetes/templates/helmreleases/csi.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/csi.yaml @@ -1,4 +1,3 @@ -{{- if .Values._namespace.etcd }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -6,14 +5,18 @@ metadata: labels: cozystack.io/repository: system cozystack.io/target-cluster-name: {{ .Release.Name }} - sharding.fluxcd.io/key: tenants spec: interval: 5m releaseName: csi - chartRef: - kind: ExternalArtifact - name: cozystack-kubernetes-application-kubevirt-kubernetes-kubevirt-csi-node - namespace: cozy-system + chart: + spec: + chart: cozy-kubevirt-csi-node + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig @@ -40,4 +43,3 @@ spec: - name: {{ .Release.Name }} namespace: {{ .Release.Namespace }} {{- end }} -{{- end }} diff --git a/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml b/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml index 25fff01c..7518601b 100644 --- a/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.addons.fluxcd.enabled .Values._namespace.etcd }} +{{- if .Values.addons.fluxcd.enabled }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -6,13 +6,17 @@ metadata: labels: cozystack.io/repository: system cozystack.io/target-cluster-name: {{ .Release.Name }} - sharding.fluxcd.io/key: tenants spec: releaseName: fluxcd-operator - chartRef: - kind: ExternalArtifact - name: cozystack-kubernetes-application-kubevirt-kubernetes-fluxcd-operator - namespace: cozy-system + chart: + spec: + chart: cozy-fluxcd-operator + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig @@ -49,14 +53,18 @@ metadata: labels: cozystack.io/repository: system cozystack.io/target-cluster-name: {{ .Release.Name }} - sharding.fluxcd.io/key: tenants spec: interval: 5m releaseName: fluxcd - chartRef: - kind: ExternalArtifact - name: cozystack-kubernetes-application-kubevirt-kubernetes-fluxcd - namespace: cozy-system + chart: + spec: + chart: cozy-fluxcd + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' 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 b4172ed1..48a20c5a 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 and $.Values.addons.gatewayAPI.enabled $.Values._namespace.etcd }} +{{- if $.Values.addons.gatewayAPI.enabled }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -6,13 +6,17 @@ metadata: labels: cozystack.io/repository: system cozystack.io/target-cluster-name: {{ .Release.Name }} - sharding.fluxcd.io/key: tenants spec: releaseName: gateway-api-crds - chartRef: - kind: ExternalArtifact - name: cozystack-kubernetes-application-kubevirt-kubernetes-gateway-api-crds - namespace: cozy-system + chart: + spec: + chart: cozy-gateway-api-crds + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml b/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml index 655dc868..fbee1724 100644 --- a/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml @@ -1,12 +1,4 @@ -{{- define "cozystack.defaultGpuOperatorValues" -}} -{{- if .Values.addons.hami.enabled }} -gpu-operator: - devicePlugin: - enabled: false -{{- end }} -{{- end }} - -{{- if and .Values.addons.gpuOperator.enabled .Values._namespace.etcd }} +{{- if .Values.addons.gpuOperator.enabled }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -14,13 +6,17 @@ metadata: labels: cozystack.io/repository: system cozystack.io/target-cluster-name: {{ .Release.Name }} - sharding.fluxcd.io/key: tenants spec: releaseName: gpu-operator - chartRef: - kind: ExternalArtifact - name: cozystack-kubernetes-application-kubevirt-kubernetes-gpu-operator - namespace: cozy-system + chart: + spec: + chart: cozy-gpu-operator + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig @@ -37,12 +33,9 @@ spec: force: true remediation: retries: -1 - {{- $defaults := fromYaml (include "cozystack.defaultGpuOperatorValues" .) }} - {{- $overrides := deepCopy (default (dict) .Values.addons.gpuOperator.valuesOverride) }} - {{- $merged := mergeOverwrite (default (dict) $defaults) $overrides }} - {{- if $merged }} + {{- with .Values.addons.gpuOperator.valuesOverride }} values: - {{- toYaml $merged | nindent 4 }} + {{- toYaml . | nindent 4 }} {{- end }} dependsOn: diff --git a/packages/apps/kubernetes/templates/helmreleases/hami.yaml b/packages/apps/kubernetes/templates/helmreleases/hami.yaml deleted file mode 100644 index f1538c7c..00000000 --- a/packages/apps/kubernetes/templates/helmreleases/hami.yaml +++ /dev/null @@ -1,49 +0,0 @@ -{{- 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 6e2183d3..f80dd7ae 100644 --- a/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml @@ -4,12 +4,9 @@ ingress-nginx: controller: kind: DaemonSet {{- if eq .Values.addons.ingressNginx.exposeMethod "Proxied" }} + hostNetwork: true service: - enabled: true - type: NodePort - nodePorts: - http: 30000 - https: 30001 + enabled: false {{- end }} {{- if not .Values.addons.certManager.enabled }} admissionWebhooks: @@ -20,7 +17,7 @@ ingress-nginx: node-role.kubernetes.io/ingress-nginx: "" {{- end }} -{{- if and .Values.addons.ingressNginx.enabled .Values._namespace.etcd }} +{{- if .Values.addons.ingressNginx.enabled }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -28,13 +25,17 @@ metadata: labels: cozystack.io/repository: system cozystack.io/target-cluster-name: {{ .Release.Name }} - sharding.fluxcd.io/key: tenants spec: releaseName: ingress-nginx - chartRef: - kind: ExternalArtifact - name: cozystack-kubernetes-application-kubevirt-kubernetes-ingress-nginx - namespace: cozy-system + chart: + spec: + chart: cozy-ingress-nginx + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/metrics-server.yaml b/packages/apps/kubernetes/templates/helmreleases/metrics-server.yaml index 3e6f9660..394e6bb4 100644 --- a/packages/apps/kubernetes/templates/helmreleases/metrics-server.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/metrics-server.yaml @@ -1,4 +1,3 @@ -{{- if .Values._namespace.etcd }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -6,13 +5,17 @@ metadata: 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 + chart: + spec: + chart: cozy-metrics-server + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig @@ -37,4 +40,3 @@ spec: 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 a811f7dd..73c3a368 100644 --- a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml @@ -1,6 +1,5 @@ {{- $targetTenant := .Values._namespace.monitoring }} -{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }} -{{- if and .Values.addons.monitoringAgents.enabled .Values._namespace.etcd }} +{{- if .Values.addons.monitoringAgents.enabled }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -8,13 +7,17 @@ metadata: labels: cozystack.io/repository: system cozystack.io/target-cluster-name: {{ .Release.Name }} - sharding.fluxcd.io/key: tenants spec: releaseName: cozy-monitoring-agents - chartRef: - kind: ExternalArtifact - name: cozystack-kubernetes-application-kubevirt-kubernetes-monitoring-agents - namespace: cozy-system + chart: + spec: + chart: cozy-monitoring-agents + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig @@ -50,7 +53,7 @@ spec: cluster: {{ .Release.Name }} tenant: {{ .Release.Namespace }} remoteWrite: - url: http://vminsert-shortterm.{{ $targetTenant }}.svc.{{ $clusterDomain }}:8480/insert/0/prometheus + url: http://vminsert-shortterm.{{ $targetTenant }}.svc:8480/insert/0/prometheus fluent-bit: readinessProbe: httpGet: @@ -73,8 +76,8 @@ spec: [OUTPUT] Name http Match kube.* - Host vlinsert-generic.{{ $targetTenant }}.svc.{{ $clusterDomain }} - port 9481 + Host vlogs-generic.{{ $targetTenant }}.svc + port 9428 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 index 3038a058..63972126 100644 --- a/packages/apps/kubernetes/templates/helmreleases/prometheus-operator-crds.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/prometheus-operator-crds.yaml @@ -1,4 +1,3 @@ -{{- if .Values._namespace.etcd }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -6,13 +5,17 @@ metadata: 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 + chart: + spec: + chart: cozy-prometheus-operator-crds + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig @@ -32,4 +35,3 @@ spec: - 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 781b9c49..0c918da6 100644 --- a/packages/apps/kubernetes/templates/helmreleases/velero.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/velero.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.addons.velero.enabled .Values._namespace.etcd }} +{{- if .Values.addons.velero.enabled }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -6,13 +6,17 @@ metadata: labels: cozystack.io/repository: system cozystack.io/target-cluster-name: {{ .Release.Name }} - sharding.fluxcd.io/key: tenants spec: releaseName: velero - chartRef: - kind: ExternalArtifact - name: cozystack-kubernetes-application-kubevirt-kubernetes-velero - namespace: cozy-system + chart: + spec: + chart: cozy-velero + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml index 55a5faac..71bdc9ee 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 and .Values.addons.monitoringAgents.enabled .Values._namespace.etcd }} +{{- if .Values.addons.monitoringAgents.enabled }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -6,14 +6,18 @@ 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 - chartRef: - kind: ExternalArtifact - name: cozystack-kubernetes-application-kubevirt-kubernetes-vertical-pod-autoscaler-crds - namespace: cozy-system + chart: + spec: + chart: cozy-vertical-pod-autoscaler-crds + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml index 74fb5a39..8a62288d 100644 --- a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml @@ -24,7 +24,7 @@ vertical-pod-autoscaler: memory: 1600Mi {{- end }} -{{- if and .Values.addons.monitoringAgents.enabled .Values._namespace.etcd }} +{{- if .Values.addons.monitoringAgents.enabled }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -32,13 +32,17 @@ metadata: labels: cozystack.io/repository: system cozystack.io/target-cluster-name: {{ .Release.Name }} - sharding.fluxcd.io/key: tenants spec: releaseName: vertical-pod-autoscaler - chartRef: - kind: ExternalArtifact - name: cozystack-kubernetes-application-kubevirt-kubernetes-vertical-pod-autoscaler - namespace: cozy-system + chart: + spec: + chart: cozy-vertical-pod-autoscaler + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml b/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml index 7302f8f5..dbb4d8dc 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 and .Values.addons.monitoringAgents.enabled .Values._namespace.etcd }} +{{- if .Values.addons.monitoringAgents.enabled }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -6,13 +6,17 @@ metadata: labels: cozystack.io/repository: system cozystack.io/target-cluster-name: {{ .Release.Name }} - sharding.fluxcd.io/key: tenants spec: releaseName: cozy-victoria-metrics-operator - chartRef: - kind: ExternalArtifact - name: cozystack-kubernetes-application-kubevirt-kubernetes-victoria-metrics-operator - namespace: cozy-system + chart: + spec: + chart: cozy-victoria-metrics-operator + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig diff --git a/packages/apps/kubernetes/templates/helmreleases/volumesnapshot-crd.yaml b/packages/apps/kubernetes/templates/helmreleases/volumesnapshot-crd.yaml index d50fd93c..83fa32d1 100644 --- a/packages/apps/kubernetes/templates/helmreleases/volumesnapshot-crd.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/volumesnapshot-crd.yaml @@ -1,4 +1,3 @@ -{{- if .Values._namespace.etcd }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -6,13 +5,17 @@ metadata: 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 + chart: + spec: + chart: cozy-vsnap-crd + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' kubeConfig: secretRef: name: {{ .Release.Name }}-admin-kubeconfig @@ -34,4 +37,3 @@ spec: - 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 4adb7458..7993dba8 100644 --- a/packages/apps/kubernetes/templates/ingress.yaml +++ b/packages/apps/kubernetes/templates/ingress.yaml @@ -14,11 +14,6 @@ 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: @@ -46,21 +41,16 @@ 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: 30000 + targetPort: 80 - appProtocol: https name: https port: 443 - targetPort: 30001 + targetPort: 443 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 bd9e2798..81426d4e 100644 --- a/packages/apps/kubernetes/templates/kccm/manager.yaml +++ b/packages/apps/kubernetes/templates/kccm/manager.yaml @@ -1,4 +1,3 @@ -{{- if .Values._namespace.etcd }} apiVersion: apps/v1 kind: Deployment metadata: @@ -23,8 +22,6 @@ 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: @@ -58,7 +55,5 @@ 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 deleted file mode 100644 index 507e00af..00000000 --- a/packages/apps/kubernetes/tests/admin_kubeconfig_wait_test.yaml +++ /dev/null @@ -1,155 +0,0 @@ -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 deleted file mode 100644 index 44528470..00000000 --- a/packages/apps/kubernetes/tests/gpu_operator_hami_test.yaml +++ /dev/null @@ -1,99 +0,0 @@ -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 deleted file mode 100644 index 27f7c75b..00000000 --- a/packages/apps/kubernetes/tests/hami_test.yaml +++ /dev/null @@ -1,153 +0,0 @@ -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 deleted file mode 100644 index c7c8196f..00000000 --- a/packages/apps/kubernetes/tests/values-ci-no-etcd.yaml +++ /dev/null @@ -1,9 +0,0 @@ -_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 deleted file mode 100644 index 13365e8c..00000000 --- a/packages/apps/kubernetes/tests/values-ci.yaml +++ /dev/null @@ -1,9 +0,0 @@ -_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 a43deaec..9ec0c416 100644 --- a/packages/apps/kubernetes/values.schema.json +++ b/packages/apps/kubernetes/values.schema.json @@ -2,142 +2,6 @@ "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 `\u003ccluster-name\u003e.\u003ctenant-host\u003e` if empty.", - "type": "string", - "default": "" - }, "addons": { "description": "Cluster addons configuration.", "type": "object", @@ -149,7 +13,6 @@ "fluxcd", "gatewayAPI", "gpuOperator", - "hami", "ingressNginx", "monitoringAgents", "velero", @@ -269,28 +132,6 @@ } } }, - "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", @@ -309,11 +150,7 @@ "exposeMethod": { "description": "Method to expose the controller. Allowed values: `Proxied`, `LoadBalancer`.", "type": "string", - "default": "Proxied", - "enum": [ - "Proxied", - "LoadBalancer" - ] + "default": "Proxied" }, "hosts": { "description": "Domains routed to this tenant cluster when `exposeMethod` is `Proxied`.", @@ -450,7 +287,7 @@ "resourcesPreset": { "description": "Preset if `resources` omitted.", "type": "string", - "default": "large", + "default": "medium", "enum": [ "nano", "micro", @@ -654,17 +491,141 @@ } } }, - "images": { - "description": "Optional image overrides for air-gapped or rate-limited registries.", + "host": { + "description": "External hostname for Kubernetes cluster. Defaults to `\u003ccluster-name\u003e.\u003ctenant-host\u003e` if empty.", + "type": "string", + "default": "" + }, + "nodeGroups": { + "description": "Worker nodes configuration map.", "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": "" + "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" + } + } } } + }, + "storageClass": { + "description": "StorageClass used to store the data.", + "type": "string", + "default": "replicated" + }, + "version": { + "description": "Kubernetes major.minor version to deploy", + "type": "string", + "default": "v1.33", + "enum": [ + "v1.33", + "v1.32", + "v1.31", + "v1.30", + "v1.29", + "v1.28" + ] } } -} +} \ No newline at end of file diff --git a/packages/apps/kubernetes/values.yaml b/packages/apps/kubernetes/values.yaml index d609476c..567d2e02 100644 --- a/packages/apps/kubernetes/values.yaml +++ b/packages/apps/kubernetes/values.yaml @@ -48,15 +48,15 @@ nodeGroups: ## ## @enum {string} Version -## @value v1.35 -## @value v1.34 ## @value v1.33 ## @value v1.32 ## @value v1.31 ## @value v1.30 +## @value v1.29 +## @value v1.28 ## @param {Version} version - Kubernetes major.minor version to deploy -version: "v1.35" +version: "v1.33" ## @param {string} host - External hostname for Kubernetes cluster. Defaults to `.` if empty. @@ -76,13 +76,9 @@ host: "" ## @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} 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. @@ -94,10 +90,6 @@ host: "" ## @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. @@ -118,7 +110,6 @@ host: "" ## @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. @@ -142,9 +133,6 @@ addons: gpuOperator: enabled: false valuesOverride: {} - hami: - enabled: false - valuesOverride: {} fluxcd: enabled: false valuesOverride: {} @@ -165,7 +153,7 @@ addons: ## @typedef {struct} APIServer - API Server configuration. ## @field {Resources} resources - CPU and memory resources for API Server. -## @field {ResourcesPreset} resourcesPreset="large" - Preset if `resources` omitted. +## @field {ResourcesPreset} resourcesPreset="medium" - Preset if `resources` omitted. ## @typedef {struct} ControllerManager - Controller Manager configuration. ## @field {Resources} resources - CPU and memory resources for Controller Manager. @@ -194,7 +182,7 @@ controlPlane: replicas: 2 apiServer: resources: {} - resourcesPreset: "large" + resourcesPreset: "medium" controllerManager: resources: {} resourcesPreset: "micro" @@ -205,10 +193,3 @@ controlPlane: server: 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/mariadb/images/mariadb-backup.tag b/packages/apps/mariadb/images/mariadb-backup.tag deleted file mode 100644 index 6c830892..00000000 --- a/packages/apps/mariadb/images/mariadb-backup.tag +++ /dev/null @@ -1 +0,0 @@ -ghcr.io/cozystack/cozystack/mariadb-backup:0.0.0@sha256:3841eb171416711977dea0cf8cd45d32344caac9727af760c37d5e1dd41ee4bb diff --git a/packages/apps/mongodb/.helmignore b/packages/apps/mongodb/.helmignore deleted file mode 100644 index 0e8a0eb3..00000000 --- a/packages/apps/mongodb/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# 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/mongodb/Makefile b/packages/apps/mongodb/Makefile deleted file mode 100644 index 37f30ccc..00000000 --- a/packages/apps/mongodb/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 82127c59..00000000 --- a/packages/apps/mongodb/README.md +++ /dev/null @@ -1,110 +0,0 @@ -# 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/files/versions.yaml b/packages/apps/mongodb/files/versions.yaml deleted file mode 100644 index ee1333c5..00000000 --- a/packages/apps/mongodb/files/versions.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# 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 deleted file mode 100755 index 832eaf76..00000000 --- a/packages/apps/mongodb/hack/update-versions.sh +++ /dev/null @@ -1,125 +0,0 @@ -#!/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 deleted file mode 100644 index 86bb6d40..00000000 --- a/packages/apps/mongodb/logos/mongodb.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/packages/apps/mongodb/templates/_versions.tpl b/packages/apps/mongodb/templates/_versions.tpl deleted file mode 100644 index 6afc6457..00000000 --- a/packages/apps/mongodb/templates/_versions.tpl +++ /dev/null @@ -1,12 +0,0 @@ -{{/* -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 deleted file mode 100644 index f7b2ba01..00000000 --- a/packages/apps/mongodb/templates/backup-secret.yaml +++ /dev/null @@ -1,11 +0,0 @@ -{{- 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 deleted file mode 100644 index 561f7672..00000000 --- a/packages/apps/mongodb/templates/credentials.yaml +++ /dev/null @@ -1,34 +0,0 @@ -{{- $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/mongodb/templates/external-svc.yaml b/packages/apps/mongodb/templates/external-svc.yaml deleted file mode 100644 index 22324514..00000000 --- a/packages/apps/mongodb/templates/external-svc.yaml +++ /dev/null @@ -1,24 +0,0 @@ -{{- 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 deleted file mode 100644 index 9273e506..00000000 --- a/packages/apps/mongodb/templates/mongodb.yaml +++ /dev/null @@ -1,191 +0,0 @@ -{{- $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 deleted file mode 100644 index 56e2150b..00000000 --- a/packages/apps/mongodb/templates/restore.yaml +++ /dev/null @@ -1,37 +0,0 @@ -{{- 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 deleted file mode 100644 index 8212e95f..00000000 --- a/packages/apps/mongodb/templates/user-secrets.yaml +++ /dev/null @@ -1,17 +0,0 @@ -{{- 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 deleted file mode 100644 index f3eca410..00000000 --- a/packages/apps/mongodb/tests/backup-secret_test.yaml +++ /dev/null @@ -1,112 +0,0 @@ -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 deleted file mode 100644 index b06924ef..00000000 --- a/packages/apps/mongodb/tests/credentials_test.yaml +++ /dev/null @@ -1,132 +0,0 @@ -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 deleted file mode 100644 index 8cc1a0a7..00000000 --- a/packages/apps/mongodb/tests/dashboard-resourcemap_test.yaml +++ /dev/null @@ -1,106 +0,0 @@ -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 deleted file mode 100644 index ed3bf597..00000000 --- a/packages/apps/mongodb/tests/external-svc_test.yaml +++ /dev/null @@ -1,154 +0,0 @@ -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 deleted file mode 100644 index 4154ca25..00000000 --- a/packages/apps/mongodb/tests/mongodb_test.yaml +++ /dev/null @@ -1,731 +0,0 @@ -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 deleted file mode 100644 index e591587b..00000000 --- a/packages/apps/mongodb/tests/restore_test.yaml +++ /dev/null @@ -1,349 +0,0 @@ -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 deleted file mode 100644 index 6d9fb388..00000000 --- a/packages/apps/mongodb/tests/user-secrets_test.yaml +++ /dev/null @@ -1,78 +0,0 @@ -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 deleted file mode 100644 index 2d077cfc..00000000 --- a/packages/apps/mongodb/values.schema.json +++ /dev/null @@ -1,290 +0,0 @@ -{ - "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 deleted file mode 100644 index df8fbe37..00000000 --- a/packages/apps/mongodb/values.yaml +++ /dev/null @@ -1,146 +0,0 @@ -## -## @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/mariadb/.helmignore b/packages/apps/mysql/.helmignore similarity index 100% rename from packages/apps/mariadb/.helmignore rename to packages/apps/mysql/.helmignore diff --git a/packages/apps/mariadb/Chart.yaml b/packages/apps/mysql/Chart.yaml similarity index 93% rename from packages/apps/mariadb/Chart.yaml rename to packages/apps/mysql/Chart.yaml index 6acc5082..f9cedb1b 100644 --- a/packages/apps/mariadb/Chart.yaml +++ b/packages/apps/mysql/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v2 -name: mariadb +name: mysql description: Managed MariaDB service icon: /logos/mariadb.svg type: application diff --git a/packages/apps/mariadb/Makefile b/packages/apps/mysql/Makefile similarity index 77% rename from packages/apps/mariadb/Makefile rename to packages/apps/mysql/Makefile index 9833f302..f4ea3f78 100644 --- a/packages/apps/mariadb/Makefile +++ b/packages/apps/mysql/Makefile @@ -1,10 +1,10 @@ MARIADB_BACKUP_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml) -include ../../../hack/common-envs.mk -include ../../../hack/package.mk +include ../../../scripts/common-envs.mk +include ../../../scripts/package.mk generate: - cozyvalues-gen -m 'mariadb' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/mariadb/types.go + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md ../../../hack/update-crd.sh update: diff --git a/packages/apps/mariadb/README.md b/packages/apps/mysql/README.md similarity index 95% rename from packages/apps/mariadb/README.md rename to packages/apps/mysql/README.md index 9d97dc5f..6d47a6d5 100644 --- a/packages/apps/mariadb/README.md +++ b/packages/apps/mysql/README.md @@ -15,7 +15,7 @@ This managed service is controlled by mariadb-operator, ensuring efficient manag ### How to switch master/slave replica ```bash -kubectl edit mariadb +kubectl edit mariadb ``` update: @@ -54,11 +54,11 @@ more details: - **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: + 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 indices** - Sometimes some indices can be corrupted on master replica, you can recover them from slave: +- **Corrupted indicies** + Sometimes some indecies 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 @@ -102,7 +102,7 @@ more details: | `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.s3Bucket` | S3 bucket used for storing backups. | `string` | `s3.example.org/mysql-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` | `` | diff --git a/packages/apps/mariadb/charts/cozy-lib b/packages/apps/mysql/charts/cozy-lib similarity index 100% rename from packages/apps/mariadb/charts/cozy-lib rename to packages/apps/mysql/charts/cozy-lib diff --git a/packages/apps/mariadb/files/versions.yaml b/packages/apps/mysql/files/versions.yaml similarity index 100% rename from packages/apps/mariadb/files/versions.yaml rename to packages/apps/mysql/files/versions.yaml diff --git a/packages/apps/mariadb/hack/update-versions.sh b/packages/apps/mysql/hack/update-versions.sh similarity index 97% rename from packages/apps/mariadb/hack/update-versions.sh rename to packages/apps/mysql/hack/update-versions.sh index 775c0327..1b58591a 100755 --- a/packages/apps/mariadb/hack/update-versions.sh +++ b/packages/apps/mysql/hack/update-versions.sh @@ -5,9 +5,9 @@ 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" +MYSQL_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +VALUES_FILE="${MYSQL_DIR}/values.yaml" +VERSIONS_FILE="${MYSQL_DIR}/files/versions.yaml" MARIADB_API_URL="https://downloads.mariadb.org/rest-api/mariadb/" # Check if jq is installed diff --git a/packages/apps/mysql/images/mariadb-backup.tag b/packages/apps/mysql/images/mariadb-backup.tag new file mode 100644 index 00000000..af6247da --- /dev/null +++ b/packages/apps/mysql/images/mariadb-backup.tag @@ -0,0 +1 @@ +ghcr.io/cozystack/cozystack/mariadb-backup:0.0.0@sha256:1c0beb1b23a109b0e13727b4c73d2c74830e11cede92858ab20101b66f45a858 diff --git a/packages/apps/mariadb/images/mariadb-backup/Dockerfile b/packages/apps/mysql/images/mariadb-backup/Dockerfile similarity index 100% rename from packages/apps/mariadb/images/mariadb-backup/Dockerfile rename to packages/apps/mysql/images/mariadb-backup/Dockerfile diff --git a/packages/apps/mariadb/logos/mariadb.svg b/packages/apps/mysql/logos/mariadb.svg similarity index 100% rename from packages/apps/mariadb/logos/mariadb.svg rename to packages/apps/mysql/logos/mariadb.svg diff --git a/packages/apps/mongodb/templates/.gitkeep b/packages/apps/mysql/templates/.gitkeep similarity index 100% rename from packages/apps/mongodb/templates/.gitkeep rename to packages/apps/mysql/templates/.gitkeep diff --git a/packages/apps/openbao/templates/_resources.tpl b/packages/apps/mysql/templates/_resources.tpl similarity index 91% rename from packages/apps/openbao/templates/_resources.tpl rename to packages/apps/mysql/templates/_resources.tpl index 7aeb976e..6539c99a 100644 --- a/packages/apps/openbao/templates/_resources.tpl +++ b/packages/apps/mysql/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/mariadb/templates/_versions.tpl b/packages/apps/mysql/templates/_versions.tpl similarity index 89% rename from packages/apps/mariadb/templates/_versions.tpl rename to packages/apps/mysql/templates/_versions.tpl index a896ea5f..cd4ee0e1 100644 --- a/packages/apps/mariadb/templates/_versions.tpl +++ b/packages/apps/mysql/templates/_versions.tpl @@ -1,4 +1,4 @@ -{{- define "mariadb.versionMap" }} +{{- define "mysql.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 }} diff --git a/packages/apps/mariadb/templates/backup-cronjob.yaml b/packages/apps/mysql/templates/backup-cronjob.yaml similarity index 96% rename from packages/apps/mariadb/templates/backup-cronjob.yaml rename to packages/apps/mysql/templates/backup-cronjob.yaml index ddb237cd..97b52208 100644 --- a/packages/apps/mariadb/templates/backup-cronjob.yaml +++ b/packages/apps/mysql/templates/backup-cronjob.yaml @@ -13,6 +13,9 @@ spec: jobTemplate: spec: backoffLimit: 2 + template: + spec: + restartPolicy: OnFailure template: metadata: annotations: @@ -41,7 +44,7 @@ spec: name: {{ .Release.Name }} key: root-password - name: MYSQL_HOST - value: "{{ .Release.Name }}-{{ if eq (int .Values.replicas) 1 }}primary{{ else }}secondary{{ end }}" + value: {{ .Release.Name }}-secondary - name: AWS_ACCESS_KEY_ID valueFrom: secretKeyRef: diff --git a/packages/apps/mariadb/templates/backup-script.yaml b/packages/apps/mysql/templates/backup-script.yaml similarity index 100% rename from packages/apps/mariadb/templates/backup-script.yaml rename to packages/apps/mysql/templates/backup-script.yaml diff --git a/packages/apps/mariadb/templates/backup-secret.yaml b/packages/apps/mysql/templates/backup-secret.yaml similarity index 100% rename from packages/apps/mariadb/templates/backup-secret.yaml rename to packages/apps/mysql/templates/backup-secret.yaml diff --git a/packages/apps/mariadb/templates/config.yaml b/packages/apps/mysql/templates/config.yaml similarity index 100% rename from packages/apps/mariadb/templates/config.yaml rename to packages/apps/mysql/templates/config.yaml diff --git a/packages/apps/mariadb/templates/dashboard-resourcemap.yaml b/packages/apps/mysql/templates/dashboard-resourcemap.yaml similarity index 100% rename from packages/apps/mariadb/templates/dashboard-resourcemap.yaml rename to packages/apps/mysql/templates/dashboard-resourcemap.yaml diff --git a/packages/apps/mariadb/templates/db.yaml b/packages/apps/mysql/templates/db.yaml similarity index 100% rename from packages/apps/mariadb/templates/db.yaml rename to packages/apps/mysql/templates/db.yaml diff --git a/packages/apps/mariadb/templates/hooks/cleanup-pvc.yaml b/packages/apps/mysql/templates/hooks/cleanup-pvc.yaml similarity index 100% rename from packages/apps/mariadb/templates/hooks/cleanup-pvc.yaml rename to packages/apps/mysql/templates/hooks/cleanup-pvc.yaml diff --git a/packages/apps/mariadb/templates/mariadb.yaml b/packages/apps/mysql/templates/mariadb.yaml similarity index 86% rename from packages/apps/mariadb/templates/mariadb.yaml rename to packages/apps/mysql/templates/mariadb.yaml index d3d5e636..b4a888d8 100644 --- a/packages/apps/mariadb/templates/mariadb.yaml +++ b/packages/apps/mysql/templates/mariadb.yaml @@ -8,7 +8,7 @@ spec: name: {{ .Release.Name }}-credentials key: root - image: "mariadb:{{ include "mariadb.versionMap" $ }}" + image: "mariadb:{{ include "mysql.versionMap" $ }}" port: 3306 @@ -29,11 +29,13 @@ spec: - {{ .Release.Name }} topologyKey: "kubernetes.io/hostname" + {{- if gt (int .Values.replicas) 1 }} replication: enabled: true #primary: # podIndex: 0 # automaticFailover: true + {{- end }} podMetadata: labels: @@ -63,6 +65,9 @@ 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 @@ -71,7 +76,7 @@ spec: storageClassName: {{ . }} {{- end }} - {{- if .Values.external }} + {{- if and .Values.external (gt (int .Values.replicas) 1) }} primaryService: type: LoadBalancer {{- end }} diff --git a/packages/apps/mariadb/templates/regsecret.yaml b/packages/apps/mysql/templates/regsecret.yaml similarity index 100% rename from packages/apps/mariadb/templates/regsecret.yaml rename to packages/apps/mysql/templates/regsecret.yaml diff --git a/packages/apps/mariadb/templates/secret.yaml b/packages/apps/mysql/templates/secret.yaml similarity index 100% rename from packages/apps/mariadb/templates/secret.yaml rename to packages/apps/mysql/templates/secret.yaml diff --git a/packages/apps/mariadb/templates/user.yaml b/packages/apps/mysql/templates/user.yaml similarity index 100% rename from packages/apps/mariadb/templates/user.yaml rename to packages/apps/mysql/templates/user.yaml diff --git a/packages/apps/bucket/templates/workloadmonitor.yaml b/packages/apps/mysql/templates/workloadmonitor.yaml similarity index 71% rename from packages/apps/bucket/templates/workloadmonitor.yaml rename to packages/apps/mysql/templates/workloadmonitor.yaml index a23f3147..9fc6d144 100644 --- a/packages/apps/bucket/templates/workloadmonitor.yaml +++ b/packages/apps/mysql/templates/workloadmonitor.yaml @@ -4,10 +4,10 @@ kind: WorkloadMonitor metadata: name: {{ $.Release.Name }} spec: - replicas: 0 - minReplicas: 0 - kind: bucket - type: s3 + replicas: {{ .Values.replicas }} + minReplicas: 1 + kind: mysql + type: mysql selector: app.kubernetes.io/instance: {{ $.Release.Name }} version: {{ $.Chart.Version }} diff --git a/packages/apps/mariadb/values.schema.json b/packages/apps/mysql/values.schema.json similarity index 99% rename from packages/apps/mariadb/values.schema.json rename to packages/apps/mysql/values.schema.json index 49df40f0..a36754b2 100644 --- a/packages/apps/mariadb/values.schema.json +++ b/packages/apps/mysql/values.schema.json @@ -2,6 +2,98 @@ "title": "Chart Values", "type": "object", "properties": { + "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/mysql-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 * * *" + } + } + }, + "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" + } + } + } + } + } + } + }, + "external": { + "description": "Enable external access from outside the cluster.", + "type": "boolean", + "default": false + }, "replicas": { "description": "Number of MariaDB replicas.", "type": "integer", @@ -73,22 +165,6 @@ "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", @@ -111,92 +187,16 @@ } } }, - "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 * * *" - } - } + "version": { + "description": "MariaDB major.minor version to deploy", + "type": "string", + "default": "v11.8", + "enum": [ + "v11.8", + "v11.4", + "v10.11", + "v10.6" + ] } } -} +} \ No newline at end of file diff --git a/packages/apps/mariadb/values.yaml b/packages/apps/mysql/values.yaml similarity index 98% rename from packages/apps/mariadb/values.yaml rename to packages/apps/mysql/values.yaml index 6d629a83..c7726b7a 100644 --- a/packages/apps/mariadb/values.yaml +++ b/packages/apps/mysql/values.yaml @@ -98,7 +98,7 @@ databases: {} backup: enabled: false s3Region: us-east-1 - s3Bucket: "s3.example.org/mariadb-backups" + s3Bucket: "s3.example.org/mysql-backups" schedule: "0 2 * * *" cleanupStrategy: "--keep-last=3 --keep-daily=3 --keep-within-weekly=1m" s3AccessKey: "" diff --git a/packages/apps/nats/Makefile b/packages/apps/nats/Makefile index 29f6f9bc..8b1dce9d 100644 --- a/packages/apps/nats/Makefile +++ b/packages/apps/nats/Makefile @@ -1,5 +1,5 @@ -include ../../../hack/package.mk +include ../../../scripts/package.mk generate: - cozyvalues-gen -m 'nats' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/nats/types.go + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md ../../../hack/update-crd.sh diff --git a/packages/apps/nats/templates/nats.yaml b/packages/apps/nats/templates/nats.yaml index e5f5cf5d..b41c1574 100644 --- a/packages/apps/nats/templates/nats.yaml +++ b/packages/apps/nats/templates/nats.yaml @@ -33,13 +33,16 @@ 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-nats-application-default-nats-system - namespace: cozy-system + chart: + spec: + chart: cozy-nats + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' interval: 5m timeout: 10m install: @@ -52,6 +55,12 @@ spec: valuesFrom: - kind: Secret name: cozystack-values + valuesKey: _cluster + targetPath: _cluster + - kind: Secret + name: cozystack-values + valuesKey: _namespace + targetPath: _namespace values: nats: container: @@ -95,6 +104,10 @@ 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 cb20b4a6..43d64a46 100644 --- a/packages/apps/nats/templates/workloadmonitor.yaml +++ b/packages/apps/nats/templates/workloadmonitor.yaml @@ -3,8 +3,6 @@ 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 605c8752..3ef5fef7 100644 --- a/packages/apps/nats/values.schema.json +++ b/packages/apps/nats/values.schema.json @@ -2,6 +2,60 @@ "title": "Chart Values", "type": "object", "properties": { + "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 + } + } + }, + "external": { + "description": "Enable external access from outside the cluster.", + "type": "boolean", + "default": false + }, + "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 + } + } + }, "replicas": { "description": "Number of replicas.", "type": "integer", @@ -59,11 +113,6 @@ "type": "string", "default": "" }, - "external": { - "description": "Enable external access from outside the cluster.", - "type": "boolean", - "default": false - }, "users": { "description": "Users configuration map.", "type": "object", @@ -77,55 +126,6 @@ } } } - }, - "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 - } - } } } -} +} \ No newline at end of file diff --git a/packages/apps/openbao/Chart.yaml b/packages/apps/openbao/Chart.yaml deleted file mode 100644 index f33fc756..00000000 --- a/packages/apps/openbao/Chart.yaml +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index b9530139..00000000 --- a/packages/apps/openbao/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index c53c9d28..00000000 --- a/packages/apps/openbao/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# 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 deleted file mode 120000 index e1813509..00000000 --- a/packages/apps/openbao/charts/cozy-lib +++ /dev/null @@ -1 +0,0 @@ -../../../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 deleted file mode 100644 index 5ce73b79..00000000 --- a/packages/apps/openbao/logos/openbao.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/packages/apps/openbao/templates/openbao.yaml b/packages/apps/openbao/templates/openbao.yaml deleted file mode 100644 index daa6f9c4..00000000 --- a/packages/apps/openbao/templates/openbao.yaml +++ /dev/null @@ -1,99 +0,0 @@ -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 deleted file mode 100644 index 56f9ec8e..00000000 --- a/packages/apps/openbao/templates/workloadmonitor.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -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 deleted file mode 100644 index 9b32ddd6..00000000 --- a/packages/apps/openbao/values.schema.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "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 deleted file mode 100644 index fc8b75cc..00000000 --- a/packages/apps/openbao/values.yaml +++ /dev/null @@ -1,41 +0,0 @@ -## -## @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/apps/opensearch/.helmignore b/packages/apps/opensearch/.helmignore deleted file mode 100644 index 0e8a0eb3..00000000 --- a/packages/apps/opensearch/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# 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/opensearch/Chart.yaml b/packages/apps/opensearch/Chart.yaml deleted file mode 100644 index 8abefadf..00000000 --- a/packages/apps/opensearch/Chart.yaml +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 1781661f..00000000 --- a/packages/apps/opensearch/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index d968c665..00000000 --- a/packages/apps/opensearch/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# 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 deleted file mode 120000 index e1813509..00000000 --- a/packages/apps/opensearch/charts/cozy-lib +++ /dev/null @@ -1 +0,0 @@ -../../../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 deleted file mode 100644 index be39fc80..00000000 --- a/packages/apps/opensearch/files/versions.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# 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 deleted file mode 100755 index b2c4c946..00000000 --- a/packages/apps/opensearch/hack/update-versions.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/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 deleted file mode 100644 index 345fdd0a..00000000 --- a/packages/apps/opensearch/logos/opensearch.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/packages/apps/opensearch/templates/.gitkeep b/packages/apps/opensearch/templates/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/apps/opensearch/templates/_versions.tpl b/packages/apps/opensearch/templates/_versions.tpl deleted file mode 100644 index 4eae4163..00000000 --- a/packages/apps/opensearch/templates/_versions.tpl +++ /dev/null @@ -1,13 +0,0 @@ -{{/* -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 deleted file mode 100644 index 91dbf8cb..00000000 --- a/packages/apps/opensearch/templates/dashboard-resourcemap.yaml +++ /dev/null @@ -1,42 +0,0 @@ -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 deleted file mode 100644 index f28626ab..00000000 --- a/packages/apps/opensearch/templates/external-svc.yaml +++ /dev/null @@ -1,39 +0,0 @@ -{{- 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 deleted file mode 100644 index 836a3d4b..00000000 --- a/packages/apps/opensearch/templates/opensearch.yaml +++ /dev/null @@ -1,105 +0,0 @@ -{{- $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 deleted file mode 100644 index d10d353a..00000000 --- a/packages/apps/opensearch/templates/security.yaml +++ /dev/null @@ -1,120 +0,0 @@ -{{- $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 deleted file mode 100644 index 1d326206..00000000 --- a/packages/apps/opensearch/templates/users.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- 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 deleted file mode 100644 index 2959ec18..00000000 --- a/packages/apps/opensearch/tests/opensearch_test.yaml +++ /dev/null @@ -1,532 +0,0 @@ -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 deleted file mode 100644 index cd8740d9..00000000 --- a/packages/apps/opensearch/tests/security_test.yaml +++ /dev/null @@ -1,207 +0,0 @@ -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 deleted file mode 100644 index f6b4990e..00000000 --- a/packages/apps/opensearch/tests/users_test.yaml +++ /dev/null @@ -1,176 +0,0 @@ -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 deleted file mode 100644 index 04b530ba..00000000 --- a/packages/apps/opensearch/values.schema.json +++ /dev/null @@ -1,239 +0,0 @@ -{ - "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 deleted file mode 100644 index 8de805e3..00000000 --- a/packages/apps/opensearch/values.yaml +++ /dev/null @@ -1,111 +0,0 @@ -## -## @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/Makefile b/packages/apps/postgres/Makefile index dff0b9c6..a2ba188f 100644 --- a/packages/apps/postgres/Makefile +++ b/packages/apps/postgres/Makefile @@ -1,7 +1,7 @@ -include ../../../hack/package.mk +include ../../../scripts/package.mk generate: - cozyvalues-gen -m 'postgresql' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/postgresql/types.go + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md ../../../hack/update-crd.sh update: diff --git a/packages/apps/postgres/README.md b/packages/apps/postgres/README.md index 4cda7284..5a550f7a 100644 --- a/packages/apps/postgres/README.md +++ b/packages/apps/postgres/README.md @@ -133,13 +133,12 @@ See: ### 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` | `""` | +| 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` | `""` | ## Parameter examples and reference diff --git a/packages/apps/postgres/templates/db.yaml b/packages/apps/postgres/templates/db.yaml index 2cdaec1d..7557c436 100644 --- a/packages/apps/postgres/templates/db.yaml +++ b/packages/apps/postgres/templates/db.yaml @@ -32,9 +32,6 @@ 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: @@ -87,8 +84,6 @@ 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/postgres/templates/init-script.yaml b/packages/apps/postgres/templates/init-script.yaml index 500d54d4..80f7c4c7 100644 --- a/packages/apps/postgres/templates/init-script.yaml +++ b/packages/apps/postgres/templates/init-script.yaml @@ -66,38 +66,6 @@ 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 < 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 deleted file mode 120000 index e1813509..00000000 --- a/packages/apps/qdrant/charts/cozy-lib +++ /dev/null @@ -1 +0,0 @@ -../../../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 deleted file mode 100644 index 3c940b5e..00000000 --- a/packages/apps/qdrant/logos/qdrant.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/packages/apps/qdrant/templates/dashboard-resourcemap.yaml b/packages/apps/qdrant/templates/dashboard-resourcemap.yaml deleted file mode 100644 index 0986951f..00000000 --- a/packages/apps/qdrant/templates/dashboard-resourcemap.yaml +++ /dev/null @@ -1,53 +0,0 @@ -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 deleted file mode 100644 index 888bd05e..00000000 --- a/packages/apps/qdrant/templates/qdrant.yaml +++ /dev/null @@ -1,43 +0,0 @@ -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 deleted file mode 100644 index 90af7c3d..00000000 --- a/packages/apps/qdrant/values.schema.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "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 deleted file mode 100644 index 7abd25ff..00000000 --- a/packages/apps/qdrant/values.yaml +++ /dev/null @@ -1,34 +0,0 @@ -## -## @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 e764e7dd..13500669 100644 --- a/packages/apps/rabbitmq/Chart.yaml +++ b/packages/apps/rabbitmq/Chart.yaml @@ -4,4 +4,4 @@ description: Managed RabbitMQ service icon: /logos/rabbitmq.svg type: application version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process -appVersion: "4.2.4" +appVersion: "3.13.2" diff --git a/packages/apps/rabbitmq/Makefile b/packages/apps/rabbitmq/Makefile index 9b045b66..8b1dce9d 100644 --- a/packages/apps/rabbitmq/Makefile +++ b/packages/apps/rabbitmq/Makefile @@ -1,9 +1,5 @@ -include ../../../hack/package.mk +include ../../../scripts/package.mk generate: - cozyvalues-gen -m 'rabbitmq' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/rabbitmq/types.go + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md ../../../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 b1f01f21..4b19c7b3 100644 --- a/packages/apps/rabbitmq/README.md +++ b/packages/apps/rabbitmq/README.md @@ -23,7 +23,6 @@ The service utilizes official RabbitMQ operator. This ensures the reliability an | `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` | ### Application-specific parameters diff --git a/packages/apps/rabbitmq/files/versions.yaml b/packages/apps/rabbitmq/files/versions.yaml deleted file mode 100644 index 0cf87dd0..00000000 --- a/packages/apps/rabbitmq/files/versions.yaml +++ /dev/null @@ -1,4 +0,0 @@ -"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 deleted file mode 100755 index 7dec5a84..00000000 --- a/packages/apps/rabbitmq/hack/update-versions.sh +++ /dev/null @@ -1,129 +0,0 @@ -#!/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 deleted file mode 100644 index 76955b33..00000000 --- a/packages/apps/rabbitmq/templates/_versions.tpl +++ /dev/null @@ -1,8 +0,0 @@ -{{- 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 bbf2efbe..b111285e 100644 --- a/packages/apps/rabbitmq/templates/rabbitmq.yaml +++ b/packages/apps/rabbitmq/templates/rabbitmq.yaml @@ -7,7 +7,6 @@ metadata: app.kubernetes.io/managed-by: {{ .Release.Service }} spec: replicas: {{ .Values.replicas }} - image: 'rabbitmq:{{ include "rabbitmq.versionMap" $ }}-management' {{- if .Values.external }} service: type: LoadBalancer diff --git a/packages/apps/rabbitmq/templates/workloadmonitor.yaml b/packages/apps/rabbitmq/templates/workloadmonitor.yaml index 66941153..0f7462c7 100644 --- a/packages/apps/rabbitmq/templates/workloadmonitor.yaml +++ b/packages/apps/rabbitmq/templates/workloadmonitor.yaml @@ -3,8 +3,6 @@ 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 43eaa206..04b8fa11 100644 --- a/packages/apps/rabbitmq/values.schema.json +++ b/packages/apps/rabbitmq/values.schema.json @@ -2,6 +2,11 @@ "title": "Chart Values", "type": "object", "properties": { + "external": { + "description": "Enable external access from outside the cluster.", + "type": "boolean", + "default": false + }, "replicas": { "description": "Number of RabbitMQ replicas.", "type": "integer", @@ -73,22 +78,6 @@ "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", @@ -137,4 +126,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/apps/rabbitmq/values.yaml b/packages/apps/rabbitmq/values.yaml index 08b6f5e6..65d5de44 100644 --- a/packages/apps/rabbitmq/values.yaml +++ b/packages/apps/rabbitmq/values.yaml @@ -34,15 +34,6 @@ storageClass: "" external: false ## -## @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 ## diff --git a/packages/apps/redis/Makefile b/packages/apps/redis/Makefile index 939b75ee..a2ba188f 100644 --- a/packages/apps/redis/Makefile +++ b/packages/apps/redis/Makefile @@ -1,7 +1,7 @@ -include ../../../hack/package.mk +include ../../../scripts/package.mk generate: - cozyvalues-gen -m 'redis' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/redis/types.go + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md ../../../hack/update-crd.sh update: diff --git a/packages/apps/redis/templates/redisfailover.yaml b/packages/apps/redis/templates/redisfailover.yaml index 160e030d..936217a3 100644 --- a/packages/apps/redis/templates/redisfailover.yaml +++ b/packages/apps/redis/templates/redisfailover.yaml @@ -75,8 +75,6 @@ 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 }} @@ -92,8 +90,6 @@ 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/values.schema.json b/packages/apps/redis/values.schema.json index a93d92ac..5c01cc31 100644 --- a/packages/apps/redis/values.schema.json +++ b/packages/apps/redis/values.schema.json @@ -2,6 +2,16 @@ "title": "Chart Values", "type": "object", "properties": { + "authEnabled": { + "description": "Enable password generation.", + "type": "boolean", + "default": true + }, + "external": { + "description": "Enable external access from outside the cluster.", + "type": "boolean", + "default": false + }, "replicas": { "description": "Number of Redis replicas.", "type": "integer", @@ -73,11 +83,6 @@ "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", @@ -86,11 +91,6 @@ "v8", "v7" ] - }, - "authEnabled": { - "description": "Enable password generation.", - "type": "boolean", - "default": true } } -} +} \ No newline at end of file diff --git a/packages/apps/tcp-balancer/Makefile b/packages/apps/tcp-balancer/Makefile index e3bf78fe..8b1dce9d 100644 --- a/packages/apps/tcp-balancer/Makefile +++ b/packages/apps/tcp-balancer/Makefile @@ -1,5 +1,5 @@ -include ../../../hack/package.mk +include ../../../scripts/package.mk generate: - cozyvalues-gen -m 'tcpbalancer' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/tcpbalancer/types.go + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md ../../../hack/update-crd.sh diff --git a/packages/apps/tcp-balancer/templates/workloadmonitor.yaml b/packages/apps/tcp-balancer/templates/workloadmonitor.yaml index 3478826b..41dce2ab 100644 --- a/packages/apps/tcp-balancer/templates/workloadmonitor.yaml +++ b/packages/apps/tcp-balancer/templates/workloadmonitor.yaml @@ -3,8 +3,6 @@ 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 20d04d80..ea30664a 100644 --- a/packages/apps/tcp-balancer/values.schema.json +++ b/packages/apps/tcp-balancer/values.schema.json @@ -2,58 +2,6 @@ "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", @@ -108,10 +56,57 @@ } } }, - "whitelistHTTP": { - "description": "Secure HTTP by whitelisting client networks (default: false).", - "type": "boolean", - "default": false + "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" + ] }, "whitelist": { "description": "List of allowed client networks.", @@ -120,6 +115,11 @@ "items": { "type": "string" } + }, + "whitelistHTTP": { + "description": "Secure HTTP by whitelisting client networks (default: false).", + "type": "boolean", + "default": false } } -} +} \ No newline at end of file diff --git a/packages/apps/tenant/Makefile b/packages/apps/tenant/Makefile index 2f51d836..8b1dce9d 100644 --- a/packages/apps/tenant/Makefile +++ b/packages/apps/tenant/Makefile @@ -1,8 +1,5 @@ -include ../../../hack/package.mk +include ../../../scripts/package.mk generate: - cozyvalues-gen -m 'tenant' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/tenant/types.go + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md ../../../hack/update-crd.sh - -test: - helm unittest . diff --git a/packages/apps/tenant/README.md b/packages/apps/tenant/README.md index 96cf5c6e..222c98a5 100644 --- a/packages/apps/tenant/README.md +++ b/packages/apps/tenant/README.md @@ -6,20 +6,15 @@ Tenants can be created recursively and are subject to the following rules: ### Tenant naming -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. +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. 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 @@ -74,44 +69,13 @@ tenant-u1 ### Common parameters -| 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` | `{}` | +| 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` | +| `isolated` | Enforce tenant namespace with network policies (default: true). | `bool` | `true` | +| `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 deleted file mode 100644 index 63dbcaca..00000000 --- a/packages/apps/tenant/templates/cilium-lb-pool.yaml +++ /dev/null @@ -1,28 +0,0 @@ -{{- $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 index 0f13daa4..9b2f2c50 100644 --- a/packages/apps/tenant/templates/cleanup-job.yaml +++ b/packages/apps/tenant/templates/cleanup-job.yaml @@ -74,12 +74,12 @@ spec: echo "Deleting Applications" kubectl delete helmreleases.helm.toolkit.fluxcd.io -n "$NAMESPACE" \ - -l 'apps.cozystack.io/application.kind,internal.cozystack.io/tenantmodule!=true' \ + -l 'cozystack.io/ui=true,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' \ + -l 'cozystack.io/ui=true,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 9a122da2..4da22fb7 100644 --- a/packages/apps/tenant/templates/etcd.yaml +++ b/packages/apps/tenant/templates/etcd.yaml @@ -5,7 +5,7 @@ metadata: name: etcd namespace: {{ include "tenant.name" . }} labels: - sharding.fluxcd.io/key: tenants + cozystack.io/ui: "true" internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} @@ -13,12 +13,17 @@ metadata: apps.cozystack.io/application.group: apps.cozystack.io apps.cozystack.io/application.name: etcd spec: - chartRef: - kind: ExternalArtifact - name: cozystack-etcd-application-default-etcd - namespace: cozy-system + chart: + spec: + chart: etcd + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-extra + namespace: cozy-public + version: '>= 0.0.0-0' interval: 5m - timeout: 30m + timeout: 10m install: remediation: retries: -1 @@ -29,4 +34,10 @@ spec: valuesFrom: - kind: Secret name: cozystack-values + valuesKey: _cluster + targetPath: _cluster + - kind: Secret + name: cozystack-values + valuesKey: _namespace + targetPath: _namespace {{- end }} diff --git a/packages/apps/tenant/templates/info.yaml b/packages/apps/tenant/templates/info.yaml index 520028c1..e1281ebb 100644 --- a/packages/apps/tenant/templates/info.yaml +++ b/packages/apps/tenant/templates/info.yaml @@ -4,7 +4,7 @@ metadata: name: info namespace: {{ include "tenant.name" . }} labels: - sharding.fluxcd.io/key: tenants + cozystack.io/ui: "true" internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} @@ -12,10 +12,15 @@ metadata: apps.cozystack.io/application.group: apps.cozystack.io apps.cozystack.io/application.name: info spec: - chartRef: - kind: ExternalArtifact - name: cozystack-info-application-default-info - namespace: cozy-system + chart: + spec: + chart: info + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-extra + namespace: cozy-public + version: '>= 0.0.0-0' interval: 5m timeout: 10m install: @@ -28,3 +33,9 @@ spec: valuesFrom: - kind: Secret name: cozystack-values + valuesKey: _cluster + targetPath: _cluster + - kind: Secret + name: cozystack-values + valuesKey: _namespace + targetPath: _namespace diff --git a/packages/apps/tenant/templates/ingress.yaml b/packages/apps/tenant/templates/ingress.yaml index 1899a4da..c9c791f1 100644 --- a/packages/apps/tenant/templates/ingress.yaml +++ b/packages/apps/tenant/templates/ingress.yaml @@ -5,7 +5,7 @@ metadata: name: ingress namespace: {{ include "tenant.name" . }} labels: - sharding.fluxcd.io/key: tenants + cozystack.io/ui: "true" internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} @@ -13,10 +13,15 @@ metadata: apps.cozystack.io/application.group: apps.cozystack.io apps.cozystack.io/application.name: ingress spec: - chartRef: - kind: ExternalArtifact - name: cozystack-ingress-application-default-ingress - namespace: cozy-system + chart: + spec: + chart: ingress + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-extra + namespace: cozy-public + version: '>= 0.0.0-0' interval: 5m timeout: 10m install: @@ -29,4 +34,10 @@ spec: valuesFrom: - kind: Secret name: cozystack-values + valuesKey: _cluster + targetPath: _cluster + - kind: Secret + name: cozystack-values + valuesKey: _namespace + targetPath: _namespace {{- end }} diff --git a/packages/apps/tenant/templates/monitoring.yaml b/packages/apps/tenant/templates/monitoring.yaml index 4d77faa6..3b0536de 100644 --- a/packages/apps/tenant/templates/monitoring.yaml +++ b/packages/apps/tenant/templates/monitoring.yaml @@ -5,7 +5,7 @@ metadata: name: monitoring namespace: {{ include "tenant.name" . }} labels: - sharding.fluxcd.io/key: tenants + cozystack.io/ui: "true" internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} @@ -13,10 +13,15 @@ metadata: apps.cozystack.io/application.group: apps.cozystack.io apps.cozystack.io/application.name: monitoring spec: - chartRef: - kind: ExternalArtifact - name: cozystack-monitoring-application-default-monitoring - namespace: cozy-system + chart: + spec: + chart: monitoring + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-extra + namespace: cozy-public + version: '>= 0.0.0-0' interval: 5m timeout: 10m install: @@ -29,4 +34,10 @@ spec: valuesFrom: - kind: Secret name: cozystack-values + valuesKey: _cluster + targetPath: _cluster + - kind: Secret + name: cozystack-values + valuesKey: _namespace + targetPath: _namespace {{- end }} diff --git a/packages/apps/tenant/templates/namespace.yaml b/packages/apps/tenant/templates/namespace.yaml index dfb83730..6c94a87f 100644 --- a/packages/apps/tenant/templates/namespace.yaml +++ b/packages/apps/tenant/templates/namespace.yaml @@ -38,12 +38,6 @@ {{- 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 @@ -64,9 +58,6 @@ metadata: 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 }} alpha.kubevirt.io/auto-memory-limits-ratio: "1.0" ownerReferences: - apiVersion: v1 @@ -86,16 +77,12 @@ metadata: 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 }} + _cluster: | + {{- .Values._cluster | toYaml | nindent 4 }} + _namespace: | + etcd: {{ $etcd | quote }} + ingress: {{ $ingress | quote }} + monitoring: {{ $monitoring | quote }} + seaweedfs: {{ $seaweedfs | quote }} + host: {{ $computedHost | quote }} {{- end }} diff --git a/packages/apps/tenant/templates/networkpolicy.yaml b/packages/apps/tenant/templates/networkpolicy.yaml index 4bd3ba02..2c15a877 100644 --- a/packages/apps/tenant/templates/networkpolicy.yaml +++ b/packages/apps/tenant/templates/networkpolicy.yaml @@ -1,3 +1,4 @@ +{{- if .Values.isolated }} --- apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy @@ -186,23 +187,6 @@ 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" . }} @@ -224,27 +208,6 @@ 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 @@ -257,3 +220,4 @@ spec: - toEndpoints: - matchLabels: cozystack.io/service: ingress +{{- end }} diff --git a/packages/apps/tenant/templates/seaweedfs.yaml b/packages/apps/tenant/templates/seaweedfs.yaml index e0002ec9..be768571 100644 --- a/packages/apps/tenant/templates/seaweedfs.yaml +++ b/packages/apps/tenant/templates/seaweedfs.yaml @@ -5,7 +5,7 @@ metadata: name: seaweedfs namespace: {{ include "tenant.name" . }} labels: - sharding.fluxcd.io/key: tenants + cozystack.io/ui: "true" internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} @@ -13,10 +13,15 @@ metadata: apps.cozystack.io/application.group: apps.cozystack.io apps.cozystack.io/application.name: seaweedfs spec: - chartRef: - kind: ExternalArtifact - name: cozystack-seaweedfs-application-default-seaweedfs - namespace: cozy-system + chart: + spec: + chart: seaweedfs + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-extra + namespace: cozy-public + version: '>= 0.0.0-0' interval: 5m timeout: 10m install: @@ -29,4 +34,10 @@ spec: valuesFrom: - kind: Secret name: cozystack-values + valuesKey: _cluster + targetPath: _cluster + - kind: Secret + name: cozystack-values + valuesKey: _namespace + targetPath: _namespace {{- end }} diff --git a/packages/apps/tenant/templates/tenant.yaml b/packages/apps/tenant/templates/tenant.yaml index 79eba4ca..6d325a07 100644 --- a/packages/apps/tenant/templates/tenant.yaml +++ b/packages/apps/tenant/templates/tenant.yaml @@ -5,10 +5,42 @@ metadata: name: {{ include "tenant.name" . }} namespace: {{ include "tenant.name" . }} --- +# == 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 + - workloads + verbs: ["get", "list", "watch"] +- apiGroups: + - core.cozystack.io + resources: + - tenantmodules + - tenantsecrets + verbs: ["get", "list", "watch"] +--- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: cozy:tenant + name: {{ include "tenant.name" . }} namespace: {{ include "tenant.name" . }} subjects: {{- if ne .Release.Namespace "tenant-root" }} @@ -30,67 +62,342 @@ subjects: name: {{ include "tenant.name" . }} namespace: {{ include "tenant.name" . }} roleRef: - kind: ClusterRole - name: cozy:tenant + kind: Role + name: {{ include "tenant.name" . }} apiGroup: rbac.authorization.k8s.io --- -# == view role binding == +# == 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 + - workloads + verbs: ["get", "list", "watch"] +--- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: cozy:tenant:view + name: {{ include "tenant.name" . }}-view namespace: {{ include "tenant.name" . }} subjects: {{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "view" (include "tenant.name" .)) | nindent 2 }} roleRef: - kind: ClusterRole - name: cozy:tenant:view + kind: Role + name: {{ include "tenant.name" . }}-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 + - workloads + verbs: ["get", "list", "watch"] + - apiGroups: + - core.cozystack.io + resources: + - tenantmodules + - tenantsecrets + verbs: ["get", "list", "watch"] --- -# == use role binding == kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: cozy:tenant:use + name: {{ include "tenant.name" . }}-use namespace: {{ include "tenant.name" . }} subjects: {{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "use" (include "tenant.name" .)) | nindent 2 }} roleRef: - kind: ClusterRole - name: cozy:tenant:use + kind: Role + name: {{ include "tenant.name" . }}-use apiGroup: rbac.authorization.k8s.io --- -# == admin role binding == +# == 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 + - virtualprivateclouds + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - cozystack.io + resources: + - workloadmonitors + - workloads + verbs: ["get", "list", "watch"] + - apiGroups: + - core.cozystack.io + resources: + - tenantmodules + - tenantsecrets + verbs: ["get", "list", "watch"] +--- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: cozy:tenant:admin + name: {{ include "tenant.name" . }}-admin namespace: {{ include "tenant.name" . }} subjects: {{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "admin" (include "tenant.name" .)) | nindent 2 }} roleRef: - kind: ClusterRole - name: cozy:tenant:admin + kind: Role + name: {{ include "tenant.name" . }}-admin apiGroup: rbac.authorization.k8s.io --- -# == super admin role binding == +# == 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 + - workloads + verbs: ["get", "list", "watch"] + - apiGroups: + - core.cozystack.io + resources: + - tenantmodules + - tenantsecrets + verbs: ["get", "list", "watch"] +--- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: cozy:tenant:super-admin + name: {{ include "tenant.name" . }}-super-admin namespace: {{ include "tenant.name" . }} subjects: {{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "super-admin" (include "tenant.name" .) ) | nindent 2 }} roleRef: - kind: ClusterRole - name: cozy:tenant:super-admin + kind: Role + name: {{ include "tenant.name" . }}-super-admin apiGroup: rbac.authorization.k8s.io --- -# == dashboard role binding == +# == 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"] +--- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: cozy:{{ include "tenant.name" . }}:dashboard + name: {{ include "tenant.name" . }} namespace: cozy-public subjects: - kind: Group @@ -110,5 +417,5 @@ subjects: namespace: {{ include "tenant.name" . }} roleRef: kind: Role - name: cozy:tenant:dashboard + name: {{ include "tenant.name" . }} apiGroup: rbac.authorization.k8s.io diff --git a/packages/apps/tenant/tests/exposure_test.yaml b/packages/apps/tenant/tests/exposure_test.yaml deleted file mode 100644 index e86fab5b..00000000 --- a/packages/apps/tenant/tests/exposure_test.yaml +++ /dev/null @@ -1,141 +0,0 @@ -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 28d9ac1e..7690e2b4 100644 --- a/packages/apps/tenant/values.schema.json +++ b/packages/apps/tenant/values.schema.json @@ -2,36 +2,31 @@ "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 + "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": "" }, "ingress": { "description": "Deploy own Ingress Controller.", "type": "boolean", "default": false }, - "seaweedfs": { - "description": "Deploy own SeaweedFS.", + "isolated": { + "description": "Enforce tenant namespace with network policies (default: true).", + "type": "boolean", + "default": true + }, + "monitoring": { + "description": "Deploy own Monitoring Stack.", "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", @@ -48,6 +43,11 @@ ], "x-kubernetes-int-or-string": true } + }, + "seaweedfs": { + "description": "Deploy own SeaweedFS.", + "type": "boolean", + "default": false } } -} +} \ No newline at end of file diff --git a/packages/apps/tenant/values.yaml b/packages/apps/tenant/values.yaml index f9f8a999..4543bb6b 100644 --- a/packages/apps/tenant/values.yaml +++ b/packages/apps/tenant/values.yaml @@ -17,8 +17,8 @@ ingress: false ## @param {bool} seaweedfs - Deploy own SeaweedFS. seaweedfs: false -## @param {string} [schedulingClass] - The name of a SchedulingClass CR to apply scheduling constraints for this tenant's workloads. -schedulingClass: "" +## @param {bool} isolated - Enforce tenant namespace with network policies (default: true). +isolated: true ## @param {map[string]quantity} resourceQuotas - Define resource quotas for the tenant. resourceQuotas: {} diff --git a/packages/system/monitoring/.helmignore b/packages/apps/virtual-machine/.helmignore similarity index 100% rename from packages/system/monitoring/.helmignore rename to packages/apps/virtual-machine/.helmignore diff --git a/packages/system/vm-default-images/Chart.yaml b/packages/apps/virtual-machine/Chart.yaml similarity index 57% rename from packages/system/vm-default-images/Chart.yaml rename to packages/apps/virtual-machine/Chart.yaml index aac0ccca..7067744b 100644 --- a/packages/system/vm-default-images/Chart.yaml +++ b/packages/apps/virtual-machine/Chart.yaml @@ -1,5 +1,7 @@ apiVersion: v2 -name: vm-default-images -description: Global Golden Image collection for virtual machines +name: virtual-machine +description: Virtual Machine (simple) +icon: /logos/vm.svg type: application version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process +appVersion: 0.14.0 diff --git a/packages/apps/virtual-machine/Makefile b/packages/apps/virtual-machine/Makefile new file mode 100644 index 00000000..b70ac622 --- /dev/null +++ b/packages/apps/virtual-machine/Makefile @@ -0,0 +1,10 @@ +include ../../../scripts/package.mk + +generate: + cozyvalues-gen -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.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.enum = $${PREFERENCES}" values.schema.json + ../../../hack/update-crd.sh diff --git a/packages/apps/virtual-machine/README.md b/packages/apps/virtual-machine/README.md new file mode 100644 index 00000000..dc6633f2 --- /dev/null +++ b/packages/apps/virtual-machine/README.md @@ -0,0 +1,277 @@ +# 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 | 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]` | +| `running` | Whether the virtual machine should be running. | `bool` | `true` | +| `instanceType` | Virtual Machine instance type. | `string` | `u1.medium` | +| `instanceProfile` | Virtual Machine preferences profile. | `string` | `ubuntu` | +| `systemDisk` | System disk configuration. | `object` | `{}` | +| `systemDisk.image` | The base image for the virtual machine. | `string` | `ubuntu` | +| `systemDisk.storage` | The size of the disk allocated for the virtual machine. | `string` | `5Gi` | +| `systemDisk.storageClass` | StorageClass used to store the data. | `string` | `replicated` | +| `subnets` | Additional subnets | `[]object` | `[]` | +| `subnets[i].name` | Subnet name | `string` | `""` | +| `gpus` | List of GPUs to attach. | `[]object` | `[]` | +| `gpus[i].name` | The name of the GPU resource to attach. | `string` | `""` | +| `resources` | Resource configuration for the virtual machine. | `object` | `{}` | +| `resources.cpu` | Number of CPU cores allocated. | `quantity` | `""` | +| `resources.sockets` | Number of CPU sockets (vCPU topology). | `quantity` | `""` | +| `resources.memory` | Amount of memory allocated. | `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 + +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/mongodb/charts/cozy-lib b/packages/apps/virtual-machine/charts/cozy-lib similarity index 100% rename from packages/apps/mongodb/charts/cozy-lib rename to packages/apps/virtual-machine/charts/cozy-lib diff --git a/packages/apps/virtual-machine/hack/update-instance-types.sh b/packages/apps/virtual-machine/hack/update-instance-types.sh new file mode 100755 index 00000000..1a248525 --- /dev/null +++ b/packages/apps/virtual-machine/hack/update-instance-types.sh @@ -0,0 +1 @@ +#!/bin/sh diff --git a/packages/apps/virtual-machine/logos/vm.svg b/packages/apps/virtual-machine/logos/vm.svg new file mode 100644 index 00000000..9c3e34d9 --- /dev/null +++ b/packages/apps/virtual-machine/logos/vm.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/apps/virtual-machine/templates/_helpers.tpl b/packages/apps/virtual-machine/templates/_helpers.tpl new file mode 100644 index 00000000..e65cad9d --- /dev/null +++ b/packages/apps/virtual-machine/templates/_helpers.tpl @@ -0,0 +1,103 @@ +{{/* +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 }} + +{{/* +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/openbao/templates/dashboard-resourcemap.yaml b/packages/apps/virtual-machine/templates/dashboard-resourcemap.yaml similarity index 67% rename from packages/apps/openbao/templates/dashboard-resourcemap.yaml rename to packages/apps/virtual-machine/templates/dashboard-resourcemap.yaml index 452a07db..4beac5dc 100644 --- a/packages/apps/openbao/templates/dashboard-resourcemap.yaml +++ b/packages/apps/virtual-machine/templates/dashboard-resourcemap.yaml @@ -8,8 +8,7 @@ rules: resources: - services resourceNames: - - {{ .Release.Name }} - - {{ .Release.Name }}-internal + - {{ include "virtual-machine.fullname" . }} verbs: ["get", "list", "watch"] - apiGroups: - cozystack.io @@ -29,3 +28,16 @@ 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/virtual-machine/templates/secret-network-config.yaml b/packages/apps/virtual-machine/templates/secret-network-config.yaml new file mode 100644 index 00000000..9800ceac --- /dev/null +++ b/packages/apps/virtual-machine/templates/secret-network-config.yaml @@ -0,0 +1,40 @@ +# if subnets are specified and image is either ubunu or alpine +{{- if and .Values.subnets (or (eq .Values.systemDisk.image "ubuntu") (eq .Values.systemDisk.image "alpine")) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "virtual-machine.fullname" $ }}-network-config +stringData: + networkData: | + network: + version: 1 + config: + {{- if eq .Values.systemDisk.image "ubuntu" }} + # main iface + - type: physical + name: enp1s0 + subnets: + - type: dhcp + # additional ifaces attached to subnets + {{- range $i, $subnet := .Values.subnets }} + - type: physical + name: enp{{ add 2 $i }}s0 + subnets: + - type: dhcp + {{- end }} + {{- else if eq .Values.systemDisk.image "alpine" }} + #main iface + - type: physical + name: eth0 + subnets: + - type: dhcp + # additional ifaces attached to subnets + {{- range $i, $subnet := .Values.subnets }} + - type: physical + name: eth{{ add1 $i }} + subnets: + - type: dhcp + {{- end }} + {{- end }} +{{- end }} diff --git a/packages/apps/virtual-machine/templates/secret.yaml b/packages/apps/virtual-machine/templates/secret.yaml new file mode 100644 index 00000000..73cd92bf --- /dev/null +++ b/packages/apps/virtual-machine/templates/secret.yaml @@ -0,0 +1,33 @@ +{{- 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 new file mode 100644 index 00000000..b12f7612 --- /dev/null +++ b/packages/apps/virtual-machine/templates/service.yaml @@ -0,0 +1,38 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "virtual-machine.fullname" . }} + labels: + apps.cozystack.io/user-service: "true" + {{- include "virtual-machine.labels" . | nindent 4 }} +{{- if .Values.external }} + annotations: + networking.cozystack.io/wholeIP: "true" +{{- 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 }} + {{- range .Values.externalPorts }} + - name: port-{{ . }} + port: {{ . }} + targetPort: {{ . }} + {{- end }} + {{- end }} +{{- else }} + - port: 65535 +{{- end }} diff --git a/packages/apps/virtual-machine/templates/vm-update-hook.yaml b/packages/apps/virtual-machine/templates/vm-update-hook.yaml new file mode 100644 index 00000000..1197c027 --- /dev/null +++ b/packages/apps/virtual-machine/templates/vm-update-hook.yaml @@ -0,0 +1,130 @@ +{{- $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) -}} + {{- $oldSize := (include "cozy-lib.resources.toFloat" $currentStorage) | float64 -}} + {{- $newSize := (include "cozy-lib.resources.toFloat" $desiredStorage) | float64 -}} + {{- if gt $newSize $oldSize -}} + {{- $needResizePVC = true -}} + {{- end -}} + {{- 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: 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 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 virtualmachines.kubevirt.io {{ $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 new file mode 100644 index 00000000..efadf3af --- /dev/null +++ b/packages/apps/virtual-machine/templates/vm.yaml @@ -0,0 +1,155 @@ +{{- 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/42/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-42-1.1.x86_64.qcow2 + {{- else if eq .Values.systemDisk.image "alpine" }} + url: https://dl-cdn.alpinelinux.org/alpine/v3.20/releases/cloud/nocloud_alpine-3.20.8-x86_64-bios-cloudinit-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 (and .Values.subnets (or (eq .Values.systemDisk.image "ubuntu") (eq .Values.systemDisk.image "alpine"))) }} + - disk: + bus: virtio + name: cloudinitdisk + {{- end }} + + interfaces: + - name: default + bridge: {} + {{- if .Values.subnets }} + {{- range $i, $subnet := .Values.subnets }} + - name: {{ $subnet.name }} + bridge: {} + {{- end }} + {{- end }} + + 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 + + {{- include "virtual-machine.nodeAffinity" . | nindent 6 }} + + volumes: + - name: systemdisk + dataVolume: + name: {{ include "virtual-machine.fullname" . }} + {{- if or .Values.cloudInit .Values.sshKeys (and .Values.subnets (or (eq .Values.systemDisk.image "ubuntu") (eq .Values.systemDisk.image "alpine"))) }} + - name: cloudinitdisk + cloudInitNoCloud: + {{- if or .Values.cloudInit .Values.sshKeys }} + secretRef: + name: {{ include "virtual-machine.fullname" . }}-cloud-init + {{- end }} + {{- if and .Values.subnets (or (eq .Values.systemDisk.image "ubuntu") (eq .Values.systemDisk.image "alpine")) }} + networkDataSecretRef: + name: {{ include "virtual-machine.fullname" . }}-network-config + {{- end }} + {{- end }} + + networks: + - name: default + pod: {} + {{- if .Values.subnets }} + {{- range $i, $subnet := .Values.subnets }} + - name: {{ $subnet.name }} + multus: + networkName: {{ $.Release.Namespace }}/{{ $subnet.name }} + {{- end }} + {{- end }} diff --git a/packages/apps/virtual-machine/values.schema.json b/packages/apps/virtual-machine/values.schema.json new file mode 100644 index 00000000..e96d6449 --- /dev/null +++ b/packages/apps/virtual-machine/values.schema.json @@ -0,0 +1,218 @@ +{ + "title": "Chart Values", + "type": "object", + "properties": { + "cloudInit": { + "description": "Cloud-init user data.", + "type": "string", + "default": "" + }, + "cloudInitSeed": { + "description": "Seed string to generate SMBIOS UUID for the VM.", + "type": "string", + "default": "" + }, + "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" + } + }, + "gpus": { + "description": "List of GPUs to attach.", + "type": "array", + "default": [], + "items": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "description": "The name of the GPU resource to attach.", + "type": "string" + } + } + } + }, + "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", + "" + ] + }, + "instanceType": { + "description": "Virtual Machine instance type.", + "type": "string", + "default": "u1.medium" + }, + "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 + } + } + }, + "running": { + "description": "Whether the virtual machine should be running.", + "type": "boolean", + "default": true + }, + "sshKeys": { + "description": "List of SSH public keys for authentication.", + "type": "array", + "default": [], + "items": { + "type": "string" + } + }, + "subnets": { + "description": "Additional subnets", + "type": "array", + "default": [], + "items": { + "type": "object", + "properties": { + "name": { + "description": "Subnet name", + "type": "string" + } + } + } + }, + "systemDisk": { + "description": "System disk configuration.", + "type": "object", + "default": {}, + "required": [ + "image", + "storage" + ], + "properties": { + "image": { + "description": "The base image for the virtual machine.", + "type": "string", + "default": "ubuntu", + "enum": [ + "ubuntu", + "cirros", + "alpine", + "fedora", + "talos" + ] + }, + "storage": { + "description": "The size of the disk allocated for the virtual machine.", + "type": "string", + "default": "5Gi" + }, + "storageClass": { + "description": "StorageClass used to store the data.", + "type": "string", + "default": "replicated" + } + } + } + } +} diff --git a/packages/apps/virtual-machine/values.yaml b/packages/apps/virtual-machine/values.yaml new file mode 100644 index 00000000..a4bfbb53 --- /dev/null +++ b/packages/apps/virtual-machine/values.yaml @@ -0,0 +1,98 @@ +## +## @section Common parameters +## + +## @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. + +## @enum {string} SystemImage - The base image for the virtual machine. +## @value ubuntu +## @value cirros +## @value alpine +## @value fedora +## @value talos + +## @typedef {struct} SystemDisk - System disk configuration. +## @field {SystemImage} image - The base image for the virtual machine. +## @field {string} storage - The size of the disk allocated for the virtual machine. +## @field {string} [storageClass] - StorageClass used to store the data. + +## @typedef {struct} Subnet - Additional subnets +## @field {string} [name] - Subnet 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} [sockets] - Number of CPU sockets (vCPU topology). +## @field {quantity} [memory] - Amount of memory allocated. + +## @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 {bool} running - Whether the virtual machine should be running. +running: true + +## @param {string} instanceType - Virtual Machine instance type. +## @param {string} instanceProfile - Virtual Machine preferences profile. +instanceType: "u1.medium" +instanceProfile: ubuntu + +## @param {SystemDisk} systemDisk - System disk configuration. +systemDisk: + image: ubuntu + storage: 5Gi + storageClass: replicated + +## @param {[]Subnet} subnets - Additional subnets +subnets: [] +## Example: +## subnets: +## - name: subnet-84dbec17 +## - name: subnet-aa8896b5 +## - name: subnet-e9b97196 + +## @param {[]GPU} gpus - List of GPUs to attach. +gpus: [] +## Example: +## gpus: +## - name: nvidia.com/GA102GL_A10 + +## @param {Resources} [resources] - Resource configuration for the virtual machine. +resources: {} +## Example: +## resources: +## cpu: "4" +## sockets: "1" +## memory: "8Gi" + +## @param {[]string} sshKeys - List of SSH public keys for authentication. +sshKeys: [] +## Example: +## sshKeys: +## - ssh-rsa ... +## - ssh-ed25519 ... +## + +## @param {string} cloudInit - Cloud-init user data. +cloudInit: "" +## Example: +## cloudInit: | +## #cloud-config +## password: ubuntu +## chpasswd: { expire: False } +## + +## @param {string} cloudInitSeed - Seed string to generate SMBIOS UUID for the VM. +cloudInitSeed: "" +## Example: +## cloudInitSeed: "upd1" diff --git a/packages/apps/vm-disk/Makefile b/packages/apps/vm-disk/Makefile index 80b1075a..8b1dce9d 100644 --- a/packages/apps/vm-disk/Makefile +++ b/packages/apps/vm-disk/Makefile @@ -1,5 +1,5 @@ -include ../../../hack/package.mk +include ../../../scripts/package.mk generate: - cozyvalues-gen -m 'vmdisk' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/vmdisk/types.go + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md ../../../hack/update-crd.sh diff --git a/packages/apps/vm-disk/README.md b/packages/apps/vm-disk/README.md index 3727d0f5..b8a4cdac 100644 --- a/packages/apps/vm-disk/README.md +++ b/packages/apps/vm-disk/README.md @@ -6,17 +6,15 @@ A Virtual Machine Disk ### Common parameters -| 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` | +| Name | Description | Type | Value | +| ------------------- | ------------------------------------------------------------------------------------------------------------------------ | ---------- | ------------ | +| `source` | The source image location used to create a disk. | `object` | `{}` | +| `source.image` | Use image by name. | `*object` | `null` | +| `source.image.name` | Name of the image to use (uploaded as "golden image" or from the list: `ubuntu`, `fedora`, `cirros`, `alpine`, `talos`). | `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` | `""` | +| `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/templates/dv.yaml b/packages/apps/vm-disk/templates/dv.yaml index 521a82b8..3d68e639 100644 --- a/packages/apps/vm-disk/templates/dv.yaml +++ b/packages/apps/vm-disk/templates/dv.yaml @@ -21,18 +21,15 @@ 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-default-images-{{ required "A valid .Values.source.image.name entry required!" .Values.source.image.name }} + name: vm-image-{{ 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/values.schema.json b/packages/apps/vm-disk/values.schema.json index d61fc359..cd2215d8 100644 --- a/packages/apps/vm-disk/values.schema.json +++ b/packages/apps/vm-disk/values.schema.json @@ -2,24 +2,16 @@ "title": "Chart Values", "type": "object", "properties": { + "optical": { + "description": "Defines if disk should be considered optical.", + "type": "boolean", + "default": false + }, "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", @@ -34,29 +26,23 @@ } }, "image": { - "description": "Use image by name from default collection.", + "description": "Use image by name.", "type": "object", "required": [ "name" ], "properties": { "name": { - "description": "Name of the image to use.", + "description": "Name of the image to use (uploaded as \"golden image\" or from the list: `ubuntu`, `fedora`, `cirros`, `alpine`, `talos`).", "type": "string" } } }, "upload": { - "description": "Upload local image.", - "type": "object" + "description": "Upload local image." } } }, - "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", @@ -77,4 +63,4 @@ "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 b9a20d68..33bd174f 100644 --- a/packages/apps/vm-disk/values.yaml +++ b/packages/apps/vm-disk/values.yaml @@ -3,21 +3,17 @@ ## ## @typedef {struct} SourceImage - Use image by name. -## @field {string} name - Name of the image to use. +## @field {string} name - Name of the image to use (uploaded as "golden image" or from the list: `ubuntu`, `fedora`, `cirros`, `alpine`, `talos`). ## @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 {*SourceImage} [image] - Use image by name. ## @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: {} diff --git a/packages/apps/vm-instance/Makefile b/packages/apps/vm-instance/Makefile index 92798e4f..105ca7db 100644 --- a/packages/apps/vm-instance/Makefile +++ b/packages/apps/vm-instance/Makefile @@ -1,7 +1,7 @@ -include ../../../hack/package.mk +include ../../../scripts/package.mk generate: - cozyvalues-gen -m 'vminstance' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/vminstance/types.go + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md #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) \ diff --git a/packages/apps/vm-instance/README.md b/packages/apps/vm-instance/README.md index 9d6a52b2..dc63508a 100644 --- a/packages/apps/vm-instance/README.md +++ b/packages/apps/vm-instance/README.md @@ -36,32 +36,28 @@ virtctl ssh @ ### Common parameters -| 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` | `""` | +| 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]` | +| `running` | Determines if the virtual machine should be running. | `bool` | `true` | +| `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` | `""` | +| `subnets` | Additional subnets | `[]object` | `[]` | +| `subnets[i].name` | Subnet 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` | `""` | +| `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 ddea90fe..e65cad9d 100644 --- a/packages/apps/vm-instance/templates/_helpers.tpl +++ b/packages/apps/vm-instance/templates/_helpers.tpl @@ -70,29 +70,6 @@ Generate a stable UUID for cloud-init re-initialization upon upgrade. {{- $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 */}} diff --git a/packages/apps/vm-instance/templates/service.yaml b/packages/apps/vm-instance/templates/service.yaml index cfeffa81..b12f7612 100644 --- a/packages/apps/vm-instance/templates/service.yaml +++ b/packages/apps/vm-instance/templates/service.yaml @@ -7,12 +7,8 @@ metadata: apps.cozystack.io/user-service: "true" {{- include "virtual-machine.labels" . | nindent 4 }} {{- if .Values.external }} - service.kubernetes.io/service-proxy-name: "cozy-proxy" annotations: - 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 }} + networking.cozystack.io/wholeIP: "true" {{- end }} spec: type: {{ ternary "LoadBalancer" "ClusterIP" .Values.external }} diff --git a/packages/apps/vm-instance/templates/vm-update-hook.yaml b/packages/apps/vm-instance/templates/vm-update-hook.yaml index 995dafff..a12e8583 100644 --- a/packages/apps/vm-instance/templates/vm-update-hook.yaml +++ b/packages/apps/vm-instance/templates/vm-update-hook.yaml @@ -2,43 +2,26 @@ {{- $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 -}} -{{- $existingHasInstanceType := and $existingVM $existingVM.spec.instancetype -}} -{{- if and $existingHasInstanceType (not $instanceType) -}} - {{- $needRemoveInstanceType = true -}} -{{- else if and $existingHasInstanceType $instanceType -}} +{{- if and $existingVM $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 $existingVM.spec.preference $instanceProfile -}} +{{- if and $existingVM $instanceProfile -}} {{- if not (eq $existingVM.spec.preference.name $instanceProfile) -}} {{- $needUpdateProfile = true -}} {{- end -}} {{- end -}} -{{- if $existingService -}} - {{- $currentServiceType := $existingService.spec.type -}} - {{- if ne $currentServiceType $desiredServiceType -}} - {{- $needRecreateService = true -}} - {{- end -}} -{{- end -}} - -{{- if or $needUpdateType $needUpdateProfile $needRecreateService $needRemoveInstanceType $needRemoveCustomResources }} +{{- if or $needUpdateType $needUpdateProfile }} apiVersion: batch/v1 kind: Job metadata: @@ -75,32 +58,13 @@ spec: --type merge \ -p '{"spec":{"instancetype":{"name": "{{ $instanceType }}", "revisionName": null}}}' {{- end }} - + {{- if $needUpdateProfile }} echo "Patching VirtualMachine for preference update..." 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 @@ -123,10 +87,6 @@ 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 55f278c1..acad3475 100644 --- a/packages/apps/vm-instance/templates/vm.yaml +++ b/packages/apps/vm-instance/templates/vm.yaml @@ -4,10 +4,6 @@ {{- 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 @@ -16,11 +12,7 @@ metadata: labels: {{- include "virtual-machine.labels" . | nindent 4 }} spec: - {{- if hasKey .Values "runStrategy" }} - runStrategy: {{ .Values.runStrategy }} - {{- else }} - runStrategy: {{ ternary "Always" "Halted" (.Values.running | default true) }} - {{- end }} + running: {{ .Values.running }} {{- with .Values.instanceType }} instancetype: kind: VirtualMachineClusterInstancetype @@ -35,22 +27,19 @@ 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: - {{- $domainRes := include "virtual-machine.domainResources" . | fromJson -}} - {{- with $domainRes.cpu }} - cpu: {{- . | toYaml | nindent 10 }} + {{- if and .Values.resources .Values.resources.cpu .Values.resources.sockets }} + cpu: + cores: {{ .Values.resources.cpu }} + sockets: {{ .Values.resources.sockets }} {{- end }} - {{- with $domainRes.resources }} - resources: {{- . | toYaml | nindent 10 }} + {{- if and .Values.resources .Values.resources.memory }} + resources: + requests: + memory: {{ .Values.resources.memory | quote }} {{- end }} firmware: uuid: {{ include "virtual-machine.stableUuid" . }} @@ -87,10 +76,12 @@ spec: interfaces: - name: default bridge: {} - {{- range $i, $net := $networks }} - - name: {{ $net.name }} + {{- if .Values.subnets }} + {{- range $i, $subnet := .Values.subnets }} + - name: {{ $subnet.name }} bridge: {} {{- end }} + {{- end }} machine: type: "" {{- with .Values.sshKeys }} @@ -122,8 +113,10 @@ spec: networks: - name: default pod: {} - {{- range $i, $net := $networks }} - - name: {{ $net.name }} + {{- if .Values.subnets }} + {{- range $i, $subnet := .Values.subnets }} + - name: {{ $subnet.name }} multus: - networkName: {{ $.Release.Namespace }}/{{ $net.name }} + networkName: {{ $.Release.Namespace }}/{{ $subnet.name }} + {{- end }} {{- end }} diff --git a/packages/apps/vm-instance/values.schema.json b/packages/apps/vm-instance/values.schema.json index 01bd30a9..ca6b34e7 100644 --- a/packages/apps/vm-instance/values.schema.json +++ b/packages/apps/vm-instance/values.schema.json @@ -2,6 +2,37 @@ "title": "Chart Values", "type": "object", "properties": { + "cloudInit": { + "description": "Cloud-init user data.", + "type": "string", + "default": "" + }, + "cloudInitSeed": { + "description": "Seed string to generate SMBIOS UUID for the VM.", + "type": "string", + "default": "" + }, + "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" + } + } + } + }, "external": { "description": "Enable external access from outside the cluster.", "type": "boolean", @@ -26,27 +57,22 @@ "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" + "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" + } + } + } }, "instanceProfile": { "description": "Virtual Machine preferences profile.", @@ -98,76 +124,10 @@ "" ] }, - "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", + "instanceType": { + "description": "Virtual Machine instance type.", "type": "string", - "default": "" + "default": "u1.medium" }, "resources": { "description": "Resource configuration for the virtual machine.", @@ -215,6 +175,11 @@ } } }, + "running": { + "description": "Determines if the virtual machine should be running.", + "type": "boolean", + "default": true + }, "sshKeys": { "description": "List of SSH public keys for authentication.", "type": "array", @@ -223,15 +188,19 @@ "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": "" + "subnets": { + "description": "Additional subnets", + "type": "array", + "default": [], + "items": { + "type": "object", + "properties": { + "name": { + "description": "Subnet name", + "type": "string" + } + } + } } } } diff --git a/packages/apps/vm-instance/values.yaml b/packages/apps/vm-instance/values.yaml index 92e399c2..9d0a1522 100644 --- a/packages/apps/vm-instance/values.yaml +++ b/packages/apps/vm-instance/values.yaml @@ -10,8 +10,8 @@ ## @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} Subnet - Additional subnets +## @field {string} [name] - Subnet name ## @typedef {struct} GPU - GPU device configuration. ## @field {string} name - The name of the GPU resource to attach. @@ -31,18 +31,8 @@ externalMethod: PortList externalPorts: - 22 -## @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 - -## @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 {bool} running - Determines if the virtual machine should be running. +running: true ## @param {string} instanceType - Virtual Machine instance type. instanceType: "u1.medium" @@ -58,15 +48,13 @@ disks: [] ## - name: example-data ## bus: sata -## @param {[]Network} networks - Networks to attach the VM to. -networks: [] +## @param {[]Subnet} subnets - Additional subnets +subnets: [] ## Example: -## networks: +## subnets: ## - name: subnet-84dbec17 ## - name: subnet-aa8896b5 - -## @param {[]Network} subnets - Deprecated: use networks instead. -subnets: [] +## - name: subnet-e9b97196 ## @param {[]GPU} gpus - List of GPUs to attach (NVIDIA driver requires at least 4 GiB RAM). gpus: [] @@ -74,9 +62,6 @@ gpus: [] ## gpus: ## - name: nvidia.com/GA102GL_A10 -## @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 {Resources} [resources] - Resource configuration for the virtual machine. resources: {} diff --git a/packages/apps/vpc/Makefile b/packages/apps/vpc/Makefile index 2f0c193f..8807454f 100644 --- a/packages/apps/vpc/Makefile +++ b/packages/apps/vpc/Makefile @@ -1,7 +1,7 @@ -include ../../../hack/package.mk +include ../../../scripts/package.mk generate: - cozyvalues-gen -m 'vpc' -v values.yaml -s values.schema.json -g ../../../api/apps/v1alpha1/vpc/types.go + cozyvalues-gen -v values.yaml -s values.schema.json ../../../hack/update-crd.sh update: diff --git a/packages/apps/vpc/templates/vpc.yaml b/packages/apps/vpc/templates/vpc.yaml index 784c181b..eb113b4f 100644 --- a/packages/apps/vpc/templates/vpc.yaml +++ b/packages/apps/vpc/templates/vpc.yaml @@ -15,37 +15,9 @@ 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) }} +{{- range $subnetName, $subnetConfig := .Values.subnets }} +{{- $subnetId := print "subnet-" (print $.Release.Namespace "/" $vpcId "/" $subnetName | sha256sum | trunc 8) }} --- apiVersion: k8s.cni.cncf.io/v1 kind: NetworkAttachmentDefinition @@ -53,7 +25,7 @@ metadata: name: {{ $subnetId }} namespace: {{ $.Release.Namespace }} labels: - cozystack.io/subnetName: {{ .name }} + cozystack.io/subnetName: {{ $subnetName }} cozystack.io/vpcId: {{ $vpcId }} cozystack.io/vpcName: {{ $.Release.Name }} cozystack.io/tenantName: {{ $.Release.Namespace }} @@ -70,13 +42,13 @@ kind: Subnet metadata: name: {{ $subnetId }} labels: - cozystack.io/subnetName: {{ .name }} + cozystack.io/subnetName: {{ $subnetName }} cozystack.io/vpcId: {{ $vpcId }} cozystack.io/vpcName: {{ $.Release.Name }} cozystack.io/tenantName: {{ $.Release.Namespace }} spec: vpc: {{ $vpcId }} - cidrBlock: {{ .cidr }} + cidrBlock: {{ $subnetConfig.cidr }} provider: "{{ $subnetId }}.{{ $.Release.Namespace }}.ovn" protocol: IPv4 enableLb: false @@ -94,15 +66,9 @@ metadata: 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 }} + {{- range $subnetName, $subnetConfig := .Values.subnets }} + {{ $subnetName }}.ID: {{ print "subnet-" (print $.Release.Namespace "/" $vpcId "/" $subnetName | sha256sum | trunc 8) }} + {{ $subnetName }}.CIDR: {{ $subnetConfig.cidr }} {{- end }} --- apiVersion: rbac.authorization.k8s.io/v1 diff --git a/packages/apps/vpc/values.schema.json b/packages/apps/vpc/values.schema.json index b25b46ed..3e888de4 100644 --- a/packages/apps/vpc/values.schema.json +++ b/packages/apps/vpc/values.schema.json @@ -4,68 +4,17 @@ "properties": { "subnets": { "description": "Subnets of a VPC", - "type": "array", - "default": [], - "items": { + "type": "object", + "default": {}, + "additionalProperties": { "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" } } } } } -} +} \ No newline at end of file diff --git a/packages/apps/vpc/values.yaml b/packages/apps/vpc/values.yaml index 8bd27589..e2bd5faa 100644 --- a/packages/apps/vpc/values.yaml +++ b/packages/apps/vpc/values.yaml @@ -3,36 +3,13 @@ ## ## @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: [] +## @param {map[string]Subnet} subnets - Subnets of a VPC +subnets: {} ## Example: ## subnets: -## - name: mysubnet0 +## mysubnet0: ## cidr: "172.16.0.0/24" -## - name: mysubnet1 +## 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/Makefile b/packages/apps/vpn/Makefile index d0b8412f..8b1dce9d 100644 --- a/packages/apps/vpn/Makefile +++ b/packages/apps/vpn/Makefile @@ -1,5 +1,5 @@ -include ../../../hack/package.mk +include ../../../scripts/package.mk generate: - cozyvalues-gen -m 'vpn' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/vpn/types.go + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md ../../../hack/update-crd.sh diff --git a/packages/apps/vpn/templates/workloadmonitor.yaml b/packages/apps/vpn/templates/workloadmonitor.yaml index 7fc1ec7a..a75f7940 100644 --- a/packages/apps/vpn/templates/workloadmonitor.yaml +++ b/packages/apps/vpn/templates/workloadmonitor.yaml @@ -2,8 +2,6 @@ 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 abfd7b52..14e85262 100644 --- a/packages/apps/vpn/values.schema.json +++ b/packages/apps/vpn/values.schema.json @@ -2,6 +2,24 @@ "title": "Chart Values", "type": "object", "properties": { + "external": { + "description": "Enable external access from outside the cluster.", + "type": "boolean", + "default": false + }, + "externalIPs": { + "description": "List of externalIPs for service. Optional. If not specified, will use LoadBalancer service by default.", + "type": "array", + "default": [], + "items": { + "type": "string" + } + }, + "host": { + "description": "Host used to substitute into generated URLs.", + "type": "string", + "default": "" + }, "replicas": { "description": "Number of VPN server replicas.", "type": "integer", @@ -54,16 +72,6 @@ "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", @@ -77,14 +85,6 @@ } } } - }, - "externalIPs": { - "description": "List of externalIPs for service. Optional. If not specified, will use LoadBalancer service by default.", - "type": "array", - "default": [], - "items": { - "type": "string" - } } } -} +} \ No newline at end of file diff --git a/packages/core/flux-aio/Makefile b/packages/core/flux-aio/Makefile index c5eb27f9..2b3c1408 100644 --- a/packages/core/flux-aio/Makefile +++ b/packages/core/flux-aio/Makefile @@ -1,7 +1,7 @@ NAME=flux-aio NAMESPACE=cozy-$(NAME) -include ../../../hack/common-envs.mk +include ../../../scripts/common-envs.mk show: cozyhr show -n $(NAMESPACE) $(NAME) --plain @@ -12,13 +12,23 @@ apply: diff: cozyhr show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f- -MANIFESTS_DIR=../../../internal/fluxinstall/manifests +update: update-old update-new -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 \ +# TODO: remove old manifest after migration to cozystack-operator +update-old: + timoni bundle build -f flux-aio.cue > templates/fluxcd.yaml + yq eval '(select(.kind == "Namespace") | .metadata.labels."pod-security.kubernetes.io/enforce") = "privileged"' -i templates/fluxcd.yaml + sed -i templates/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 + -e '/value: .svc/a \ {{- include "cozy.kubernetes_envs" . | nindent 12 }}' \ + -e '/hostNetwork: true/i \ dnsPolicy: ClusterFirstWithHostNet' + +update-new: + timoni bundle build -f flux-aio.cue > ../../../internal/fluxinstall/manifests/fluxcd.yaml + yq eval '(select(.kind == "Namespace") | .metadata.labels."pod-security.kubernetes.io/enforce") = "privileged"' -i ../../../internal/fluxinstall/manifests/fluxcd.yaml + sed -i ../../../internal/fluxinstall/manifests/fluxcd.yaml \ + -e '/timoni/d' \ + -e 's|\.cluster\.local\.,||g' -e 's|\.cluster\.local\,||g' -e 's|\.cluster\.local\.||g' + # TODO: solve dns issue with hostNetwork for installing helmreleases in tenant k8s clusters + #-e '/hostNetwork: true/i \ dnsPolicy: ClusterFirstWithHostNet' diff --git a/packages/core/flux-aio/flux-aio.cue b/packages/core/flux-aio/flux-aio.cue index e47d20aa..8c067c3b 100644 --- a/packages/core/flux-aio/flux-aio.cue +++ b/packages/core/flux-aio/flux-aio.cue @@ -10,19 +10,6 @@ bundle: { 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 deleted file mode 120000 index f9bb5aad..00000000 --- a/packages/core/flux-aio/manifests +++ /dev/null @@ -1 +0,0 @@ -../../../internal/fluxinstall/manifests \ No newline at end of file diff --git a/packages/core/flux-aio/templates/_helpers.tpl b/packages/core/flux-aio/templates/_helpers.tpl new file mode 100644 index 00000000..e22979ba --- /dev/null +++ b/packages/core/flux-aio/templates/_helpers.tpl @@ -0,0 +1,13 @@ +{{- define "cozy.kubernetes_envs" }} +{{- $cozyDeployment := lookup "apps/v1" "Deployment" "cozy-system" "cozystack" }} +{{- $cozyContainers := dig "spec" "template" "spec" "containers" dict $cozyDeployment }} +{{- range $cozyContainers }} +{{- if eq .name "cozystack" }} +{{- range .env }} +{{- if has .name (list "KUBERNETES_SERVICE_HOST" "KUBERNETES_SERVICE_PORT") }} +- {{ toJson . }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/core/flux-aio/templates/fluxcd.yaml b/packages/core/flux-aio/templates/fluxcd.yaml new file mode 100644 index 00000000..71a354c6 --- /dev/null +++ b/packages/core/flux-aio/templates/fluxcd.yaml @@ -0,0 +1,11957 @@ +--- +# 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 + {{- include "cozy.kubernetes_envs" . | nindent 12 }} + 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 + {{- include "cozy.kubernetes_envs" . | nindent 12 }} + 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 + {{- include "cozy.kubernetes_envs" . | nindent 12 }} + 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 + {{- include "cozy.kubernetes_envs" . | nindent 12 }} + 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=source-watcher.$(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 + {{- include "cozy.kubernetes_envs" . | nindent 12 }} + 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 + dnsPolicy: ClusterFirstWithHostNet + hostNetwork: true + priorityClassName: system-cluster-critical + securityContext: + fsGroup: 1337 + serviceAccountName: flux + terminationGracePeriodSeconds: 120 + tolerations: + - key: node.kubernetes.io/not-ready + operator: Exists + - effect: NoExecute + key: node.kubernetes.io/unreachable + operator: Exists + tolerationSeconds: 300 + volumes: + - emptyDir: {} + name: data + - emptyDir: {} + name: tmp diff --git a/packages/core/installer/.helmignore b/packages/core/installer/.helmignore deleted file mode 100644 index 6901ff3d..00000000 --- a/packages/core/installer/.helmignore +++ /dev/null @@ -1,9 +0,0 @@ -# VCS and IDE -.git -.gitignore - -# Build artifacts -Makefile -images/ -example/ -*.tgz diff --git a/packages/core/installer/Makefile b/packages/core/installer/Makefile index a661bed4..4c19c258 100644 --- a/packages/core/installer/Makefile +++ b/packages/core/installer/Makefile @@ -1,52 +1,57 @@ NAME=installer NAMESPACE=cozy-system -include ../../../hack/common-envs.mk +include ../../../scripts/common-envs.mk pre-checks: ../../../hack/pre-checks.sh show: - cozyhr show --namespace $(NAMESPACE) $(NAME) --plain + cozyhr show -n $(NAMESPACE) $(NAME) --plain apply: - cozyhr show --namespace $(NAMESPACE) $(NAME) --plain | kubectl apply -f - + cozyhr show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- diff: - cozyhr show --namespace $(NAMESPACE) $(NAME) --plain | kubectl diff -f - + cozyhr show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f - -image: pre-checks image-operator image-packages chart +image: pre-checks image-cozystack + +image-cozystack: + docker buildx build -f images/cozystack/Dockerfile ../../.. \ + --tag $(REGISTRY)/installer:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/installer:latest \ + --cache-to type=inline \ + --metadata-file images/installer.json \ + $(BUILDX_ARGS) + 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 + +update-version: + TAG="$(call settag,$(TAG))" \ + yq -i '.cozystackOperator.cozystackVersion = strenv(TAG)' values.yaml 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/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 + --tag $(REGISTRY)/cozystack-operator:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/cozystack-operator:latest \ + --cache-to type=inline \ + --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-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 -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 +image-packages: update-version + mkdir -p ../../../_out/assets images + flux push artifact \ + oci://$(REGISTRY)/platform-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)/platform-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.platformSource = (strenv(REPO) + "@" + strenv(DIGEST))' values.yaml diff --git a/internal/crdinstall/manifests/.gitattributes b/packages/core/installer/definitions/.gitattributes similarity index 100% rename from internal/crdinstall/manifests/.gitattributes rename to packages/core/installer/definitions/.gitattributes diff --git a/internal/crdinstall/manifests/cozystack.io_packages.yaml b/packages/core/installer/definitions/cozystack.io_packages.yaml similarity index 100% rename from internal/crdinstall/manifests/cozystack.io_packages.yaml rename to packages/core/installer/definitions/cozystack.io_packages.yaml diff --git a/internal/crdinstall/manifests/cozystack.io_packagesources.yaml b/packages/core/installer/definitions/cozystack.io_packagesources.yaml similarity index 92% rename from internal/crdinstall/manifests/cozystack.io_packagesources.yaml rename to packages/core/installer/definitions/cozystack.io_packagesources.yaml index 1d0037df..0acfcdd2 100644 --- a/internal/crdinstall/manifests/cozystack.io_packagesources.yaml +++ b/packages/core/installer/definitions/cozystack.io_packagesources.yaml @@ -118,19 +118,6 @@ spec: 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: |- diff --git a/packages/core/installer/images/cozystack-operator/Dockerfile b/packages/core/installer/images/cozystack-operator/Dockerfile index 4268b2ba..8c4cb79c 100644 --- a/packages/core/installer/images/cozystack-operator/Dockerfile +++ b/packages/core/installer/images/cozystack-operator/Dockerfile @@ -2,7 +2,6 @@ FROM golang:1.25-alpine as builder ARG TARGETOS ARG TARGETARCH -ARG VERSION=dev RUN apk add --no-cache make git @@ -13,7 +12,7 @@ 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}" \ + -ldflags="-w -s" \ -o /cozystack-operator \ ./cmd/cozystack-operator diff --git a/packages/core/installer/images/cozystack/Dockerfile b/packages/core/installer/images/cozystack/Dockerfile new file mode 100644 index 00000000..8e1ae219 --- /dev/null +++ b/packages/core/installer/images/cozystack/Dockerfile @@ -0,0 +1,41 @@ +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.25-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 + +FROM alpine:3.22 + +RUN wget -O- https://github.com/cozystack/cozyhr/raw/refs/heads/main/hack/install.sh | sh -s -- -v 1.5.0 + +RUN apk add --no-cache make kubectl helm coreutils git jq openssl + +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=k8s-await-election-builder /k8s-await-election /usr/bin/k8s-await-election + +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 new file mode 100644 index 00000000..c1d18d8a --- /dev/null +++ b/packages/core/installer/images/cozystack/Dockerfile.dockerignore @@ -0,0 +1 @@ +_out diff --git a/packages/core/installer/templates/cozystack-operator.yaml b/packages/core/installer/templates/cozystack-operator.yaml index aded0995..d5efa8b4 100644 --- a/packages/core/installer/templates/cozystack-operator.yaml +++ b/packages/core/installer/templates/cozystack-operator.yaml @@ -1,7 +1,4 @@ -{{- $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 -}} +{{- if .Values.cozystackOperator.enabled }} --- apiVersion: v1 kind: Namespace @@ -10,8 +7,6 @@ metadata: labels: cozystack.io/system: "true" pod-security.kubernetes.io/enforce: privileged - annotations: - helm.sh/resource-policy: keep --- apiVersion: v1 kind: ServiceAccount @@ -59,12 +54,9 @@ spec: 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 + - --health-probe-bind-address= + - --cozystack-version={{ .Values.cozystackOperator.cozystackVersion }} {{- if .Values.cozystackOperator.disableTelemetry }} - --disable-telemetry {{- end }} @@ -73,31 +65,58 @@ spec: {{- 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" + 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" + effect: "NoSchedule" - key: "node.cilium.io/agent-not-ready" operator: "Exists" - - key: "node.cloudprovider.kubernetes.io/uninitialized" - operator: "Exists" + effect: "NoSchedule" +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.cozystack-platform +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + components: + - install: + namespace: cozy-system + releaseName: cozystack-platform + name: cozystack-platform + path: core/platform + valuesFiles: + - values.yaml + - name: isp-full + components: + - install: + namespace: cozy-system + releaseName: cozystack-platform + name: cozystack-platform + path: core/platform + valuesFiles: + - values.yaml + - values-isp-full.yaml + - name: isp-hosted + components: + - install: + namespace: cozy-system + releaseName: cozystack-platform + name: cozystack-platform + path: core/platform + valuesFiles: + - values.yaml + - values-isp-hosted.yaml +{{- end }} diff --git a/packages/core/installer/templates/cozystack.yaml b/packages/core/installer/templates/cozystack.yaml new file mode 100644 index 00000000..24ca0557 --- /dev/null +++ b/packages/core/installer/templates/cozystack.yaml @@ -0,0 +1,81 @@ +{{- if not .Values.cozystackOperator.enabled }} +--- +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: INSTALL_FLUX + value: "true" + - 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 + tolerations: + - key: "node.kubernetes.io/not-ready" + operator: "Exists" + effect: "NoSchedule" + - key: "node.cilium.io/agent-not-ready" + operator: "Exists" + effect: "NoSchedule" +{{- end }} diff --git a/packages/core/installer/templates/crds.yaml b/packages/core/installer/templates/crds.yaml new file mode 100644 index 00000000..cffc1205 --- /dev/null +++ b/packages/core/installer/templates/crds.yaml @@ -0,0 +1,6 @@ +{{- if .Values.cozystackOperator.enabled }} +{{- range $path, $_ := .Files.Glob "definitions/*.yaml" }} +--- +{{ $.Files.Get $path }} +{{- end }} +{{- end }} diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index eef691ea..0fcf6c25 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,15 +1,8 @@ -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: - # 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" + image: ghcr.io/cozystack/cozystack/installer:v0.38.2@sha256:9ff92b655de6f9bea3cba4cd42dcffabd9aace6966dcfb1cc02dda2420ea4a15 +cozystackOperator: + enabled: false + image: ghcr.io/cozystack/cozystack/cozystack-operator:latest@sha256:f7f6e0fd9e896b7bfa642d0bfa4378bc14e646bc5c2e86e2e09a82770ef33181 + platformSourceUrl: 'oci://ghcr.io/cozystack/cozystack/platform-packages' + platformSourceRef: 'digest=sha256:0576491291b33936cdf770a5c5b5692add97339c1505fc67a92df9d69dfbfdf6' + cozystackVersion: latest diff --git a/packages/core/platform/Makefile b/packages/core/platform/Makefile index 15ed7b36..2ea59153 100644 --- a/packages/core/platform/Makefile +++ b/packages/core/platform/Makefile @@ -1,28 +1,34 @@ -NAME=cozystack-platform +NAME=platform NAMESPACE=cozy-system -include ../../../hack/common-envs.mk +include ../../../scripts/common-envs.mk show: - cozyhr show --namespace $(NAMESPACE) $(NAME) + cozyhr show -n $(NAMESPACE) $(NAME) --plain apply: - cozyhr apply --namespace $(NAMESPACE) $(NAME) + cozyhr show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- + kubectl delete helmreleases.helm.toolkit.fluxcd.io -l cozystack.io/marked-for-deletion=true -A reconcile: apply +namespaces-show: + cozyhr show -n $(NAMESPACE) $(NAME) --plain -s templates/namespaces.yaml + +namespaces-apply: + cozyhr show -n $(NAMESPACE) $(NAME) --plain -s templates/namespaces.yaml | kubectl apply -f- + diff: - cozyhr diff --namespace $(NAMESPACE) $(NAME) + cozyhr show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f- -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 \ +image: image-assets +image-assets: + docker buildx build -f images/cozystack-assets/Dockerfile ../../.. \ + --tag $(REGISTRY)/cozystack-assets:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/cozystack-assets:latest \ --cache-to type=inline \ - --metadata-file images/migrations.json \ + --metadata-file images/cozystack-assets.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 + IMAGE="$(REGISTRY)/cozystack-assets:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/cozystack-assets.json -o json -r)" \ + yq -i '.assets.image = strenv(IMAGE)' values.yaml + rm -f images/cozystack-assets.json diff --git a/packages/core/platform/bundles/distro-full.yaml b/packages/core/platform/bundles/distro-full.yaml new file mode 100644 index 00000000..bf915d4e --- /dev/null +++ b/packages/core/platform/bundles/distro-full.yaml @@ -0,0 +1,429 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} + +releases: +- 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: lineage-controller-webhook + releaseName: lineage-controller-webhook + chart: cozy-lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cilium,cert-manager] + +- name: cozystack-resource-definition-crd + releaseName: cozystack-resource-definition-crd + chart: cozystack-resource-definition-crd + namespace: cozy-system + dependsOn: [cilium] + +- name: bootbox-rd + releaseName: bootbox-rd + chart: bootbox-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: bucket-rd + releaseName: bucket-rd + chart: bucket-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: clickhouse-rd + releaseName: clickhouse-rd + chart: clickhouse-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: etcd-rd + releaseName: etcd-rd + chart: etcd-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: ferretdb-rd + releaseName: ferretdb-rd + chart: ferretdb-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: foundationdb-rd + releaseName: foundationdb-rd + chart: foundationdb-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: http-cache-rd + releaseName: http-cache-rd + chart: http-cache-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: info-rd + releaseName: info-rd + chart: info-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: ingress-rd + releaseName: ingress-rd + chart: ingress-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: kafka-rd + releaseName: kafka-rd + chart: kafka-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: kubernetes-rd + releaseName: kubernetes-rd + chart: kubernetes-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: monitoring-rd + releaseName: monitoring-rd + chart: monitoring-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: mysql-rd + releaseName: mysql-rd + chart: mysql-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: nats-rd + releaseName: nats-rd + chart: nats-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: postgres-rd + releaseName: postgres-rd + chart: postgres-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: rabbitmq-rd + releaseName: rabbitmq-rd + chart: rabbitmq-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: redis-rd + releaseName: redis-rd + chart: redis-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: seaweedfs-rd + releaseName: seaweedfs-rd + chart: seaweedfs-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: tcp-balancer-rd + releaseName: tcp-balancer-rd + chart: tcp-balancer-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: tenant-rd + releaseName: tenant-rd + chart: tenant-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: virtual-machine-rd + releaseName: virtual-machine-rd + chart: virtual-machine-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: virtualprivatecloud-rd + releaseName: virtualprivatecloud-rd + chart: virtualprivatecloud-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: vm-disk-rd + releaseName: vm-disk-rd + chart: vm-disk-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: vm-instance-rd + releaseName: vm-instance-rd + chart: vm-instance-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: vpn-rd + releaseName: vpn-rd + chart: vpn-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- 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,cert-manager] + +- name: prometheus-operator-crds + releaseName: prometheus-operator-crds + chart: cozy-prometheus-operator-crds + namespace: cozy-victoria-metrics-operator + dependsOn: [] + +- name: metrics-server + releaseName: metrics-server + chart: cozy-metrics-server + namespace: cozy-monitoring + dependsOn: [cilium,prometheus-operator-crds] + +- name: victoria-metrics-operator + releaseName: victoria-metrics-operator + chart: cozy-victoria-metrics-operator + namespace: cozy-victoria-metrics-operator + optional: true + dependsOn: [cilium,cert-manager,prometheus-operator-crds] + +- name: monitoring-agents + releaseName: monitoring-agents + chart: cozy-monitoring-agents + namespace: cozy-monitoring + privileged: true + optional: true + dependsOn: [cilium,victoria-metrics-operator,metrics-server] + 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: foundationdb-operator + releaseName: foundationdb-operator + chart: cozy-foundationdb-operator + namespace: cozy-foundationdb-operator + optional: true + dependsOn: [cilium,cert-manager] + +- 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,cert-manager-issuers] + +- 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] + +- name: hetzner-robotlb + releaseName: robotlb + optional: true + chart: cozy-hetzner-robotlb + namespace: cozy-hetzner-robotlb + dependsOn: [cilium] diff --git a/packages/core/platform/bundles/distro-hosted.yaml b/packages/core/platform/bundles/distro-hosted.yaml new file mode 100644 index 00000000..e2aa5b03 --- /dev/null +++ b/packages/core/platform/bundles/distro-hosted.yaml @@ -0,0 +1,186 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} + +releases: +- 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: lineage-controller-webhook + releaseName: lineage-controller-webhook + chart: cozy-lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cert-manager] + +- 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: prometheus-operator-crds + releaseName: prometheus-operator-crds + chart: cozy-prometheus-operator-crds + namespace: cozy-victoria-metrics-operator + dependsOn: [] + +- name: metrics-server + releaseName: metrics-server + chart: cozy-metrics-server + namespace: cozy-monitoring + dependsOn: [prometheus-operator-crds] + +- name: victoria-metrics-operator + releaseName: victoria-metrics-operator + chart: cozy-victoria-metrics-operator + namespace: cozy-victoria-metrics-operator + optional: true + dependsOn: [prometheus-operator-crds,cert-manager] + +- name: monitoring-agents + releaseName: monitoring-agents + chart: cozy-monitoring-agents + namespace: cozy-monitoring + privileged: true + optional: true + dependsOn: [victoria-metrics-operator, metrics-server] + 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: foundationdb-operator + releaseName: foundationdb-operator + chart: cozy-foundationdb-operator + namespace: cozy-foundationdb-operator + optional: true + dependsOn: [cert-manager] + +- 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 + +- name: hetzner-robotlb + releaseName: robotlb + optional: true + chart: cozy-hetzner-robotlb + namespace: cozy-hetzner-robotlb diff --git a/packages/core/platform/bundles/paas-full.yaml b/packages/core/platform/bundles/paas-full.yaml new file mode 100644 index 00000000..b82e3ef4 --- /dev/null +++ b/packages/core/platform/bundles/paas-full.yaml @@ -0,0 +1,605 @@ +{{- $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: 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: kubeovn-plunger + releaseName: kubeovn-plunger + chart: cozy-kubeovn-plunger + namespace: cozy-kubeovn + dependsOn: [cilium,kubeovn] + +- name: multus + releaseName: multus + chart: cozy-multus + namespace: cozy-multus + privileged: true + dependsOn: [cilium,kubeovn] + +- 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,cozystack-controller] + +- 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: backup-controller + releaseName: backup-controller + chart: cozy-backup-controller + namespace: cozy-backup-controller + dependsOn: [cilium,kubeovn] + +- name: lineage-controller-webhook + releaseName: lineage-controller-webhook + chart: cozy-lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cilium,kubeovn,cert-manager] + +- name: cozystack-resource-definition-crd + releaseName: cozystack-resource-definition-crd + chart: cozystack-resource-definition-crd + namespace: cozy-system + dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller] + +- name: bootbox-rd + releaseName: bootbox-rd + chart: bootbox-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: bucket-rd + releaseName: bucket-rd + chart: bucket-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: clickhouse-rd + releaseName: clickhouse-rd + chart: clickhouse-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: etcd-rd + releaseName: etcd-rd + chart: etcd-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: ferretdb-rd + releaseName: ferretdb-rd + chart: ferretdb-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: foundationdb-rd + releaseName: foundationdb-rd + chart: foundationdb-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: http-cache-rd + releaseName: http-cache-rd + chart: http-cache-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: info-rd + releaseName: info-rd + chart: info-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: ingress-rd + releaseName: ingress-rd + chart: ingress-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: kafka-rd + releaseName: kafka-rd + chart: kafka-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: kubernetes-rd + releaseName: kubernetes-rd + chart: kubernetes-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: monitoring-rd + releaseName: monitoring-rd + chart: monitoring-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: mysql-rd + releaseName: mysql-rd + chart: mysql-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: nats-rd + releaseName: nats-rd + chart: nats-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: postgres-rd + releaseName: postgres-rd + chart: postgres-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: rabbitmq-rd + releaseName: rabbitmq-rd + chart: rabbitmq-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: redis-rd + releaseName: redis-rd + chart: redis-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: seaweedfs-rd + releaseName: seaweedfs-rd + chart: seaweedfs-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: tcp-balancer-rd + releaseName: tcp-balancer-rd + chart: tcp-balancer-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: tenant-rd + releaseName: tenant-rd + chart: tenant-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: virtual-machine-rd + releaseName: virtual-machine-rd + chart: virtual-machine-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: virtualprivatecloud-rd + releaseName: virtualprivatecloud-rd + chart: virtualprivatecloud-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: vm-disk-rd + releaseName: vm-disk-rd + chart: vm-disk-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: vm-instance-rd + releaseName: vm-instance-rd + chart: vm-instance-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: vpn-rd + releaseName: vpn-rd + chart: vpn-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- 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: prometheus-operator-crds + releaseName: prometheus-operator-crds + chart: cozy-prometheus-operator-crds + namespace: cozy-victoria-metrics-operator + dependsOn: [] + +- name: metrics-server + releaseName: metrics-server + chart: cozy-metrics-server + namespace: cozy-monitoring + dependsOn: [cilium,kubeovn,prometheus-operator-crds] + +- name: victoria-metrics-operator + releaseName: victoria-metrics-operator + chart: cozy-victoria-metrics-operator + namespace: cozy-victoria-metrics-operator + dependsOn: [cilium,kubeovn,cert-manager,prometheus-operator-crds] + +- name: monitoring-agents + releaseName: monitoring-agents + chart: cozy-monitoring-agents + namespace: cozy-monitoring + privileged: true + dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds, metrics-server] + 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: foundationdb-operator + releaseName: foundationdb-operator + chart: cozy-foundationdb-operator + namespace: cozy-foundationdb-operator + dependsOn: [cilium,kubeovn,cert-manager] + +- 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] + +- name: hetzner-robotlb + releaseName: robotlb + optional: true + chart: cozy-hetzner-robotlb + namespace: cozy-hetzner-robotlb + dependsOn: [cilium, kubeovn] diff --git a/packages/core/platform/bundles/paas-hosted.yaml b/packages/core/platform/bundles/paas-hosted.yaml new file mode 100644 index 00000000..6db50c7f --- /dev/null +++ b/packages/core/platform/bundles/paas-hosted.yaml @@ -0,0 +1,417 @@ +{{- $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: 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: [cozystack-controller] + values: + cozystackAPI: + localK8sAPIEndpoint: + enabled: false + +- 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: backup-controller + releaseName: backup-controller + chart: cozy-backup-controller + namespace: cozy-backup-controller + +- name: lineage-controller-webhook + releaseName: lineage-controller-webhook + chart: cozy-lineage-controller-webhook + namespace: cozy-system + dependsOn: [cozystack-controller,cert-manager] + +- name: cozystack-resource-definition-crd + releaseName: cozystack-resource-definition-crd + chart: cozystack-resource-definition-crd + namespace: cozy-system + dependsOn: [cozystack-api,cozystack-controller] + +- name: bootbox-rd + releaseName: bootbox-rd + chart: bootbox-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: bucket-rd + releaseName: bucket-rd + chart: bucket-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: clickhouse-rd + releaseName: clickhouse-rd + chart: clickhouse-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: etcd-rd + releaseName: etcd-rd + chart: etcd-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: ferretdb-rd + releaseName: ferretdb-rd + chart: ferretdb-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: foundationdb-rd + releaseName: foundationdb-rd + chart: foundationdb-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: http-cache-rd + releaseName: http-cache-rd + chart: http-cache-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: info-rd + releaseName: info-rd + chart: info-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: ingress-rd + releaseName: ingress-rd + chart: ingress-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: kafka-rd + releaseName: kafka-rd + chart: kafka-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: kubernetes-rd + releaseName: kubernetes-rd + chart: kubernetes-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: monitoring-rd + releaseName: monitoring-rd + chart: monitoring-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: mysql-rd + releaseName: mysql-rd + chart: mysql-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: nats-rd + releaseName: nats-rd + chart: nats-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: postgres-rd + releaseName: postgres-rd + chart: postgres-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: rabbitmq-rd + releaseName: rabbitmq-rd + chart: rabbitmq-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: redis-rd + releaseName: redis-rd + chart: redis-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: seaweedfs-rd + releaseName: seaweedfs-rd + chart: seaweedfs-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: tcp-balancer-rd + releaseName: tcp-balancer-rd + chart: tcp-balancer-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: tenant-rd + releaseName: tenant-rd + chart: tenant-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: virtual-machine-rd + releaseName: virtual-machine-rd + chart: virtual-machine-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: virtualprivatecloud-rd + releaseName: virtualprivatecloud-rd + chart: virtualprivatecloud-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: vm-disk-rd + releaseName: vm-disk-rd + chart: vm-disk-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: vm-instance-rd + releaseName: vm-instance-rd + chart: vm-instance-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- name: vpn-rd + releaseName: vpn-rd + chart: vpn-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + +- 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: prometheus-operator-crds + releaseName: prometheus-operator-crds + chart: cozy-prometheus-operator-crds + namespace: cozy-victoria-metrics-operator + dependsOn: [] + +- name: metrics-server + releaseName: metrics-server + chart: cozy-metrics-server + namespace: cozy-monitoring + dependsOn: [prometheus-operator-crds] + +- name: victoria-metrics-operator + releaseName: victoria-metrics-operator + chart: cozy-victoria-metrics-operator + namespace: cozy-victoria-metrics-operator + dependsOn: [cert-manager,prometheus-operator-crds] + +- name: monitoring-agents + releaseName: monitoring-agents + chart: cozy-monitoring-agents + namespace: cozy-monitoring + privileged: true + dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds, metrics-server] + 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: foundationdb-operator + releaseName: foundationdb-operator + chart: cozy-foundationdb-operator + namespace: cozy-foundationdb-operator + dependsOn: [cert-manager] + +- 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,cozystack-api] + {{- 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] + +- name: hetzner-robotlb + releaseName: robotlb + optional: true + chart: cozy-hetzner-robotlb + namespace: cozy-hetzner-robotlb diff --git a/packages/core/platform/images/cozystack-assets/Dockerfile b/packages/core/platform/images/cozystack-assets/Dockerfile new file mode 100644 index 00000000..bf284de3 --- /dev/null +++ b/packages/core/platform/images/cozystack-assets/Dockerfile @@ -0,0 +1,25 @@ +FROM golang:1.25-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 + +COPY --from=builder /src/_out/repos /cozystack/assets/repos +COPY --from=builder /cozystack-assets-server /usr/bin/cozystack-assets-server +COPY --from=builder /src/dashboards /cozystack/assets/dashboards + +WORKDIR /cozystack +ENTRYPOINT ["/usr/bin/cozystack-assets-server"] diff --git a/packages/core/platform/images/migrations/Dockerfile b/packages/core/platform/images/migrations/Dockerfile deleted file mode 100644 index b35808d5..00000000 --- a/packages/core/platform/images/migrations/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -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/packages/core/platform/images/migrations/migrations/21 b/packages/core/platform/images/migrations/migrations/21 deleted file mode 100755 index bd5fda5f..00000000 --- a/packages/core/platform/images/migrations/migrations/21 +++ /dev/null @@ -1,30 +0,0 @@ -#!/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/23 b/packages/core/platform/images/migrations/migrations/23 deleted file mode 100755 index 7cb9c85e..00000000 --- a/packages/core/platform/images/migrations/migrations/23 +++ /dev/null @@ -1,18 +0,0 @@ -#!/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 deleted file mode 100755 index cb34b041..00000000 --- a/packages/core/platform/images/migrations/migrations/24 +++ /dev/null @@ -1,73 +0,0 @@ -#!/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 deleted file mode 100755 index 655cce23..00000000 --- a/packages/core/platform/images/migrations/migrations/25 +++ /dev/null @@ -1,23 +0,0 @@ -#!/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 deleted file mode 100755 index 96fb9851..00000000 --- a/packages/core/platform/images/migrations/migrations/26 +++ /dev/null @@ -1,172 +0,0 @@ -#!/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 deleted file mode 100755 index 5708ebbb..00000000 --- a/packages/core/platform/images/migrations/migrations/27 +++ /dev/null @@ -1,29 +0,0 @@ -#!/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 deleted file mode 100755 index 5174c9b0..00000000 --- a/packages/core/platform/images/migrations/migrations/28 +++ /dev/null @@ -1,629 +0,0 @@ -#!/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 deleted file mode 100755 index b72c2a93..00000000 --- a/packages/core/platform/images/migrations/migrations/29 +++ /dev/null @@ -1,733 +0,0 @@ -#!/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/packages/core/platform/images/migrations/migrations/30 b/packages/core/platform/images/migrations/migrations/30 deleted file mode 100755 index 64b89305..00000000 --- a/packages/core/platform/images/migrations/migrations/30 +++ /dev/null @@ -1,116 +0,0 @@ -#!/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 deleted file mode 100755 index 2a261d9b..00000000 --- a/packages/core/platform/images/migrations/migrations/31 +++ /dev/null @@ -1,45 +0,0 @@ -#!/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 deleted file mode 100755 index c93a9312..00000000 --- a/packages/core/platform/images/migrations/migrations/32 +++ /dev/null @@ -1,92 +0,0 @@ -#!/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 deleted file mode 100755 index 5da6788f..00000000 --- a/packages/core/platform/images/migrations/migrations/33 +++ /dev/null @@ -1,30 +0,0 @@ -#!/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 deleted file mode 100755 index f031d590..00000000 --- a/packages/core/platform/images/migrations/migrations/34 +++ /dev/null @@ -1,46 +0,0 @@ -#!/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 deleted file mode 100755 index a7471180..00000000 --- a/packages/core/platform/images/migrations/migrations/35 +++ /dev/null @@ -1,21 +0,0 @@ -#!/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 deleted file mode 100755 index 0f0a94dd..00000000 --- a/packages/core/platform/images/migrations/migrations/36 +++ /dev/null @@ -1,22 +0,0 @@ -#!/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 deleted file mode 100755 index 856da262..00000000 --- a/packages/core/platform/images/migrations/migrations/37 +++ /dev/null @@ -1,78 +0,0 @@ -#!/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 deleted file mode 100755 index 59536cb1..00000000 --- a/packages/core/platform/images/migrations/migrations/38 +++ /dev/null @@ -1,52 +0,0 @@ -#!/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/packages/core/platform/images/migrations/run-migrations.sh b/packages/core/platform/images/migrations/run-migrations.sh deleted file mode 100755 index a8224ef7..00000000 --- a/packages/core/platform/images/migrations/run-migrations.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/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/backupstrategy-controller.yaml b/packages/core/platform/sources/backupstrategy-controller.yaml deleted file mode 100644 index b86c5c0d..00000000 --- a/packages/core/platform/sources/backupstrategy-controller.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -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 index ee640176..a1c8a481 100644 --- a/packages/core/platform/sources/bootbox-application.yaml +++ b/packages/core/platform/sources/bootbox-application.yaml @@ -17,6 +17,11 @@ spec: - name: cozy-lib path: library/cozy-lib components: + - name: bootbox-system + path: system/bootbox + install: + releaseName: bootbox-application + namespace: cozy-system - name: bootbox path: extra/bootbox libraries: ["cozy-lib"] diff --git a/packages/core/platform/sources/capi-provider-bootstrap-kubeadm.yaml b/packages/core/platform/sources/capi-providers-bootstrap.yaml similarity index 58% rename from packages/core/platform/sources/capi-provider-bootstrap-kubeadm.yaml rename to packages/core/platform/sources/capi-providers-bootstrap.yaml index 90cea107..0469b1bc 100644 --- a/packages/core/platform/sources/capi-provider-bootstrap-kubeadm.yaml +++ b/packages/core/platform/sources/capi-providers-bootstrap.yaml @@ -2,7 +2,7 @@ apiVersion: cozystack.io/v1alpha1 kind: PackageSource metadata: - name: cozystack.capi-provider-bootstrap-kubeadm + name: cozystack.capi-providers-bootstrap spec: sourceRef: kind: OCIRepository @@ -10,17 +10,6 @@ spec: 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 diff --git a/packages/core/platform/sources/capi-provider-core.yaml b/packages/core/platform/sources/capi-providers-core.yaml similarity index 92% rename from packages/core/platform/sources/capi-provider-core.yaml rename to packages/core/platform/sources/capi-providers-core.yaml index 91af6617..e5b6cc99 100644 --- a/packages/core/platform/sources/capi-provider-core.yaml +++ b/packages/core/platform/sources/capi-providers-core.yaml @@ -2,7 +2,7 @@ apiVersion: cozystack.io/v1alpha1 kind: PackageSource metadata: - name: cozystack.capi-provider-core + name: cozystack.capi-providers-core spec: sourceRef: kind: OCIRepository diff --git a/packages/core/platform/sources/capi-provider-cp-kamaji.yaml b/packages/core/platform/sources/capi-providers-cpprovider.yaml similarity index 58% rename from packages/core/platform/sources/capi-provider-cp-kamaji.yaml rename to packages/core/platform/sources/capi-providers-cpprovider.yaml index 08c29b8f..7b63260d 100644 --- a/packages/core/platform/sources/capi-provider-cp-kamaji.yaml +++ b/packages/core/platform/sources/capi-providers-cpprovider.yaml @@ -2,7 +2,7 @@ apiVersion: cozystack.io/v1alpha1 kind: PackageSource metadata: - name: cozystack.capi-provider-cp-kamaji + name: cozystack.capi-providers-cpprovider spec: sourceRef: kind: OCIRepository @@ -10,18 +10,6 @@ spec: 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 diff --git a/packages/core/platform/sources/capi-provider-infra-kubevirt.yaml b/packages/core/platform/sources/capi-providers-infraprovider.yaml similarity index 57% rename from packages/core/platform/sources/capi-provider-infra-kubevirt.yaml rename to packages/core/platform/sources/capi-providers-infraprovider.yaml index 341e1920..88bebc09 100644 --- a/packages/core/platform/sources/capi-provider-infra-kubevirt.yaml +++ b/packages/core/platform/sources/capi-providers-infraprovider.yaml @@ -2,7 +2,7 @@ apiVersion: cozystack.io/v1alpha1 kind: PackageSource metadata: - name: cozystack.capi-provider-infra-kubevirt + name: cozystack.capi-providers-infraprovider spec: sourceRef: kind: OCIRepository @@ -10,18 +10,6 @@ spec: 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 diff --git a/packages/core/platform/sources/cluster-autoscaler-azure.yaml b/packages/core/platform/sources/cluster-autoscaler-azure.yaml deleted file mode 100644 index 7709f3f7..00000000 --- a/packages/core/platform/sources/cluster-autoscaler-azure.yaml +++ /dev/null @@ -1,24 +0,0 @@ ---- -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 deleted file mode 100644 index bbb1a85b..00000000 --- a/packages/core/platform/sources/cluster-autoscaler-hetzner.yaml +++ /dev/null @@ -1,24 +0,0 @@ ---- -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 deleted file mode 100644 index 2dc800ab..00000000 --- a/packages/core/platform/sources/clustersecret-operator.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -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 index 041b968f..fac0f5fc 100644 --- a/packages/core/platform/sources/cozy-proxy.yaml +++ b/packages/core/platform/sources/cozy-proxy.yaml @@ -18,4 +18,4 @@ spec: path: system/cozy-proxy install: namespace: cozy-system - releaseName: cozy-proxy + releaseName: cozystack diff --git a/packages/core/platform/sources/cozystack-engine.yaml b/packages/core/platform/sources/cozystack-engine.yaml index 596c81c4..ce06b9d8 100644 --- a/packages/core/platform/sources/cozystack-engine.yaml +++ b/packages/core/platform/sources/cozystack-engine.yaml @@ -17,18 +17,18 @@ spec: - name: cozy-lib path: library/cozy-lib components: - - name: application-definition-crd - path: system/application-definition-crd + - name: cozystack-resource-definition-crd + path: system/cozystack-resource-definition-crd install: namespace: cozy-system - releaseName: application-definition-crd + releaseName: cozystack-resource-definition-crd - name: cozystack-controller path: system/cozystack-controller install: namespace: cozy-system releaseName: cozystack-controller dependsOn: - - application-definition-crd + - cozystack-resource-definition-crd - name: cozystack-api path: system/cozystack-api install: @@ -36,7 +36,7 @@ spec: releaseName: cozystack-api dependsOn: - cozystack-controller - - application-definition-crd + - cozystack-resource-definition-crd - name: lineage-controller-webhook path: system/lineage-controller-webhook install: @@ -44,7 +44,7 @@ spec: releaseName: lineage-controller-webhook dependsOn: - cozystack-controller - - application-definition-crd + - cozystack-resource-definition-crd - name: dashboard path: system/dashboard install: @@ -53,28 +53,27 @@ spec: dependsOn: - cozystack-api - cozystack-controller - - application-definition-crd + - cozystack-resource-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 + - name: cozystack-resource-definition-crd + path: system/cozystack-resource-definition-crd install: namespace: cozy-system - releaseName: application-definition-crd + releaseName: cozystack-resource-definition-crd - name: cozystack-controller path: system/cozystack-controller install: namespace: cozy-system releaseName: cozystack-controller dependsOn: - - application-definition-crd + - cozystack-resource-definition-crd - name: cozystack-api path: system/cozystack-api install: @@ -82,7 +81,7 @@ spec: releaseName: cozystack-api dependsOn: - cozystack-controller - - application-definition-crd + - cozystack-resource-definition-crd - name: lineage-controller-webhook path: system/lineage-controller-webhook install: @@ -90,7 +89,7 @@ spec: releaseName: lineage-controller-webhook dependsOn: - cozystack-controller - - application-definition-crd + - cozystack-resource-definition-crd - name: dashboard path: system/dashboard install: @@ -100,7 +99,7 @@ spec: - cozystack-api - cozystack-controller - keycloak-configure - - application-definition-crd + - cozystack-resource-definition-crd - name: keycloak-configure path: system/keycloak-configure install: diff --git a/packages/core/platform/sources/cozystack-scheduler.yaml b/packages/core/platform/sources/cozystack-scheduler.yaml deleted file mode 100644 index 52e85a4f..00000000 --- a/packages/core/platform/sources/cozystack-scheduler.yaml +++ /dev/null @@ -1,30 +0,0 @@ ---- -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-operator.yaml b/packages/core/platform/sources/etcd-operator.yaml index 5f42a4a0..599ed2a3 100644 --- a/packages/core/platform/sources/etcd-operator.yaml +++ b/packages/core/platform/sources/etcd-operator.yaml @@ -14,7 +14,6 @@ spec: dependsOn: - cozystack.networking - cozystack.cert-manager - - cozystack.vertical-pod-autoscaler components: - name: etcd-operator path: system/etcd-operator diff --git a/packages/core/platform/sources/mongodb-application.yaml b/packages/core/platform/sources/ferretdb-application.yaml similarity index 64% rename from packages/core/platform/sources/mongodb-application.yaml rename to packages/core/platform/sources/ferretdb-application.yaml index b6106fe1..447745a5 100644 --- a/packages/core/platform/sources/mongodb-application.yaml +++ b/packages/core/platform/sources/ferretdb-application.yaml @@ -2,7 +2,7 @@ apiVersion: cozystack.io/v1alpha1 kind: PackageSource metadata: - name: cozystack.mongodb-application + name: cozystack.ferretdb-application spec: sourceRef: kind: OCIRepository @@ -17,11 +17,11 @@ spec: - name: cozy-lib path: library/cozy-lib components: - - name: mongodb - path: apps/mongodb - libraries: ["cozy-lib"] - - name: mongodb-rd - path: system/mongodb-rd + - name: ferretdb + path: apps/ferretdb + libraries: [cozy-lib] + - name: ferretdb-rd + path: system/ferretdb-rd install: namespace: cozy-system - releaseName: mongodb-rd + releaseName: ferretdb-rd diff --git a/packages/core/platform/sources/flux-plunger.yaml b/packages/core/platform/sources/flux-plunger.yaml deleted file mode 100644 index bbee0b34..00000000 --- a/packages/core/platform/sources/flux-plunger.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -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/hami.yaml b/packages/core/platform/sources/hami.yaml deleted file mode 100644 index 0184e405..00000000 --- a/packages/core/platform/sources/hami.yaml +++ /dev/null @@ -1,24 +0,0 @@ ---- -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 deleted file mode 100644 index c2773bdd..00000000 --- a/packages/core/platform/sources/harbor-application.yaml +++ /dev/null @@ -1,32 +0,0 @@ ---- -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/ingress-nginx.yaml b/packages/core/platform/sources/ingress-nginx.yaml deleted file mode 100644 index b51e096f..00000000 --- a/packages/core/platform/sources/ingress-nginx.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -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/keycloak.yaml b/packages/core/platform/sources/keycloak.yaml index 545d70a5..a9dc64b4 100644 --- a/packages/core/platform/sources/keycloak.yaml +++ b/packages/core/platform/sources/keycloak.yaml @@ -14,13 +14,9 @@ spec: 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/kubernetes-application.yaml b/packages/core/platform/sources/kubernetes-application.yaml index 088383ad..0acde1c4 100644 --- a/packages/core/platform/sources/kubernetes-application.yaml +++ b/packages/core/platform/sources/kubernetes-application.yaml @@ -14,10 +14,10 @@ spec: 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 + - cozystack.capi-providers-bootstrap + - cozystack.capi-providers-core + - cozystack.capi-providers-cpprovider + - cozystack.capi-providers-infraprovider libraries: - name: cozy-lib path: library/cozy-lib @@ -52,8 +52,6 @@ spec: 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 diff --git a/packages/core/platform/sources/linstor-gui.yaml b/packages/core/platform/sources/linstor-gui.yaml deleted file mode 100644 index 005e1fb7..00000000 --- a/packages/core/platform/sources/linstor-gui.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -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 deleted file mode 100644 index fad3eeb7..00000000 --- a/packages/core/platform/sources/linstor-scheduler.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -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 index 6e2ec01a..f440affe 100644 --- a/packages/core/platform/sources/linstor.yaml +++ b/packages/core/platform/sources/linstor.yaml @@ -18,19 +18,11 @@ spec: - 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: diff --git a/packages/core/platform/sources/local-ccm.yaml b/packages/core/platform/sources/local-ccm.yaml deleted file mode 100644 index 5317abf8..00000000 --- a/packages/core/platform/sources/local-ccm.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -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/metrics-server.yaml b/packages/core/platform/sources/metrics-server.yaml deleted file mode 100644 index 607cd7f0..00000000 --- a/packages/core/platform/sources/metrics-server.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -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-operator.yaml b/packages/core/platform/sources/mongodb-operator.yaml deleted file mode 100644 index e3d6fe9e..00000000 --- a/packages/core/platform/sources/mongodb-operator.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -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 index 206699b6..9585c5aa 100644 --- a/packages/core/platform/sources/monitoring-agents.yaml +++ b/packages/core/platform/sources/monitoring-agents.yaml @@ -13,7 +13,6 @@ spec: - name: default dependsOn: - cozystack.networking - - cozystack.metrics-server - cozystack.victoria-metrics-operator - cozystack.vertical-pod-autoscaler components: diff --git a/packages/core/platform/sources/monitoring-application.yaml b/packages/core/platform/sources/monitoring-application.yaml index 119aaa37..0f01eddd 100644 --- a/packages/core/platform/sources/monitoring-application.yaml +++ b/packages/core/platform/sources/monitoring-application.yaml @@ -13,16 +13,10 @@ spec: - 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"] diff --git a/packages/core/platform/sources/monitoring.yaml b/packages/core/platform/sources/monitoring.yaml deleted file mode 100644 index ea2007ec..00000000 --- a/packages/core/platform/sources/monitoring.yaml +++ /dev/null @@ -1,43 +0,0 @@ - -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/mariadb-application.yaml b/packages/core/platform/sources/mysql-application.yaml similarity index 71% rename from packages/core/platform/sources/mariadb-application.yaml rename to packages/core/platform/sources/mysql-application.yaml index 34ff901b..4b22e36e 100644 --- a/packages/core/platform/sources/mariadb-application.yaml +++ b/packages/core/platform/sources/mysql-application.yaml @@ -2,7 +2,7 @@ apiVersion: cozystack.io/v1alpha1 kind: PackageSource metadata: - name: cozystack.mariadb-application + name: cozystack.mysql-application spec: sourceRef: kind: OCIRepository @@ -18,11 +18,11 @@ spec: - name: cozy-lib path: library/cozy-lib components: - - name: mariadb - path: apps/mariadb + - name: mysql + path: apps/mysql libraries: ["cozy-lib"] - - name: mariadb-rd - path: system/mariadb-rd + - name: mysql-rd + path: system/mysql-rd install: namespace: cozy-system - releaseName: mariadb-rd + releaseName: mysql-rd diff --git a/packages/core/platform/sources/networking.yaml b/packages/core/platform/sources/networking.yaml index bece76f8..57fff6fc 100644 --- a/packages/core/platform/sources/networking.yaml +++ b/packages/core/platform/sources/networking.yaml @@ -33,53 +33,6 @@ spec: 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: @@ -110,34 +63,3 @@ spec: 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/openbao-application.yaml b/packages/core/platform/sources/openbao-application.yaml deleted file mode 100644 index 438148af..00000000 --- a/packages/core/platform/sources/openbao-application.yaml +++ /dev/null @@ -1,29 +0,0 @@ ---- -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 deleted file mode 100644 index 19358c21..00000000 --- a/packages/core/platform/sources/opensearch-application.yaml +++ /dev/null @@ -1,28 +0,0 @@ ---- -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 deleted file mode 100644 index 21dd7a43..00000000 --- a/packages/core/platform/sources/opensearch-operator.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -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 index 5d7b220b..b5953069 100644 --- a/packages/core/platform/sources/postgres-application.yaml +++ b/packages/core/platform/sources/postgres-application.yaml @@ -13,7 +13,6 @@ spec: - name: default dependsOn: - cozystack.networking - - cozystack.postgres-operator libraries: - name: cozy-lib path: library/cozy-lib diff --git a/packages/core/platform/sources/qdrant-application.yaml b/packages/core/platform/sources/qdrant-application.yaml deleted file mode 100644 index 6477cc37..00000000 --- a/packages/core/platform/sources/qdrant-application.yaml +++ /dev/null @@ -1,29 +0,0 @@ ---- -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/external-dns-application.yaml b/packages/core/platform/sources/virtual-machine-application.yaml similarity index 52% rename from packages/core/platform/sources/external-dns-application.yaml rename to packages/core/platform/sources/virtual-machine-application.yaml index 0a37dc52..b2583e7e 100644 --- a/packages/core/platform/sources/external-dns-application.yaml +++ b/packages/core/platform/sources/virtual-machine-application.yaml @@ -2,7 +2,7 @@ apiVersion: cozystack.io/v1alpha1 kind: PackageSource metadata: - name: cozystack.external-dns-application + name: cozystack.virtual-machine-application spec: sourceRef: kind: OCIRepository @@ -10,20 +10,20 @@ spec: namespace: cozy-system path: / variants: - - name: default + - name: kubevirt dependsOn: - cozystack.networking + - cozystack.kubevirt + - cozystack.kubevirt-cdi 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 + - name: virtual-machine + path: apps/virtual-machine + libraries: [cozy-lib] + - name: virtual-machine-rd + path: system/virtual-machine-rd install: namespace: cozy-system - releaseName: external-dns-rd + releaseName: virtual-machine-rd diff --git a/packages/core/platform/sources/vm-default-images.yaml b/packages/core/platform/sources/vm-default-images.yaml deleted file mode 100644 index 16cd6a94..00000000 --- a/packages/core/platform/sources/vm-default-images.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -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/templates/_helpers.tpl b/packages/core/platform/templates/_helpers.tpl index 4bc02429..c656c7f8 100644 --- a/packages/core/platform/templates/_helpers.tpl +++ b/packages/core/platform/templates/_helpers.tpl @@ -1,72 +1,108 @@ -{{- 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 -}} +{{/* +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 }} {{- 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.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 }} - -{{- 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) +Get Kubernetes API Endpoint from cozystack deployment +Returns host:port format */}} -{{- 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) }} +{{- define "cozystack.kubernetesAPIEndpoint" -}} +{{- $cozyDeployment := lookup "apps/v1" "Deployment" "cozy-system" "cozystack" }} +{{- $cozyContainers := dig "spec" "template" "spec" "containers" list $cozyDeployment }} +{{- $kubernetesServiceHost := "" }} +{{- $kubernetesServicePort := "" }} +{{- range $cozyContainers }} +{{- if eq .name "cozystack" }} +{{- range .env }} +{{- if eq .name "KUBERNETES_SERVICE_HOST" }} +{{- $kubernetesServiceHost = .value }} +{{- end }} +{{- if eq .name "KUBERNETES_SERVICE_PORT" }} +{{- $kubernetesServicePort = .value }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} +{{- if eq $kubernetesServiceHost "" }} +{{- $kubernetesServiceHost = "kubernetes.default.svc" }} +{{- end }} +{{- if eq $kubernetesServicePort "" }} +{{- $kubernetesServicePort = "443" }} +{{- end }} +{{- printf "%s:%s" $kubernetesServiceHost $kubernetesServicePort }} +{{- end -}} + +{{- define "cozystack.defaultDashboardValues" -}} +kubeapps: +{{- if .Capabilities.APIVersions.Has "source.toolkit.fluxcd.io/v1" }} +{{- with (lookup "source.toolkit.fluxcd.io/v1" "HelmRepository" "cozy-public" "").items }} + redis: + master: + podAnnotations: + {{- range $index, $repo := . }} + {{- with (($repo.status).artifact).revision }} + repository.cozystack.io/{{ $repo.metadata.name }}: {{ quote . }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} + frontend: + resourcesPreset: "none" + dashboard: + resourcesPreset: "none" + {{- $cozystackBranding:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} + {{- $branding := dig "data" "branding" "" $cozystackBranding }} + {{- if $branding }} + customLocale: + "Kubeapps": {{ $branding }} + {{- end }} + customStyle: | + {{- $logoImage := dig "data" "logo" "" $cozystackBranding }} + {{- if $logoImage }} + .kubeapps-logo { + background-image: {{ $logoImage }} + } + {{- end }} + #serviceaccount-selector { + display: none; + } + .login-moreinfo { + display: none; + } + a[href="#/docs"] { + display: none; + } + .login-group .clr-form-control .clr-control-label { + display: none; + } + .appview-separator div.appview-first-row div.center { + display: none; + } + .appview-separator div.appview-first-row section[aria-labelledby="app-secrets"] { + display: none; + } + .appview-first-row section[aria-labelledby="access-urls-title"] { + width: 100%; + } + .header-version { + display: none; + } + .label.label-info-secondary { + display: none; + } {{- end }} diff --git a/packages/core/platform/templates/apps.yaml b/packages/core/platform/templates/apps.yaml index 6e1ae25a..46c9a370 100644 --- a/packages/core/platform/templates/apps.yaml +++ b/packages/core/platform/templates/apps.yaml @@ -1,49 +1,121 @@ -{{- $kubeRootCa := lookup "v1" "ConfigMap" "kube-system" "kube-root-ca.crt" }} -{{- $cozystackCm := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $bundleName := .Values.bundles.system.variant }} +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $cozystackBranding := lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} +{{- $cozystackScheduling := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} +{{- $bundleName := index $cozyConfig.data "bundle-name" }} {{- $bundle := tpl (.Files.Get (printf "bundles/%s.yaml" $bundleName)) . | fromYaml }} -{{- /* 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 -}} +{{/* Default values for _cluster config to ensure all required keys exist */}} +{{- $clusterDefaults := dict + "root-host" "" + "bundle-name" "" + "clusterissuer" "http01" + "oidc-enabled" "false" + "expose-services" "" + "expose-ingress" "tenant-root" + "expose-external-ips" "" + "cluster-domain" "cozy.local" + "api-server-endpoint" "" +}} +{{- $clusterConfig := mergeOverwrite $clusterDefaults ($cozyConfig.data | default dict) }} +{{- $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 }} +--- +apiVersion: v1 +kind: Namespace +metadata: + annotations: + helm.sh/resource-policy: keep + labels: + tenant.cozystack.io/tenant-root: "" + 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: v1 kind: Secret metadata: name: cozystack-values - namespace: cozy-system + namespace: tenant-root labels: 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 }} + _cluster: | + {{- $clusterConfig | toYaml | nindent 4 }} + {{- with $cozystackBranding.data }} + branding: + {{- . | toYaml | nindent 6 }} + {{- end }} + {{- with $cozystackScheduling.data }} + scheduling: + {{- . | toYaml | nindent 6 }} + {{- end }} + _namespace: | + etcd: tenant-root + monitoring: tenant-root + ingress: tenant-root + seaweedfs: tenant-root + host: {{ $host | quote }} +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: tenant-root + namespace: tenant-root + labels: + cozystack.io/ui: "true" + apps.cozystack.io/application.kind: Tenant + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.name: tenant-root +spec: + interval: 0s + releaseName: tenant-root + install: + remediation: + retries: -1 + upgrade: + remediation: + retries: -1 + chart: + spec: + chart: tenant + version: '>= 0.0.0-0' + sourceRef: + kind: HelmRepository + name: cozystack-apps + namespace: cozy-public + valuesFrom: + - kind: Secret + name: cozystack-values + valuesKey: _namespace + targetPath: _namespace + optional: false + - kind: Secret + name: cozystack-values + valuesKey: _cluster + targetPath: _cluster + optional: false + values: + host: "{{ $host }}" + dependsOn: + {{- range $x := $bundle.releases }} + {{- if has $x.name (list "cilium" "kubeovn") }} + - name: {{ $x.name }} + namespace: {{ $x.namespace }} + {{- end }} + {{- end }} diff --git a/packages/core/platform/templates/bundles/iaas.yaml b/packages/core/platform/templates/bundles/iaas.yaml deleted file mode 100644 index 66ec98b2..00000000 --- a/packages/core/platform/templates/bundles/iaas.yaml +++ /dev/null @@ -1,25 +0,0 @@ -{{- 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 deleted file mode 100644 index 9682d447..00000000 --- a/packages/core/platform/templates/bundles/naas.yaml +++ /dev/null @@ -1,8 +0,0 @@ -{{- 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 deleted file mode 100644 index 54854368..00000000 --- a/packages/core/platform/templates/bundles/paas.yaml +++ /dev/null @@ -1,24 +0,0 @@ -{{- 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 deleted file mode 100644 index 6c587c82..00000000 --- a/packages/core/platform/templates/bundles/system.yaml +++ /dev/null @@ -1,158 +0,0 @@ -{{- 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 deleted file mode 100644 index 6e9fb640..00000000 --- a/packages/core/platform/templates/containerd-registry-secret.yaml +++ /dev/null @@ -1,35 +0,0 @@ -{{- 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-assets.yaml b/packages/core/platform/templates/cozystack-assets.yaml new file mode 100644 index 00000000..61ab8dca --- /dev/null +++ b/packages/core/platform/templates/cozystack-assets.yaml @@ -0,0 +1,73 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: cozystack-assets + namespace: cozy-system + labels: + app: cozystack-assets +spec: + serviceName: cozystack-assets + replicas: 1 + selector: + matchLabels: + app: cozystack-assets + template: + metadata: + labels: + app: cozystack-assets + spec: + hostNetwork: true + containers: + - name: assets-server + image: "{{ .Values.assets.image }}" + args: + - "-dir=/cozystack/assets" + - "-address=:8123" + ports: + - name: http + containerPort: 8123 + hostPort: 8123 + tolerations: + - operator: Exists +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: cozystack-assets-reader + namespace: cozy-system +rules: + - apiGroups: [""] + resources: + - pods/proxy + resourceNames: + - cozystack-assets-0 + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: cozystack-assets-reader + namespace: cozy-system +subjects: + - kind: User + name: cozystack-assets-reader + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: Role + name: cozystack-assets-reader + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: v1 +kind: Service +metadata: + name: cozystack-assets + namespace: cozy-system +spec: + ports: + - name: http + port: 80 + targetPort: 8123 + selector: + app: cozystack-assets + type: ClusterIP diff --git a/packages/core/platform/templates/cozystack-version.yaml b/packages/core/platform/templates/cozystack-version.yaml deleted file mode 100644 index 09b845c2..00000000 --- a/packages/core/platform/templates/cozystack-version.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{- $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 new file mode 100644 index 00000000..83ab18ea --- /dev/null +++ b/packages/core/platform/templates/helmreleases.yaml @@ -0,0 +1,102 @@ +{{- $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 "") }} +{{- $oidcEnabled := (index (default dict $cozyConfig.data) "oidc-enabled") | default "false" | eq "true" }} + +{{/* collect dependency namespaces from releases */}} +{{- range $x := $bundle.releases }} +{{- $_ := set $dependencyNamespaces $x.name $x.namespace }} +{{- end }} + +{{- range $x := $bundle.releases }} + +{{- $shouldInstall := true }} +{{- $shouldDelete := false }} +{{- $notEnabledOptionalComponent := and ($x.optional) (not (has $x.name $enabledComponents)) }} +{{- $disabledComponent := has $x.name $disabledComponents }} +{{- $isKeycloakComponent := or (eq $x.name "keycloak") (eq $x.name "keycloak-operator") (eq $x.name "keycloak-configure") }} + +{{- if and $isKeycloakComponent (not $oidcEnabled) }} +{{- $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 }} +{{- else if or $disabledComponent $notEnabledOptionalComponent }} +{{- $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 = mergeOverwrite $values (fromYaml .) }} + {{- end }} + {{- with $values }} + values: + {{- toYaml . | nindent 4}} + {{- end }} + valuesFrom: + - kind: Secret + name: cozystack-values + valuesKey: _cluster + targetPath: _cluster + + {{- 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 new file mode 100644 index 00000000..47954869 --- /dev/null +++ b/packages/core/platform/templates/helmrepos.yaml @@ -0,0 +1,40 @@ +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: cozystack-system + namespace: cozy-system + labels: + cozystack.io/repository: system +spec: + interval: 5m0s + url: https://{{ include "cozystack.kubernetesAPIEndpoint" . }}/api/v1/namespaces/cozy-system/pods/cozystack-assets-0/proxy/repos/system + certSecretRef: + name: cozystack-assets-tls +--- +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: https://{{ include "cozystack.kubernetesAPIEndpoint" . }}/api/v1/namespaces/cozy-system/pods/cozystack-assets-0/proxy/repos/apps + certSecretRef: + name: cozystack-assets-tls +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: cozystack-extra + namespace: cozy-public + labels: + cozystack.io/repository: extra +spec: + interval: 5m0s + url: https://{{ include "cozystack.kubernetesAPIEndpoint" . }}/api/v1/namespaces/cozy-system/pods/cozystack-assets-0/proxy/repos/extra + certSecretRef: + name: cozystack-assets-tls diff --git a/packages/core/platform/templates/migration-hook.yaml b/packages/core/platform/templates/migration-hook.yaml deleted file mode 100644 index 67b09820..00000000 --- a/packages/core/platform/templates/migration-hook.yaml +++ /dev/null @@ -1,69 +0,0 @@ -{{- 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 new file mode 100644 index 00000000..58eca481 --- /dev/null +++ b/packages/core/platform/templates/namespaces.yaml @@ -0,0 +1,75 @@ +{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $cozystackBranding := lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} +{{- $cozystackScheduling := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} +{{- $bundleName := index $cozyConfig.data "bundle-name" }} +{{/* Default values for _cluster config to ensure all required keys exist */}} +{{- $clusterDefaults := dict + "root-host" "" + "bundle-name" "" + "clusterissuer" "http01" + "oidc-enabled" "false" + "expose-services" "" + "expose-ingress" "tenant-root" + "expose-external-ips" "" + "cluster-domain" "cozy.local" + "api-server-endpoint" "" +}} +{{- $clusterConfig := mergeOverwrite $clusterDefaults ($cozyConfig.data | default dict) }} +{{- $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 }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: cozystack-values + namespace: {{ $namespace }} + labels: + reconcile.fluxcd.io/watch: Enabled +type: Opaque +stringData: + _cluster: | + {{- $clusterConfig | toYaml | nindent 4 }} + {{- with $cozystackBranding.data }} + branding: + {{- . | toYaml | nindent 6 }} + {{- end }} + {{- with $cozystackScheduling.data }} + scheduling: + {{- . | toYaml | nindent 6 }} + {{- end }} +{{- end }} diff --git a/packages/core/platform/templates/repository.yaml b/packages/core/platform/templates/repository.yaml deleted file mode 100644 index 9bd9f5a1..00000000 --- a/packages/core/platform/templates/repository.yaml +++ /dev/null @@ -1,17 +0,0 @@ -{{- $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 deleted file mode 100644 index 4486155a..00000000 --- a/packages/core/platform/templates/scheduling.yaml +++ /dev/null @@ -1,11 +0,0 @@ -{{- 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 index 9d4eca37..8b010f10 100644 --- a/packages/core/platform/templates/sources.yaml +++ b/packages/core/platform/templates/sources.yaml @@ -1,4 +1,6 @@ +{{/* {{- 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 deleted file mode 100644 index 4fd5ff59..00000000 --- a/packages/core/platform/values-isp-full-generic.yaml +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index c79ff4ba..00000000 --- a/packages/core/platform/values-isp-full.yaml +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index c3af0deb..00000000 --- a/packages/core/platform/values-isp-hosted.yaml +++ /dev/null @@ -1,12 +0,0 @@ -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 index 605e23bc..363d1921 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -1,137 +1,2 @@ -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 +assets: + image: ghcr.io/cozystack/cozystack/cozystack-assets:latest@sha256:19b166819d0205293c85d8351a3e038dc4c146b876a8e2ae21dce1d54f0b9e33 diff --git a/packages/core/talos/Makefile b/packages/core/talos/Makefile index e06793b9..24d9c9f2 100644 --- a/packages/core/talos/Makefile +++ b/packages/core/talos/Makefile @@ -3,7 +3,7 @@ NAMESPACE=cozy-system TALOS_VERSION=$(shell awk '/^version:/ {print $$2}' images/talos/profiles/installer.yaml) -include ../../../hack/common-envs.mk +include ../../../scripts/common-envs.mk update: hack/gen-profiles.sh @@ -30,27 +30,9 @@ image-matchbox: 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: +talos-initramfs talos-kernel talos-installer talos-iso talos-nocloud talos-metal: mkdir -p ../../../_out/assets - cat images/talos/profiles/$(subst build-talos-,,$@).yaml | \ + 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- diff --git a/packages/core/talos/images/talos/profiles/initramfs.yaml b/packages/core/talos/images/talos/profiles/initramfs.yaml index 182fb3e8..9663d86f 100644 --- a/packages/core/talos/images/talos/profiles/initramfs.yaml +++ b/packages/core/talos/images/talos/profiles/initramfs.yaml @@ -3,24 +3,24 @@ arch: amd64 platform: metal secureboot: false -version: v1.12.6 +version: v1.11.3 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.12.6" + imageRef: "ghcr.io/siderolabs/installer:v1.11.3" 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 + - imageRef: ghcr.io/siderolabs/amd-ucode:20250917@sha256:ff11ee9f1565d9f9b095a3dc41fb7962b211169b2ef05d658a488398cb98e2d2 + - imageRef: ghcr.io/siderolabs/amdgpu:20250917-v1.11.3@sha256:527b694ddbc4b40e9529d736bfe9874cc786773aa5a1070bbefe77feb9a8a304 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250917@sha256:ac6aaaa0d3312e72279a5cde7de0d71fb61774aa2f97a4e56dd914a9f1dde4d1 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250917@sha256:c25225c371e81485c64f339864ede410b560f07eb0fc2702a73315e977a6323d + - imageRef: ghcr.io/siderolabs/i915:20250917-v1.11.3@sha256:e8db985ff2ef702d5f3989b0138e1b9dd5ac5e885a3adefa5b42ee6fa32b7027 + - imageRef: ghcr.io/siderolabs/intel-ucode:20250812@sha256:31142ac037235e6779eea9f638e6399080a1f09e7c323ffa30b37488004057a5 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250917@sha256:7094e5db6931a1b68240416b65ddc0f3b546bd9b8520e3cfb1ddebcbfc83e890 + - imageRef: ghcr.io/siderolabs/drbd:9.2.14-v1.11.3@sha256:4393756875751e2664a04e96c1ccff84c99958ca819dd93b46b82ad8f3b4be67 + - imageRef: ghcr.io/siderolabs/zfs:2.3.3-v1.11.3@sha256:3c0b34a760914980ac234e66f130d829e428018e46420b7bca33219b1cc2dd87 output: kind: initramfs imageOptions: {} diff --git a/packages/core/talos/images/talos/profiles/installer.yaml b/packages/core/talos/images/talos/profiles/installer.yaml index c56c1d32..aedff886 100644 --- a/packages/core/talos/images/talos/profiles/installer.yaml +++ b/packages/core/talos/images/talos/profiles/installer.yaml @@ -3,24 +3,24 @@ arch: amd64 platform: metal secureboot: false -version: v1.12.6 +version: v1.11.3 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.12.6" + imageRef: "ghcr.io/siderolabs/installer:v1.11.3" 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 + - imageRef: ghcr.io/siderolabs/amd-ucode:20250917@sha256:ff11ee9f1565d9f9b095a3dc41fb7962b211169b2ef05d658a488398cb98e2d2 + - imageRef: ghcr.io/siderolabs/amdgpu:20250917-v1.11.3@sha256:527b694ddbc4b40e9529d736bfe9874cc786773aa5a1070bbefe77feb9a8a304 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250917@sha256:ac6aaaa0d3312e72279a5cde7de0d71fb61774aa2f97a4e56dd914a9f1dde4d1 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250917@sha256:c25225c371e81485c64f339864ede410b560f07eb0fc2702a73315e977a6323d + - imageRef: ghcr.io/siderolabs/i915:20250917-v1.11.3@sha256:e8db985ff2ef702d5f3989b0138e1b9dd5ac5e885a3adefa5b42ee6fa32b7027 + - imageRef: ghcr.io/siderolabs/intel-ucode:20250812@sha256:31142ac037235e6779eea9f638e6399080a1f09e7c323ffa30b37488004057a5 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250917@sha256:7094e5db6931a1b68240416b65ddc0f3b546bd9b8520e3cfb1ddebcbfc83e890 + - imageRef: ghcr.io/siderolabs/drbd:9.2.14-v1.11.3@sha256:4393756875751e2664a04e96c1ccff84c99958ca819dd93b46b82ad8f3b4be67 + - imageRef: ghcr.io/siderolabs/zfs:2.3.3-v1.11.3@sha256:3c0b34a760914980ac234e66f130d829e428018e46420b7bca33219b1cc2dd87 output: kind: installer imageOptions: {} diff --git a/packages/core/talos/images/talos/profiles/iso.yaml b/packages/core/talos/images/talos/profiles/iso.yaml index 25fc336a..1f46d36a 100644 --- a/packages/core/talos/images/talos/profiles/iso.yaml +++ b/packages/core/talos/images/talos/profiles/iso.yaml @@ -3,24 +3,24 @@ arch: amd64 platform: metal secureboot: false -version: v1.12.6 +version: v1.11.3 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.12.6" + imageRef: "ghcr.io/siderolabs/installer:v1.11.3" 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 + - imageRef: ghcr.io/siderolabs/amd-ucode:20250917@sha256:ff11ee9f1565d9f9b095a3dc41fb7962b211169b2ef05d658a488398cb98e2d2 + - imageRef: ghcr.io/siderolabs/amdgpu:20250917-v1.11.3@sha256:527b694ddbc4b40e9529d736bfe9874cc786773aa5a1070bbefe77feb9a8a304 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250917@sha256:ac6aaaa0d3312e72279a5cde7de0d71fb61774aa2f97a4e56dd914a9f1dde4d1 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250917@sha256:c25225c371e81485c64f339864ede410b560f07eb0fc2702a73315e977a6323d + - imageRef: ghcr.io/siderolabs/i915:20250917-v1.11.3@sha256:e8db985ff2ef702d5f3989b0138e1b9dd5ac5e885a3adefa5b42ee6fa32b7027 + - imageRef: ghcr.io/siderolabs/intel-ucode:20250812@sha256:31142ac037235e6779eea9f638e6399080a1f09e7c323ffa30b37488004057a5 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250917@sha256:7094e5db6931a1b68240416b65ddc0f3b546bd9b8520e3cfb1ddebcbfc83e890 + - imageRef: ghcr.io/siderolabs/drbd:9.2.14-v1.11.3@sha256:4393756875751e2664a04e96c1ccff84c99958ca819dd93b46b82ad8f3b4be67 + - imageRef: ghcr.io/siderolabs/zfs:2.3.3-v1.11.3@sha256:3c0b34a760914980ac234e66f130d829e428018e46420b7bca33219b1cc2dd87 output: kind: iso imageOptions: {} diff --git a/packages/core/talos/images/talos/profiles/kernel.yaml b/packages/core/talos/images/talos/profiles/kernel.yaml index d0153bf8..4e4f3685 100644 --- a/packages/core/talos/images/talos/profiles/kernel.yaml +++ b/packages/core/talos/images/talos/profiles/kernel.yaml @@ -3,24 +3,24 @@ arch: amd64 platform: metal secureboot: false -version: v1.12.6 +version: v1.11.3 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.12.6" + imageRef: "ghcr.io/siderolabs/installer:v1.11.3" 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 + - imageRef: ghcr.io/siderolabs/amd-ucode:20250917@sha256:ff11ee9f1565d9f9b095a3dc41fb7962b211169b2ef05d658a488398cb98e2d2 + - imageRef: ghcr.io/siderolabs/amdgpu:20250917-v1.11.3@sha256:527b694ddbc4b40e9529d736bfe9874cc786773aa5a1070bbefe77feb9a8a304 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250917@sha256:ac6aaaa0d3312e72279a5cde7de0d71fb61774aa2f97a4e56dd914a9f1dde4d1 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250917@sha256:c25225c371e81485c64f339864ede410b560f07eb0fc2702a73315e977a6323d + - imageRef: ghcr.io/siderolabs/i915:20250917-v1.11.3@sha256:e8db985ff2ef702d5f3989b0138e1b9dd5ac5e885a3adefa5b42ee6fa32b7027 + - imageRef: ghcr.io/siderolabs/intel-ucode:20250812@sha256:31142ac037235e6779eea9f638e6399080a1f09e7c323ffa30b37488004057a5 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250917@sha256:7094e5db6931a1b68240416b65ddc0f3b546bd9b8520e3cfb1ddebcbfc83e890 + - imageRef: ghcr.io/siderolabs/drbd:9.2.14-v1.11.3@sha256:4393756875751e2664a04e96c1ccff84c99958ca819dd93b46b82ad8f3b4be67 + - imageRef: ghcr.io/siderolabs/zfs:2.3.3-v1.11.3@sha256:3c0b34a760914980ac234e66f130d829e428018e46420b7bca33219b1cc2dd87 output: kind: kernel imageOptions: {} diff --git a/packages/core/talos/images/talos/profiles/metal.yaml b/packages/core/talos/images/talos/profiles/metal.yaml index 579cc333..54a5a93d 100644 --- a/packages/core/talos/images/talos/profiles/metal.yaml +++ b/packages/core/talos/images/talos/profiles/metal.yaml @@ -3,24 +3,24 @@ arch: amd64 platform: metal secureboot: false -version: v1.12.6 +version: v1.11.3 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.12.6" + imageRef: "ghcr.io/siderolabs/installer:v1.11.3" 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 + - imageRef: ghcr.io/siderolabs/amd-ucode:20250917@sha256:ff11ee9f1565d9f9b095a3dc41fb7962b211169b2ef05d658a488398cb98e2d2 + - imageRef: ghcr.io/siderolabs/amdgpu:20250917-v1.11.3@sha256:527b694ddbc4b40e9529d736bfe9874cc786773aa5a1070bbefe77feb9a8a304 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250917@sha256:ac6aaaa0d3312e72279a5cde7de0d71fb61774aa2f97a4e56dd914a9f1dde4d1 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250917@sha256:c25225c371e81485c64f339864ede410b560f07eb0fc2702a73315e977a6323d + - imageRef: ghcr.io/siderolabs/i915:20250917-v1.11.3@sha256:e8db985ff2ef702d5f3989b0138e1b9dd5ac5e885a3adefa5b42ee6fa32b7027 + - imageRef: ghcr.io/siderolabs/intel-ucode:20250812@sha256:31142ac037235e6779eea9f638e6399080a1f09e7c323ffa30b37488004057a5 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250917@sha256:7094e5db6931a1b68240416b65ddc0f3b546bd9b8520e3cfb1ddebcbfc83e890 + - imageRef: ghcr.io/siderolabs/drbd:9.2.14-v1.11.3@sha256:4393756875751e2664a04e96c1ccff84c99958ca819dd93b46b82ad8f3b4be67 + - imageRef: ghcr.io/siderolabs/zfs:2.3.3-v1.11.3@sha256:3c0b34a760914980ac234e66f130d829e428018e46420b7bca33219b1cc2dd87 output: kind: image imageOptions: { diskSize: 1306525696, diskFormat: raw } diff --git a/packages/core/talos/images/talos/profiles/nocloud.yaml b/packages/core/talos/images/talos/profiles/nocloud.yaml index 24ad7f3c..5e0f8cf1 100644 --- a/packages/core/talos/images/talos/profiles/nocloud.yaml +++ b/packages/core/talos/images/talos/profiles/nocloud.yaml @@ -3,24 +3,24 @@ arch: amd64 platform: nocloud secureboot: false -version: v1.12.6 +version: v1.11.3 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.12.6" + imageRef: "ghcr.io/siderolabs/installer:v1.11.3" 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 + - imageRef: ghcr.io/siderolabs/amd-ucode:20250917@sha256:ff11ee9f1565d9f9b095a3dc41fb7962b211169b2ef05d658a488398cb98e2d2 + - imageRef: ghcr.io/siderolabs/amdgpu:20250917-v1.11.3@sha256:527b694ddbc4b40e9529d736bfe9874cc786773aa5a1070bbefe77feb9a8a304 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250917@sha256:ac6aaaa0d3312e72279a5cde7de0d71fb61774aa2f97a4e56dd914a9f1dde4d1 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250917@sha256:c25225c371e81485c64f339864ede410b560f07eb0fc2702a73315e977a6323d + - imageRef: ghcr.io/siderolabs/i915:20250917-v1.11.3@sha256:e8db985ff2ef702d5f3989b0138e1b9dd5ac5e885a3adefa5b42ee6fa32b7027 + - imageRef: ghcr.io/siderolabs/intel-ucode:20250812@sha256:31142ac037235e6779eea9f638e6399080a1f09e7c323ffa30b37488004057a5 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250917@sha256:7094e5db6931a1b68240416b65ddc0f3b546bd9b8520e3cfb1ddebcbfc83e890 + - imageRef: ghcr.io/siderolabs/drbd:9.2.14-v1.11.3@sha256:4393756875751e2664a04e96c1ccff84c99958ca819dd93b46b82ad8f3b4be67 + - imageRef: ghcr.io/siderolabs/zfs:2.3.3-v1.11.3@sha256:3c0b34a760914980ac234e66f130d829e428018e46420b7bca33219b1cc2dd87 output: kind: image imageOptions: { diskSize: 1306525696, diskFormat: raw } diff --git a/packages/core/testing/Chart.yaml b/packages/core/testing/Chart.yaml old mode 100644 new mode 100755 diff --git a/packages/core/testing/Makefile b/packages/core/testing/Makefile old mode 100644 new mode 100755 index ce21a8e1..f345d155 --- 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 ../../../hack/common-envs.mk +include ../../../scripts/common-envs.mk help: ## Show this help. @@ -25,17 +25,23 @@ image-e2e-sandbox: yq -i '.e2e.image = strenv(IMAGE)' values.yaml rm -f images/e2e-sandbox.json -test: test-openapi test-apps ## Run the end-to-end tests in existing sandbox +test: test-cluster 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: +install-cozystack: copy-installer-manifest 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' diff --git a/packages/core/testing/images/e2e-sandbox/Dockerfile b/packages/core/testing/images/e2e-sandbox/Dockerfile old mode 100644 new mode 100755 index 2f94991f..ce6cabdd --- 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 COZYHR_VERSION=1.6.1 +ARG COZYHR_VERSION=1.5.0 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 bash-completion +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 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 \ @@ -21,13 +21,5 @@ RUN curl -sSL "https://fluxcd.io/install.sh" | bash 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 100644 new mode 100755 index 9d4bdd10..de6bb330 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v1.3.0@sha256:0367a03b981df2a3ea13f411d4cb7869c2bf2c89c07d3d5c8971b9a28921ccef + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.38.2@sha256:84be9e42bc2c04b0765c8b89e0a9728c49ebf4676a92522b007af96ae9aec68d diff --git a/packages/extra/Makefile b/packages/extra/Makefile index dd3293a0..5872855b 100644 --- a/packages/extra/Makefile +++ b/packages/extra/Makefile @@ -1,7 +1,7 @@ OUT=../../_out/repos/extra CHARTS := $(shell find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}') -include ../../hack/common-envs.mk +include ../../scripts/common-envs.mk repo: rm -rf "$(OUT)" diff --git a/packages/extra/bootbox/Makefile b/packages/extra/bootbox/Makefile index 57fa0a77..d9a1e261 100644 --- a/packages/extra/bootbox/Makefile +++ b/packages/extra/bootbox/Makefile @@ -1,7 +1,7 @@ NAME=bootbox NAMESPACE=tenant-root -include ../../../hack/package.mk +include ../../../scripts/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index f51c7675..2e63d30b 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v1.3.0@sha256:85b8e04bf6f0690612dd63e80475df269f4a436d16680f8a40f2860cf16e2f74 +ghcr.io/cozystack/cozystack/matchbox:v0.38.2@sha256:9cd7f46fcae119a3f8e35b428b018d0cb6da7b0cdd2ce764cc9fbf6dcd903f27 diff --git a/packages/extra/bootbox/templates/matchbox/ingress.yaml b/packages/extra/bootbox/templates/matchbox/ingress.yaml index 5eef3489..fa62165b 100644 --- a/packages/extra/bootbox/templates/matchbox/ingress.yaml +++ b/packages/extra/bootbox/templates/matchbox/ingress.yaml @@ -1,5 +1,4 @@ -{{- $solver := (index .Values._cluster "solver") | default "http01" }} -{{- $clusterIssuer := (index .Values._cluster "issuer-name") | default "letsencrypt-prod" }} +{{- $issuerType := (index .Values._cluster "clusterissuer") | default "http01" }} {{- $ingress := .Values._namespace.ingress }} {{- $host := .Values._namespace.host }} apiVersion: networking.k8s.io/v1 @@ -9,10 +8,10 @@ metadata: labels: app: bootbox annotations: - {{- if eq $solver "http01" }} - acme.cert-manager.io/http01-ingress-ingressclassname: {{ $ingress }} + {{- if ne $issuerType "cloudflare" }} + acme.cert-manager.io/http01-ingress-class: {{ $ingress }} {{- end }} - cert-manager.io/cluster-issuer: {{ $clusterIssuer }} + cert-manager.io/cluster-issuer: letsencrypt-prod {{- 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/values.schema.json b/packages/extra/bootbox/values.schema.json index 8e243c12..994f47cd 100644 --- a/packages/extra/bootbox/values.schema.json +++ b/packages/extra/bootbox/values.schema.json @@ -2,19 +2,6 @@ "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", @@ -91,6 +78,19 @@ } } } + }, + "whitelist": { + "description": "List of client networks.", + "type": "array", + "default": [], + "items": { + "type": "string" + } + }, + "whitelistHTTP": { + "description": "Secure HTTP by enabling client networks whitelisting.", + "type": "boolean", + "default": true } } -} +} \ No newline at end of file diff --git a/packages/extra/etcd/Makefile b/packages/extra/etcd/Makefile index 2b3ed61e..b309346c 100644 --- a/packages/extra/etcd/Makefile +++ b/packages/extra/etcd/Makefile @@ -1,10 +1,7 @@ NAME=etcd -include ../../../hack/package.mk +include ../../../scripts/package.mk generate: 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/templates/etcd-cluster.yaml b/packages/extra/etcd/templates/etcd-cluster.yaml index a604b448..a26ae173 100644 --- a/packages/extra/etcd/templates/etcd-cluster.yaml +++ b/packages/extra/etcd/templates/etcd-cluster.yaml @@ -46,15 +46,6 @@ 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 }} @@ -104,7 +95,6 @@ spec: - {{ .Release.Name }} secretName: etcd-peer-ca-tls privateKey: - rotationPolicy: Never algorithm: RSA size: 4096 issuerRef: @@ -131,7 +121,6 @@ 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 0478129f..089df920 100644 --- a/packages/extra/etcd/templates/etcd-defrag.yaml +++ b/packages/extra/etcd/templates/etcd-defrag.yaml @@ -4,14 +4,9 @@ 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: diff --git a/packages/extra/etcd/templates/hook/job.yaml b/packages/extra/etcd/templates/hook/job.yaml new file mode 100644 index 00000000..3bf2f84b --- /dev/null +++ b/packages/extra/etcd/templates/hook/job.yaml @@ -0,0 +1,39 @@ +{{- $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: docker.io/alpine/k8s:1.33.4 + 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 new file mode 100644 index 00000000..327eeadb --- /dev/null +++ b/packages/extra/etcd/templates/hook/role.yaml @@ -0,0 +1,26 @@ +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 new file mode 100644 index 00000000..0ee0ffd1 --- /dev/null +++ b/packages/extra/etcd/templates/hook/rolebinding.yaml @@ -0,0 +1,15 @@ +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 new file mode 100644 index 00000000..552fb5fc --- /dev/null +++ b/packages/extra/etcd/templates/hook/serviceaccount.yaml @@ -0,0 +1,7 @@ +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 new file mode 100644 index 00000000..cc9375bb --- /dev/null +++ b/packages/extra/etcd/templates/version.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: etcd-deployed-version +data: + version: {{ .Chart.Version }} diff --git a/packages/extra/etcd/tests/no-post-upgrade-hook_test.yaml b/packages/extra/etcd/tests/no-post-upgrade-hook_test.yaml deleted file mode 100644 index 0e4f5aa3..00000000 --- a/packages/extra/etcd/tests/no-post-upgrade-hook_test.yaml +++ /dev/null @@ -1,34 +0,0 @@ -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 3c66664c..0f696c57 100644 --- a/packages/extra/etcd/values.schema.json +++ b/packages/extra/etcd/values.schema.json @@ -2,25 +2,6 @@ "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", @@ -60,6 +41,25 @@ "x-kubernetes-int-or-string": true } } + }, + "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": "" } } -} +} \ No newline at end of file diff --git a/packages/extra/external-dns/Chart.yaml b/packages/extra/external-dns/Chart.yaml deleted file mode 100644 index d9788a41..00000000 --- a/packages/extra/external-dns/Chart.yaml +++ /dev/null @@ -1,6 +0,0 @@ -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 deleted file mode 100644 index 8b8fbc2f..00000000 --- a/packages/extra/external-dns/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 027182c1..00000000 --- a/packages/extra/external-dns/README.md +++ /dev/null @@ -1,88 +0,0 @@ -# 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 deleted file mode 120000 index e1813509..00000000 --- a/packages/extra/external-dns/charts/cozy-lib +++ /dev/null @@ -1 +0,0 @@ -../../../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 deleted file mode 100644 index b2f956f3..00000000 --- a/packages/extra/external-dns/config.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "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 deleted file mode 100644 index b22ad8c4..00000000 --- a/packages/extra/external-dns/logos/external-dns.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/packages/extra/external-dns/templates/dashboard-resourcemap.yaml b/packages/extra/external-dns/templates/dashboard-resourcemap.yaml deleted file mode 100644 index edd96b74..00000000 --- a/packages/extra/external-dns/templates/dashboard-resourcemap.yaml +++ /dev/null @@ -1,23 +0,0 @@ -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 deleted file mode 100644 index cdfb8901..00000000 --- a/packages/extra/external-dns/templates/external-dns.yaml +++ /dev/null @@ -1,169 +0,0 @@ -{{- 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 deleted file mode 100644 index 08de0f8e..00000000 --- a/packages/extra/external-dns/values.schema.json +++ /dev/null @@ -1,193 +0,0 @@ -{ - "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 deleted file mode 100644 index c40d2dff..00000000 --- a/packages/extra/external-dns/values.yaml +++ /dev/null @@ -1,149 +0,0 @@ -## -## @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/Makefile b/packages/extra/info/Makefile index 02e04d53..e09b33a0 100644 --- a/packages/extra/info/Makefile +++ b/packages/extra/info/Makefile @@ -1,6 +1,6 @@ NAME=etcd -include ../../../hack/package.mk +include ../../../scripts/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/extra/info/templates/kubeconfig.yaml b/packages/extra/info/templates/kubeconfig.yaml index d2331654..8a5c150d 100644 --- a/packages/extra/info/templates/kubeconfig.yaml +++ b/packages/extra/info/templates/kubeconfig.yaml @@ -1,18 +1,15 @@ {{- $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 }} +{{- $k8sClientSecret := lookup "v1" "Secret" "cozy-keycloak" "k8s-client" }} + +{{- if $k8sClientSecret }} +{{- $apiServerEndpoint := index .Values._cluster "api-server-endpoint" }} +{{- $managementKubeconfigEndpoint := default "" (index .Values._cluster "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 }} --- apiVersion: v1 kind: Secret @@ -43,6 +40,7 @@ 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/ingress/Makefile b/packages/extra/ingress/Makefile index 65b53c03..8134cb22 100644 --- a/packages/extra/ingress/Makefile +++ b/packages/extra/ingress/Makefile @@ -1,6 +1,6 @@ NAME=ingress -include ../../../hack/package.mk +include ../../../scripts/package.mk update: get-cloudflare-ips @@ -10,6 +10,3 @@ get-cloudflare-ips: generate: 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 c541d8e9..0e786dfb 100644 --- a/packages/extra/ingress/README.md +++ b/packages/extra/ingress/README.md @@ -14,17 +14,3 @@ | `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 8e1f00fb..13ad9a6b 100644 --- a/packages/extra/ingress/templates/nginx-ingress.yaml +++ b/packages/extra/ingress/templates/nginx-ingress.yaml @@ -1,30 +1,19 @@ {{- $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: - chartRef: - kind: ExternalArtifact - name: cozystack-ingress-application-default-ingress-system - namespace: cozy-system + chart: + spec: + chart: cozy-ingress-nginx + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' interval: 5m timeout: 10m install: @@ -37,6 +26,12 @@ spec: valuesFrom: - kind: Secret name: cozystack-values + valuesKey: _cluster + targetPath: _cluster + - kind: Secret + name: cozystack-values + valuesKey: _namespace + targetPath: _namespace values: ingress-nginx: fullnameOverride: {{ trimPrefix "tenant-" .Release.Namespace }}-ingress @@ -55,12 +50,9 @@ spec: enabled: false {{- end }} service: - {{- if and (eq $exposeIngress .Release.Namespace) (eq $exposeMode "loadBalancer") }} - type: LoadBalancer - externalTrafficPolicy: Local - {{- else if and (eq $exposeIngress .Release.Namespace) $exposeIPsList }} + {{- if and (eq $exposeIngress .Release.Namespace) $exposeExternalIPs }} externalIPs: - {{- toYaml $exposeIPsList | nindent 12 }} + {{- toYaml (splitList "," $exposeExternalIPs) | nindent 12 }} type: ClusterIP externalTrafficPolicy: Cluster {{- else }} diff --git a/packages/extra/ingress/tests/exposure_test.yaml b/packages/extra/ingress/tests/exposure_test.yaml deleted file mode 100644 index 1c76b3da..00000000 --- a/packages/extra/ingress/tests/exposure_test.yaml +++ /dev/null @@ -1,165 +0,0 @@ -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 7a53a197..650a5824 100644 --- a/packages/extra/ingress/values.schema.json +++ b/packages/extra/ingress/values.schema.json @@ -2,24 +2,16 @@ "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 }, + "replicas": { + "description": "Number of ingress-nginx replicas.", + "type": "integer", + "default": 2 + }, "resources": { "description": "Explicit CPU and memory configuration for each ingress-nginx replica. When omitted, the preset defined in `resourcesPreset` is applied.", "type": "object", @@ -66,6 +58,14 @@ "xlarge", "2xlarge" ] + }, + "whitelist": { + "description": "List of client networks.", + "type": "array", + "default": [], + "items": { + "type": "string" + } } } -} +} \ No newline at end of file diff --git a/packages/apps/qdrant/.helmignore b/packages/extra/monitoring/.helmignore similarity index 82% rename from packages/apps/qdrant/.helmignore rename to packages/extra/monitoring/.helmignore index 3de7d4a5..1ea0ae84 100644 --- a/packages/apps/qdrant/.helmignore +++ b/packages/extra/monitoring/.helmignore @@ -1,4 +1,3 @@ .helmignore /logos /Makefile -/hack diff --git a/packages/extra/monitoring/Makefile b/packages/extra/monitoring/Makefile index 1ae213b6..b21607ab 100644 --- a/packages/extra/monitoring/Makefile +++ b/packages/extra/monitoring/Makefile @@ -2,8 +2,8 @@ GRAFANA_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml) NAME=monitoring -include ../../../hack/common-envs.mk -include ../../../hack/package.mk +include ../../../scripts/common-envs.mk +include ../../../scripts/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/system/monitoring/dashboards-infra.list b/packages/extra/monitoring/dashboards.list similarity index 74% rename from packages/system/monitoring/dashboards-infra.list rename to packages/extra/monitoring/dashboards.list index 4c7e494d..21ecb974 100644 --- a/packages/system/monitoring/dashboards-infra.list +++ b/packages/extra/monitoring/dashboards.list @@ -1,3 +1,23 @@ +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 @@ -11,29 +31,11 @@ control-plane/control-plane-status control-plane/deprecated-resources control-plane/dns-coredns control-plane/kube-etcd -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 +kubevirt/kubevirt-control-plane flux/flux-control-plane flux/flux-stats -kubevirt/kubevirt-control-plane +kafka/strimzi-kafka goldpinger/goldpinger -cache/nginx-vts-stats +clickhouse/altinity-clickhouse-operator-dashboard 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/extra/monitoring/images/grafana.tag b/packages/extra/monitoring/images/grafana.tag new file mode 100644 index 00000000..9d53b4f1 --- /dev/null +++ b/packages/extra/monitoring/images/grafana.tag @@ -0,0 +1 @@ +ghcr.io/cozystack/cozystack/grafana:0.0.0@sha256:c63978e1ed0304e8518b31ddee56c4e8115541b997d8efbe1c0a74da57140399 diff --git a/packages/system/monitoring/images/grafana/Dockerfile b/packages/extra/monitoring/images/grafana/Dockerfile similarity index 84% rename from packages/system/monitoring/images/grafana/Dockerfile rename to packages/extra/monitoring/images/grafana/Dockerfile index cc65c9d3..f8597a5c 100644 --- a/packages/system/monitoring/images/grafana/Dockerfile +++ b/packages/extra/monitoring/images/grafana/Dockerfile @@ -13,4 +13,3 @@ 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/system/monitoring/patches/1.diff b/packages/extra/monitoring/patches/1.diff similarity index 100% rename from packages/system/monitoring/patches/1.diff rename to packages/extra/monitoring/patches/1.diff diff --git a/packages/system/monitoring/templates/alerta/alerta-db.yaml b/packages/extra/monitoring/templates/alerta/alerta-db.yaml similarity index 65% rename from packages/system/monitoring/templates/alerta/alerta-db.yaml rename to packages/extra/monitoring/templates/alerta/alerta-db.yaml index af9dc72c..845cd8ba 100644 --- a/packages/system/monitoring/templates/alerta/alerta-db.yaml +++ b/packages/extra/monitoring/templates/alerta/alerta-db.yaml @@ -5,9 +5,6 @@ metadata: name: alerta-db spec: instances: 2 - {{- $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 }} @@ -36,3 +33,17 @@ 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/system/monitoring/templates/alerta/alerta.yaml b/packages/extra/monitoring/templates/alerta/alerta.yaml similarity index 89% rename from packages/system/monitoring/templates/alerta/alerta.yaml rename to packages/extra/monitoring/templates/alerta/alerta.yaml index d30e698d..76b7a02b 100644 --- a/packages/system/monitoring/templates/alerta/alerta.yaml +++ b/packages/extra/monitoring/templates/alerta/alerta.yaml @@ -1,5 +1,4 @@ -{{- $solver := (index .Values._cluster "solver") | default "http01" }} -{{- $clusterIssuer := (index .Values._cluster "issuer-name") | default "letsencrypt-prod" }} +{{- $issuerType := (index .Values._cluster "clusterissuer") | default "http01" }} {{- $ingress := .Values._namespace.ingress }} {{- $host := .Values._namespace.host }} @@ -140,14 +139,6 @@ spec: - 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: @@ -180,10 +171,10 @@ metadata: labels: app: alerta annotations: - {{- if eq $solver "http01" }} - acme.cert-manager.io/http01-ingress-ingressclassname: {{ $ingress }} + {{- if ne $issuerType "cloudflare" }} + acme.cert-manager.io/http01-ingress-class: {{ $ingress }} {{- end }} - cert-manager.io/cluster-issuer: {{ $clusterIssuer }} + cert-manager.io/cluster-issuer: letsencrypt-prod spec: ingressClassName: {{ $ingress }} tls: @@ -202,6 +193,20 @@ 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: @@ -254,3 +259,17 @@ spec: 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/extra/monitoring/templates/dashboard-resourcemap.yaml b/packages/extra/monitoring/templates/dashboard-resourcemap.yaml index 5a5a3def..894a11d4 100644 --- a/packages/extra/monitoring/templates/dashboard-resourcemap.yaml +++ b/packages/extra/monitoring/templates/dashboard-resourcemap.yaml @@ -42,9 +42,7 @@ rules: - {{ .name }}-vminsert {{- end }} {{- range .Values.logsStorages }} - - {{ .name }}-vlstorage - - {{ .name }}-vlselect - - {{ .name }}-vlinsert + - {{ $.Release.Name }}-vlogs-{{ .name }} {{- end }} {{- range .Values.metricsStorages }} - vmalert-{{ .name }} diff --git a/packages/extra/monitoring/templates/dashboards.yaml b/packages/extra/monitoring/templates/dashboards.yaml new file mode 100644 index 00000000..522df88b --- /dev/null +++ b/packages/extra/monitoring/templates/dashboards.yaml @@ -0,0 +1,16 @@ +{{- 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-assets.cozy-system.svc/dashboards/{{ . }}.json +{{- end }} +{{- end }} diff --git a/packages/system/monitoring/templates/grafana/db.yaml b/packages/extra/monitoring/templates/grafana/db.yaml similarity index 61% rename from packages/system/monitoring/templates/grafana/db.yaml rename to packages/extra/monitoring/templates/grafana/db.yaml index afc2d0d7..662f5cf4 100644 --- a/packages/system/monitoring/templates/grafana/db.yaml +++ b/packages/extra/monitoring/templates/grafana/db.yaml @@ -4,9 +4,6 @@ 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 }} @@ -30,3 +27,17 @@ spec: 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/system/monitoring/templates/grafana/grafana.yaml b/packages/extra/monitoring/templates/grafana/grafana.yaml similarity index 86% rename from packages/system/monitoring/templates/grafana/grafana.yaml rename to packages/extra/monitoring/templates/grafana/grafana.yaml index d65a7dc4..1eadda9e 100644 --- a/packages/system/monitoring/templates/grafana/grafana.yaml +++ b/packages/extra/monitoring/templates/grafana/grafana.yaml @@ -1,5 +1,4 @@ -{{- $solver := (index .Values._cluster "solver") | default "http01" }} -{{- $clusterIssuer := (index .Values._cluster "issuer-name") | default "letsencrypt-prod" }} +{{- $issuerType := (index .Values._cluster "clusterissuer") | default "http01" }} {{- $ingress := .Values._namespace.ingress }} {{- $host := .Values._namespace.host }} --- @@ -73,10 +72,10 @@ spec: ingress: metadata: annotations: - {{- if eq $solver "http01" }} - acme.cert-manager.io/http01-ingress-ingressclassname: "{{ $ingress }}" + {{- if ne $issuerType "cloudflare" }} + acme.cert-manager.io/http01-ingress-class: "{{ $ingress }}" {{- end }} - cert-manager.io/cluster-issuer: {{ $clusterIssuer }} + cert-manager.io/cluster-issuer: letsencrypt-prod spec: ingressClassName: "{{ $ingress }}" rules: @@ -94,3 +93,16 @@ 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/system/monitoring/templates/grafana/secret.yaml b/packages/extra/monitoring/templates/grafana/secret.yaml similarity index 100% rename from packages/system/monitoring/templates/grafana/secret.yaml rename to packages/extra/monitoring/templates/grafana/secret.yaml diff --git a/packages/extra/monitoring/templates/helmrelease.yaml b/packages/extra/monitoring/templates/helmrelease.yaml deleted file mode 100644 index 0c3c2377..00000000 --- a/packages/extra/monitoring/templates/helmrelease.yaml +++ /dev/null @@ -1,24 +0,0 @@ -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/system/monitoring/templates/vlogs/grafana-datasource.yaml b/packages/extra/monitoring/templates/vlogs/grafana-datasource.yaml similarity index 81% rename from packages/system/monitoring/templates/vlogs/grafana-datasource.yaml rename to packages/extra/monitoring/templates/vlogs/grafana-datasource.yaml index 72755c6f..0fa41288 100644 --- a/packages/system/monitoring/templates/vlogs/grafana-datasource.yaml +++ b/packages/extra/monitoring/templates/vlogs/grafana-datasource.yaml @@ -8,7 +8,7 @@ spec: access: proxy type: victoriametrics-logs-datasource name: vlogs-{{ .name }} - url: http://vlselect-{{ .name }}.{{ $.Release.Namespace }}.svc:9471 + url: http://vlogs-{{ .name }}.{{ $.Release.Namespace }}.svc:9428 instanceSelector: matchLabels: dashboards: grafana diff --git a/packages/extra/monitoring/templates/vlogs/vlogs.yaml b/packages/extra/monitoring/templates/vlogs/vlogs.yaml new file mode 100644 index 00000000..a82bca00 --- /dev/null +++ b/packages/extra/monitoring/templates/vlogs/vlogs.yaml @@ -0,0 +1,37 @@ +{{- range .Values.logsStorages }} +apiVersion: operator.victoriametrics.com/v1beta1 +kind: VLogs +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 }} + 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/system/monitoring/templates/vm/grafana-datasource.yaml b/packages/extra/monitoring/templates/vm/grafana-datasource.yaml similarity index 100% rename from packages/system/monitoring/templates/vm/grafana-datasource.yaml rename to packages/extra/monitoring/templates/vm/grafana-datasource.yaml diff --git a/packages/system/monitoring/templates/vm/vmagent.yaml b/packages/extra/monitoring/templates/vm/vmagent.yaml similarity index 69% rename from packages/system/monitoring/templates/vm/vmagent.yaml rename to packages/extra/monitoring/templates/vm/vmagent.yaml index 98bff1e1..2c6c391a 100644 --- a/packages/system/monitoring/templates/vm/vmagent.yaml +++ b/packages/extra/monitoring/templates/vm/vmagent.yaml @@ -1,4 +1,4 @@ -{{- if and (ne .Release.Namespace "tenant-root") (ne .Release.Namespace "cozy-monitoring") }} +{{- if ne .Release.Namespace "tenant-root" }} apiVersion: operator.victoriametrics.com/v1beta1 kind: VMAgent metadata: @@ -11,9 +11,6 @@ spec: 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" @@ -24,10 +21,6 @@ spec: scrapeInterval: 30s selectAllByDefault: false - {{- with .Values.vmagent.inlineScrapeConfig }} - inlineScrapeConfig: | - {{- . | nindent 4 }} - {{- end }} podScrapeNamespaceSelector: matchLabels: namespace.cozystack.io/monitoring: {{ .Release.Namespace }} diff --git a/packages/system/monitoring/templates/vm/vmalert-scrape.yaml b/packages/extra/monitoring/templates/vm/vmalert-scrape.yaml similarity index 100% rename from packages/system/monitoring/templates/vm/vmalert-scrape.yaml rename to packages/extra/monitoring/templates/vm/vmalert-scrape.yaml diff --git a/packages/system/monitoring/templates/vm/vmalert.yaml b/packages/extra/monitoring/templates/vm/vmalert.yaml similarity index 75% rename from packages/system/monitoring/templates/vm/vmalert.yaml rename to packages/extra/monitoring/templates/vm/vmalert.yaml index 8da03e15..d66fc42c 100644 --- a/packages/system/monitoring/templates/vm/vmalert.yaml +++ b/packages/extra/monitoring/templates/vm/vmalert.yaml @@ -23,5 +23,19 @@ 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/system/monitoring/templates/vm/vmcluster-scrape.yaml b/packages/extra/monitoring/templates/vm/vmcluster-scrape.yaml similarity index 100% rename from packages/system/monitoring/templates/vm/vmcluster-scrape.yaml rename to packages/extra/monitoring/templates/vm/vmcluster-scrape.yaml diff --git a/packages/system/monitoring/templates/vm/vmcluster.yaml b/packages/extra/monitoring/templates/vm/vmcluster.yaml similarity index 58% rename from packages/system/monitoring/templates/vm/vmcluster.yaml rename to packages/extra/monitoring/templates/vm/vmcluster.yaml index 1bc39923..5f86afa3 100644 --- a/packages/system/monitoring/templates/vm/vmcluster.yaml +++ b/packages/extra/monitoring/templates/vm/vmcluster.yaml @@ -49,4 +49,49 @@ 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/system/monitoring/templates/vpa.yaml b/packages/extra/monitoring/templates/vpa.yaml similarity index 50% rename from packages/system/monitoring/templates/vpa.yaml rename to packages/extra/monitoring/templates/vpa.yaml index 551f8310..8b90c0ba 100644 --- a/packages/system/monitoring/templates/vpa.yaml +++ b/packages/extra/monitoring/templates/vpa.yaml @@ -87,92 +87,3 @@ 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/extra/monitoring/templates/workloadmonitors.yaml b/packages/extra/monitoring/templates/workloadmonitors.yaml deleted file mode 100644 index 5d803351..00000000 --- a/packages/extra/monitoring/templates/workloadmonitors.yaml +++ /dev/null @@ -1,180 +0,0 @@ -{{- 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 4bc6906e..0a6f0e64 100644 --- a/packages/extra/monitoring/values.schema.json +++ b/packages/extra/monitoring/values.schema.json @@ -2,11 +2,302 @@ "title": "Chart Values", "type": "object", "properties": { + "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 + } + } + } + } + } + } + }, "host": { "description": "The hostname used to access Grafana externally (defaults to 'grafana' subdomain for the tenant host).", "type": "string", "default": "" }, + "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" + } + } + } + }, "metricsStorages": { "description": "Configuration of metrics storage instances.", "type": "array", @@ -281,297 +572,6 @@ } } }, - "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", @@ -579,14 +579,12 @@ "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", @@ -597,4 +595,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/extra/monitoring/values.yaml b/packages/extra/monitoring/values.yaml index c521f389..ab32b1b2 100644 --- a/packages/extra/monitoring/values.yaml +++ b/packages/extra/monitoring/values.yaml @@ -178,7 +178,3 @@ vmagent: 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/Makefile b/packages/extra/seaweedfs/Makefile index eaa1b906..be84180b 100644 --- a/packages/extra/seaweedfs/Makefile +++ b/packages/extra/seaweedfs/Makefile @@ -1,6 +1,6 @@ NAME=seaweedfs -include ../../../hack/package.mk +include ../../../scripts/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/extra/seaweedfs/README.md b/packages/extra/seaweedfs/README.md index 62bb9bf2..a6ad408f 100644 --- a/packages/extra/seaweedfs/README.md +++ b/packages/extra/seaweedfs/README.md @@ -1,4 +1,4 @@ -# Managed SeaweedFS Service +# Managed NATS Service ## Parameters @@ -13,68 +13,46 @@ ### 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` | +| 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.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` | `""` | +| `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 index 9b413da5..ec59113f 100644 --- a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag +++ b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/objectstorage-sidecar:v1.3.0@sha256:5bcccbdb13979a16cee535eb5fbcdf0d87973689010a10b7b25e55c5be3edaa6 +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.38.2@sha256:ff3281fe53a97d2cd5cd94bd4c4d8ff08189508729869bb39b3f60c80da5f919 diff --git a/packages/extra/seaweedfs/images/seaweedfs-cosi-driver.tag b/packages/extra/seaweedfs/images/seaweedfs-cosi-driver.tag index 52494779..f07c125d 100644 --- a/packages/extra/seaweedfs/images/seaweedfs-cosi-driver.tag +++ b/packages/extra/seaweedfs/images/seaweedfs-cosi-driver.tag @@ -1 +1 @@ -ghcr.io/seaweedfs/seaweedfs-cosi-driver:v0.3.0 +ghcr.io/seaweedfs/seaweedfs-cosi-driver:v0.2.0 diff --git a/packages/extra/seaweedfs/templates/client/cosi-bucket-class.yaml b/packages/extra/seaweedfs/templates/client/cosi-bucket-class.yaml index ce049b31..76eda0dc 100644 --- a/packages/extra/seaweedfs/templates/client/cosi-bucket-class.yaml +++ b/packages/extra/seaweedfs/templates/client/cosi-bucket-class.yaml @@ -7,32 +7,10 @@ metadata: 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/dashboard-resourcemap.yaml b/packages/extra/seaweedfs/templates/dashboard-resourcemap.yaml index dfd408da..ec8860b7 100644 --- a/packages/extra/seaweedfs/templates/dashboard-resourcemap.yaml +++ b/packages/extra/seaweedfs/templates/dashboard-resourcemap.yaml @@ -25,21 +25,8 @@ rules: resourceNames: - {{ $.Release.Name }}-master - {{ $.Release.Name }}-filer - - {{ $.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 }} + - {{ $.Release.Name }}-db verbs: ["get", "list", "watch"] {{- end }} diff --git a/packages/extra/seaweedfs/templates/seaweedfs.yaml b/packages/extra/seaweedfs/templates/seaweedfs.yaml index 2f5720ca..4ef17dec 100644 --- a/packages/extra/seaweedfs/templates/seaweedfs.yaml +++ b/packages/extra/seaweedfs/templates/seaweedfs.yaml @@ -16,65 +16,6 @@ {{- 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) }} @@ -95,19 +36,20 @@ {{- 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: - chartRef: - kind: ExternalArtifact - name: cozystack-seaweedfs-application-default-seaweedfs-system - namespace: cozy-system + chart: + spec: + chart: cozy-seaweedfs + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-system + namespace: cozy-system + version: '>= 0.0.0-0' interval: 5m timeout: 10m install: @@ -120,6 +62,12 @@ spec: valuesFrom: - kind: Secret name: cozystack-values + valuesKey: _cluster + targetPath: _cluster + - kind: Secret + name: cozystack-values + valuesKey: _namespace + targetPath: _namespace values: global: serviceAccountName: "{{ .Release.Namespace }}-seaweedfs" @@ -153,77 +101,30 @@ spec: 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") }} + {{ if 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 }}" + {{ with $zone.replicas }} + replicas: {{ . }} {{- 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: "{{ . }}" + {{- if $zone.size }} + size: "{{ $zone.size }}" + {{- else }} + size: "{{ $.Values.volume.size }}" + {{- end }} + {{- if $zone.storageClass }} + storageClass: {{ $zone.storageClass }} + {{- else if $.Values.volume.storageClass }} + storageClass: {{ $.Values.volume.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: @@ -242,10 +143,8 @@ spec: annotations: nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" - {{- if eq $solver "http01" }} - acme.cert-manager.io/http01-ingress-ingressclassname: {{ $ingress }} - {{- end }} - cert-manager.io/cluster-issuer: {{ $clusterIssuer }} + acme.cert-manager.io/http01-ingress-class: {{ $ingress }} + cert-manager.io/cluster-issuer: letsencrypt-prod tls: - hosts: - {{ .Values.host | default (printf "s3.%s" $host) }} @@ -305,22 +204,6 @@ spec: 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 }} --- @@ -329,7 +212,7 @@ kind: WorkloadMonitor metadata: name: {{ $.Release.Name }}-volume-{{ $zoneName }} spec: - replicas: {{ ternary $zoneSpec.replicas $.Values.volume.replicas (hasKey $zoneSpec "replicas") }} + replicas: {{ default $.Values.volume.replicas $zoneSpec.replicas }} minReplicas: 1 kind: seaweedfs type: volume @@ -337,22 +220,6 @@ spec: 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 }} --- diff --git a/packages/extra/seaweedfs/templates/storage-pool-bucket-classes.yaml b/packages/extra/seaweedfs/templates/storage-pool-bucket-classes.yaml deleted file mode 100644 index bf58340a..00000000 --- a/packages/extra/seaweedfs/templates/storage-pool-bucket-classes.yaml +++ /dev/null @@ -1,55 +0,0 @@ -{{- 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/values.schema.json b/packages/extra/seaweedfs/values.schema.json index 9b48043d..4003df9e 100644 --- a/packages/extra/seaweedfs/values.schema.json +++ b/packages/extra/seaweedfs/values.schema.json @@ -2,26 +2,6 @@ "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", @@ -100,65 +80,6 @@ } } }, - "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", @@ -236,99 +157,149 @@ } } }, + "host": { + "description": "The hostname used to access SeaweedFS externally (defaults to 's3' subdomain for the tenant host).", + "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" + ] + } + } + }, + "replicationFactor": { + "description": "Replication factor: number of replicas for each volume in the SeaweedFS cluster.", + "type": "integer", + "default": 2 + }, + "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" + ] + } + } + }, + "topology": { + "description": "The topology of the SeaweedFS cluster.", + "type": "string", + "default": "Simple", + "enum": [ + "Simple", + "MultiZone", + "Client" + ] + }, "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", @@ -407,96 +378,6 @@ "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" @@ -513,74 +394,11 @@ } ], "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 9965d5d0..e2fc02fd 100644 --- a/packages/extra/seaweedfs/values.yaml +++ b/packages/extra/seaweedfs/values.yaml @@ -76,49 +76,26 @@ filer: 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. diff --git a/packages/library/Makefile b/packages/library/Makefile index 620dcf10..da811e7e 100644 --- a/packages/library/Makefile +++ b/packages/library/Makefile @@ -1,7 +1,7 @@ OUT=../../_out/repos/library CHARTS := $(shell find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}') -include ../../hack/common-envs.mk +include ../../scripts/common-envs.mk repo: rm -rf "$(OUT)" diff --git a/packages/library/cozy-lib/Makefile b/packages/library/cozy-lib/Makefile index 925f90c1..362bf32c 100644 --- a/packages/library/cozy-lib/Makefile +++ b/packages/library/cozy-lib/Makefile @@ -1,5 +1,5 @@ -include ../../../hack/common-envs.mk -include ../../../hack/package.mk +include ../../../scripts/common-envs.mk +include ../../../scripts/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md diff --git a/packages/library/cozy-lib/templates/_strings.tpl b/packages/library/cozy-lib/templates/_strings.tpl deleted file mode 100644 index 0ba8153f..00000000 --- a/packages/library/cozy-lib/templates/_strings.tpl +++ /dev/null @@ -1,3 +0,0 @@ -{{- 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 9173d353..e068be8a 100644 --- a/packages/system/Makefile +++ b/packages/system/Makefile @@ -2,7 +2,7 @@ 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 ../../hack/common-envs.mk +include ../../scripts/common-envs.mk repo: rm -rf "$(OUT)" diff --git a/packages/system/application-definition-crd/Chart.yaml b/packages/system/application-definition-crd/Chart.yaml deleted file mode 100644 index f272bf43..00000000 --- a/packages/system/application-definition-crd/Chart.yaml +++ /dev/null @@ -1,3 +0,0 @@ -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 deleted file mode 100644 index adb378af..00000000 --- a/packages/system/application-definition-crd/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -export NAME=application-definition-crd -export NAMESPACE=cozy-system - -include ../../../hack/package.mk diff --git a/packages/system/application-definition-crd/templates/crd.yaml b/packages/system/application-definition-crd/templates/crd.yaml deleted file mode 100644 index 3c94f229..00000000 --- a/packages/system/application-definition-crd/templates/crd.yaml +++ /dev/null @@ -1,2 +0,0 @@ ---- -{{ .Files.Get "definition/cozystack.io_applicationdefinitions.yaml" }} diff --git a/packages/system/backup-controller/Makefile b/packages/system/backup-controller/Makefile index 472a99ba..56d58f20 100644 --- a/packages/system/backup-controller/Makefile +++ b/packages/system/backup-controller/Makefile @@ -1,8 +1,8 @@ NAME=backup-controller NAMESPACE=cozy-backup-controller -include ../../../hack/common-envs.mk -include ../../../hack/package.mk +include ../../../scripts/common-envs.mk +include ../../../scripts/package.mk image: image-backup-controller diff --git a/packages/system/backup-controller/definitions/backups.cozystack.io_backupclasses.yaml b/packages/system/backup-controller/definitions/backups.cozystack.io_backupclasses.yaml deleted file mode 100644 index 4af8cf7d..00000000 --- a/packages/system/backup-controller/definitions/backups.cozystack.io_backupclasses.yaml +++ /dev/null @@ -1,171 +0,0 @@ ---- -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 index 7a0ed6f5..367ca8e6 100644 --- a/packages/system/backup-controller/definitions/backups.cozystack.io_backupjobs.yaml +++ b/packages/system/backup-controller/definitions/backups.cozystack.io_backupjobs.yaml @@ -14,11 +14,7 @@ spec: singular: backupjob scope: Namespaced versions: - - additionalPrinterColumns: - - jsonPath: .status.phase - name: Phase - type: string - name: v1alpha1 + - name: v1alpha1 schema: openAPIV3Schema: description: |- @@ -50,7 +46,6 @@ spec: 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: |- @@ -69,17 +64,6 @@ spec: - 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. @@ -96,9 +80,54 @@ spec: type: string type: object x-kubernetes-map-type: atomic + storageRef: + description: |- + StorageRef holds a reference to the Storage object that describes where + the backup will be stored. + 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 + strategyRef: + description: |- + StrategyRef holds a reference to the driver-specific BackupStrategy object + that describes how the backup should be created. + 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: - applicationRef - - backupClassName + - storageRef + - strategyRef type: object status: description: BackupJobStatus represents the observed state of a BackupJob. @@ -204,5 +233,3 @@ spec: - 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 index d48df533..13d9bc62 100644 --- a/packages/system/backup-controller/definitions/backups.cozystack.io_backups.yaml +++ b/packages/system/backup-controller/definitions/backups.cozystack.io_backups.yaml @@ -85,6 +85,28 @@ spec: type: string type: object x-kubernetes-map-type: atomic + storageRef: + description: |- + StorageRef refers to the Storage object that describes where the backup + artifact is stored. + 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 strategyRef: description: |- StrategyRef refers to the driver-specific BackupStrategy that was used @@ -115,6 +137,7 @@ spec: type: string required: - applicationRef + - storageRef - strategyRef - takenAt type: object @@ -205,14 +228,6 @@ spec: 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: diff --git a/packages/system/backup-controller/definitions/backups.cozystack.io_plans.yaml b/packages/system/backup-controller/definitions/backups.cozystack.io_plans.yaml index 94c09334..1c6829cc 100644 --- a/packages/system/backup-controller/definitions/backups.cozystack.io_plans.yaml +++ b/packages/system/backup-controller/definitions/backups.cozystack.io_plans.yaml @@ -47,7 +47,6 @@ spec: 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: |- @@ -66,12 +65,6 @@ spec: - 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: @@ -87,10 +80,55 @@ spec: [`cron`]. If omitted, defaults to `cron`. type: string type: object + storageRef: + description: |- + StorageRef holds a reference to the Storage object that + describes the location where the backup will be stored. + 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 + strategyRef: + description: |- + StrategyRef holds a reference to the Strategy object that + describes, how a backup copy is to be created. + 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: - applicationRef - - backupClassName - schedule + - storageRef + - strategyRef type: object status: properties: diff --git a/packages/system/backup-controller/definitions/backups.cozystack.io_restorejobs.yaml b/packages/system/backup-controller/definitions/backups.cozystack.io_restorejobs.yaml index b9465994..607a69b2 100644 --- a/packages/system/backup-controller/definitions/backups.cozystack.io_restorejobs.yaml +++ b/packages/system/backup-controller/definitions/backups.cozystack.io_restorejobs.yaml @@ -14,11 +14,7 @@ spec: singular: restorejob scope: Namespaced versions: - - additionalPrinterColumns: - - jsonPath: .status.phase - name: Phase - type: string - name: v1alpha1 + - name: v1alpha1 schema: openAPIV3Schema: description: RestoreJob represents a single execution of a restore from a @@ -59,12 +55,6 @@ spec: 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 @@ -176,5 +166,3 @@ spec: type: object served: true storage: true - subresources: - status: {} diff --git a/packages/system/backup-controller/templates/rbac.yaml b/packages/system/backup-controller/templates/rbac.yaml index da2460c0..71c4af69 100644 --- a/packages/system/backup-controller/templates/rbac.yaml +++ b/packages/system/backup-controller/templates/rbac.yaml @@ -3,21 +3,9 @@ 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/tenant-clusterroles.yaml b/packages/system/backup-controller/templates/tenant-clusterroles.yaml deleted file mode 100644 index 1e9eb775..00000000 --- a/packages/system/backup-controller/templates/tenant-clusterroles.yaml +++ /dev/null @@ -1,44 +0,0 @@ ---- -# == 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 index 34e033ce..557c201a 100644 --- a/packages/system/backup-controller/values.yaml +++ b/packages/system/backup-controller/values.yaml @@ -1,5 +1,5 @@ backupController: - image: "ghcr.io/cozystack/cozystack/backup-controller:v1.3.0@sha256:e1a083dc92f26dfef004f47c1cd20a6357174aad835004f58e751c494b76649a" + image: "" replicas: 2 debug: false metrics: diff --git a/packages/system/backupstrategy-controller/Chart.yaml b/packages/system/backupstrategy-controller/Chart.yaml index bf556f3b..fd135712 100644 --- a/packages/system/backupstrategy-controller/Chart.yaml +++ b/packages/system/backupstrategy-controller/Chart.yaml @@ -1,3 +1,3 @@ apiVersion: v2 -name: cozy-backupstrategy-controller +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/backupstrategy-controller/Makefile b/packages/system/backupstrategy-controller/Makefile index e6f23ca7..a5556838 100644 --- a/packages/system/backupstrategy-controller/Makefile +++ b/packages/system/backupstrategy-controller/Makefile @@ -1,8 +1,8 @@ NAME=backupstrategy-controller NAMESPACE=cozy-backup-controller -include ../../../hack/common-envs.mk -include ../../../hack/package.mk +include ../../../scripts/common-envs.mk +include ../../../scripts/package.mk image: image-backupstrategy-controller 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 index b4fea209..c40ef22c 100644 --- a/packages/system/backupstrategy-controller/definitions/strategy.backups.cozystack.io_jobs.yaml +++ b/packages/system/backupstrategy-controller/definitions/strategy.backups.cozystack.io_jobs.yaml @@ -353,6 +353,7 @@ 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 @@ -367,6 +368,7 @@ 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 @@ -534,6 +536,7 @@ 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 @@ -548,6 +551,7 @@ 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 @@ -641,8 +645,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 subtracting - "weight" from 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 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 @@ -713,6 +717,7 @@ 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 @@ -727,6 +732,7 @@ 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 @@ -894,6 +900,7 @@ 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 @@ -908,6 +915,7 @@ 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 @@ -1040,9 +1048,8 @@ spec: present in a Container. properties: name: - description: |- - Name of the environment variable. - May consist of any printable ASCII characters except '='. + description: Name of the environment variable. + Must be a C_IDENTIFIER. type: string value: description: |- @@ -1101,43 +1108,6 @@ 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 @@ -1200,14 +1170,14 @@ spec: 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 + 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 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 + a set of ConfigMaps properties: configMapRef: description: The ConfigMap to select from @@ -1228,9 +1198,8 @@ spec: 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 '='. + 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 @@ -1281,8 +1250,7 @@ spec: 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. + description: Exec specifies the action to take. properties: command: description: |- @@ -1297,7 +1265,7 @@ spec: x-kubernetes-list-type: atomic type: object httpGet: - description: HTTPGet specifies an HTTP GET request + description: HTTPGet specifies the http request to perform. properties: host: @@ -1348,8 +1316,8 @@ spec: - port type: object sleep: - description: Sleep represents a duration that - the container should sleep. + description: Sleep represents the duration that + the container should sleep before being terminated. properties: seconds: description: Seconds is the number of seconds @@ -1362,8 +1330,8 @@ spec: 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. + for the backward compatibility. There are no validation of this field and + lifecycle hooks will fail in runtime when tcp handler is specified. properties: host: description: 'Optional: Host name to connect @@ -1395,8 +1363,7 @@ spec: 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. + description: Exec specifies the action to take. properties: command: description: |- @@ -1411,7 +1378,7 @@ spec: x-kubernetes-list-type: atomic type: object httpGet: - description: HTTPGet specifies an HTTP GET request + description: HTTPGet specifies the http request to perform. properties: host: @@ -1462,8 +1429,8 @@ spec: - port type: object sleep: - description: Sleep represents a duration that - the container should sleep. + description: Sleep represents the duration that + the container should sleep before being terminated. properties: seconds: description: Seconds is the number of seconds @@ -1476,8 +1443,8 @@ spec: 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. + for the backward compatibility. There are no validation of this field and + lifecycle hooks will fail in runtime when tcp handler is specified. properties: host: description: 'Optional: Host name to connect @@ -1496,12 +1463,6 @@ 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: |- @@ -1511,8 +1472,7 @@ spec: 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. + description: Exec specifies the action to take. properties: command: description: |- @@ -1533,7 +1493,8 @@ spec: format: int32 type: integer grpc: - description: GRPC specifies a GRPC HealthCheckRequest. + description: GRPC specifies an action involving + a GRPC port. properties: port: description: Port number of the gRPC service. @@ -1552,7 +1513,7 @@ spec: - port type: object httpGet: - description: HTTPGet specifies an HTTP GET request + description: HTTPGet specifies the http request to perform. properties: host: @@ -1620,7 +1581,7 @@ spec: format: int32 type: integer tcpSocket: - description: TCPSocket specifies a connection to + description: TCPSocket specifies an action involving a TCP port. properties: host: @@ -1726,8 +1687,7 @@ spec: 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. + description: Exec specifies the action to take. properties: command: description: |- @@ -1748,7 +1708,8 @@ spec: format: int32 type: integer grpc: - description: GRPC specifies a GRPC HealthCheckRequest. + description: GRPC specifies an action involving + a GRPC port. properties: port: description: Port number of the gRPC service. @@ -1767,7 +1728,7 @@ spec: - port type: object httpGet: - description: HTTPGet specifies an HTTP GET request + description: HTTPGet specifies the http request to perform. properties: host: @@ -1835,7 +1796,7 @@ spec: format: int32 type: integer tcpSocket: - description: TCPSocket specifies a connection to + description: TCPSocket specifies an action involving a TCP port. properties: host: @@ -1909,7 +1870,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This field depends on the + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -1964,10 +1925,10 @@ spec: 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, + 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, 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: + 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" @@ -1979,59 +1940,6 @@ 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. @@ -2238,8 +2146,7 @@ spec: 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. + description: Exec specifies the action to take. properties: command: description: |- @@ -2260,7 +2167,8 @@ spec: format: int32 type: integer grpc: - description: GRPC specifies a GRPC HealthCheckRequest. + description: GRPC specifies an action involving + a GRPC port. properties: port: description: Port number of the gRPC service. @@ -2279,7 +2187,7 @@ spec: - port type: object httpGet: - description: HTTPGet specifies an HTTP GET request + description: HTTPGet specifies the http request to perform. properties: host: @@ -2347,7 +2255,7 @@ spec: format: int32 type: integer tcpSocket: - description: TCPSocket specifies a connection to + description: TCPSocket specifies an action involving a TCP port. properties: host: @@ -2562,13 +2470,9 @@ spec: options of a pod. properties: name: - description: |- - Name is this DNS resolver option's name. - Required. + description: Required. type: string value: - description: Value is this DNS resolver option's - value. type: string type: object type: array @@ -2652,9 +2556,8 @@ spec: present in a Container. properties: name: - description: |- - Name of the environment variable. - May consist of any printable ASCII characters except '='. + description: Name of the environment variable. + Must be a C_IDENTIFIER. type: string value: description: |- @@ -2713,43 +2616,6 @@ 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 @@ -2812,14 +2678,14 @@ spec: 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 + 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 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 + a set of ConfigMaps properties: configMapRef: description: The ConfigMap to select from @@ -2840,9 +2706,8 @@ spec: 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 '='. + 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 @@ -2890,8 +2755,7 @@ spec: 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. + description: Exec specifies the action to take. properties: command: description: |- @@ -2906,7 +2770,7 @@ spec: x-kubernetes-list-type: atomic type: object httpGet: - description: HTTPGet specifies an HTTP GET request + description: HTTPGet specifies the http request to perform. properties: host: @@ -2957,8 +2821,8 @@ spec: - port type: object sleep: - description: Sleep represents a duration that - the container should sleep. + description: Sleep represents the duration that + the container should sleep before being terminated. properties: seconds: description: Seconds is the number of seconds @@ -2971,8 +2835,8 @@ spec: 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. + for the backward compatibility. There are no validation of this field and + lifecycle hooks will fail in runtime when tcp handler is specified. properties: host: description: 'Optional: Host name to connect @@ -3004,8 +2868,7 @@ spec: 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. + description: Exec specifies the action to take. properties: command: description: |- @@ -3020,7 +2883,7 @@ spec: x-kubernetes-list-type: atomic type: object httpGet: - description: HTTPGet specifies an HTTP GET request + description: HTTPGet specifies the http request to perform. properties: host: @@ -3071,8 +2934,8 @@ spec: - port type: object sleep: - description: Sleep represents a duration that - the container should sleep. + description: Sleep represents the duration that + the container should sleep before being terminated. properties: seconds: description: Seconds is the number of seconds @@ -3085,8 +2948,8 @@ spec: 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. + for the backward compatibility. There are no validation of this field and + lifecycle hooks will fail in runtime when tcp handler is specified. properties: host: description: 'Optional: Host name to connect @@ -3105,19 +2968,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. properties: exec: - description: Exec specifies a command to execute - in the container. + description: Exec specifies the action to take. properties: command: description: |- @@ -3138,7 +2994,8 @@ spec: format: int32 type: integer grpc: - description: GRPC specifies a GRPC HealthCheckRequest. + description: GRPC specifies an action involving + a GRPC port. properties: port: description: Port number of the gRPC service. @@ -3157,7 +3014,7 @@ spec: - port type: object httpGet: - description: HTTPGet specifies an HTTP GET request + description: HTTPGet specifies the http request to perform. properties: host: @@ -3225,7 +3082,7 @@ spec: format: int32 type: integer tcpSocket: - description: TCPSocket specifies a connection to + description: TCPSocket specifies an action involving a TCP port. properties: host: @@ -3319,8 +3176,7 @@ spec: description: Probes are not allowed for ephemeral containers. properties: exec: - description: Exec specifies a command to execute - in the container. + description: Exec specifies the action to take. properties: command: description: |- @@ -3341,7 +3197,8 @@ spec: format: int32 type: integer grpc: - description: GRPC specifies a GRPC HealthCheckRequest. + description: GRPC specifies an action involving + a GRPC port. properties: port: description: Port number of the gRPC service. @@ -3360,7 +3217,7 @@ spec: - port type: object httpGet: - description: HTTPGet specifies an HTTP GET request + description: HTTPGet specifies the http request to perform. properties: host: @@ -3428,7 +3285,7 @@ spec: format: int32 type: integer tcpSocket: - description: TCPSocket specifies a connection to + description: TCPSocket specifies an action involving a TCP port. properties: host: @@ -3501,7 +3358,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This field depends on the + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -3557,53 +3414,9 @@ spec: 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 + This may only be set for init containers. 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 + type: string securityContext: description: |- Optional: SecurityContext defines the security options the ephemeral container should be run with. @@ -3802,8 +3615,7 @@ spec: description: Probes are not allowed for ephemeral containers. properties: exec: - description: Exec specifies a command to execute - in the container. + description: Exec specifies the action to take. properties: command: description: |- @@ -3824,7 +3636,8 @@ spec: format: int32 type: integer grpc: - description: GRPC specifies a GRPC HealthCheckRequest. + description: GRPC specifies an action involving + a GRPC port. properties: port: description: Port number of the gRPC service. @@ -3843,7 +3656,7 @@ spec: - port type: object httpGet: - description: HTTPGet specifies an HTTP GET request + description: HTTPGet specifies the http request to perform. properties: host: @@ -3911,7 +3724,7 @@ spec: format: int32 type: integer tcpSocket: - description: TCPSocket specifies a connection to + description: TCPSocket specifies an action involving a TCP port. properties: host: @@ -4142,9 +3955,7 @@ spec: 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`. + If this option is set, the ports that will be used must be specified. Default to false. type: boolean hostPID: @@ -4169,19 +3980,6 @@ 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. @@ -4217,7 +4015,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 - that value or the sum of the normal containers. Limits are applied to init containers + 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. @@ -4263,9 +4061,8 @@ spec: present in a Container. properties: name: - description: |- - Name of the environment variable. - May consist of any printable ASCII characters except '='. + description: Name of the environment variable. + Must be a C_IDENTIFIER. type: string value: description: |- @@ -4324,43 +4121,6 @@ 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 @@ -4423,14 +4183,14 @@ spec: 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 + 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 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 + a set of ConfigMaps properties: configMapRef: description: The ConfigMap to select from @@ -4451,9 +4211,8 @@ spec: 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 '='. + 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 @@ -4504,8 +4263,7 @@ spec: 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. + description: Exec specifies the action to take. properties: command: description: |- @@ -4520,7 +4278,7 @@ spec: x-kubernetes-list-type: atomic type: object httpGet: - description: HTTPGet specifies an HTTP GET request + description: HTTPGet specifies the http request to perform. properties: host: @@ -4571,8 +4329,8 @@ spec: - port type: object sleep: - description: Sleep represents a duration that - the container should sleep. + description: Sleep represents the duration that + the container should sleep before being terminated. properties: seconds: description: Seconds is the number of seconds @@ -4585,8 +4343,8 @@ spec: 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. + for the backward compatibility. There are no validation of this field and + lifecycle hooks will fail in runtime when tcp handler is specified. properties: host: description: 'Optional: Host name to connect @@ -4618,8 +4376,7 @@ spec: 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. + description: Exec specifies the action to take. properties: command: description: |- @@ -4634,7 +4391,7 @@ spec: x-kubernetes-list-type: atomic type: object httpGet: - description: HTTPGet specifies an HTTP GET request + description: HTTPGet specifies the http request to perform. properties: host: @@ -4685,8 +4442,8 @@ spec: - port type: object sleep: - description: Sleep represents a duration that - the container should sleep. + description: Sleep represents the duration that + the container should sleep before being terminated. properties: seconds: description: Seconds is the number of seconds @@ -4699,8 +4456,8 @@ spec: 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. + for the backward compatibility. There are no validation of this field and + lifecycle hooks will fail in runtime when tcp handler is specified. properties: host: description: 'Optional: Host name to connect @@ -4719,12 +4476,6 @@ 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: |- @@ -4734,8 +4485,7 @@ spec: 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. + description: Exec specifies the action to take. properties: command: description: |- @@ -4756,7 +4506,8 @@ spec: format: int32 type: integer grpc: - description: GRPC specifies a GRPC HealthCheckRequest. + description: GRPC specifies an action involving + a GRPC port. properties: port: description: Port number of the gRPC service. @@ -4775,7 +4526,7 @@ spec: - port type: object httpGet: - description: HTTPGet specifies an HTTP GET request + description: HTTPGet specifies the http request to perform. properties: host: @@ -4843,7 +4594,7 @@ spec: format: int32 type: integer tcpSocket: - description: TCPSocket specifies a connection to + description: TCPSocket specifies an action involving a TCP port. properties: host: @@ -4949,8 +4700,7 @@ spec: 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. + description: Exec specifies the action to take. properties: command: description: |- @@ -4971,7 +4721,8 @@ spec: format: int32 type: integer grpc: - description: GRPC specifies a GRPC HealthCheckRequest. + description: GRPC specifies an action involving + a GRPC port. properties: port: description: Port number of the gRPC service. @@ -4990,7 +4741,7 @@ spec: - port type: object httpGet: - description: HTTPGet specifies an HTTP GET request + description: HTTPGet specifies the http request to perform. properties: host: @@ -5058,7 +4809,7 @@ spec: format: int32 type: integer tcpSocket: - description: TCPSocket specifies a connection to + description: TCPSocket specifies an action involving a TCP port. properties: host: @@ -5132,7 +4883,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This field depends on the + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -5187,10 +4938,10 @@ spec: 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, + 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, 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: + 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" @@ -5202,59 +4953,6 @@ 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. @@ -5461,8 +5159,7 @@ spec: 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. + description: Exec specifies the action to take. properties: command: description: |- @@ -5483,7 +5180,8 @@ spec: format: int32 type: integer grpc: - description: GRPC specifies a GRPC HealthCheckRequest. + description: GRPC specifies an action involving + a GRPC port. properties: port: description: Port number of the gRPC service. @@ -5502,7 +5200,7 @@ spec: - port type: object httpGet: - description: HTTPGet specifies an HTTP GET request + description: HTTPGet specifies the http request to perform. properties: host: @@ -5570,7 +5268,7 @@ spec: format: int32 type: integer tcpSocket: - description: TCPSocket specifies a connection to + description: TCPSocket specifies an action involving a TCP port. properties: host: @@ -5788,7 +5486,6 @@ spec: - spec.hostPID - spec.hostIPC - spec.hostUsers - - spec.resources - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile @@ -5938,74 +5635,6 @@ spec: 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. @@ -6130,32 +5759,6 @@ spec: 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. @@ -6493,6 +6096,7 @@ 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: |- @@ -6503,6 +6107,7 @@ 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: |- @@ -6560,8 +6165,6 @@ spec: 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: @@ -6593,10 +6196,8 @@ spec: - 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. + 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: @@ -6635,10 +6236,8 @@ spec: - 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. + description: azureFile represents an Azure File Service + mount on the host and bind mount to the pod. properties: readOnly: description: |- @@ -6657,9 +6256,8 @@ spec: - 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. + description: cephFS represents a Ceph FS mount on the + host that shares a pod's lifetime properties: monitors: description: |- @@ -6712,8 +6310,6 @@ spec: 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: @@ -6825,7 +6421,7 @@ spec: csi: description: csi (Container Storage Interface) represents ephemeral storage that is handled by certain external - CSI drivers. + CSI drivers (Beta feature). properties: driver: description: |- @@ -7232,13 +6828,15 @@ 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 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. + 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: |- @@ -7294,7 +6892,6 @@ spec: 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 @@ -7340,9 +6937,9 @@ spec: - 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. + 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: |- @@ -7358,8 +6955,6 @@ spec: 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: @@ -7395,7 +6990,7 @@ spec: 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 + 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: @@ -7419,11 +7014,12 @@ spec: 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. + More info: https://examples.k8s.io/volumes/glusterfs/README.md properties: endpoints: - description: endpoints is the endpoint name that - details Glusterfs topology. + 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: |- @@ -7477,7 +7073,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) before 1.33. + 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: @@ -7502,7 +7098,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://kubernetes.io/docs/concepts/storage/volumes/#iscsi + More info: https://examples.k8s.io/volumes/iscsi/README.md properties: chapAuthDiscovery: description: chapAuthDiscovery defines whether support @@ -7627,9 +7223,9 @@ spec: - 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. + description: photonPersistentDisk represents a PhotonController + persistent disk attached and mounted on kubelets host + machine properties: fsType: description: |- @@ -7645,11 +7241,8 @@ spec: - 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. + description: portworxVolume represents a portworx volume + attached and mounted on kubelets host machine properties: fsType: description: |- @@ -7928,111 +7521,6 @@ 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 @@ -8125,9 +7613,8 @@ spec: 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. + description: quobyte represents a Quobyte mount on the + host that shares a pod's lifetime properties: group: description: |- @@ -8166,7 +7653,7 @@ spec: 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. + More info: https://examples.k8s.io/volumes/rbd/README.md properties: fsType: description: |- @@ -8238,9 +7725,8 @@ spec: - 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. + description: scaleIO represents a ScaleIO persistent + volume attached and mounted on Kubernetes nodes. properties: fsType: default: xfs @@ -8373,9 +7859,8 @@ spec: 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. + description: storageOS represents a StorageOS volume + attached and mounted on Kubernetes nodes. properties: fsType: description: |- @@ -8420,10 +7905,8 @@ spec: 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. + description: vsphereVolume represents a vSphere volume + attached and mounted on kubelets host machine properties: fsType: description: |- 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 index 34254aed..4433c7cb 100644 --- a/packages/system/backupstrategy-controller/definitions/strategy.backups.cozystack.io_veleroes.yaml +++ b/packages/system/backupstrategy-controller/definitions/strategy.backups.cozystack.io_veleroes.yaml @@ -39,924 +39,6 @@ spec: 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: diff --git a/packages/system/backupstrategy-controller/images/backupstrategy-controller/Dockerfile b/packages/system/backupstrategy-controller/images/backupstrategy-controller/Dockerfile index c4f60746..e896f473 100644 --- a/packages/system/backupstrategy-controller/images/backupstrategy-controller/Dockerfile +++ b/packages/system/backupstrategy-controller/images/backupstrategy-controller/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.25-alpine AS builder +FROM golang:1.24-alpine AS builder ARG TARGETOS ARG TARGETARCH diff --git a/packages/system/backupstrategy-controller/templates/rbac.yaml b/packages/system/backupstrategy-controller/templates/rbac.yaml index 634ea88b..85431a4b 100644 --- a/packages/system/backupstrategy-controller/templates/rbac.yaml +++ b/packages/system/backupstrategy-controller/templates/rbac.yaml @@ -3,80 +3,9 @@ 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/values.yaml b/packages/system/backupstrategy-controller/values.yaml index d6453124..6b04244a 100644 --- a/packages/system/backupstrategy-controller/values.yaml +++ b/packages/system/backupstrategy-controller/values.yaml @@ -1,5 +1,5 @@ backupStrategyController: - image: "ghcr.io/cozystack/cozystack/backupstrategy-controller:v1.3.0@sha256:be0a9ec1f4307064b16388a24628aee46e06252738338add80b99ea1e04e62bf" + image: "" replicas: 2 debug: false metrics: diff --git a/packages/system/bootbox-rd/Makefile b/packages/system/bootbox-rd/Makefile index 9d03ab2b..b570a84f 100644 --- a/packages/system/bootbox-rd/Makefile +++ b/packages/system/bootbox-rd/Makefile @@ -1,4 +1,4 @@ export NAME=bootbox-rd export NAMESPACE=cozy-system -include ../../../hack/package.mk +include ../../../scripts/package.mk diff --git a/packages/system/bootbox-rd/cozyrds/bootbox.yaml b/packages/system/bootbox-rd/cozyrds/bootbox.yaml index 667740e3..f47bf8f6 100644 --- a/packages/system/bootbox-rd/cozyrds/bootbox.yaml +++ b/packages/system/bootbox-rd/cozyrds/bootbox.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: ApplicationDefinition +kind: CozystackResourceDefinition metadata: name: bootbox spec: @@ -8,15 +8,17 @@ spec: 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"}}}}}} + {"title":"Chart Values","type":"object","properties":{"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"}}}},"whitelist":{"description":"List of client networks.","type":"array","default":[],"items":{"type":"string"}},"whitelistHTTP":{"description":"Secure HTTP by enabling client networks whitelisting.","type":"boolean","default":true}}} release: prefix: "" labels: - sharding.fluxcd.io/key: tenants - chartRef: - kind: ExternalArtifact - name: cozystack-bootbox-application-default-bootbox - namespace: cozy-system + cozystack.io/ui: "true" + chart: + name: bootbox + sourceRef: + kind: HelmRepository + name: cozystack-extra + namespace: cozy-public dashboard: category: Administration singular: BootBox diff --git a/packages/system/bootbox/Makefile b/packages/system/bootbox/Makefile index 2e666462..ce4e1af0 100644 --- a/packages/system/bootbox/Makefile +++ b/packages/system/bootbox/Makefile @@ -1,7 +1,7 @@ export NAME=bootbox export NAMESPACE=cozy-$(NAME) -include ../../../hack/package.mk +include ../../../scripts/package.mk update: rm -rf charts diff --git a/packages/system/bootbox/templates/bootbox.yaml b/packages/system/bootbox/templates/bootbox.yaml index fb0c8fe5..45cd07ce 100644 --- a/packages/system/bootbox/templates/bootbox.yaml +++ b/packages/system/bootbox/templates/bootbox.yaml @@ -4,16 +4,21 @@ metadata: annotations: helm.sh/resource-policy: keep labels: - sharding.fluxcd.io/key: tenants + cozystack.io/ui: "true" 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: - chartRef: - kind: ExternalArtifact - name: cozystack-bootbox-application-default-bootbox - namespace: cozy-system + chart: + spec: + chart: bootbox + reconcileStrategy: Revision + sourceRef: + kind: HelmRepository + name: cozystack-extra + namespace: cozy-public + version: '>= 0.0.0-0' interval: 1m0s timeout: 5m0s diff --git a/packages/system/bucket-rd/Makefile b/packages/system/bucket-rd/Makefile index 259617e8..53e89367 100644 --- a/packages/system/bucket-rd/Makefile +++ b/packages/system/bucket-rd/Makefile @@ -1,4 +1,4 @@ export NAME=bucket-rd export NAMESPACE=cozy-system -include ../../../hack/package.mk +include ../../../scripts/package.mk diff --git a/packages/system/bucket-rd/cozyrds/bucket.yaml b/packages/system/bucket-rd/cozyrds/bucket.yaml index 7eab56b6..889a36b5 100644 --- a/packages/system/bucket-rd/cozyrds/bucket.yaml +++ b/packages/system/bucket-rd/cozyrds/bucket.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: ApplicationDefinition +kind: CozystackResourceDefinition metadata: name: bucket spec: @@ -8,15 +8,17 @@ spec: 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"}}}}}} + {"title":"Chart Values","type":"object","properties":{}} release: prefix: bucket- labels: - sharding.fluxcd.io/key: tenants - chartRef: - kind: ExternalArtifact - name: cozystack-bucket-application-default-bucket - namespace: cozy-system + cozystack.io/ui: "true" + chart: + name: bucket + sourceRef: + kind: HelmRepository + name: cozystack-apps + namespace: cozy-public dashboard: singular: Bucket plural: Buckets @@ -26,14 +28,13 @@ spec: tags: - storage icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODNfMzA5MSkiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik03MiAzMC4xNjQxTDExNy45ODMgMzYuNzc4OVY0MC42NzM5QzExNy45ODMgNDYuNDY1MyA5Ny4zODYyIDUxLjEzMzIgNzEuOTgyNyA1MS4xMzMyQzQ2LjU3OTIgNTEuMTMzMiAyNiA0Ni40NjUzIDI2IDQwLjY3MzlWMzYuNDQzMUw3MiAzMC4xNjQxWk03MiA1OC4yNjc4QzkxLjIwODQgNTguMjY3OCAxMDcuNjU4IDU1LjU5ODYgMTE0LjU0NyA1MS44MDQ4TDExNi44MDMgNDguMTExTDExNy43MjMgNDQuNzUzVjQ4LjkxNzFMMTAyLjY3OSAxMTEuMDMzQzEwMi42NzkgMTE0Ljg5NSA4OC45NTMzIDExOCA3Mi4wMTcyIDExOEM1NS4wODEyIDExOCA0MS4zNzQzIDExNC44OTUgNDEuMzc0MyAxMTEuMDMzTDI2LjMzIDQ4LjkxNzFWNDQuODM2OUwyOS44MDA3IDUxLjkzODJDMzYuNzA2NSA1NS42NjUzIDUyLjk5OTcgNTguMjY3OCA3MiA1OC4yNjc4WiIgZmlsbD0iIzhDMzEyMyIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTcyLjAwMDMgMjZDOTcuNDAzOCAyNiAxMTggMzAuNjgzOSAxMTggMzYuNDQyQzExOCA0Mi4yIDk3LjM4NjYgNDYuODUwNyA3Mi4wMDAzIDQ2Ljg1MDdDNDYuNjE0MSA0Ni44NTA3IDI2LjAxNzYgNDIuMjM0NSAyNi4wMTc2IDM2LjQ0MkMyNi4wMTc2IDMwLjY0OTQgNDYuNTk2OCAyNiA3Mi4wMDAzIDI2Wk03Mi4wMDAzIDU0LjEwMzdDOTUuNjg1NyA1NC4xMDM3IDExNS4xNzIgNTAuMDU4IDExNy43MDYgNDQuODE5N0wxMDIuNjYyIDEwNi45MzdDMTAyLjY2MiAxMTAuNzk5IDg4LjkzNjQgMTEzLjkwNSA3Mi4wMDAzIDExMy45MDVDNTUuMDY0MyAxMTMuOTA1IDQxLjMzOSAxMTAuODE2IDQxLjMzOSAxMDYuOTU0TDI2LjI5NTkgNDQuODM3QzI4Ljg0NjYgNTAuMDU4IDQ4LjMzMzMgNTQuMTAzNyA3Mi4wMDAzIDU0LjEwMzdaIiBmaWxsPSIjRTA1MjQzIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNjEuMTcyNSA2MC4wMjkzSDgxLjA5MjhWNzkuMTY3Nkg2MS4xNzI1VjYwLjAyOTNaTTQ1LjMzMDEgOTUuMzY4OEM0NS4zMzAxIDkwLjE0MiA0OS43MTA0IDg1LjkzNDIgNTUuMTUxMSA4NS45MzQyQzYwLjU5MTcgODUuOTM0MiA2NC45NzIxIDkwLjE0MiA2NC45NzIxIDk1LjM2ODhDNjQuOTcyMSAxMDAuNTk2IDYwLjU5MTcgMTA0LjgwMyA1NS4xNTExIDEwNC44MDNDNDkuNzEwNCAxMDQuODAzIDQ1LjMzMDEgMTAwLjU5NiA0NS4zMzAxIDk1LjM2ODhaTTk2LjQ0ODcgMTA0LjM2OEg3Ni43NzIyTDg2LjYxMDUgODYuNzczN0w5Ni40NDg3IDEwNC4zNjhaIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4M18zMDkxIiB4MT0iMCIgeTE9IjAiIHgyPSIxNTEiIHkyPSIxODAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0ZGRjBFRSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNFQzg4N0QiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K - keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "locking"], ["spec", "storagePool"], ["spec", "users"]] + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"]] secrets: exclude: [] include: - resourceNames: + - bucket-{{ .name }} - bucket-{{ .name }}-credentials - - matchLabels: - apps.cozystack.io/user-secret: "true" ingresses: exclude: [] include: diff --git a/packages/system/bucket/Makefile b/packages/system/bucket/Makefile index 87944b28..d555b71c 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 ../../../hack/common-envs.mk -include ../../../hack/package.mk +include ../../../scripts/common-envs.mk +include ../../../scripts/package.mk update: @echo Nothing to update diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index 889db0af..1e12e68b 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:fb65e734bbdbdaef2238769cc2ecfb54dbddaf1e0952ad438a9b3e26b9dbb4b5 +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:3825c9b4b6238f88f1b0de73bd18866a7e5f83f178d28fe2830f3bf24efb187d diff --git a/packages/system/bucket/images/s3manager/Dockerfile b/packages/system/bucket/images/s3manager/Dockerfile index e97adf07..179acead 100644 --- a/packages/system/bucket/images/s3manager/Dockerfile +++ b/packages/system/bucket/images/s3manager/Dockerfile @@ -9,7 +9,6 @@ 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 2f569042..f631b144 100644 --- a/packages/system/bucket/images/s3manager/cozystack.patch +++ b/packages/system/bucket/images/s3manager/cozystack.patch @@ -1,235 +1,3 @@ -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 @@ -256,298 +24,3 @@ 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 5c13cb2d..7e115de0 100644 --- a/packages/system/bucket/templates/deployment.yaml +++ b/packages/system/bucket/templates/deployment.yaml @@ -1,12 +1,3 @@ -{{- $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: @@ -26,6 +17,19 @@ spec: image: "{{ $.Files.Get "images/s3manager.tag" | trim }}" env: - name: ENDPOINT - value: {{ $endpoint | quote }} + valueFrom: + secretKeyRef: + name: {{ .Values.bucketName }}-credentials + key: endpoint - 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 b7ffaf8b..f7b4eed4 100644 --- a/packages/system/bucket/templates/ingress.yaml +++ b/packages/system/bucket/templates/ingress.yaml @@ -1,20 +1,22 @@ {{- $host := .Values._namespace.host }} {{- $ingress := .Values._namespace.ingress }} -{{- $solver := (index .Values._cluster "solver") | default "http01" }} -{{- $clusterIssuer := (index .Values._cluster "issuer-name") | default "letsencrypt-prod" }} +{{- $issuerType := (index .Values._cluster "clusterissuer") | default "http01" }} 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 eq $solver "http01" }} - acme.cert-manager.io/http01-ingress-ingressclassname: {{ $ingress }} + {{- if ne $issuerType "cloudflare" }} + acme.cert-manager.io/http01-ingress-class: {{ $ingress }} {{- end }} - cert-manager.io/cluster-issuer: {{ $clusterIssuer }} + cert-manager.io/cluster-issuer: letsencrypt-prod spec: ingressClassName: {{ $ingress }} tls: diff --git a/packages/system/bucket/templates/secret.yaml b/packages/system/bucket/templates/secret.yaml index 683a0972..15474569 100644 --- a/packages/system/bucket/templates/secret.yaml +++ b/packages/system/bucket/templates/secret.yaml @@ -1,2 +1,24 @@ -{{/* Secrets previously used for s3manager credential injection and nginx basic auth */}} -{{/* are no longer needed — s3manager now handles authentication via its own login page */}} +{{- $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" }} +{{- $bucketName := index $bucketInfo.spec "bucketName" }} + +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.bucketName }}-credentials +type: Opaque +stringData: + accessKey: {{ $accessKeyID | quote }} + secretKey: {{ $accessSecretKey | quote }} + endpoint: {{ trimPrefix "https://" $endpoint }} + bucketName: {{ $bucketName | quote }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.bucketName }}-ui-auth +data: + auth: {{ htpasswd $accessKeyID $accessSecretKey | b64enc | quote }} diff --git a/packages/system/bucket/templates/user-credentials.yaml b/packages/system/bucket/templates/user-credentials.yaml deleted file mode 100644 index 7ccdd731..00000000 --- a/packages/system/bucket/templates/user-credentials.yaml +++ /dev/null @@ -1,20 +0,0 @@ -{{- 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 739c4977..e1499c6e 100644 --- a/packages/system/bucket/values.yaml +++ b/packages/system/bucket/values.yaml @@ -1,2 +1 @@ bucketName: "cozystack" -users: {} diff --git a/packages/system/capi-operator/Makefile b/packages/system/capi-operator/Makefile index 9349f549..dc421cee 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 ../../../hack/package.mk +include ../../../scripts/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 54d8ca8b..f588e439 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 ../../../hack/package.mk +include ../../../scripts/package.mk diff --git a/packages/system/capi-providers-core/Makefile b/packages/system/capi-providers-core/Makefile index f5f038c1..a9bae779 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 ../../../hack/package.mk +include ../../../scripts/package.mk diff --git a/packages/system/capi-providers-cpprovider/Makefile b/packages/system/capi-providers-cpprovider/Makefile index caec8d96..06f0dd6d 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 ../../../hack/package.mk +include ../../../scripts/package.mk diff --git a/packages/system/capi-providers-cpprovider/files/components.gz b/packages/system/capi-providers-cpprovider/files/components.gz index 930a26af..60ac302a 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 64fc7d6d..d30e7373 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 - mode: DaemonSet + version: v0.28.6 properties: extraArgs: description: |- @@ -120,31 +120,10 @@ 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 @@ -190,20 +169,15 @@ spec: 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. + default: v0.28.6 + description: Version for Konnectivity agent. 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: |- @@ -230,7 +204,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This field depends on the + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -282,11 +256,8 @@ spec: 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. + default: v0.28.6 + description: Container image version of the Konnectivity server. type: string required: - port @@ -439,7 +410,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This field depends on the + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -589,7 +560,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This field depends on the + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -649,16 +620,6 @@ 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: @@ -942,6 +903,7 @@ 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 @@ -956,6 +918,7 @@ 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 @@ -1116,6 +1079,7 @@ 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 @@ -1130,6 +1094,7 @@ 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 @@ -1218,8 +1183,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 subtracting - "weight" from 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 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) @@ -1283,6 +1248,7 @@ 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 @@ -1297,6 +1263,7 @@ 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 @@ -1457,6 +1424,7 @@ 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 @@ -1471,6 +1439,7 @@ 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 @@ -1618,9 +1587,7 @@ spec: 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 '='. + description: Name of the environment variable. Must be a C_IDENTIFIER. type: string value: description: |- @@ -1674,42 +1641,6 @@ 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 @@ -1765,13 +1696,13 @@ spec: 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 + 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 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 + description: EnvFromSource represents the source of a set of ConfigMaps properties: configMapRef: description: The ConfigMap to select from @@ -1791,9 +1722,7 @@ spec: 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 '='. + 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 @@ -2042,12 +1971,6 @@ 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: |- @@ -2438,7 +2361,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This field depends on the + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -2492,10 +2415,10 @@ spec: 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, + 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, 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: + 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" @@ -2507,57 +2430,6 @@ 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. @@ -3079,9 +2951,7 @@ spec: 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 '='. + description: Name of the environment variable. Must be a C_IDENTIFIER. type: string value: description: |- @@ -3135,42 +3005,6 @@ 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 @@ -3226,13 +3060,13 @@ spec: 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 + 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 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 + description: EnvFromSource represents the source of a set of ConfigMaps properties: configMapRef: description: The ConfigMap to select from @@ -3252,9 +3086,7 @@ spec: 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 '='. + 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 @@ -3503,12 +3335,6 @@ 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: |- @@ -3899,7 +3725,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This field depends on the + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -3953,10 +3779,10 @@ spec: 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, + 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, 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: + 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" @@ -3968,57 +3794,6 @@ 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. @@ -5140,13 +4915,15 @@ 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 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. + 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: |- @@ -5320,9 +5097,12 @@ 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. + 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: |- @@ -5376,7 +5156,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) before 1.33. + 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: @@ -5401,7 +5181,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://kubernetes.io/docs/concepts/storage/volumes/#iscsi + More info: https://examples.k8s.io/volumes/iscsi/README.md properties: chapAuthDiscovery: description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication @@ -5791,110 +5571,6 @@ 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: @@ -6024,6 +5700,7 @@ 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: |- @@ -6522,6 +6199,7 @@ 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: |- @@ -6532,6 +6210,7 @@ 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: |- @@ -6591,7 +6270,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This field depends on the + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -6647,14 +6326,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 @@ -6662,12 +6341,12 @@ spec: type: string preferredAddressTypes: default: + - Hostname - InternalIP - ExternalIP - - Hostname description: |- Ordered list of the preferred NodeAddressTypes to use for kubelet connections. - Default to InternalIP, ExternalIP, Hostname. + Default to Hostname, InternalIP, ExternalIP. items: enum: - Hostname @@ -6678,7 +6357,6 @@ spec: type: string minItems: 1 type: array - x-kubernetes-list-type: set type: object network: default: @@ -6879,7 +6557,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This field depends on the + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -7166,7 +6844,7 @@ spec: agent: default: image: registry.k8s.io/kas-network-proxy/proxy-agent - mode: DaemonSet + version: v0.28.6 properties: extraArgs: description: |- @@ -7177,31 +6855,10 @@ 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 @@ -7247,20 +6904,15 @@ spec: 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. + default: v0.28.6 + description: Version for Konnectivity agent. 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: |- @@ -7287,7 +6939,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This field depends on the + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -7339,11 +6991,8 @@ spec: 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. + default: v0.28.6 + description: Container image version of the Konnectivity server. type: string required: - port @@ -7496,7 +7145,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This field depends on the + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -7631,7 +7280,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This field depends on the + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -7691,16 +7340,6 @@ 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: @@ -7984,6 +7623,7 @@ 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 @@ -7998,6 +7638,7 @@ 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 @@ -8158,6 +7799,7 @@ 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 @@ -8172,6 +7814,7 @@ 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 @@ -8260,8 +7903,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 subtracting - "weight" from 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 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) @@ -8325,6 +7968,7 @@ 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 @@ -8339,6 +7983,7 @@ 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 @@ -8499,6 +8144,7 @@ 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 @@ -8513,6 +8159,7 @@ 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 @@ -8660,9 +8307,7 @@ spec: 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 '='. + description: Name of the environment variable. Must be a C_IDENTIFIER. type: string value: description: |- @@ -8716,42 +8361,6 @@ 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 @@ -8807,13 +8416,13 @@ spec: 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 + 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 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 + description: EnvFromSource represents the source of a set of ConfigMaps properties: configMapRef: description: The ConfigMap to select from @@ -8833,9 +8442,7 @@ spec: 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 '='. + 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 @@ -9084,12 +8691,6 @@ 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: |- @@ -9480,7 +9081,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This field depends on the + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -9534,10 +9135,10 @@ spec: 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, + 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, 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: + 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" @@ -9549,57 +9150,6 @@ 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. @@ -10121,9 +9671,7 @@ spec: 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 '='. + description: Name of the environment variable. Must be a C_IDENTIFIER. type: string value: description: |- @@ -10177,42 +9725,6 @@ 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 @@ -10268,13 +9780,13 @@ spec: 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 + 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 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 + description: EnvFromSource represents the source of a set of ConfigMaps properties: configMapRef: description: The ConfigMap to select from @@ -10294,9 +9806,7 @@ spec: 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 '='. + 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 @@ -10545,12 +10055,6 @@ 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: |- @@ -10941,7 +10445,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This field depends on the + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -10995,10 +10499,10 @@ spec: 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, + 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, 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: + 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" @@ -11010,57 +10514,6 @@ 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. @@ -12182,13 +11635,15 @@ 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 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. + 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: |- @@ -12362,9 +11817,12 @@ 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. + 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: |- @@ -12418,7 +11876,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) before 1.33. + 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: @@ -12443,7 +11901,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://kubernetes.io/docs/concepts/storage/volumes/#iscsi + More info: https://examples.k8s.io/volumes/iscsi/README.md properties: chapAuthDiscovery: description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication @@ -12833,110 +12291,6 @@ 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: @@ -13066,6 +12420,7 @@ 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: |- @@ -13564,6 +12919,7 @@ 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: |- @@ -13574,6 +12930,7 @@ 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: |- @@ -13633,7 +12990,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This field depends on the + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -13689,14 +13046,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 @@ -13704,12 +13061,12 @@ spec: type: string preferredAddressTypes: default: + - Hostname - InternalIP - ExternalIP - - Hostname description: |- Ordered list of the preferred NodeAddressTypes to use for kubelet connections. - Default to InternalIP, ExternalIP, Hostname. + Default to Hostname, InternalIP, ExternalIP. items: enum: - Hostname @@ -13720,7 +13077,6 @@ spec: type: string minItems: 1 type: array - x-kubernetes-list-type: set type: object network: default: @@ -13914,7 +13270,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This field depends on the + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -14160,8 +13516,6 @@ rules: - metal3clusters verbs: - get - - list - - watch - apiGroups: - kamaji.clastix.io resources: @@ -14272,14 +13626,14 @@ spec: - --dynamic-infrastructure-clusters=${CACPPK_INFRASTRUCTURE_CLUSTERS:= } command: - /manager - image: docker.io/clastix/cluster-api-control-plane-provider-kamaji:v0.16.0 + image: docker.io/clastix/cluster-api-control-plane-provider-kamaji:v0.15.0 livenessProbe: httpGet: path: /healthz port: 8081 initialDelaySeconds: 15 periodSeconds: 20 - name: controller + name: manager 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 d22c9ab0..b282734a 100644 --- a/packages/system/capi-providers-cpprovider/files/metadata.yaml +++ b/packages/system/capi-providers-cpprovider/files/metadata.yaml @@ -5,9 +5,6 @@ # 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 736c06a5..d69ab12b 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.16.0-cp + name: v0.15.1-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 125a82c7..b173be14 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.16.0-cp + version: v0.15.1-cp fetchConfig: selector: matchLabels: diff --git a/packages/system/capi-providers-infraprovider/Makefile b/packages/system/capi-providers-infraprovider/Makefile index 042a4f0e..8e4423f3 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 ../../../hack/package.mk +include ../../../scripts/package.mk diff --git a/packages/system/cert-manager-crds/Makefile b/packages/system/cert-manager-crds/Makefile index 7e7370ac..0d665914 100644 --- a/packages/system/cert-manager-crds/Makefile +++ b/packages/system/cert-manager-crds/Makefile @@ -1,5 +1,8 @@ -export NAME=cert-manager-crds -export NAMESPACE=cozy-cert-manager - -include ../../../hack/package.mk +include ../../../scripts/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 new file mode 100644 index 00000000..300db669 --- /dev/null +++ b/packages/system/cert-manager-crds/charts/cert-manager/Chart.yaml @@ -0,0 +1,26 @@ +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 new file mode 100644 index 00000000..6fa25cc9 --- /dev/null +++ b/packages/system/cert-manager-crds/charts/cert-manager/README.md @@ -0,0 +1,1994 @@ +# 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/templates/_helpers.tpl b/packages/system/cert-manager-crds/charts/cert-manager/templates/_helpers.tpl similarity index 95% rename from packages/system/cert-manager-crds/templates/_helpers.tpl rename to packages/system/cert-manager-crds/charts/cert-manager/templates/_helpers.tpl index f85373f3..e15fa191 100644 --- a/packages/system/cert-manager-crds/templates/_helpers.tpl +++ b/packages/system/cert-manager-crds/charts/cert-manager/templates/_helpers.tpl @@ -187,17 +187,6 @@ 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/charts/cert-manager/templates/crds.yaml b/packages/system/cert-manager-crds/charts/cert-manager/templates/crds.yaml new file mode 100644 index 00000000..00930f9c --- /dev/null +++ b/packages/system/cert-manager-crds/charts/cert-manager/templates/crds.yaml @@ -0,0 +1,12013 @@ +# {{- 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 new file mode 100644 index 00000000..d04da90c --- /dev/null +++ b/packages/system/cert-manager-crds/charts/cert-manager/values.schema.json @@ -0,0 +1,2135 @@ +{ + "$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 new file mode 100644 index 00000000..7a1c2953 --- /dev/null +++ b/packages/system/cert-manager-crds/charts/cert-manager/values.yaml @@ -0,0 +1,1455 @@ +# +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/templates/crd-acme.cert-manager.io_challenges.yaml b/packages/system/cert-manager-crds/templates/crd-acme.cert-manager.io_challenges.yaml deleted file mode 100644 index 5bed0cd8..00000000 --- a/packages/system/cert-manager-crds/templates/crd-acme.cert-manager.io_challenges.yaml +++ /dev/null @@ -1,3281 +0,0 @@ -{{- 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 deleted file mode 100644 index 3242fc41..00000000 --- a/packages/system/cert-manager-crds/templates/crd-acme.cert-manager.io_orders.yaml +++ /dev/null @@ -1,274 +0,0 @@ -{{- 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 deleted file mode 100644 index e25ad1d0..00000000 --- a/packages/system/cert-manager-crds/templates/crd-cert-manager.io_certificaterequests.yaml +++ /dev/null @@ -1,319 +0,0 @@ -{{- 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 deleted file mode 100644 index 6689de66..00000000 --- a/packages/system/cert-manager-crds/templates/crd-cert-manager.io_certificates.yaml +++ /dev/null @@ -1,816 +0,0 @@ -{{- 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 deleted file mode 100644 index 790d4b5c..00000000 --- a/packages/system/cert-manager-crds/templates/crd-cert-manager.io_clusterissuers.yaml +++ /dev/null @@ -1,3815 +0,0 @@ -{{- 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 deleted file mode 100644 index 43277f84..00000000 --- a/packages/system/cert-manager-crds/templates/crd-cert-manager.io_issuers.yaml +++ /dev/null @@ -1,3814 +0,0 @@ -{{- 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 15136853..0b21fc93 100644 --- a/packages/system/cert-manager-crds/values.yaml +++ b/packages/system/cert-manager-crds/values.yaml @@ -1,8 +1,2 @@ -global: - commonLabels: {} - -creator: helm - -crds: - enabled: true - keep: true +cert-manager: + installCRDs: true diff --git a/packages/system/cert-manager-issuers/Makefile b/packages/system/cert-manager-issuers/Makefile index 8808dbfd..a7a6ce10 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 ../../../hack/package.mk +include ../../../scripts/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 3b582082..e93f3f67 100644 --- a/packages/system/cert-manager-issuers/templates/cluster-issuers.yaml +++ b/packages/system/cert-manager-issuers/templates/cluster-issuers.yaml @@ -1,7 +1,6 @@ -{{- $solver := (index .Values._cluster "solver") | default "http01" }} -{{- $exposeIngress := (index .Values._cluster "expose-ingress") | default "tenant-root" }} +{{- $issuerType := (index .Values._cluster "clusterissuer") | default "http01" }} -apiVersion: cert-manager.io/v1 +apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod @@ -11,16 +10,16 @@ spec: name: letsencrypt-prod server: https://acme-v02.api.letsencrypt.org/directory solvers: - - {{- if eq $solver "dns01" }} + - {{- if eq $issuerType "cloudflare" }} dns01: cloudflare: apiTokenSecretRef: name: cloudflare-api-token-secret key: api-token {{- else }} - http01: - ingress: - ingressClassName: {{ $exposeIngress }} + http01: + ingress: + class: nginx {{- end }} --- @@ -35,16 +34,16 @@ spec: name: letsencrypt-stage server: https://acme-staging-v02.api.letsencrypt.org/directory solvers: - - {{- if eq $solver "dns01" }} + - {{- if eq $issuerType "cloudflare" }} dns01: cloudflare: apiTokenSecretRef: name: cloudflare-api-token-secret key: api-token {{- else }} - http01: - ingress: - ingressClassName: {{ $exposeIngress }} + http01: + ingress: + class: nginx {{- end }} --- diff --git a/packages/system/cert-manager/Makefile b/packages/system/cert-manager/Makefile index c3ff574b..d48ad5be 100644 --- a/packages/system/cert-manager/Makefile +++ b/packages/system/cert-manager/Makefile @@ -1,13 +1,10 @@ export NAME=cert-manager export NAMESPACE=cozy-$(NAME) -include ../../../hack/package.mk +include ../../../scripts/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 2756247d..2a49d00c 100644 --- a/packages/system/cert-manager/charts/cert-manager/Chart.yaml +++ b/packages/system/cert-manager/charts/cert-manager/Chart.yaml @@ -6,7 +6,7 @@ annotations: fingerprint: 1020CF3C033D4F35BAE1C19E1226061C665DF13E url: https://cert-manager.io/public-keys/cert-manager-keyring-2021-09-20-1020CF3C033D4F35BAE1C19E1226061C665DF13E.gpg apiVersion: v2 -appVersion: v1.19.3 +appVersion: v1.17.2 description: A Helm chart for cert-manager home: https://cert-manager.io icon: https://raw.githubusercontent.com/cert-manager/community/4d35a69437d21b76322157e6284be4cd64e6d2b7/logo/logo-small.png @@ -23,4 +23,4 @@ maintainers: name: cert-manager sources: - https://github.com/cert-manager/cert-manager -version: v1.19.3 +version: v1.17.2 diff --git a/packages/system/cert-manager/charts/cert-manager/README.md b/packages/system/cert-manager/charts/cert-manager/README.md index 456e740d..1d502429 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 creates TLS certificates for workloads in your Kubernetes or OpenShift cluster and renews the certificates before they expire. +cert-manager is a Kubernetes addon to automate the management and issuance of +TLS certificates from various issuing sources. -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/). +It will ensure certificates are valid and up to date periodically, and attempt +to renew certificates at an appropriate time before expiry. ## Prerequisites @@ -13,21 +13,23 @@ cert-manager can obtain certificates from a [variety of certificate authorities] ## 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/helm/). +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 +``` 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 jetstack/cert-manager \ - --namespace cert-manager \ - --create-namespace \ - --version v1.19.3 \ - --set crds.enabled=true +## Install the cert-manager helm chart +$ helm install cert-manager --namespace cert-manager --version v1.17.2 jetstack/cert-manager ``` In order to begin issuing certificates, you will need to set up a ClusterIssuer @@ -54,25 +56,17 @@ 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: -> ☢️ 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 -> ``` +```console +$ kubectl delete -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.2/cert-manager.crds.yaml +``` ## Configuration @@ -93,18 +87,6 @@ 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 @@ -126,18 +108,6 @@ 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 @@ -260,13 +230,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` @@ -330,7 +300,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, e.g., "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 eg. "cainjector.name" which resolves to the value "cainjector"). #### **serviceAccount.create** ~ `bool` > Default value: @@ -401,10 +371,10 @@ config: kubernetesAPIBurst: 9000 numberOfConcurrentWorkers: 200 enableGatewayAPI: true - # Feature gates as of v1.18.1. Listed with their default values. + # Feature gates as of v1.17.0. Listed with their default values. # See https://cert-manager.io/docs/cli/controller/ featureGates: - AdditionalCertificateOutputFormats: true # GA - default=true + AdditionalCertificateOutputFormats: true # BETA - default=true AllAlpha: false # ALPHA - default=false AllBeta: false # BETA - default=false ExperimentalCertificateSigningRequestControllers: false # ALPHA - default=false @@ -416,10 +386,8 @@ config: ServerSideApply: false # ALPHA - default=false StableCertificateRequestName: true # BETA - default=true UseCertificateRequestBasicConstraints: false # ALPHA - default=false - UseDomainQualifiedFinalizer: true # GA - default=true + UseDomainQualifiedFinalizer: true # BETA - default=false 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: @@ -457,7 +425,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, e.g., 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 eg. you are using approver-policy, you can enable 'disableAutoApproval'. ref: https://cert-manager.io/docs/concepts/certificaterequest/#approval #### **extraArgs** ~ `array` @@ -716,7 +684,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 cannot 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 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 @@ -735,14 +703,13 @@ 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** ~ `string,integer` +#### **prometheus.servicemonitor.targetPort** ~ `number` > Default value: > ```yaml -> http-metrics +> 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 @@ -1002,13 +969,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. @@ -1326,8 +1293,6 @@ 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. @@ -1349,8 +1314,6 @@ 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. @@ -1479,14 +1442,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 4d0b4b60..341d1012 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/NOTES.txt +++ b/packages/system/cert-manager/charts/cert-manager/templates/NOTES.txt @@ -1,12 +1,6 @@ {{- 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 f85373f3..e15fa191 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/_helpers.tpl +++ b/packages/system/cert-manager/charts/cert-manager/templates/_helpers.tpl @@ -187,17 +187,6 @@ 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 b5434caa..dc14ab02 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/cainjector-deployment.yaml +++ b/packages/system/cert-manager/charts/cert-manager/templates/cainjector-deployment.yaml @@ -67,9 +67,6 @@ 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 }} @@ -139,13 +136,9 @@ spec: {{- toYaml . | nindent 12 }} {{- end }} {{- end }} - {{- $nodeSelector := .Values.global.nodeSelector | default dict }} - {{- $nodeSelector = merge $nodeSelector (.Values.cainjector.nodeSelector | default dict) }} - {{- with $nodeSelector }} + {{- with .Values.cainjector.nodeSelector }} nodeSelector: - {{- range $key, $value := . }} - {{ $key }}: {{ $value | quote }} - {{- end }} + {{- toYaml . | nindent 8 }} {{- 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 new file mode 100644 index 00000000..f5f8ec43 --- /dev/null +++ b/packages/system/cert-manager/charts/cert-manager/templates/crds.yaml @@ -0,0 +1,12036 @@ +# {{- 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 453e8238..8a4a9734 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/deployment.yaml +++ b/packages/system/cert-manager/charts/cert-manager/templates/deployment.yaml @@ -66,9 +66,6 @@ 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 }} @@ -212,13 +209,9 @@ spec: failureThreshold: {{ .failureThreshold }} {{- end }} {{- end }} - {{- $nodeSelector := .Values.global.nodeSelector | default dict }} - {{- $nodeSelector = merge $nodeSelector (.Values.nodeSelector | default dict) }} - {{- with $nodeSelector }} + {{- with .Values.nodeSelector }} nodeSelector: - {{- range $key, $value := . }} - {{ $key }}: {{ $value | quote }} - {{- end }} + {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.affinity }} affinity: @@ -241,4 +234,4 @@ spec: {{- end }} {{- with .Values.hostAliases }} hostAliases: {{ toYaml . | nindent 8 }} - {{- end }} + {{- end }} \ No newline at end of file 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 7acd5711..baae425f 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.fullname" . }}-tokenrequest + name: {{ template "cert-manager.serviceAccountName" . }}-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" . }}-tokenrequest + name: {{ include "cert-manager.fullname" . }}-{{ template "cert-manager.serviceAccountName" . }}-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.fullname" . }}-tokenrequest + name: {{ template "cert-manager.serviceAccountName" . }}-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 fac93d0a..698ddef8 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/serviceaccount.yaml +++ b/packages/system/cert-manager/charts/cert-manager/templates/serviceaccount.yaml @@ -12,8 +12,7 @@ metadata: {{- with .Values.serviceAccount.annotations }} annotations: {{- range $k, $v := . }} - {{- $value := $v | quote }} - {{- printf "%s: %s" (tpl $k $) (tpl $value $) | nindent 4 }} + {{- printf "%s: %s" (tpl $k $) (tpl $v $) | 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 a29f3c6a..dd1beec8 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/servicemonitor.yaml +++ b/packages/system/cert-manager/charts/cert-manager/templates/servicemonitor.yaml @@ -16,9 +16,7 @@ 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 }} @@ -56,12 +54,8 @@ 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 f68d5409..183cff4e 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,9 +41,6 @@ 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 }} @@ -79,13 +76,9 @@ spec: volumeMounts: {{- toYaml . | nindent 12 }} {{- end }} - {{- $nodeSelector := .Values.global.nodeSelector | default dict }} - {{- $nodeSelector = merge $nodeSelector (.Values.startupapicheck.nodeSelector | default dict) }} - {{- with $nodeSelector }} + {{- with .Values.startupapicheck.nodeSelector }} nodeSelector: - {{- range $key, $value := . }} - {{ $key }}: {{ $value | quote }} - {{- end }} + {{- toYaml . | nindent 8 }} {{- 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 d2b10ae8..857cf353 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/webhook-deployment.yaml +++ b/packages/system/cert-manager/charts/cert-manager/templates/webhook-deployment.yaml @@ -66,9 +66,6 @@ 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 }} @@ -105,7 +102,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 }} @@ -140,7 +137,11 @@ spec: livenessProbe: httpGet: path: /livez - port: healthcheck + {{- if $config.healthzPort }} + port: {{ $config.healthzPort }} + {{- else }} + port: 6080 + {{- end }} scheme: HTTP initialDelaySeconds: {{ .Values.webhook.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.webhook.livenessProbe.periodSeconds }} @@ -150,7 +151,11 @@ spec: readinessProbe: httpGet: path: /healthz - port: healthcheck + {{- if $config.healthzPort }} + port: {{ $config.healthzPort }} + {{- else }} + port: 6080 + {{- end }} scheme: HTTP initialDelaySeconds: {{ .Values.webhook.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.webhook.readinessProbe.periodSeconds }} @@ -183,13 +188,9 @@ spec: {{- toYaml . | nindent 12 }} {{- end }} {{- end }} - {{- $nodeSelector := .Values.global.nodeSelector | default dict }} - {{- $nodeSelector = merge $nodeSelector (.Values.webhook.nodeSelector | default dict) }} - {{- with $nodeSelector }} + {{- with .Values.webhook.nodeSelector }} nodeSelector: - {{- range $key, $value := . }} - {{ $key }}: {{ $value | quote }} - {{- end }} + {{- toYaml . | nindent 8 }} {{- 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 7f90b6c3..36d1d0ca 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, e.g., 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 eg. 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.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", + "description": "This property is used to configure options for the controller pod. This allows setting options that would usually be provided using flags.\n\nIf `apiVersion` and `kind` are unspecified they default to the current latest version (currently `controller.config.cert-manager.io/v1alpha1`). You can pin the version by specifying the `apiVersion` yourself.\n\nFor example:\nconfig:\n apiVersion: controller.config.cert-manager.io/v1alpha1\n kind: ControllerConfiguration\n logging:\n verbosity: 2\n format: text\n leaderElectionConfig:\n namespace: kube-system\n kubernetesAPIQPS: 9000\n kubernetesAPIBurst: 9000\n numberOfConcurrentWorkers: 200\n enableGatewayAPI: true\n # Feature gates as of v1.17.0. Listed with their default values.\n # See https://cert-manager.io/docs/cli/controller/\n featureGates:\n AdditionalCertificateOutputFormats: true # BETA - default=true\n AllAlpha: false # ALPHA - default=false\n AllBeta: false # BETA - default=false\n ExperimentalCertificateSigningRequestControllers: false # ALPHA - default=false\n ExperimentalGatewayAPISupport: true # BETA - default=true\n LiteralCertificateSubject: true # BETA - default=true\n NameConstraints: true # BETA - default=true\n OtherNames: false # ALPHA - default=false\n SecretsFilteredCaching: true # BETA - default=true\n ServerSideApply: false # ALPHA - default=false\n StableCertificateRequestName: true # BETA - default=true\n UseCertificateRequestBasicConstraints: false # ALPHA - default=false\n UseDomainQualifiedFinalizer: true # BETA - default=false\n ValidateCAA: false # ALPHA - default=false\n # Configure the metrics server for TLS\n # See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls\n metricsTLSConfig:\n dynamic:\n secretNamespace: \"cert-manager\"\n secretName: \"cert-manager-metrics-ca\"\n dnsNames:\n - cert-manager-metrics", "type": "object" }, "helm-values.containerSecurityContext": { @@ -689,9 +689,6 @@ "commonLabels": { "$ref": "#/$defs/helm-values.global.commonLabels" }, - "hostUsers": { - "$ref": "#/$defs/helm-values.global.hostUsers" - }, "imagePullSecrets": { "$ref": "#/$defs/helm-values.global.imagePullSecrets" }, @@ -701,9 +698,6 @@ "logLevel": { "$ref": "#/$defs/helm-values.global.logLevel" }, - "nodeSelector": { - "$ref": "#/$defs/helm-values.global.nodeSelector" - }, "podSecurityPolicy": { "$ref": "#/$defs/helm-values.global.podSecurityPolicy" }, @@ -724,10 +718,6 @@ "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\"", @@ -773,11 +763,6 @@ "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": { @@ -936,7 +921,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, e.g., \"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 eg. \"cainjector.name\" which resolves to the value \"cainjector\").", "type": "string" }, "helm-values.namespace": { @@ -980,10 +965,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).", @@ -1015,7 +1000,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 cannot 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 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": { @@ -1192,8 +1177,9 @@ "type": "string" }, "helm-values.prometheus.servicemonitor.targetPort": { - "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." + "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, @@ -1901,11 +1887,6 @@ "ipBlock": { "cidr": "0.0.0.0/0" } - }, - { - "ipBlock": { - "cidr": "::/0" - } } ] } @@ -1927,11 +1908,6 @@ "ipBlock": { "cidr": "0.0.0.0/0" } - }, - { - "ipBlock": { - "cidr": "::/0" - } } ] } @@ -1972,10 +1948,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 54257c79..a8c94f8b 100644 --- a/packages/system/cert-manager/charts/cert-manager/values.yaml +++ b/packages/system/cert-manager/charts/cert-manager/values.yaml @@ -12,16 +12,6 @@ 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: @@ -38,19 +28,6 @@ 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 @@ -140,14 +117,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 @@ -199,7 +176,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, e.g., "cainjector.name" which resolves +# these annotations (some resources use eg. "cainjector.name" which resolves # to the value "cainjector"). # +docs:property # nameOverride: "my-cert-manager" @@ -254,10 +231,10 @@ enableCertificateOwnerRef: false # kubernetesAPIBurst: 9000 # numberOfConcurrentWorkers: 200 # enableGatewayAPI: true -# # Feature gates as of v1.18.1. Listed with their default values. +# # Feature gates as of v1.17.0. Listed with their default values. # # See https://cert-manager.io/docs/cli/controller/ # featureGates: -# AdditionalCertificateOutputFormats: true # GA - default=true +# AdditionalCertificateOutputFormats: true # BETA - default=true # AllAlpha: false # ALPHA - default=false # AllBeta: false # BETA - default=false # ExperimentalCertificateSigningRequestControllers: false # ALPHA - default=false @@ -269,10 +246,8 @@ enableCertificateOwnerRef: false # ServerSideApply: false # ALPHA - default=false # StableCertificateRequestName: true # BETA - default=true # UseCertificateRequestBasicConstraints: false # ALPHA - default=false -# UseDomainQualifiedFinalizer: true # GA - default=true +# UseDomainQualifiedFinalizer: true # BETA - default=false # 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: @@ -303,7 +278,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, e.g., you are using approver-policy, you can enable 'disableAutoApproval'. +# because eg. you are using approver-policy, you can enable 'disableAutoApproval'. # ref: https://cert-manager.io/docs/concepts/certificaterequest/#approval # +docs:property approveSignerNames: @@ -459,6 +434,7 @@ 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: @@ -526,7 +502,7 @@ prometheus: # ServiceMonitor resource. # 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 + # Note that you can not enable both PodMonitor and ServiceMonitor as they are # mutually exclusive. Enabling both will result in an error. enabled: true @@ -546,8 +522,7 @@ prometheus: # The target port to set on the ServiceMonitor. This must match the port that the # cert-manager controller is listening on for metrics. - # +docs:type=string,integer - targetPort: http-metrics + targetPort: 9402 # The path to scrape for metrics. path: /metrics @@ -581,7 +556,7 @@ prometheus: # +docs:property endpointAdditionalProperties: {} - # Note that you cannot enable both PodMonitor and ServiceMonitor as they are mutually exclusive. Enabling both will result in an error. + # 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 @@ -731,14 +706,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 @@ -984,8 +959,6 @@ 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. @@ -1007,8 +980,6 @@ webhook: to: - ipBlock: cidr: 0.0.0.0/0 - - ipBlock: - cidr: "::/0" # Additional volumes to add to the cert-manager controller pod. volumes: [] @@ -1102,14 +1073,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 e69de29b..5accf95f 100644 --- a/packages/system/cert-manager/values.yaml +++ b/packages/system/cert-manager/values.yaml @@ -0,0 +1,2 @@ +cert-manager: + installCRDs: false diff --git a/packages/system/cilium-networkpolicy/Makefile b/packages/system/cilium-networkpolicy/Makefile index a24a54b5..c81b87e9 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 ../../../hack/common-envs.mk -include ../../../hack/package.mk +include ../../../scripts/common-envs.mk +include ../../../scripts/package.mk diff --git a/packages/system/cilium/Makefile b/packages/system/cilium/Makefile index 71b47a77..4d1c6ae7 100644 --- a/packages/system/cilium/Makefile +++ b/packages/system/cilium/Makefile @@ -3,24 +3,15 @@ CILIUM_TAG=$(shell awk '$$1 == "version:" {print $$2}' charts/cilium/Chart.yaml) export NAME=cilium export NAMESPACE=cozy-$(NAME) -include ../../../hack/common-envs.mk -include ../../../hack/package.mk +include ../../../scripts/common-envs.mk +include ../../../scripts/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.19 + helm pull cilium/cilium --untar --untardir charts --version 1.18 $(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_INPLACE) "s/ARG VERSION=.*/ARG VERSION=v$${version}/" images/cilium/Dockerfile diff --git a/packages/system/cilium/charts/cilium/Chart.yaml b/packages/system/cilium/charts/cilium/Chart.yaml index 5fe2baed..479d2347 100644 --- a/packages/system/cilium/charts/cilium/Chart.yaml +++ b/packages/system/cilium/charts/cilium/Chart.yaml @@ -41,8 +41,11 @@ annotations: 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 + 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 @@ -76,7 +79,7 @@ annotations: Cilium Gateway Class Config\n description: |\n CiliumGatewayClassConfig defines a configuration for Gateway API GatewayClass.\n" apiVersion: v2 -appVersion: 1.19.3 +appVersion: 1.18.5 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 @@ -92,4 +95,4 @@ kubeVersion: '>= 1.21.0-0' name: cilium sources: - https://github.com/cilium/cilium -version: 1.19.3 +version: 1.18.5 diff --git a/packages/system/cilium/charts/cilium/README.md b/packages/system/cilium/charts/cilium/README.md index d7697c56..4244e8e0 100644 --- a/packages/system/cilium/charts/cilium/README.md +++ b/packages/system/cilium/charts/cilium/README.md @@ -1,6 +1,6 @@ # cilium -![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) +![Version: 1.18.5](https://img.shields.io/badge/Version-1.18.5-informational?style=flat-square) ![AppVersion: 1.18.5](https://img.shields.io/badge/AppVersion-1.18.5-informational?style=flat-square) Cilium is open source software for providing and transparently securing network connectivity and loadbalancing between application workloads such as @@ -59,14 +59,10 @@ 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 | `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.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.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 | @@ -77,7 +73,7 @@ contributors across the globe, there is almost always someone available to help. | authentication.mutual.spire.enabled | bool | `false` | Enable SPIRE integration (beta) | | authentication.mutual.spire.install.agent.affinity | object | `{}` | SPIRE agent affinity configuration | | authentication.mutual.spire.install.agent.annotations | object | `{}` | SPIRE agent annotations | -| authentication.mutual.spire.install.agent.image | object | `{"digest":"sha256:5106ac601272a88684db14daf7f54b9a45f31f77bb16a906bd5e87756ee7b97c","override":null,"pullPolicy":"IfNotPresent","repository":"ghcr.io/spiffe/spire-agent","tag":"1.9.6","useDigest":true}` | SPIRE agent image | +| authentication.mutual.spire.install.agent.image | object | `{"digest":"sha256:163970884fba18860cac93655dc32b6af85a5dcf2ebb7e3e119a10888eff8fcd","override":null,"pullPolicy":"IfNotPresent","repository":"ghcr.io/spiffe/spire-agent","tag":"1.12.4","useDigest":true}` | SPIRE agent image | | authentication.mutual.spire.install.agent.labels | object | `{}` | SPIRE agent labels | | authentication.mutual.spire.install.agent.nodeSelector | object | `{}` | SPIRE agent nodeSelector configuration ref: ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector | | authentication.mutual.spire.install.agent.podSecurityContext | object | `{}` | Security context to be added to spire agent pods. SecurityContext holds pod-level security attributes and common container settings. ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod | @@ -89,7 +85,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: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.initImage | object | `{"digest":"sha256:d80cd694d3e9467884fcb94b8ca1e20437d8a501096cdf367a5a1918a34fc2fd","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 | @@ -99,7 +95,7 @@ contributors across the globe, there is almost always someone available to help. | authentication.mutual.spire.install.server.dataStorage.enabled | bool | `true` | Enable SPIRE server data storage | | authentication.mutual.spire.install.server.dataStorage.size | string | `"1Gi"` | Size of the SPIRE server data storage | | authentication.mutual.spire.install.server.dataStorage.storageClass | string | `nil` | StorageClass of the SPIRE server data storage | -| authentication.mutual.spire.install.server.image | object | `{"digest":"sha256:59a0b92b39773515e25e68a46c40d3b931b9c1860bc445a79ceb45a805cab8b4","override":null,"pullPolicy":"IfNotPresent","repository":"ghcr.io/spiffe/spire-server","tag":"1.9.6","useDigest":true}` | SPIRE server image | +| authentication.mutual.spire.install.server.image | object | `{"digest":"sha256:34147f27066ab2be5cc10ca1d4bfd361144196467155d46c45f3519f41596e49","override":null,"pullPolicy":"IfNotPresent","repository":"ghcr.io/spiffe/spire-server","tag":"1.12.4","useDigest":true}` | SPIRE server image | | authentication.mutual.spire.install.server.initContainers | list | `[]` | SPIRE server init containers | | authentication.mutual.spire.install.server.labels | object | `{}` | SPIRE server labels | | authentication.mutual.spire.install.server.nodeSelector | object | `{}` | SPIRE server nodeSelector configuration ref: ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector | @@ -118,14 +114,13 @@ 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. | -| 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,"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 | 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 CiliumBGPPeeringPolicy CRDs. | | bgpControlPlane.enabled | bool | `false` | Enables the BGP control plane. | -| bgpControlPlane.legacyOriginAttribute | object | `{"enabled":false}` | Legacy BGP ORIGIN attribute settings | +| bgpControlPlane.legacyOriginAttribute | object | `{"enabled":false}` | Legacy BGP ORIGIN attribute settings (BGPv2 only) | | 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. | @@ -133,20 +128,20 @@ contributors across the globe, there is almost always someone available to help. | 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 | -| 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. | +| 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. | | 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). Note netkit is incompatible with TPROXY (`bpf.tproxy`). | +| bpf.datapathMode | string | `veth` | Mode for Pod devices for the core datapath (veth, netkit, netkit-l2) | | 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. | +| bpf.events.default | object | `{"burstLimit":null,"rateLimit":null}` | Default settings for all types of events except dbg and pcap. | | 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. | @@ -163,23 +158,19 @@ 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. Note this is incompatible with netkit (`bpf.datapathMode=netkit`, `bpf.datapathMode=netkit-l2`). | +| bpf.tproxy | bool | `false` | Configure the eBPF-based TPROXY (beta) to reduce reliance on iptables rules for implementing Layer 7 policy. | | 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":{}},"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 | object | `{"affinity":{},"annotations":{"cronJob":{},"job":{}},"extraVolumeMounts":[],"extraVolumes":[],"generateCA":true,"image":{"digest":"sha256:2825dbfa6f89cbed882fd1d81e46a56c087e35885825139923aa29eb8aec47a9","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/certgen","tag":"v0.3.1","useDigest":true},"nodeSelector":{},"podLabels":{},"priorityClassName":"","resources":{},"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.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. | @@ -188,7 +179,7 @@ contributors across the globe, there is almost always someone available to help. | 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 | string | `nil` | Seconds after which the completed job pod will be deleted | +| certgen.ttlSecondsAfterFinished | int | `1800` | 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 | @@ -214,7 +205,7 @@ 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:a8136a7615d6c6041d3aa6f2674d17beaec238170d669507ccc05328a778e2b7","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/clustermesh-apiserver","tag":"v1.19.3","useDigest":true}` | Clustermesh API server image. | +| clustermesh.apiserver.image | object | `{"digest":"sha256:952f07c30390847e4d9dfaa19a76c4eca946251ffbc4f6459946570f93ee72f1","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/clustermesh-apiserver","tag":"v1.18.5","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. | @@ -264,65 +255,38 @@ 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. | +| 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.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.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.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.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. 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.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.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 | `[]` | Clusters to be peered in the mesh. @schema type: [object, array] @schema | +| clustermesh.config.clusters | list | `[]` | List of clusters to be peered in the mesh. | | 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. 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.config.enabled | bool | `false` | Enable the Clustermesh explicit configuration. | | 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 (deprecated; use clustermesh.mcsapi.enabled) | +| clustermesh.enableMCSAPISupport | bool | `false` | Enable Multi-Cluster Services API support | | 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.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. | +| clustermesh.policyDefaultLocalCluster | bool | `false` | Control whether policy rules assume by default the local cluster if not explicitly selected | +| clustermesh.useAPIServer | bool | `false` | Deploy clustermesh-apiserver for clustermesh | | 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. | @@ -337,17 +301,15 @@ contributors across the globe, there is almost always someone available to help. | 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 | `{"limits":{"cpu":1,"memory":"1Gi"},"requests":{"cpu":"100m","memory":"10Mi"}}` | Specifies the resources for the cni initContainer | +| cni.resources | object | `{"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. | @@ -356,8 +318,8 @@ contributors across the globe, there is almost always someone available to help. | 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.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 | +| 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 | | 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 | @@ -376,13 +338,12 @@ contributors across the globe, there is almost always someone available to help. | egressGateway.reconciliationTriggerInterval | string | `"1s"` | Time between triggers of egress gateway state reconciliations | | 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` unless ipam eni mode is active | 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 | | 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 | | 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. | @@ -394,39 +355,14 @@ 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":"","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.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.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 | @@ -437,24 +373,12 @@ 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. | | 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. | @@ -470,8 +394,7 @@ contributors across the globe, there is almost always someone available to help. | 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: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.image | object | `{"digest":"sha256:3108521821c6922695ff1f6ef24b09026c94b195283f8bfbfc0fa49356a156e1","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium-envoy","tag":"v1.34.12-1765374555-6a93b0bbba8d6dc75b651cbafeedb062b2997716","useDigest":true}` | Envoy container image. | | 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 | @@ -483,7 +406,6 @@ 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 | @@ -517,7 +439,6 @@ contributors across the globe, there is almost always someone available to help. | 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. | @@ -561,13 +482,12 @@ contributors across the globe, there is almost always someone available to help. | 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":[{"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 | object | `{"dynamic":{"config":{"configMapName":"cilium-flowlog-config","content":[{"excludeFilters":[],"fieldMask":[],"fileCompress":false,"fileMaxBackups":5,"fileMaxSizeMb":10,"filePath":"/var/run/cilium/hubble/events.log","includeFilters":[],"name":"all"}],"createConfigMap":true},"enabled":false},"static":{"allowList":[],"denyList":[],"enabled":false,"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":[{"excludeFilters":[],"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 | `[{"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.content | list | `[{"excludeFilters":[],"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.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 | object | `{"allowList":[],"denyList":[],"enabled":false,"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.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. | @@ -615,12 +535,9 @@ contributors across the globe, there is almost always someone available to help. | 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:5ee21d57b6ef2aa6db67e603a735fdceb162454b352b7335b651456e308f681b","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/hubble-relay","tag":"v1.19.3","useDigest":true}` | Hubble-relay container image. | +| hubble.relay.image | object | `{"digest":"sha256:17212962c92ff52384f94e407ffe3698714fcbd35c7575f67f24032d6224e446","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/hubble-relay","tag":"v1.18.5","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/ | @@ -630,9 +547,7 @@ contributors across the globe, there is almost always someone available to help. | hubble.relay.podLabels | object | `{}` | Labels to be added to hubble-relay pods | | 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,"scrapeTimeout":null}}` | Enable prometheus metrics for hubble-relay on the configured port at /metrics | @@ -726,14 +641,13 @@ 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. | | 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. | +| image | object | `{"digest":"sha256:2c92fb05962a346eaf0ce11b912ba434dc10bd54b9989e970416681f4a069628","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium","tag":"v1.18.5","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. | @@ -768,11 +682,6 @@ 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. | @@ -821,13 +730,12 @@ 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","l7":{"algorithm":"round_robin","backend":"disabled","ports":[]},"serviceTopology":false}` | Configure service load balancing | +| loadBalancer | object | `{"acceleration":"disabled","l7":{"algorithm":"round_robin","backend":"disabled","ports":[]}}` | 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.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. | -| 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) | @@ -836,18 +744,19 @@ contributors across the globe, there is almost always someone available to help. | monitor | object | `{"enabled":false}` | cilium-monitor sidecar. | | monitor.enabled | bool | `false` | Enable the cilium-monitor sidecar. | | name | string | `"cilium"` | Agent daemonset name. | -| namespaceOverride | string | `""` | namespaceOverride allows to override the destination namespace for Cilium resources. | +| 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. | | 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 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}` | Configure N-S k8s service loadbalancing | +| nodePort | object | `{"addresses":null,"autoProtectPortRange":true,"bindProtection":true,"enableHealthCheck":true,"enableHealthCheckLoadBalancerIP":false,"enabled":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 | @@ -857,7 +766,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:50b9cf9c280096b59b80d2fc8ee6638facef79ac18998a22f0cbc40d5d28c16f","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/startup-script","tag":"1763560095-8f36c34","useDigest":true}` | node-init image. | +| nodeinit.image | object | `{"digest":"sha256:5bdca3c2dec2c79f58d45a7a560bf1098c2126350c901379fe850b7f78d3d757","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/startup-script","tag":"1755531540-60ee83e","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. | @@ -870,7 +779,6 @@ contributors across the globe, there is almost always someone available to help. | 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 | @@ -885,7 +793,7 @@ 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: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.image | object | `{"alibabacloudDigest":"sha256:2e60f635495eb2837296ced5475875c281a05765d5ddd644a05e126bbb080b3c","awsDigest":"sha256:7608025d8b727a10f21d924d8e4f40beb176cefd690320433452816ad8776f52","azureDigest":"sha256:126667e000267f893cb81042bf8a710ad2f219619eb9ce06e8949333bd325ac6","genericDigest":"sha256:36c3f6f14c8ced7f45b40b0a927639894b44269dd653f9528e7a0dc363a4eb99","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/operator","suffix":"","tag":"v1.18.5","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 | @@ -896,12 +804,10 @@ contributors across the globe, there is almost always someone available to help. | operator.podLabels | object | `{}` | Labels 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,"scrapeTimeout":null},"tls":{"enabled":false,"server":{"existingSecret":"","mtls":{"enabled":false}}}}` | 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}}` | 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. | @@ -910,8 +816,6 @@ contributors across the globe, there is almost always someone available to help. | 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/ | @@ -924,30 +828,25 @@ contributors across the globe, there is almost always someone available to help. | 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"},"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.envoy.image | object | `{"digest":"sha256:3108521821c6922695ff1f6ef24b09026c94b195283f8bfbfc0fa49356a156e1","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium-envoy","tag":"v1.34.12-1765374555-6a93b0bbba8d6dc75b651cbafeedb062b2997716","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:2e61680593cddca8b6c055f6d4c849d87a26a1c91c7e3b8b56c7fb76ab7b7b10","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium","tag":"v1.19.3","useDigest":true}` | Cilium pre-flight image. | +| preflight.image | object | `{"digest":"sha256:2c92fb05962a346eaf0ce11b912ba434dc10bd54b9989e970416681f4a069628","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium","tag":"v1.18.5","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/ | @@ -991,37 +890,24 @@ contributors across the globe, there is almost always someone available to help. | 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","SYSLOG"]` | 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"]` | 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 | -| 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. | @@ -1043,12 +929,11 @@ 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" | +| underlayProtocol | string | `"ipv4"` | IP family for the underlay. | | 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-envoy/configmap/bootstrap-config.yaml b/packages/system/cilium/charts/cilium/files/cilium-envoy/configmap/bootstrap-config.yaml index 90ebf4ac..52439049 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 @@ -167,8 +167,6 @@ 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: @@ -185,8 +183,6 @@ 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: @@ -208,8 +204,6 @@ 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: @@ -226,8 +220,6 @@ 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: @@ -300,7 +292,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: "{{ .Values.envoy.maxGlobalDownstreamConnections }}" + max_active_downstream_connections: "50000" applicationLogConfig: logFormat: {{- if .Values.envoy.log.format_json }} @@ -312,4 +304,3 @@ 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 68e6b50b..aa63cac8 100644 --- a/packages/system/cilium/charts/cilium/files/nodeinit/startup.bash +++ b/packages/system/cilium/charts/cilium/files/nodeinit/startup.bash @@ -156,14 +156,6 @@ 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/_extensions.tpl b/packages/system/cilium/charts/cilium/templates/_extensions.tpl index 8c0e5c20..bd8ba80b 100644 --- a/packages/system/cilium/charts/cilium/templates/_extensions.tpl +++ b/packages/system/cilium/charts/cilium/templates/_extensions.tpl @@ -21,24 +21,6 @@ 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 @@ -90,87 +72,3 @@ 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 e90aa482..ba91c353 100644 --- a/packages/system/cilium/charts/cilium/templates/_helpers.tpl +++ b/packages/system/cilium/charts/cilium/templates/_helpers.tpl @@ -131,16 +131,12 @@ To override the namespace and configMap when using `auto`: {{- define "k8sServiceHost" }} {{- $configmapName := default "cluster-info" .Values.k8sServiceLookupConfigMapName }} {{- $configmapNamespace := default "kube-public" .Values.k8sServiceLookupNamespace }} - {{- if eq .Values.k8sServiceHost "auto" }} + {{- if and (eq .Values.k8sServiceHost "auto") (lookup "v1" "ConfigMap" $configmapNamespace $configmapName) }} {{- $configmap := (lookup "v1" "ConfigMap" $configmapNamespace $configmapName) }} - {{- 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 }} + {{- $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 }} {{- .Values.k8sServiceHost | quote }} {{- 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 57b13447..eaca204e 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-agent/clusterrole.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-agent/clusterrole.yaml @@ -94,6 +94,7 @@ rules: - 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 fff1b384..c706da51 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-agent/daemonset.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-agent/daemonset.yaml @@ -10,7 +10,6 @@ {{- $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 @@ -57,6 +56,19 @@ 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 }} @@ -122,7 +134,7 @@ spec: httpGet: host: {{ .Values.ipv4.enabled | ternary "127.0.0.1" "::1" | quote }} path: /healthz - port: health + port: {{ .Values.healthPort }} scheme: HTTP httpHeaders: - name: "brief" @@ -142,7 +154,7 @@ spec: httpGet: host: {{ .Values.ipv4.enabled | ternary "127.0.0.1" "::1" | quote }} path: /healthz - port: health + port: {{ .Values.healthPort }} scheme: HTTP httpHeaders: - name: "brief" @@ -165,7 +177,7 @@ spec: httpGet: host: {{ .Values.ipv4.enabled | ternary "127.0.0.1" "::1" | quote }} path: /healthz - port: health + port: {{ .Values.healthPort }} scheme: HTTP httpHeaders: - name: "brief" @@ -238,17 +250,12 @@ 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 }} @@ -273,6 +280,7 @@ spec: hostPort: {{ .Values.hubble.metrics.port }} protocol: TCP {{- end }} + {{- end }} securityContext: {{- if .Values.securityContext.privileged }} privileged: true @@ -367,10 +375,6 @@ 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 }} @@ -386,14 +390,8 @@ 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 }} @@ -449,7 +447,6 @@ spec: {{- toYaml .Values.extraContainers | nindent 6 }} {{- end }} initContainers: - {{- if $buildDaemonConfig }} - name: config image: {{ include "cilium.image" .Values.image | quote }} imagePullPolicy: {{ .Values.image.pullPolicy }} @@ -516,17 +513,6 @@ 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. @@ -538,15 +524,12 @@ spec: value: {{ .Values.cgroup.hostRoot }} - name: BIN_PATH value: {{ .Values.cni.binPath }} - {{- if .Values.cgroup.autoMount.resources }} + {{- with .Values.cgroup.autoMount.resources }} resources: - {{- toYaml .Values.cgroup.autoMount.resources | trim | nindent 10 }} - {{- else if .Values.initResources }} - resources: - {{- toYaml .Values.initResources | trim | nindent 10 }} + {{- toYaml . | trim | nindent 10 }} {{- end }} command: - - bash + - sh - -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 @@ -592,7 +575,7 @@ spec: - name: BIN_PATH value: {{ .Values.cni.binPath }} command: - - bash + - sh - -ec # The statically linked Go program binary is invoked to avoid any # dependency on utilities like sh that can be missing on certain @@ -660,7 +643,7 @@ spec: {{- toYaml . | trim | nindent 10 }} {{- end }} command: - - bash + - sh - -c - | until test -s {{ (print "/tmp/cilium-bootstrap.d/" (.Values.nodeinit.bootstrapFile | base)) | quote }}; do @@ -838,7 +821,7 @@ spec: {{- end }} {{- if and .Values.clustermesh.config.enabled (not (and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.kvstoremesh.enabled )) }} hostAliases: - {{- range $_, $cluster := (include "clustermesh-clusters" . | fromJson) }} + {{- range $cluster := .Values.clustermesh.config.clusters }} {{- range $ip := $cluster.ips }} - ip: {{ $ip }} hostnames: [ "{{ $cluster.name }}.{{ $.Values.clustermesh.config.domain }}" ] @@ -846,20 +829,9 @@ spec: {{- end }} {{- end }} volumes: - {{- if $buildDaemonConfig }} - # For sharing configuration between the "config" initContainer and the agent + # 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: @@ -1020,11 +992,6 @@ 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: 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 df60d89b..89266e0d 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.agent (not .Values.preflight.enabled) .Values.serviceAccounts.cilium.create $readSecretsOnlyFromSecretsNamespace .Values.tls.secretsNamespace.name }} +{{- if and .Values.operator.enabled .Values.serviceAccounts.operator.create $readSecretsOnlyFromSecretsNamespace .Values.tls.secretsNamespace.name }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role 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 5caf2f15..c76350b3 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-agent/rolebinding.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-agent/rolebinding.yaml @@ -126,7 +126,7 @@ subjects: namespace: {{ include "cilium.namespace" . }} {{- end}} -{{- if and .Values.agent (not .Values.preflight.enabled) .Values.serviceAccounts.cilium.create $readSecretsOnlyFromSecretsNamespace .Values.tls.secretsNamespace.name }} +{{- if and (not .Values.preflight.enabled) $readSecretsOnlyFromSecretsNamespace .Values.tls.secretsNamespace.name }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding 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 91569863..7dd15d02 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-ca-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-ca-secret.yaml @@ -11,13 +11,8 @@ kind: Secret metadata: name: {{ .commonCASecretName }} namespace: {{ include "cilium.namespace" . }} - labels: {{- with .Values.commonLabels }} - {{- toYaml . | nindent 4 }} - {{- end }} - cilium.io/helm-template-non-idempotent: "true" - {{- with .Values.nonIdempotentAnnotations }} - annotations: + labels: {{- 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 5d76944d..a9bb1cd9 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-configmap.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-configmap.yaml @@ -33,6 +33,12 @@ {{- 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 */ -}} @@ -46,6 +52,7 @@ {{- if .Values.azure.enabled }} {{- $azureUsePrimaryAddress = "false" -}} {{- end }} + {{- $defaultKubeProxyReplacement = "disabled" -}} {{- $defaultDNSProxyEnableTransparentMode = "true" -}} {{- end -}} @@ -64,10 +71,6 @@ {{- 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) -}} @@ -255,14 +258,6 @@ 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" @@ -461,12 +456,6 @@ 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 @@ -516,7 +505,7 @@ data: cluster-name: {{ .Values.cluster.name | quote }} {{- if hasKey .Values.cluster "id" }} - # Unique ID of the cluster. Must be unique across all connected clusters and + # Unique ID of the cluster. Must be unique across all conneted clusters and # in the range of 1 and 255. Only relevant when building a mesh of clusters. cluster-id: "{{ .Values.cluster.id }}" {{- end }} @@ -537,7 +526,7 @@ data: {{- end }} {{- end }} - routing-mode: {{ .Values.routingMode | default (ternary "native" "tunnel" (or .Values.eni.enabled .Values.gke.enabled)) | quote }} + routing-mode: {{ .Values.routingMode | default (ternary "native" "tunnel" .Values.gke.enabled) | quote }} tunnel-protocol: {{ .Values.tunnelProtocol | default "vxlan" | quote }} {{- if eq .Values.routingMode "native" }} @@ -569,10 +558,6 @@ data: service-no-backend-response: "{{ .Values.serviceNoBackendResponse }}" {{- end}} -{{- if .Values.policyDenyResponse }} - policy-deny-response: "{{ .Values.policyDenyResponse }}" -{{- end}} - {{- if .Values.MTU }} mtu: {{ .Values.MTU | quote }} {{- end }} @@ -590,35 +575,6 @@ 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 }} @@ -644,39 +600,17 @@ 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 # @@ -753,8 +687,6 @@ 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 }} @@ -762,20 +694,11 @@ data: {{- end }} {{- if .Values.encryption.strictMode.enabled }} - # --- 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 }} + enable-encryption-strict-mode: {{ .Values.encryption.strictMode.enabled | quote }} -{{- if .Values.encryption.strictMode.ingress.enabled }} - enable-encryption-strict-mode-ingress: {{ .Values.encryption.strictMode.ingress.enabled | quote }} -{{- end }} + encryption-strict-mode-cidr: {{ .Values.encryption.strictMode.cidr | 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 }} + encryption-strict-mode-allow-remote-node-identities: {{ .Values.encryption.strictMode.allowRemoteNodeIdentities | quote }} {{- end }} enable-xt-socket-fallback: {{ .Values.enableXTSocketFallback | quote }} @@ -850,10 +773,6 @@ data: 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 }} @@ -870,6 +789,9 @@ data: {{- end }} {{- if hasKey .Values "nodePort" }} +{{- if 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 }} @@ -908,18 +830,24 @@ data: {{- end }} {{- if hasKey .Values.loadBalancer "serviceTopology" }} enable-service-topology: {{ .Values.loadBalancer.serviceTopology | quote }} -{{- end }} +# {{- 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.bpf.monitorTraceIPOption }} - ip-tracing-option-type: {{ .Values.bpf.monitorTraceIPOption | quote }} +{{- if .Values.sessionAffinity }} + enable-session-affinity: {{ .Values.sessionAffinity | quote }} +{{- end }} +{{- if .Values.svcSourceRangeCheck }} + enable-svc-source-range-check: {{ .Values.svcSourceRangeCheck | quote }} {{- end }} {{- if hasKey .Values "l2NeighDiscovery" }} @@ -932,16 +860,12 @@ data: 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 }} @@ -1049,10 +973,6 @@ 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. @@ -1120,10 +1040,8 @@ data: 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 }} @@ -1160,28 +1078,10 @@ 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 }} @@ -1192,10 +1092,18 @@ 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 }} @@ -1264,11 +1172,20 @@ 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 }} @@ -1305,8 +1222,6 @@ data: enable-pmtu-discovery: "true" {{- end }} - packetization-layer-pmtud-mode: {{ .Values.pmtuDiscovery.packetizationLayerPMTUDMode | quote }} - {{- if not .Values.securityContext.privileged }} procfs: "/host/proc" {{- end }} @@ -1381,16 +1296,11 @@ data: {{- end }} {{- if .Values.operator.unmanagedPodWatcher.restart }} - {{- $interval := .Values.operator.unmanagedPodWatcher.intervalSeconds }} - unmanaged-pod-watcher-interval: {{ printf "%ds" (int $interval) | quote }} + unmanaged-pod-watcher-interval: {{ .Values.operator.unmanagedPodWatcher.intervalSeconds | 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 @@ -1460,14 +1370,10 @@ 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 }} @@ -1496,14 +1402,13 @@ 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: {{ (or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport) | quote }} - clustermesh-mcs-api-install-crds: {{ .Values.clustermesh.mcsapi.installCRDs | quote }} + clustermesh-enable-mcs-api: {{ .Values.clustermesh.enableMCSAPISupport | 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 }} @@ -1515,14 +1420,6 @@ data: 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 4511e7ad..91c981cb 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 $envoyDS }} --- 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 2afc2e97..a5decd02 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-envoy/daemonset.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-envoy/daemonset.yaml @@ -22,7 +22,10 @@ spec: selector: matchLabels: k8s-app: cilium-envoy - {{- include "envoy.updateStrategy" . | nindent 2 }} + {{- with .Values.envoy.updateStrategy }} + updateStrategy: + {{- toYaml . | trim | nindent 4 }} + {{- end }} template: metadata: annotations: @@ -66,7 +69,6 @@ spec: securityContext: {{- toYaml . | nindent 8 }} {{- end }} - {{- include "envoy.initContainers" . | nindent 6 }} containers: - name: cilium-envoy image: {{ include "cilium.image" .Values.envoy.image | quote }} @@ -92,7 +94,6 @@ 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 }} @@ -156,7 +157,6 @@ spec: - name: KUBERNETES_SERVICE_PORT value: {{ include "k8sServicePort" . }} {{- end }} - {{- include "envoy.env.extra" . | nindent 8 }} {{- with .Values.envoy.extraEnv }} {{- toYaml . | trim | nindent 8 }} {{- end }} @@ -164,7 +164,19 @@ spec: resources: {{- toYaml . | trim | nindent 10 }} {{- end }} - {{- include "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 }} securityContext: {{- if .Values.envoy.securityContext.privileged }} privileged: true @@ -197,7 +209,6 @@ spec: mountPath: /sys/fs/bpf mountPropagation: HostToContainer {{- end }} - {{- include "envoy.volumeMounts.extra" . | nindent 8 }} {{- range .Values.envoy.extraHostPathMounts }} - name: {{ .name }} mountPath: {{ .mountPath }} @@ -221,7 +232,10 @@ spec: {{- if .Values.envoy.dnsPolicy }} dnsPolicy: {{ .Values.envoy.dnsPolicy }} {{- end }} - {{- include "envoy.affinity" . | nindent 6 }} + {{- with .Values.envoy.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} {{- with .Values.envoy.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} @@ -255,7 +269,6 @@ 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 8da47943..6b982c28 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: {{ .Values.envoy.prometheus.port }} + targetPort: envoy-metrics {{- 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 f25afeee..5d16d7ca 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-ingress-service.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-ingress-service.yaml @@ -49,8 +49,8 @@ spec: externalTrafficPolicy: {{ .Values.ingressController.service.externalTrafficPolicy }} {{- end }} --- -apiVersion: discovery.k8s.io/v1 -kind: EndpointSlice +apiVersion: v1 +kind: Endpoints metadata: name: {{ .Values.ingressController.service.name }} namespace: {{ include "cilium.namespace" . }} @@ -65,10 +65,9 @@ metadata: annotations: {{- toYaml .Values.ingressController.service.annotations | nindent 4 }} {{- end }} -addressType: IPv4 -endpoints: +subsets: - addresses: - - "192.192.192.192" -ports: -- port: 9999 + - ip: "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 4edbeada..add6ae5a 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-nodeinit/daemonset.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-nodeinit/daemonset.yaml @@ -122,8 +122,6 @@ 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 c147e2b5..4fcb5985 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 or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} +{{- if or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.enableMCSAPISupport }} - create - update - delete @@ -78,17 +78,6 @@ 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: @@ -125,20 +114,6 @@ 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: - "" @@ -252,6 +227,7 @@ rules: - update resourceNames: - ciliumloadbalancerippools.cilium.io + - ciliumbgppeeringpolicies.cilium.io - ciliumbgpclusterconfigs.cilium.io - ciliumbgppeerconfigs.cilium.io - ciliumbgpadvertisements.cilium.io @@ -272,15 +248,12 @@ rules: - 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 @@ -328,10 +301,6 @@ 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 }} @@ -383,7 +352,7 @@ rules: - update - patch {{- end }} -{{- if or .Values.gatewayAPI.enabled .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} +{{- if or .Values.gatewayAPI.enabled .Values.clustermesh.enableMCSAPISupport }} - apiGroups: - multicluster.x-k8s.io resources: @@ -392,14 +361,14 @@ rules: - get - list - watch -{{- if or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} +{{- if .Values.clustermesh.enableMCSAPISupport }} - create - update - patch - delete {{- end }} {{- end }} -{{- if or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} +{{- if .Values.clustermesh.enableMCSAPISupport }} - apiGroups: - multicluster.x-k8s.io resources: @@ -407,15 +376,6 @@ 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: @@ -441,10 +401,4 @@ 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 f4cddff8..606807f3 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.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} + {{- if or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.enableMCSAPISupport }} - name: CILIUM_CLUSTERMESH_CONFIG value: /var/lib/cilium/clustermesh/ {{- end }} @@ -170,7 +170,6 @@ spec: - name: AZURE_RESOURCE_GROUP value: {{ .Values.azure.resourceGroup }} {{- end }} - {{- if .Values.azure.clientID }} - name: AZURE_CLIENT_ID valueFrom: secretKeyRef: @@ -182,15 +181,11 @@ spec: name: cilium-azure key: AZURE_CLIENT_SECRET {{- end }} - {{- end }} {{- with .Values.operator.extraEnv }} {{- toYaml . | nindent 8 }} {{- end }} - ports: - - name: health - containerPort: 9234 - hostPort: 9234 {{- if .Values.operator.prometheus.enabled }} + ports: - name: prometheus containerPort: {{ .Values.operator.prometheus.port }} {{- if .Values.operator.hostNetwork }} @@ -204,7 +199,7 @@ spec: host: {{ .Values.ipv4.enabled | ternary "127.0.0.1" "::1" | quote }} {{- end }} path: /healthz - port: health + port: 9234 scheme: HTTP initialDelaySeconds: 60 periodSeconds: 10 @@ -215,7 +210,7 @@ spec: host: {{ .Values.ipv4.enabled | ternary "127.0.0.1" "::1" | quote }} {{- end }} path: /healthz - port: health + port: 9234 scheme: HTTP initialDelaySeconds: 0 periodSeconds: 5 @@ -235,7 +230,7 @@ spec: readOnly: true {{- end }} {{- end }} - {{- if or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} + {{- if or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.enableMCSAPISupport }} - name: clustermesh-secrets mountPath: /var/lib/cilium/clustermesh readOnly: true @@ -250,11 +245,6 @@ 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 }} @@ -266,15 +256,13 @@ 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 }} - {{- $sc := include "cilium.operator.securityContext" . | trim }} - {{- if $sc }} + {{- with .Values.operator.securityContext }} securityContext: - {{- $sc | nindent 10 }} + {{- toYaml . | trim | nindent 10 }} {{- end }} terminationMessagePolicy: FallbackToLogsOnError hostNetwork: {{ .Values.operator.hostNetwork }} @@ -307,25 +295,23 @@ spec: nodeSelector: {{- toYaml . | trim | nindent 8 }} {{- end }} - {{- 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 )) }} + {{- if and (or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.enableMCSAPISupport) .Values.clustermesh.config.enabled (not (and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.kvstoremesh.enabled )) }} hostAliases: - {{- range $_, $cluster := (include "clustermesh-clusters" . | fromJson) }} + {{- range $cluster := .Values.clustermesh.config.clusters }} {{- range $ip := $cluster.ips }} - ip: {{ $ip }} hostnames: [ "{{ $cluster.name }}.{{ $.Values.clustermesh.config.domain }}" ] {{- end }} {{- end }} {{- end }} - {{- if or (.Values.operator.tolerations) (hasKey .Values "agentNotReadyTaintKey") }} - tolerations: {{- with .Values.operator.tolerations }} + 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 @@ -374,7 +360,7 @@ spec: {{- with .Values.operator.extraVolumes }} {{- toYaml . | nindent 6 }} {{- end }} - {{- if or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} + {{- if or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.enableMCSAPISupport }} # To read the clustermesh configuration - name: clustermesh-secrets projected: @@ -431,25 +417,4 @@ 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/role.yaml b/packages/system/cilium/charts/cilium/templates/cilium-operator/role.yaml index 11515ced..8f7acd9f 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-operator/role.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-operator/role.yaml @@ -83,35 +83,3 @@ 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 22ac17bc..56b89209 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-operator/rolebinding.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-operator/rolebinding.yaml @@ -77,29 +77,3 @@ subjects: name: {{ .Values.serviceAccounts.operator.name | quote }} 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 6346e136..4ac55d7a 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-operator/secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-operator/secret.yaml @@ -1,6 +1,5 @@ {{- if .Values.operator.enabled }} {{- if .Values.azure.enabled }} -{{- if .Values.azure.clientID }} apiVersion: v1 kind: Secret metadata: @@ -20,4 +19,3 @@ data: AZURE_CLIENT_SECRET: {{ default "" .Values.azure.clientSecret | b64enc | quote }} {{- end }} {{- end }} -{{- end }} 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 fbf511cd..bf0f07da 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrole.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrole.yaml @@ -94,6 +94,7 @@ rules: - cilium.io resources: - ciliumloadbalancerippools + - ciliumbgppeeringpolicies - ciliumbgpnodeconfigs - ciliumbgpadvertisements - ciliumbgppeerconfigs 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 b5418fe5..17c39a41 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-preflight/daemonset.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-preflight/daemonset.yaml @@ -213,6 +213,9 @@ spec: - name: envoy-artifacts mountPath: /var/run/cilium/envoy/artifacts readOnly: true + - name: envoy-config + mountPath: /var/run/cilium/envoy/ + readOnly: true {{- with .Values.preflight.resources }} resources: {{- toYaml . | trim | nindent 12 }} @@ -277,6 +280,14 @@ spec: hostPath: path: "{{ .Values.daemon.runPath }}/envoy/artifacts" type: DirectoryOrCreate + - name: envoy-config + configMap: + name: {{ .Values.envoy.bootstrapConfigMap | default "cilium-envoy-config" | quote }} + # note: the leading zero means this number is in octal representation: do not remove it + defaultMode: 0400 + items: + - key: bootstrap-config.json + path: bootstrap-config.json {{- end }} {{- with .Values.preflight.extraVolumes }} {{- toYaml . | nindent 6 }} 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 600ccfeb..944b0629 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-secrets-namespace.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-secrets-namespace.yaml @@ -20,9 +20,6 @@ metadata: {{- with $.Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} - {{- with $.Values.secretsNamespaceLabels }} - {{- toYaml . | nindent 4 }} - {{- end }} annotations: {{- with $.Values.secretsNamespaceAnnotations }} {{- toYaml . | nindent 4 }} 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 88288eb8..8565f585 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrole.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrole.yaml @@ -50,7 +50,7 @@ rules: - get - list - watch -{{- if or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} +{{- if .Values.clustermesh.enableMCSAPISupport }} - apiGroups: - multicluster.x-k8s.io resources: 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 1146209a..b0366e3b 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/deployment.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/deployment.yaml @@ -137,7 +137,6 @@ spec: - --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://0.0.0.0:{{ .Values.clustermesh.apiserver.metrics.etcd.port }} - --metrics={{ .Values.clustermesh.apiserver.metrics.etcd.mode }} @@ -209,13 +208,12 @@ spec: - --prometheus-serve-addr=:{{ .Values.clustermesh.apiserver.metrics.port }} - --controller-group-metrics=all {{- end }} - {{- if or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} + {{- if .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 }} @@ -305,14 +303,12 @@ spec: {{- 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 }} @@ -509,7 +505,7 @@ spec: {{- end }} {{- if and .Values.clustermesh.config.enabled .Values.clustermesh.apiserver.kvstoremesh.enabled }} hostAliases: - {{- range $_, $cluster := (include "clustermesh-clusters" . | fromJson) }} + {{- range $cluster := .Values.clustermesh.config.clusters }} {{- range $ip := $cluster.ips }} - ip: {{ $ip }} hostnames: [ "{{ $cluster.name }}.{{ $.Values.clustermesh.config.domain }}" ] 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 5e20234b..6ef3f63f 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 and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") (not .Values.clustermesh.apiserver.service.externallyCreated) }} +{{- if and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") }} apiVersion: v1 kind: Service metadata: 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 2fdccf47..7ba8cb12 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,18 +9,10 @@ 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 }} @@ -92,7 +84,7 @@ spec: volumeMounts: {{- toYaml . | nindent 10 }} {{- end }} - hostNetwork: false + hostNetwork: true {{- with .Values.certgen.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} @@ -104,6 +96,7 @@ 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 }} @@ -115,11 +108,9 @@ spec: volumes: {{- toYaml . | nindent 6 }} {{- end }} - {{- with .Values.certgen.affinity }} affinity: + {{- with .Values.certgen.affinity }} {{- toYaml . | nindent 8 }} {{- end }} - {{- with .Values.certgen.ttlSecondsAfterFinished }} - ttlSecondsAfterFinished: {{ . }} - {{- end }} + ttlSecondsAfterFinished: {{ .Values.certgen.ttlSecondsAfterFinished }} {{- 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 4b88d92c..ebda21bd 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 @@ -16,8 +16,6 @@ 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 574aee13..72f8dc60 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,18 +1,9 @@ {{- 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-{{$checkSum}} + name: clustermesh-apiserver-generate-certs namespace: {{ include "cilium.namespace" . }} labels: k8s-app: clustermesh-apiserver-generate-certs @@ -20,14 +11,13 @@ 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 }} - {{- end }} -{{ $jobSpec }} +{{ include "clustermesh-apiserver-generate-certs.job.spec" . }} {{- 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 1f6dc153..6e822701 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 @@ -38,6 +38,7 @@ 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-helm/admin-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/admin-secret.yaml index 49325d14..fa49c9ce 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 @@ -8,16 +8,12 @@ kind: Secret metadata: name: clustermesh-apiserver-admin-cert namespace: {{ include "cilium.namespace" . }} - labels: {{- with .Values.commonLabels }} + labels: {{- toYaml . | nindent 4 }} {{- end }} - cilium.io/helm-template-non-idempotent: "true" - annotations: {{- with .Values.clustermesh.annotations }} - {{- toYaml . | nindent 4 }} - {{- end }} - {{- with .Values.nonIdempotentAnnotations }} + annotations: {{- toYaml . | nindent 4 }} {{- end }} type: kubernetes.io/tls 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 3d34bd68..0589a9e7 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 @@ -8,16 +8,12 @@ kind: Secret metadata: name: clustermesh-apiserver-local-cert namespace: {{ include "cilium.namespace" . }} - labels: {{- with .Values.commonLabels }} + labels: {{- toYaml . | nindent 4 }} {{- end }} - cilium.io/helm-template-non-idempotent: "true" - annotations: {{- with .Values.clustermesh.annotations }} - {{- toYaml . | nindent 4 }} - {{- end }} - {{- with .Values.nonIdempotentAnnotations }} + annotations: {{- 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 11bfc51d..42afe0fe 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 @@ -8,16 +8,12 @@ kind: Secret metadata: name: clustermesh-apiserver-remote-cert namespace: {{ include "cilium.namespace" . }} - labels: {{- with .Values.commonLabels }} + labels: {{- toYaml . | nindent 4 }} {{- end }} - cilium.io/helm-template-non-idempotent: "true" - annotations: {{- with .Values.clustermesh.annotations }} - {{- toYaml . | nindent 4 }} - {{- end }} - {{- with .Values.nonIdempotentAnnotations }} + annotations: {{- 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 0df9a20d..e49478cb 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 @@ -10,16 +10,12 @@ kind: Secret metadata: name: clustermesh-apiserver-server-cert namespace: {{ include "cilium.namespace" . }} - labels: {{- with .Values.commonLabels }} + labels: {{- toYaml . | nindent 4 }} {{- end }} - cilium.io/helm-template-non-idempotent: "true" - annotations: {{- with .Values.clustermesh.annotations }} - {{- toYaml . | nindent 4 }} - {{- end }} - {{- with .Values.nonIdempotentAnnotations }} + annotations: {{- toYaml . | nindent 4 }} {{- end }} type: kubernetes.io/tls 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 d742e4e7..c736eb1e 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 - (and .Values.clustermesh.useAPIServer .Values.clustermesh.config.enabled (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") (eq "true" (include "identityAllocationCRD" .))) + (and .Values.clustermesh.useAPIServer (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 (include "clustermesh-clusters" . | fromJson) }} + {{- range .Values.clustermesh.config.clusters }} - 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 abe9bdb8..47c3393c 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-config/_helpers.tpl +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-config/_helpers.tpl @@ -43,26 +43,3 @@ 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 d60d6f1c..5a3a7aa8 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 @@ -18,7 +18,7 @@ data: {{- $kvstoremesh := and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.kvstoremesh.enabled }} {{- $override := ternary (printf "https://clustermesh-apiserver.%s.svc:2379" (include "cilium.namespace" .)) "" $kvstoremesh }} {{- $local_etcd := and $kvstoremesh (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "external") }} - {{- range (include "clustermesh-clusters" . | fromJson) }} + {{- range .Values.clustermesh.config.clusters }} {{ .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 }} 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 2828cfd2..3cdc7828 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,7 +15,7 @@ metadata: {{- toYaml . | nindent 4 }} {{- end }} data: - {{- range (include "clustermesh-clusters" . | fromJson) }} + {{- range .Values.clustermesh.config.clusters }} {{ .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 }} 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 deleted file mode 100644 index 08fcea1b..00000000 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/clusterrole.yaml +++ /dev/null @@ -1,29 +0,0 @@ -{{- 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 deleted file mode 100644 index 7a1867f5..00000000 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/clusterrolebinding.yaml +++ /dev/null @@ -1,28 +0,0 @@ -{{- 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 deleted file mode 100644 index ac339f9f..00000000 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-clusterrole.yaml +++ /dev/null @@ -1,22 +0,0 @@ -{{- 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 deleted file mode 100644 index 4b70ccf4..00000000 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-clusterrolebinding.yaml +++ /dev/null @@ -1,22 +0,0 @@ -{{- 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 deleted file mode 100644 index 52f42fae..00000000 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-role.yaml +++ /dev/null @@ -1,36 +0,0 @@ -{{- 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 deleted file mode 100644 index f5caf1a1..00000000 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-rolebinding.yaml +++ /dev/null @@ -1,23 +0,0 @@ -{{- 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 deleted file mode 100644 index 4e572a13..00000000 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-serviceaccount.yaml +++ /dev/null @@ -1,20 +0,0 @@ -{{- 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 deleted file mode 100644 index 9f9c3ccd..00000000 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job.yaml +++ /dev/null @@ -1,82 +0,0 @@ -{{- 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 9df77bae..26b6219a 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble-relay/configmap.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble-relay/configmap.yaml @@ -29,8 +29,6 @@ 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 }}" @@ -46,10 +44,4 @@ 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-ui/clusterrole.yaml b/packages/system/cilium/charts/cilium/templates/hubble-ui/clusterrole.yaml index ebb8cbd6..b8607bd9 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble-ui/clusterrole.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble-ui/clusterrole.yaml @@ -14,6 +14,14 @@ metadata: {{- end }} rules: +- apiGroups: + - networking.k8s.io + resources: + - networkpolicies + verbs: + - get + - list + - watch - apiGroups: - "" resources: @@ -35,4 +43,12 @@ 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 07a94dce..c3b3dc5a 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: http + port: 8081 readinessProbe: httpGet: path: / - port: http + port: 8081 {{- with .Values.hubble.ui.frontend.resources }} resources: {{- toYaml . | trim | nindent 10 }} @@ -184,12 +184,8 @@ spec: defaultMode: 420 name: hubble-ui-nginx name: hubble-ui-nginx-conf - - name: tmp-dir - {{- if .Values.hubble.ui.tmpVolume }} - {{- toYaml .Values.hubble.ui.tmpVolume | nindent 8 }} - {{- else }} - emptyDir: {} - {{- end }} + - emptyDir: {} + name: tmp-dir {{- 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/tls-cronjob/_job-spec.tpl b/packages/system/cilium/charts/cilium/templates/hubble/tls-cronjob/_job-spec.tpl index 06fb3347..72a1f3d8 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 @@ -137,6 +137,7 @@ 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 }} @@ -148,11 +149,9 @@ spec: volumes: {{- toYaml . | nindent 6 }} {{- end }} - {{- with .Values.certgen.affinity }} affinity: + {{- with .Values.certgen.affinity }} {{- toYaml . | nindent 8 }} {{- end }} - {{- with .Values.certgen.ttlSecondsAfterFinished }} - ttlSecondsAfterFinished: {{ . }} - {{- end }} + ttlSecondsAfterFinished: {{ .Values.certgen.ttlSecondsAfterFinished }} {{- 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 b49c00a6..697806c6 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,8 +23,6 @@ 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 96371916..5e4e67ff 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,18 +1,9 @@ {{- 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-{{$checkSum}} + name: hubble-generate-certs namespace: {{ include "cilium.namespace" . }} labels: k8s-app: hubble-generate-certs @@ -21,14 +12,13 @@ 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 }} - {{- end }} -{{ $jobSpec }} +{{ include "hubble-generate-certs.job.spec" . }} {{- 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 d334b986..0cc13efa 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,17 +10,13 @@ kind: Secret metadata: name: hubble-metrics-server-certs namespace: {{ include "cilium.namespace" . }} - labels: {{- with .Values.commonLabels }} + labels: {{- toYaml . | nindent 4 }} {{- end }} - cilium.io/helm-template-non-idempotent: "true" - annotations: {{- with .Values.hubble.annotations }} - {{- toYaml . | nindent 4 }} - {{- end }} - {{- with .Values.nonIdempotentAnnotations }} + annotations: {{- 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 6f001dc9..fa0c908e 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 @@ -17,17 +17,13 @@ kind: Secret metadata: name: hubble-relay-client-certs namespace: {{ include "cilium.namespace" . }} - labels: {{- with .Values.commonLabels }} + labels: {{- toYaml . | nindent 4 }} {{- end }} - cilium.io/helm-template-non-idempotent: "true" - annotations: {{- with .Values.hubble.annotations }} - {{- toYaml . | nindent 4 }} - {{- end }} - {{- with .Values.nonIdempotentAnnotations }} + annotations: {{- toYaml . | nindent 4 }} {{- end }} type: kubernetes.io/tls 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 229148a0..986b3cac 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,17 +10,13 @@ kind: Secret metadata: name: hubble-relay-server-certs namespace: {{ include "cilium.namespace" . }} - labels: {{- with .Values.commonLabels }} + labels: {{- toYaml . | nindent 4 }} {{- end }} - cilium.io/helm-template-non-idempotent: "true" - annotations: {{- with .Values.hubble.annotations }} - {{- toYaml . | nindent 4 }} - {{- end }} - {{- with .Values.nonIdempotentAnnotations }} + annotations: {{- 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 4d214a56..b7bedb89 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 @@ -18,17 +18,13 @@ kind: Secret metadata: name: hubble-server-certs namespace: {{ include "cilium.namespace" . }} - labels: {{- with .Values.commonLabels }} + labels: {{- toYaml . | nindent 4 }} {{- end }} - cilium.io/helm-template-non-idempotent: "true" - annotations: {{- with .Values.hubble.annotations }} - {{- toYaml . | nindent 4 }} - {{- end }} - {{- with .Values.nonIdempotentAnnotations }} + annotations: {{- toYaml . | nindent 4 }} {{- end }} type: kubernetes.io/tls 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 8c1b40aa..e1f62ead 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,17 +10,13 @@ metadata: name: hubble-ui-client-certs namespace: {{ include "cilium.namespace" . }} - labels: {{- with .Values.commonLabels }} + labels: {{- toYaml . | nindent 4 }} {{- end }} - cilium.io/helm-template-non-idempotent: "true" - annotations: {{- with .Values.hubble.annotations }} - {{- toYaml . | nindent 4 }} - {{- end }} - {{- with .Values.nonIdempotentAnnotations }} + annotations: {{- toYaml . | nindent 4 }} {{- end }} type: kubernetes.io/tls 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 deleted file mode 100644 index 9d65c1a8..00000000 --- a/packages/system/cilium/charts/cilium/templates/standalone-dns-proxy/configmap.yaml +++ /dev/null @@ -1,28 +0,0 @@ -{{- 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 deleted file mode 100644 index 7ea150a4..00000000 --- a/packages/system/cilium/charts/cilium/templates/standalone-dns-proxy/daemonset.yaml +++ /dev/null @@ -1,80 +0,0 @@ -{{- 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 ac3164b6..4fff21a3 100644 --- a/packages/system/cilium/charts/cilium/templates/validate.yaml +++ b/packages/system/cilium/charts/cilium/templates/validate.yaml @@ -220,22 +220,3 @@ {{- 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/ztunnel/daemonset.yaml b/packages/system/cilium/charts/cilium/templates/ztunnel/daemonset.yaml deleted file mode 100644 index f9363068..00000000 --- a/packages/system/cilium/charts/cilium/templates/ztunnel/daemonset.yaml +++ /dev/null @@ -1,165 +0,0 @@ -{{- 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 deleted file mode 100644 index 520857dc..00000000 --- a/packages/system/cilium/charts/cilium/templates/ztunnel/secret.yaml +++ /dev/null @@ -1,23 +0,0 @@ -{{- 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 deleted file mode 100644 index 4ef9e2bc..00000000 --- a/packages/system/cilium/charts/cilium/templates/ztunnel/serviceaccount.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- 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 65c84af5..fb1ea4c3 100644 --- a/packages/system/cilium/charts/cilium/values.schema.json +++ b/packages/system/cilium/charts/cilium/values.schema.json @@ -58,27 +58,6 @@ "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" @@ -461,14 +440,6 @@ "properties": { "enabled": { "type": "boolean" - }, - "nodeSpec": { - "properties": { - "azureInterfaceName": { - "type": "string" - } - }, - "type": "object" } }, "type": "object" @@ -673,14 +644,6 @@ "monitorInterval": { "type": "string" }, - "monitorTraceIPOption": { - "minimum": 0, - "maximum": 255, - "type": [ - "null", - "integer" - ] - }, "natMax": { "type": [ "null", @@ -705,12 +668,6 @@ "integer" ] }, - "policyMapPressureMetricsThreshold": { - "type": [ - "null", - "number" - ] - }, "policyStatsMapMax": { "type": [ "null", @@ -757,17 +714,6 @@ }, "type": "object" }, - "cronJob": { - "properties": { - "failedJobsHistoryLimit": { - "type": "integer" - }, - "successfulJobsHistoryLimit": { - "type": "integer" - } - }, - "type": "object" - }, "extraVolumeMounts": { "items": {}, "type": "array" @@ -822,10 +768,7 @@ "type": "array" }, "ttlSecondsAfterFinished": { - "type": [ - "null", - "integer" - ] + "type": "integer" } }, "type": "object" @@ -1356,9 +1299,6 @@ "Cluster" ] }, - "externallyCreated": { - "type": "boolean" - }, "internalTrafficPolicy": { "enum": [ "Local", @@ -1429,6 +1369,17 @@ }, "type": "object" }, + "client": { + "properties": { + "cert": { + "type": "string" + }, + "key": { + "type": "string" + } + }, + "type": "object" + }, "enableSecrets": { "type": "boolean" }, @@ -1501,17 +1452,11 @@ }, "type": "object" }, - "cacheTTL": { - "type": "string" - }, "config": { "properties": { "clusters": { "items": {}, - "type": [ - "object", - "array" - ] + "type": "array" }, "domain": { "type": "string" @@ -1531,85 +1476,6 @@ "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" }, @@ -1671,27 +1537,10 @@ }, "resources": { "properties": { - "limits": { - "properties": { - "cpu": { - "type": [ - "integer", - "string" - ] - }, - "memory": { - "type": "string" - } - }, - "type": "object" - }, "requests": { "properties": { "cpu": { - "type": [ - "integer", - "string" - ] + "type": "string" }, "memory": { "type": "string" @@ -1714,21 +1563,6 @@ "object" ] }, - "configDriftDetection": { - "properties": { - "driftChecker": { - "type": "boolean" - }, - "enabled": { - "type": "boolean" - }, - "ignoredKeys": { - "items": {}, - "type": "array" - } - }, - "type": "object" - }, "connectivityProbeFrequencyRatio": { "type": [ "null", @@ -1744,6 +1578,14 @@ "crdWaitTimeout": { "type": "string" }, + "customCalls": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, "daemon": { "properties": { "allowedConfigOverrides": { @@ -1907,9 +1749,6 @@ "enableMasqueradeRouteSource": { "type": "boolean" }, - "enableNoServiceEndpointsRoutable": { - "type": "boolean" - }, "enableNonDefaultDenyPolicies": { "type": "boolean" }, @@ -1958,30 +1797,8 @@ "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" @@ -1996,184 +1813,6 @@ } }, "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" @@ -2189,9 +1828,6 @@ "endpointLockdownOnMapOverflow": { "type": "boolean" }, - "endpointPolicyUpdateTimeoutDuration": { - "type": "null" - }, "endpointRoutes": { "properties": { "enabled": { @@ -2233,49 +1869,6 @@ "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" @@ -2418,12 +2011,6 @@ "string" ] }, - "clusterMaxConnections": { - "type": "integer" - }, - "clusterMaxRequests": { - "type": "integer" - }, "connectTimeoutSeconds": { "type": "integer" }, @@ -2517,10 +2104,6 @@ }, "type": "object" }, - "initContainers": { - "items": {}, - "type": "array" - }, "initialFetchTimeoutSeconds": { "type": "integer" }, @@ -2588,9 +2171,6 @@ "maxConnectionDurationSeconds": { "type": "integer" }, - "maxGlobalDownstreamConnections": { - "type": "integer" - }, "maxRequestsPerConnection": { "type": "integer" }, @@ -2813,9 +2393,6 @@ }, "type": "object" }, - "useOriginalSourceAddress": { - "type": "boolean" - }, "xffNumTrustedHopsL7PolicyEgress": { "type": "integer" }, @@ -3037,17 +2614,10 @@ "anyOf": [ { "properties": { - "aggregationInterval": { - "type": "string" - }, "excludeFilters": { "items": {}, "type": "array" }, - "fieldAggregate": { - "items": {}, - "type": "array" - }, "fieldMask": { "items": {}, "type": "array" @@ -3091,9 +2661,6 @@ }, "static": { "properties": { - "aggregationInterval": { - "type": "string" - }, "allowList": { "items": {}, "type": "array" @@ -3105,10 +2672,6 @@ "enabled": { "type": "boolean" }, - "fieldAggregate": { - "items": {}, - "type": "array" - }, "fieldMask": { "items": {}, "type": "array" @@ -3474,23 +3037,6 @@ "listenPort": { "type": "string" }, - "logOptions": { - "properties": { - "format": { - "type": [ - "null", - "string" - ] - }, - "level": { - "type": [ - "null", - "string" - ] - } - }, - "type": "object" - }, "nodeSelector": { "properties": { "kubernetes.io/os": { @@ -3554,15 +3100,9 @@ "address": { "type": "string" }, - "blockProfileRate": { - "type": "integer" - }, "enabled": { "type": "boolean" }, - "mutexProfileFraction": { - "type": "integer" - }, "port": { "type": "integer" } @@ -4140,9 +3680,6 @@ }, "type": "object" }, - "tmpVolume": { - "type": "object" - }, "tolerations": { "items": {}, "type": "array" @@ -4384,33 +3921,6 @@ "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": { @@ -4677,9 +4187,6 @@ } }, "type": "object" - }, - "serviceTopology": { - "type": "boolean" } }, "type": "object" @@ -4771,6 +4278,9 @@ }, "enableHealthCheckLoadBalancerIP": { "type": "boolean" + }, + "enabled": { + "type": "boolean" } }, "type": "object" @@ -4884,10 +4394,7 @@ "requests": { "properties": { "cpu": { - "type": [ - "integer", - "string" - ] + "type": "string" }, "memory": { "type": "string" @@ -4979,9 +4486,6 @@ } }, "type": "object" - }, - "waitForCloudInit": { - "type": "boolean" } }, "type": "object" @@ -5190,15 +4694,9 @@ "address": { "type": "string" }, - "blockProfileRate": { - "type": "integer" - }, "enabled": { "type": "boolean" }, - "mutexProfileFraction": { - "type": "integer" - }, "port": { "type": "integer" } @@ -5256,30 +4754,6 @@ } }, "type": "object" - }, - "tls": { - "properties": { - "enabled": { - "type": "boolean" - }, - "server": { - "properties": { - "existingSecret": { - "type": "string" - }, - "mtls": { - "properties": { - "enabled": { - "type": "boolean" - } - }, - "type": "object" - } - }, - "type": "object" - } - }, - "type": "object" } }, "type": "object" @@ -5392,12 +4866,6 @@ }, "restart": { "type": "boolean" - }, - "selector": { - "type": [ - "null", - "string" - ] } }, "type": "object" @@ -5434,9 +4902,6 @@ "properties": { "enabled": { "type": "boolean" - }, - "packetizationLayerPMTUDMode": { - "type": "string" } }, "type": "object" @@ -5475,9 +4940,6 @@ "array" ] }, - "policyDenyResponse": { - "type": "string" - }, "policyEnforcementMode": { "type": "string" }, @@ -5486,15 +4948,9 @@ "address": { "type": "string" }, - "blockProfileRate": { - "type": "integer" - }, "enabled": { "type": "boolean" }, - "mutexProfileFraction": { - "type": "integer" - }, "port": { "type": "integer" } @@ -5907,9 +5363,6 @@ "secretsNamespaceAnnotations": { "type": "object" }, - "secretsNamespaceLabels": { - "type": "object" - }, "securityContext": { "properties": { "allowPrivilegeEscalation": { @@ -5969,9 +5422,6 @@ { "type": "string" }, - { - "type": "string" - }, { "type": "string" } @@ -6087,23 +5537,6 @@ }, "type": "object" }, - "corednsMCSAPI": { - "properties": { - "annotations": { - "type": "object" - }, - "automount": { - "type": "boolean" - }, - "create": { - "type": "boolean" - }, - "name": { - "type": "string" - } - }, - "type": "object" - }, "envoy": { "properties": { "annotations": { @@ -6225,23 +5658,6 @@ } }, "type": "object" - }, - "ztunnel": { - "properties": { - "annotations": { - "type": "object" - }, - "automount": { - "type": "boolean" - }, - "create": { - "type": "boolean" - }, - "name": { - "type": "string" - } - }, - "type": "object" } }, "type": "object" @@ -6260,86 +5676,6 @@ }, "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": { @@ -6351,6 +5687,9 @@ }, "type": "object" }, + "svcSourceRangeCheck": { + "type": "boolean" + }, "synchronizeK8sNodes": { "type": "boolean" }, @@ -6435,9 +5774,6 @@ }, "type": "object" }, - "tmpVolume": { - "type": "object" - }, "tolerations": { "items": { "anyOf": [ diff --git a/packages/system/cilium/charts/cilium/values.yaml b/packages/system/cilium/charts/cilium/values.yaml index 66f76982..5fac5be5 100644 --- a/packages/system/cilium/charts/cilium/values.yaml +++ b/packages/system/cilium/charts/cilium/values.yaml @@ -6,6 +6,7 @@ # 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] @@ -28,7 +29,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, policy, or tagged), and flow is + # 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"). # @@ -38,7 +39,6 @@ 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 @@ -204,18 +204,6 @@ 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. @@ -224,22 +212,6 @@ agent: true 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 @@ -247,10 +219,10 @@ image: # @schema override: ~ repository: "quay.io/cilium/cilium" - tag: "v1.19.3" + tag: "v1.18.5" pullPolicy: "IfNotPresent" # cilium-digest - digest: sha256:2e61680593cddca8b6c055f6d4c849d87a26a1c91c7e3b8b56c7fb76ab7b7b10 + digest: sha256:2c92fb05962a346eaf0ce11b912ba434dc10bd54b9989e970416681f4a069628 useDigest: true # -- Scheduling configurations for cilium pods scheduling: @@ -391,8 +363,6 @@ 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 @@ -463,16 +433,9 @@ 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. @@ -505,7 +468,8 @@ l2podAnnouncements: interface: "eth0" # -- 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. +# -- This feature set enables virtual BGP routers to be created via +# CiliumBGPPeeringPolicy CRDs. bgpControlPlane: # -- Enables the BGP control plane. enabled: false @@ -515,9 +479,9 @@ bgpControlPlane: create: false # -- The name of the secret namespace to which Cilium agents are given read access name: kube-system - # -- Status reporting settings + # -- Status reporting settings (BGPv2 only) statusReport: - # -- Enable/Disable BGP status reporting + # -- 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. enabled: true @@ -527,7 +491,7 @@ bgpControlPlane: mode: "default" # -- IP pool to allocate the BGP router-id from when the mode is ip-pool. ipPool: "" - # -- Legacy BGP ORIGIN attribute settings + # -- Legacy BGP ORIGIN attribute settings (BGPv2 only) legacyOriginAttribute: # -- Enable/Disable advertising LoadBalancerIP routes with the legacy # BGP ORIGIN attribute value INCOMPLETE (2) instead of the default IGP (0). @@ -537,11 +501,6 @@ 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 @@ -589,7 +548,7 @@ 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. + # -- Default settings for all types of events except dbg and pcap. default: # @schema # type: [null, integer] @@ -649,12 +608,6 @@ 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] @@ -712,8 +665,7 @@ bpf: # type: [null, boolean] # @schema # -- (bool) 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`). + # for implementing Layer 7 policy. # @default -- `false` tproxy: ~ # @schema @@ -723,15 +675,6 @@ 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 @@ -739,8 +682,7 @@ bpf: # supported kernels. # @default -- `true` enableTCX: true - # -- (string) Mode for Pod devices for the core datapath (veth, netkit, netkit-l2). - # Note netkit is incompatible with TPROXY (`bpf.tproxy`). + # -- (string) Mode for Pod devices for the core datapath (veth, netkit, netkit-l2) # @default -- `veth` datapathMode: veth # -- Enable BPF clock source probing for more efficient tick retrieval. @@ -828,17 +770,8 @@ 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. @@ -863,6 +796,10 @@ 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" @@ -905,12 +842,6 @@ 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 @@ -929,6 +860,9 @@ forceDeviceDetection: false # -- Enable setting identity mark for local traffic. # enableIdentityMark: true +# -- Enable Kubernetes EndpointSlice feature in Cilium if the cluster supports it. +# enableK8sEndpointSlice: true + # -- CiliumEndpointSlice configuration options. ciliumEndpointSlice: # -- Enable Cilium EndpointSlice feature. @@ -1108,33 +1042,20 @@ enableXTSocketFallback: true encryption: # -- Enable transparent network encryption. enabled: false - # -- Encryption method. Can be one of ipsec, wireguard or ztunnel. + # -- Encryption method. Can be either ipsec or wireguard. 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 Encryption Pod2Pod strict mode. + # -- Configure the WireGuard Pod2Pod strict mode. strictMode: - # -- Enable Encryption Pod2Pod strict mode. (deprecated: please use encryption.strictMode.egress.enabled) + # -- Enable WireGuard Pod2Pod strict mode. enabled: false - # -- CIDR for the Encryption Pod2Pod strict mode. (deprecated: please use encryption.strictMode.egress.cidr) + # -- CIDR for the WireGuard Pod2Pod strict mode. cidr: "" - # -- Allow dynamic lookup of remote node identities. (deprecated: please use encryption.strictMode.egress.allowRemoteNodeIdentities) + # -- 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 - 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 @@ -1155,89 +1076,9 @@ 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] @@ -1286,32 +1127,6 @@ 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: [] - # -- 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: @@ -1327,8 +1142,6 @@ healthCheckICMPFailureThreshold: 3 hostFirewall: # -- Enables the enforcement of host policies in the eBPF datapath. enabled: false -# -- Enable routing to a service that has zero endpoints -enableNoServiceEndpointsRoutable: true # -- Configure socket LB socketLB: # -- Enable socket LB @@ -1352,15 +1165,12 @@ certgen: # @schema override: ~ repository: "quay.io/cilium/certgen" - tag: "v0.4.1" - digest: "sha256:f0c656830e856d26b24b0e144df1f8b327d3b46748d76a630514111fc365b697" + tag: "v0.3.1" + digest: "sha256:2825dbfa6f89cbed882fd1d81e46a56c087e35885825139923aa29eb8aec47a9" useDigest: true pullPolicy: "IfNotPresent" - # @schema - # type: [null, integer] - # @schema # -- Seconds after which the completed job pod will be deleted - ttlSecondsAfterFinished: null + ttlSecondsAfterFinished: 1800 # -- Labels to be added to hubble-certgen pods podLabels: {} # -- Annotations to be added to the hubble-certgen initial Job and CronJob @@ -1385,11 +1195,6 @@ certgen: 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 @@ -1405,9 +1210,6 @@ 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. @@ -1701,9 +1503,9 @@ hubble: # @schema override: ~ repository: "quay.io/cilium/hubble-relay" - tag: "v1.19.3" + tag: "v1.18.5" # hubble-relay-digest - digest: sha256:5ee21d57b6ef2aa6db67e603a735fdceb162454b352b7335b651456e308f681b + digest: sha256:17212962c92ff52384f94e407ffe3698714fcbd35c7575f67f24032d6224e446 useDigest: true pullPolicy: "IfNotPresent" # -- Specifies the resources for the hubble-relay pods @@ -1914,24 +1716,6 @@ 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 @@ -2127,11 +1911,6 @@ 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: # --- Static exporter configuration. @@ -2144,14 +1923,6 @@ 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: [] @@ -2177,8 +1948,6 @@ hubble: content: - name: all fieldMask: [] - fieldAggregate: [] - aggregationInterval: "0s" includeFilters: [] excludeFilters: [] filePath: "/var/run/cilium/hubble/events.log" @@ -2271,30 +2040,11 @@ ipam: # refill the bucket up to the burst size capacity. # @default -- `4.0` externalAPILimitQPS: ~ - # -- 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: [] +# -- defaultLBServiceIPAM indicates the default LoadBalancer Service IPAM when +# no LoadBalancer class is set. Applicable values: lbipam, nodeipam, none # @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 @@ -2405,7 +2155,7 @@ maglev: {} # type: [null, boolean] # @schema # -- (bool) Enables masquerading of IPv4 traffic leaving the node from endpoints. -# @default -- `true` unless ipam eni mode is active +# @default -- `true` unless ipam eni mode is active enableIPv4Masquerade: ~ # -- Enables masquerading of IPv6 traffic leaving the node from endpoints. enableIPv6Masquerade: true @@ -2492,7 +2242,8 @@ loadBalancer: # -- serviceTopology enables K8s Topology Aware Hints -based service # endpoints filtering - serviceTopology: false + # serviceTopology: false + # -- L7 LoadBalancer l7: # -- Enable L7 service load balancing via envoy proxy. @@ -2515,6 +2266,8 @@ 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" @@ -2558,10 +2311,6 @@ 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 @@ -2686,12 +2435,6 @@ 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 @@ -2708,9 +2451,6 @@ envoy: 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 @@ -2725,12 +2465,10 @@ envoy: # @schema override: ~ repository: "quay.io/cilium/cilium-envoy" - tag: "v1.36.6-1776000132-2437d2edeaf4d9b56ef279bd0d71127440c067aa" + tag: "v1.34.12-1765374555-6a93b0bbba8d6dc75b651cbafeedb062b2997716" pullPolicy: "IfNotPresent" - digest: "sha256:ba0ab8adac082d50d525fd2c5ba096c8facea3a471561b7c61c7a5b9c2e0de0d" + digest: "sha256:3108521821c6922695ff1f6ef24b09026c94b195283f8bfbfc0fa49356a156e1" useDigest: true - # -- Init containers added to the cilium Envoy DaemonSet. - initContainers: [] # -- Additional containers added to the cilium Envoy DaemonSet. extraContainers: [] # -- Additional envoy container arguments. @@ -2961,15 +2699,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. @@ -3052,9 +2791,6 @@ tls: # @default -- `"vxlan"` tunnelProtocol: "" # -- IP family for the underlay. -# Possible values: -# - "ipv4" -# - "ipv6" # @default -- `"ipv4"` underlayProtocol: "" # -- Enable native-routing mode or tunneling mode. @@ -3075,11 +2811,6 @@ 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, @@ -3110,15 +2841,15 @@ operator: # @schema override: ~ repository: "quay.io/cilium/operator" - tag: "v1.19.3" + tag: "v1.18.5" # operator-generic-digest - genericDigest: sha256:205b09b0ed6accbf9fe688d312a9f0fcfc6a316fc081c23fbffb472af5dd62cd + genericDigest: sha256:36c3f6f14c8ced7f45b40b0a927639894b44269dd653f9528e7a0dc363a4eb99 # operator-azure-digest - azureDigest: sha256:699c1571a3df1a98882ee13610d47cffb7b34ee7e8d276096db798a5f6c7e4cb + azureDigest: sha256:126667e000267f893cb81042bf8a710ad2f219619eb9ce06e8949333bd325ac6 # operator-aws-digest - awsDigest: sha256:a53dcbfb77282bf2ddd3abbe60f6d49762e7c1389a36cb35b71d504644a56640 + awsDigest: sha256:7608025d8b727a10f21d924d8e4f40beb176cefd690320433452816ad8776f52 # operator-alibabacloud-digest - alibabacloudDigest: sha256:176321a65123373ff8c7823b25183102cbad98375e8d6c80b96d68b6e8491103 + alibabacloudDigest: sha256:2e60f635495eb2837296ced5475875c281a05765d5ddd644a05e126bbb080b3c useDigest: true pullPolicy: "IfNotPresent" suffix: "" @@ -3257,10 +2988,6 @@ 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: @@ -3294,17 +3021,6 @@ 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 @@ -3338,12 +3054,6 @@ 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 @@ -3354,8 +3064,8 @@ nodeinit: # @schema override: ~ repository: "quay.io/cilium/startup-script" - tag: "1763560095-8f36c34" - digest: "sha256:50b9cf9c280096b59b80d2fc8ee6638facef79ac18998a22f0cbc40d5d28c16f" + tag: "1755531540-60ee83e" + digest: "sha256:5bdca3c2dec2c79f58d45a7a560bf1098c2126350c901379fe850b7f78d3d757" useDigest: true pullPolicy: "IfNotPresent" # -- The priority class to use for the nodeinit pod. @@ -3398,9 +3108,6 @@ 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. @@ -3423,8 +3130,6 @@ 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: "" @@ -3443,9 +3148,9 @@ preflight: # @schema override: ~ repository: "quay.io/cilium/cilium" - tag: "v1.19.3" + tag: "v1.18.5" # cilium-digest - digest: sha256:2e61680593cddca8b6c055f6d4c849d87a26a1c91c7e3b8b56c7fb76ab7b7b10 + digest: sha256:2c92fb05962a346eaf0ce11b912ba434dc10bd54b9989e970416681f4a069628 useDigest: true pullPolicy: "IfNotPresent" envoy: @@ -3456,9 +3161,9 @@ preflight: # @schema override: ~ repository: "quay.io/cilium/cilium-envoy" - tag: "v1.36.6-1776000132-2437d2edeaf4d9b56ef279bd0d71127440c067aa" + tag: "v1.34.12-1765374555-6a93b0bbba8d6dc75b651cbafeedb062b2997716" pullPolicy: "IfNotPresent" - digest: "sha256:ba0ab8adac082d50d525fd2c5ba096c8facea3a471561b7c61c7a5b9c2e0de0d" + digest: "sha256:3108521821c6922695ff1f6ef24b09026c94b195283f8bfbfc0fa49356a156e1" useDigest: true # -- The priority class to use for the preflight pod. priorityClassName: "" @@ -3558,9 +3263,7 @@ enableCriticalPriorityClass: true # on AArch64 as the images do not currently ship a version of Envoy. #disableEnvoyVersionCheck: false 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. + # -- Deploy clustermesh-apiserver for clustermesh 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 @@ -3568,132 +3271,44 @@ 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 (deprecated; use clustermesh.mcsapi.enabled) + # -- Enable Multi-Cluster Services API support enableMCSAPISupport: false # -- Control whether policy rules assume by default the local cluster if not explicitly selected - policyDefaultLocalCluster: true + policyDefaultLocalCluster: false # -- 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 - # -- Clusters to be peered in the mesh. - # @schema - # type: [object, array] - # @schema + # -- List of clusters to be peered in the mesh. clusters: [] - # You can use a dict of clusters (recommended): # clusters: - # # -- 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 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 - # # -- (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. + # # -- 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: @@ -3702,9 +3317,9 @@ clustermesh: # @schema override: ~ repository: "quay.io/cilium/clustermesh-apiserver" - tag: "v1.19.3" + tag: "v1.18.5" # clustermesh-apiserver-digest - digest: sha256:a8136a7615d6c6041d3aa6f2674d17beaec238170d669507ccc05328a778e2b7 + digest: sha256:952f07c30390847e4d9dfaa19a76c4eca946251ffbc4f6459946570f93ee72f1 useDigest: true pullPolicy: "IfNotPresent" # -- TCP port for the clustermesh-apiserver health API. @@ -3793,12 +3408,17 @@ clustermesh: # - "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: @@ -3967,15 +3587,13 @@ 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: migration - # -- (deprecated) Allow users to provide their own certificates + authMode: legacy + # -- 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 @@ -3984,14 +3602,7 @@ clustermesh: auto: # -- 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. + # If set to false, the certs to be provided by setting appropriate values below. enabled: true # Sets the method to auto-generate certificates. Supported values: # - helm: This method uses Helm to generate all certificates. @@ -4026,9 +3637,7 @@ 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: [] @@ -4037,16 +3646,17 @@ 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: "" - # -- Deprecated, as secrets will always need to be created externally if `auto` is disabled. + key: "" + # -- base64 encoded PEM values for the clustermesh-apiserver client certificate and private key. + # Used if 'auto' is not enabled. + client: + cert: "" 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: @@ -4201,7 +3811,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: false + enabled: true # -- 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. @@ -4239,7 +3849,7 @@ authentication: override: ~ repository: "docker.io/library/busybox" tag: "1.37.0" - digest: "sha256:1487d0af5f52b4ba31c7e465126ee2123fe3f2305d638e7827681e7cf6c83d5e" + digest: "sha256:d80cd694d3e9467884fcb94b8ca1e20437d8a501096cdf367a5a1918a34fc2fd" useDigest: true pullPolicy: "IfNotPresent" # SPIRE agent configuration @@ -4253,8 +3863,8 @@ authentication: # @schema override: ~ repository: "ghcr.io/spiffe/spire-agent" - tag: "1.9.6" - digest: "sha256:5106ac601272a88684db14daf7f54b9a45f31f77bb16a906bd5e87756ee7b97c" + tag: "1.12.4" + digest: "sha256:163970884fba18860cac93655dc32b6af85a5dcf2ebb7e3e119a10888eff8fcd" useDigest: true pullPolicy: "IfNotPresent" # -- SPIRE agent service account @@ -4308,8 +3918,8 @@ authentication: # @schema override: ~ repository: "ghcr.io/spiffe/spire-server" - tag: "1.9.6" - digest: "sha256:59a0b92b39773515e25e68a46c40d3b931b9c1860bc445a79ceb45a805cab8b4" + tag: "1.12.4" + digest: "sha256:34147f27066ab2be5cc10ca1d4bfd361144196467155d46c45f3519f41596e49" useDigest: true pullPolicy: "IfNotPresent" # -- SPIRE server service account @@ -4394,41 +4004,3 @@ 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 8039b40c..83b87cfd 100644 --- a/packages/system/cilium/charts/cilium/values.yaml.tmpl +++ b/packages/system/cilium/charts/cilium/values.yaml.tmpl @@ -3,6 +3,7 @@ # 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] @@ -26,7 +27,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, policy, or tagged), and flow is + # 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"). # @@ -36,7 +37,6 @@ debug: # - envoy # - datapath # - policy - # - tagged verbose: ~ # -- Set the agent-internal metrics sampling frequency. This sets the @@ -207,18 +207,6 @@ 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. @@ -227,22 +215,6 @@ agent: true 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 @@ -396,8 +368,6 @@ 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 @@ -470,16 +440,9 @@ 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. @@ -512,7 +475,8 @@ l2podAnnouncements: interface: "eth0" # -- 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. +# -- This feature set enables virtual BGP routers to be created via +# CiliumBGPPeeringPolicy CRDs. bgpControlPlane: # -- Enables the BGP control plane. enabled: false @@ -522,9 +486,9 @@ bgpControlPlane: create: false # -- The name of the secret namespace to which Cilium agents are given read access name: kube-system - # -- Status reporting settings + # -- Status reporting settings (BGPv2 only) statusReport: - # -- Enable/Disable BGP status reporting + # -- 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. enabled: true @@ -534,7 +498,7 @@ bgpControlPlane: mode: "default" # -- IP pool to allocate the BGP router-id from when the mode is ip-pool. ipPool: "" - # -- Legacy BGP ORIGIN attribute settings + # -- Legacy BGP ORIGIN attribute settings (BGPv2 only) legacyOriginAttribute: # -- Enable/Disable advertising LoadBalancerIP routes with the legacy # BGP ORIGIN attribute value INCOMPLETE (2) instead of the default IGP (0). @@ -544,11 +508,6 @@ 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 @@ -596,7 +555,7 @@ 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. + # -- Default settings for all types of events except dbg and pcap. default: # @schema # type: [null, integer] @@ -656,12 +615,6 @@ 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] @@ -719,8 +672,7 @@ bpf: # type: [null, boolean] # @schema # -- (bool) 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`). + # for implementing Layer 7 policy. # @default -- `false` tproxy: ~ # @schema @@ -730,15 +682,6 @@ 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 @@ -746,8 +689,7 @@ bpf: # supported kernels. # @default -- `true` enableTCX: true - # -- (string) Mode for Pod devices for the core datapath (veth, netkit, netkit-l2). - # Note netkit is incompatible with TPROXY (`bpf.tproxy`). + # -- (string) Mode for Pod devices for the core datapath (veth, netkit, netkit-l2) # @default -- `veth` datapathMode: veth # -- Enable BPF clock source probing for more efficient tick retrieval. @@ -836,17 +778,8 @@ 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. @@ -871,6 +804,10 @@ 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" @@ -913,13 +850,6 @@ 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 @@ -939,6 +869,9 @@ forceDeviceDetection: false # -- Enable setting identity mark for local traffic. # enableIdentityMark: true +# -- Enable Kubernetes EndpointSlice feature in Cilium if the cluster supports it. +# enableK8sEndpointSlice: true + # -- CiliumEndpointSlice configuration options. ciliumEndpointSlice: # -- Enable Cilium EndpointSlice feature. @@ -1123,33 +1056,20 @@ enableXTSocketFallback: true encryption: # -- Enable transparent network encryption. enabled: false - # -- Encryption method. Can be one of ipsec, wireguard or ztunnel. + # -- Encryption method. Can be either ipsec or wireguard. 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 Encryption Pod2Pod strict mode. + # -- Configure the WireGuard Pod2Pod strict mode. strictMode: - # -- Enable Encryption Pod2Pod strict mode. (deprecated: please use encryption.strictMode.egress.enabled) + # -- Enable WireGuard Pod2Pod strict mode. enabled: false - # -- CIDR for the Encryption Pod2Pod strict mode. (deprecated: please use encryption.strictMode.egress.cidr) + # -- CIDR for the WireGuard Pod2Pod strict mode. cidr: "" - # -- Allow dynamic lookup of remote node identities. (deprecated: please use encryption.strictMode.egress.allowRemoteNodeIdentities) + # -- 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 - 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 @@ -1170,89 +1090,9 @@ 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] @@ -1301,33 +1141,6 @@ 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: [] - # -- 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: @@ -1343,8 +1156,6 @@ healthCheckICMPFailureThreshold: 3 hostFirewall: # -- Enables the enforcement of host policies in the eBPF datapath. enabled: false -# -- Enable routing to a service that has zero endpoints -enableNoServiceEndpointsRoutable: true # -- Configure socket LB socketLB: # -- Enable socket LB @@ -1372,11 +1183,8 @@ 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: null + ttlSecondsAfterFinished: 1800 # -- Labels to be added to hubble-certgen pods podLabels: {} # -- Annotations to be added to the hubble-certgen initial Job and CronJob @@ -1401,11 +1209,6 @@ certgen: 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 @@ -1421,9 +1224,6 @@ 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. @@ -1930,24 +1730,6 @@ 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 @@ -2143,13 +1925,6 @@ 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: # --- Static exporter configuration. @@ -2162,14 +1937,6 @@ 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: [] @@ -2195,8 +1962,6 @@ hubble: content: - name: all fieldMask: [] - fieldAggregate: [] - aggregationInterval: "0s" includeFilters: [] excludeFilters: [] filePath: "/var/run/cilium/hubble/events.log" @@ -2291,30 +2056,11 @@ ipam: # refill the bucket up to the burst size capacity. # @default -- `4.0` externalAPILimitQPS: ~ - # -- 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: [] +# -- defaultLBServiceIPAM indicates the default LoadBalancer Service IPAM when +# no LoadBalancer class is set. Applicable values: lbipam, nodeipam, none # @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 @@ -2401,7 +2147,7 @@ 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@ @@ -2431,7 +2177,7 @@ maglev: {} # type: [null, boolean] # @schema # -- (bool) Enables masquerading of IPv4 traffic leaving the node from endpoints. -# @default -- `true` unless ipam eni mode is active +# @default -- `true` unless ipam eni mode is active enableIPv4Masquerade: ~ # -- Enables masquerading of IPv6 traffic leaving the node from endpoints. enableIPv6Masquerade: true @@ -2520,7 +2266,7 @@ loadBalancer: # -- serviceTopology enables K8s Topology Aware Hints -based service # endpoints filtering - serviceTopology: false + # serviceTopology: false # -- L7 LoadBalancer l7: @@ -2544,6 +2290,8 @@ 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" @@ -2588,10 +2336,6 @@ 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 @@ -2716,12 +2460,6 @@ 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 @@ -2738,9 +2476,6 @@ envoy: 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 @@ -2759,8 +2494,6 @@ 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. @@ -2993,16 +2726,17 @@ 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. @@ -3085,9 +2819,6 @@ tls: # @default -- `"vxlan"` tunnelProtocol: "" # -- IP family for the underlay. -# Possible values: -# - "ipv4" -# - "ipv6" # @default -- `"ipv4"` underlayProtocol: "" # -- Enable native-routing mode or tunneling mode. @@ -3108,11 +2839,6 @@ 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, @@ -3198,7 +2924,7 @@ operator: # @schema # type: [null, array] # @schema - tolerations: + tolerations: - key: "node-role.kubernetes.io/control-plane" operator: Exists - key: "node-role.kubernetes.io/master" #deprecated @@ -3290,10 +3016,6 @@ 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: @@ -3327,17 +3049,6 @@ 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 @@ -3371,12 +3082,6 @@ 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 @@ -3431,9 +3136,6 @@ 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. @@ -3458,8 +3160,6 @@ 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: "" @@ -3593,9 +3293,7 @@ enableCriticalPriorityClass: true # on AArch64 as the images do not currently ship a version of Envoy. #disableEnvoyVersionCheck: false 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. + # -- Deploy clustermesh-apiserver for clustermesh 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 @@ -3603,133 +3301,45 @@ 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 (deprecated; use clustermesh.mcsapi.enabled) + # -- Enable Multi-Cluster Services API support enableMCSAPISupport: false # -- Control whether policy rules assume by default the local cluster if not explicitly selected - policyDefaultLocalCluster: true + policyDefaultLocalCluster: false # -- 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 - # -- Clusters to be peered in the mesh. - # @schema - # type: [object, array] - # @schema + # -- List of clusters to be peered in the mesh. clusters: [] - # You can use a dict of clusters (recommended): # clusters: - # # -- 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 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 - # # -- (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. + # # -- 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: @@ -3835,12 +3445,17 @@ clustermesh: # - "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: @@ -4009,15 +3624,13 @@ 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: migration - # -- (deprecated) Allow users to provide their own certificates + authMode: legacy + # -- 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 @@ -4026,14 +3639,7 @@ clustermesh: auto: # -- 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. + # If set to false, the certs to be provided by setting appropriate values below. enabled: true # Sets the method to auto-generate certificates. Supported values: # - helm: This method uses Helm to generate all certificates. @@ -4065,13 +3671,10 @@ 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: [] @@ -4080,16 +3683,17 @@ 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: "" - # -- Deprecated, as secrets will always need to be created externally if `auto` is disabled. + key: "" + # -- base64 encoded PEM values for the clustermesh-apiserver client certificate and private key. + # Used if 'auto' is not enabled. + client: + cert: "" 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: @@ -4244,7 +3848,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: false + enabled: true # -- 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. @@ -4437,41 +4041,4 @@ 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 32fc6fb8..23c3d16a 100644 --- a/packages/system/cilium/images/cilium/Dockerfile +++ b/packages/system/cilium/images/cilium/Dockerfile @@ -1,2 +1,2 @@ -ARG VERSION=v1.19.3 +ARG VERSION=v1.18.5 FROM quay.io/cilium/cilium:${VERSION} diff --git a/packages/system/cilium/values-apparmor.yaml b/packages/system/cilium/values-apparmor.yaml deleted file mode 100644 index 0712836c..00000000 --- a/packages/system/cilium/values-apparmor.yaml +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index c303ef0a..00000000 --- a/packages/system/cilium/values-kilo.yaml +++ /dev/null @@ -1,3 +0,0 @@ -cilium: - hostFirewall: - enabled: false diff --git a/packages/system/cilium/values.yaml b/packages/system/cilium/values.yaml index 9aba7cb9..95159b1f 100644 --- a/packages/system/cilium/values.yaml +++ b/packages/system/cilium/values.yaml @@ -15,11 +15,10 @@ cilium: mode: "kubernetes" image: repository: ghcr.io/cozystack/cozystack/cilium - tag: 1.19.3 - digest: "sha256:700f06f4803a838a8e830be5ace4650e3ad82bdefabfb2f4d110368d307a5efb" + tag: 1.17.8 + digest: "sha256:81262986a41487bfa3d0465091d3a386def5bd1ab476350bd4af2fdee5846fe6" 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 289631d6..e821b664 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 ../../../hack/package.mk +include ../../../scripts/package.mk update: rm -rf charts diff --git a/packages/system/clickhouse-rd/Makefile b/packages/system/clickhouse-rd/Makefile index 792ef31b..4ac0738a 100644 --- a/packages/system/clickhouse-rd/Makefile +++ b/packages/system/clickhouse-rd/Makefile @@ -1,4 +1,4 @@ export NAME=clickhouse-rd export NAMESPACE=cozy-system -include ../../../hack/package.mk +include ../../../scripts/package.mk diff --git a/packages/system/clickhouse-rd/cozyrds/clickhouse.yaml b/packages/system/clickhouse-rd/cozyrds/clickhouse.yaml index 3655a8db..6948fce0 100644 --- a/packages/system/clickhouse-rd/cozyrds/clickhouse.yaml +++ b/packages/system/clickhouse-rd/cozyrds/clickhouse.yaml @@ -1,5 +1,5 @@ apiVersion: cozystack.io/v1alpha1 -kind: ApplicationDefinition +kind: CozystackResourceDefinition metadata: name: clickhouse spec: @@ -8,15 +8,17 @@ spec: 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}}}}} + {"title":"Chart Values","type":"object","properties":{"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}}},"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},"replicas":{"description":"Number of ClickHouse replicas.","type":"integer","default":2},"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"]},"shards":{"description":"Number of ClickHouse shards.","type":"integer","default":1},"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":""},"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"}}}}}} release: prefix: clickhouse- labels: - sharding.fluxcd.io/key: tenants - chartRef: - kind: ExternalArtifact - name: cozystack-clickhouse-application-default-clickhouse - namespace: cozy-system + cozystack.io/ui: "true" + chart: + name: clickhouse + sourceRef: + kind: HelmRepository + name: cozystack-apps + namespace: cozy-public dashboard: category: PaaS singular: ClickHouse diff --git a/packages/system/cluster-autoscaler/Chart.yaml b/packages/system/cluster-autoscaler/Chart.yaml deleted file mode 100644 index 9aa2bb43..00000000 --- a/packages/system/cluster-autoscaler/Chart.yaml +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 605d4d4e..00000000 --- a/packages/system/cluster-autoscaler/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -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/cluster-autoscaler/charts/cluster-autoscaler/.helmignore b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/.helmignore deleted file mode 100644 index 0e8a0eb3..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# 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/cluster-autoscaler/charts/cluster-autoscaler/Chart.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/Chart.yaml deleted file mode 100644 index 0c46f2c8..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/Chart.yaml +++ /dev/null @@ -1,13 +0,0 @@ -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 deleted file mode 100644 index 8a9da750..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/README.md +++ /dev/null @@ -1,545 +0,0 @@ -# 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 deleted file mode 100644 index 0567e283..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/README.md.gotmpl +++ /dev/null @@ -1,426 +0,0 @@ -{{ 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 deleted file mode 100644 index 1a87a3d1..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/NOTES.txt +++ /dev/null @@ -1,18 +0,0 @@ -{{- 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 deleted file mode 100644 index c7e80f4d..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/_helpers.tpl +++ /dev/null @@ -1,160 +0,0 @@ -{{/* 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 deleted file mode 100644 index e6a9018e..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/clusterrole.yaml +++ /dev/null @@ -1,210 +0,0 @@ -{{- 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 deleted file mode 100644 index 59e6ef67..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/clusterrolebinding.yaml +++ /dev/null @@ -1,22 +0,0 @@ -{{- 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 deleted file mode 100644 index 6cd0c406..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/configmap.yaml +++ /dev/null @@ -1,416 +0,0 @@ -{{- 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 deleted file mode 100644 index cb4982b3..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/deployment.yaml +++ /dev/null @@ -1,380 +0,0 @@ -{{- 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 deleted file mode 100644 index a9bb3b6b..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/extra-manifests.yaml +++ /dev/null @@ -1,4 +0,0 @@ -{{ 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 deleted file mode 100644 index 0f8a69ec..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/pdb.yaml +++ /dev/null @@ -1,29 +0,0 @@ -{{- 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 deleted file mode 100644 index e3ce5997..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/podsecuritypolicy.yaml +++ /dev/null @@ -1,42 +0,0 @@ -{{- 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 deleted file mode 100644 index 8259f14f..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/priority-expander-configmap.yaml +++ /dev/null @@ -1,25 +0,0 @@ -{{- 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 deleted file mode 100644 index 097c969e..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/prometheusrule.yaml +++ /dev/null @@ -1,15 +0,0 @@ -{{- 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 deleted file mode 100644 index 80cf30a1..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/role.yaml +++ /dev/null @@ -1,96 +0,0 @@ -{{- 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 deleted file mode 100644 index 9436aabe..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/rolebinding.yaml +++ /dev/null @@ -1,23 +0,0 @@ -{{- 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 deleted file mode 100644 index 760cc3c5..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/secret.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{- 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 deleted file mode 100644 index c8bd4079..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/service.yaml +++ /dev/null @@ -1,43 +0,0 @@ -{{- 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 deleted file mode 100644 index 465b5aad..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/serviceaccount.yaml +++ /dev/null @@ -1,17 +0,0 @@ -{{- 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 deleted file mode 100644 index 9ce83a2e..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/servicemonitor.yaml +++ /dev/null @@ -1,36 +0,0 @@ -{{ 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 deleted file mode 100644 index 560dab00..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/vpa.yaml +++ /dev/null @@ -1,22 +0,0 @@ -{{- 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 deleted file mode 100644 index 9e41d35b..00000000 --- a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/values.yaml +++ /dev/null @@ -1,507 +0,0 @@ -## 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 deleted file mode 100644 index 7720481a..00000000 --- a/packages/system/cluster-autoscaler/values-azure.yaml +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 8e19fc53..00000000 --- a/packages/system/cluster-autoscaler/values-hetzner.yaml +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index eaef53d9..00000000 --- a/packages/system/cluster-autoscaler/values.yaml +++ /dev/null @@ -1,3 +0,0 @@ -cluster-autoscaler: - extraArgs: - enforce-node-group-min-size: true diff --git a/packages/system/clustersecret-operator/.helmignore b/packages/system/clustersecret-operator/.helmignore deleted file mode 100644 index d5c178e8..00000000 --- a/packages/system/clustersecret-operator/.helmignore +++ /dev/null @@ -1,3 +0,0 @@ -images -hack -.gitkeep diff --git a/packages/system/clustersecret-operator/Makefile b/packages/system/clustersecret-operator/Makefile deleted file mode 100644 index 34fa1464..00000000 --- a/packages/system/clustersecret-operator/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -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/clustersecret-operator/charts/clustersecret-operator/.helmignore b/packages/system/clustersecret-operator/charts/clustersecret-operator/.helmignore deleted file mode 100644 index 0e8a0eb3..00000000 --- a/packages/system/clustersecret-operator/charts/clustersecret-operator/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# 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/clustersecret-operator/charts/clustersecret-operator/Chart.yaml b/packages/system/clustersecret-operator/charts/clustersecret-operator/Chart.yaml deleted file mode 100644 index 447e8530..00000000 --- a/packages/system/clustersecret-operator/charts/clustersecret-operator/Chart.yaml +++ /dev/null @@ -1,6 +0,0 @@ -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 deleted file mode 100644 index 11b21f84..00000000 --- a/packages/system/clustersecret-operator/charts/clustersecret-operator/README.md +++ /dev/null @@ -1,74 +0,0 @@ -# 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 deleted file mode 100644 index e28a99b3..00000000 --- a/packages/system/clustersecret-operator/charts/clustersecret-operator/crds/clustersecrets.yaml +++ /dev/null @@ -1,106 +0,0 @@ -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 deleted file mode 100644 index 4f012e93..00000000 --- a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/_helpers-controller.tpl +++ /dev/null @@ -1,13 +0,0 @@ -{{- 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 deleted file mode 100644 index 77a8a372..00000000 --- a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/_helpers-webhook.tpl +++ /dev/null @@ -1,13 +0,0 @@ -{{- 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 deleted file mode 100644 index 48b65844..00000000 --- a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/_helpers.tpl +++ /dev/null @@ -1,51 +0,0 @@ -{{/* -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 deleted file mode 100644 index e42a33a3..00000000 --- a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/controller-deployment.yaml +++ /dev/null @@ -1,96 +0,0 @@ ---- -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 deleted file mode 100644 index 6f1985d5..00000000 --- a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/controller-pdb.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{- 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 deleted file mode 100644 index 040a5559..00000000 --- a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/controller-rbac.yaml +++ /dev/null @@ -1,74 +0,0 @@ ---- -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 deleted file mode 100644 index 83205ec0..00000000 --- a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/tests/rbac.yaml +++ /dev/null @@ -1,58 +0,0 @@ ---- -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 deleted file mode 100644 index 2c163a78..00000000 --- a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/tests/test-1.yaml +++ /dev/null @@ -1,44 +0,0 @@ -{{- $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 deleted file mode 100644 index 5e49e23c..00000000 --- a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/webhook-admission.yaml +++ /dev/null @@ -1,107 +0,0 @@ ---- -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 deleted file mode 100644 index df766a52..00000000 --- a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/webhook-deployment.yaml +++ /dev/null @@ -1,109 +0,0 @@ ---- -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 deleted file mode 100644 index bdfc1bc1..00000000 --- a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/webhook-pdb.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{- 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 deleted file mode 100644 index c149e28a..00000000 --- a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/webhook-rbac.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -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 deleted file mode 100644 index 3eb14836..00000000 --- a/packages/system/clustersecret-operator/charts/clustersecret-operator/values.yaml +++ /dev/null @@ -1,138 +0,0 @@ -# -- 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 deleted file mode 100644 index ff7b161a..00000000 --- a/packages/system/clustersecret-operator/values.yaml +++ /dev/null @@ -1 +0,0 @@ -clustersecret-operator: {} diff --git a/packages/system/coredns/Makefile b/packages/system/coredns/Makefile index 4aca5b38..a610a862 100644 --- a/packages/system/coredns/Makefile +++ b/packages/system/coredns/Makefile @@ -1,7 +1,7 @@ export NAME=coredns export NAMESPACE=kube-system -include ../../../hack/package.mk +include ../../../scripts/package.mk update: rm -rf charts diff --git a/packages/system/coredns/values.yaml b/packages/system/coredns/values.yaml index 7f6403b8..a1061a1e 100644 --- a/packages/system/coredns/values.yaml +++ b/packages/system/coredns/values.yaml @@ -6,6 +6,3 @@ coredns: 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 c1da95c7..8f4f6192 100644 --- a/packages/system/cozy-proxy/Makefile +++ b/packages/system/cozy-proxy/Makefile @@ -1,8 +1,8 @@ NAME=cozy-proxy NAMESPACE=cozy-system -include ../../../hack/common-envs.mk -include ../../../hack/package.mk +include ../../../scripts/common-envs.mk +include ../../../scripts/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 58f166f6..13352680 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.3.0 -appVersion: 0.3.0 +version: 0.2.0 +appVersion: 0.2.0 diff --git a/packages/system/cozy-proxy/charts/cozy-proxy/values.yaml b/packages/system/cozy-proxy/charts/cozy-proxy/values.yaml index e143e926..8cde5bed 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.3.0 + tag: v0.2.0 pullPolicy: IfNotPresent daemonset: diff --git a/packages/system/cozystack-api/Makefile b/packages/system/cozystack-api/Makefile index c4e6f459..a3e0d931 100644 --- a/packages/system/cozystack-api/Makefile +++ b/packages/system/cozystack-api/Makefile @@ -1,8 +1,8 @@ NAME=cozystack-api NAMESPACE=cozy-system -include ../../../hack/common-envs.mk -include ../../../hack/package.mk +include ../../../scripts/common-envs.mk +include ../../../scripts/package.mk run-local: openssl req -nodes -new -x509 -keyout /tmp/ca.key -out /tmp/ca.crt -subj "/CN=kube-ca" diff --git a/packages/system/cozystack-api/templates/certmanager.yaml b/packages/system/cozystack-api/templates/certmanager.yaml index 4f73768a..def27bd1 100644 --- a/packages/system/cozystack-api/templates/certmanager.yaml +++ b/packages/system/cozystack-api/templates/certmanager.yaml @@ -18,8 +18,6 @@ spec: issuerRef: name: cozystack-api-selfsigned isCA: true - privateKey: - rotationPolicy: Never --- apiVersion: cert-manager.io/v1 kind: Issuer diff --git a/packages/system/cozystack-api/templates/deployment.yaml b/packages/system/cozystack-api/templates/deployment.yaml index 9febfe1e..1a63a0e0 100644 --- a/packages/system/cozystack-api/templates/deployment.yaml +++ b/packages/system/cozystack-api/templates/deployment.yaml @@ -1,12 +1,18 @@ apiVersion: apps/v1 +{{- if .Values.cozystackAPI.localK8sAPIEndpoint.enabled }} +kind: DaemonSet +{{- else }} kind: Deployment +{{- end }} metadata: name: cozystack-api namespace: cozy-system labels: app: cozystack-api spec: + {{- if not .Values.cozystackAPI.localK8sAPIEndpoint.enabled }} replicas: {{ .Values.cozystackAPI.replicas }} + {{- end }} selector: matchLabels: app: cozystack-api @@ -15,22 +21,26 @@ spec: labels: app: cozystack-api spec: - tolerations: - - operator: Exists serviceAccountName: cozystack-api - affinity: - nodeAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 100 - preference: - matchExpressions: - - key: node-role.kubernetes.io/control-plane - operator: Exists + {{- if .Values.cozystackAPI.localK8sAPIEndpoint.enabled }} + nodeSelector: + node-role.kubernetes.io/control-plane: "" + {{- end }} containers: - name: cozystack-api args: - --tls-cert-file=/tmp/cozystack-api-certs/tls.crt - --tls-private-key-file=/tmp/cozystack-api-certs/tls.key + {{- if .Values.cozystackAPI.localK8sAPIEndpoint.enabled }} + env: + - name: KUBERNETES_SERVICE_HOST + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: KUBERNETES_SERVICE_PORT + value: "6443" + {{- end }} image: "{{ .Values.cozystackAPI.image }}" ports: - containerPort: 443 diff --git a/packages/system/cozystack-api/templates/hook.yaml b/packages/system/cozystack-api/templates/hook.yaml index 852b2db0..3c6b3080 100644 --- a/packages/system/cozystack-api/templates/hook.yaml +++ b/packages/system/cozystack-api/templates/hook.yaml @@ -1,5 +1,16 @@ -{{- $previous := lookup "apps/v1" "DaemonSet" .Release.Namespace "cozystack-api" }} +{{- $shouldRunUpdateHook := false }} +{{- $previousKind := "Deployment" }} +{{- $previousKindPlural := "deployments" }} +{{- if not .Values.cozystackAPI.localK8sAPIEndpoint.enabled }} + {{- $previousKind = "DaemonSet" }} + {{- $previousKindPlural = "daemonsets" }} +{{- end }} +{{- $previous := lookup "apps/v1" $previousKind .Release.Namespace "cozystack-api" }} {{- if $previous }} + {{- $shouldRunUpdateHook = true }} +{{- end }} + +{{- if $shouldRunUpdateHook }} --- apiVersion: batch/v1 kind: Job @@ -25,7 +36,7 @@ spec: - -exc - |- kubectl --namespace={{ .Release.Namespace }} delete --ignore-not-found \ - daemonsets.apps cozystack-api + {{ $previousKindPlural }}.apps cozystack-api restartPolicy: Never --- apiVersion: rbac.authorization.k8s.io/v1 @@ -40,7 +51,7 @@ rules: - apiGroups: - "apps" resources: - - "daemonsets" + - "{{ $previousKindPlural }}" verbs: - get - delete diff --git a/packages/system/cozystack-api/templates/service.yaml b/packages/system/cozystack-api/templates/service.yaml index 64ba149d..abe67abc 100644 --- a/packages/system/cozystack-api/templates/service.yaml +++ b/packages/system/cozystack-api/templates/service.yaml @@ -4,7 +4,9 @@ metadata: name: cozystack-api namespace: cozy-system spec: - trafficDistribution: PreferClose + {{- if .Values.cozystackAPI.localK8sAPIEndpoint.enabled }} + internalTrafficPolicy: Local + {{- end }} ports: - port: 443 protocol: TCP diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index dddabf54..8bf0a803 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,3 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v1.3.0@sha256:5fa8648821cf1e9e08cf7c2899c4b1c4226bb74c6773327141456c7d3f2b9b7e + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.38.2@sha256:d17f1c59658731e5a2063c3db348adbc03b5cd31720052016b68449164cf2f14 + localK8sAPIEndpoint: + enabled: true replicas: 2 diff --git a/packages/system/cozystack-basics/Chart.yaml b/packages/system/cozystack-basics/Chart.yaml deleted file mode 100644 index 8135baef..00000000 --- a/packages/system/cozystack-basics/Chart.yaml +++ /dev/null @@ -1,3 +0,0 @@ -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 deleted file mode 100644 index 2d5f6c59..00000000 --- a/packages/system/cozystack-basics/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index f270f4e1..00000000 --- a/packages/system/cozystack-basics/templates/clusterroles.yaml +++ /dev/null @@ -1,264 +0,0 @@ ---- -# == 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 deleted file mode 100644 index b76816b4..00000000 --- a/packages/system/cozystack-basics/templates/cozy-public.yaml +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 8c0d1c7a..00000000 --- a/packages/system/cozystack-basics/templates/cozystack-values-secret.yaml +++ /dev/null @@ -1,20 +0,0 @@ ---- -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 deleted file mode 100644 index f7656319..00000000 --- a/packages/system/cozystack-basics/templates/dashboard-role.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -# == 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 deleted file mode 100644 index e36540c4..00000000 --- a/packages/system/cozystack-basics/templates/monitoring-external-services.yaml +++ /dev/null @@ -1,27 +0,0 @@ ---- -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 deleted file mode 100644 index 93f5129e..00000000 --- a/packages/system/cozystack-basics/templates/tenant-root.yaml +++ /dev/null @@ -1,28 +0,0 @@ ---- -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 deleted file mode 100644 index b8b5e457..00000000 --- a/packages/system/cozystack-basics/values.yaml +++ /dev/null @@ -1 +0,0 @@ -_cluster: {} diff --git a/packages/system/cozystack-controller/Makefile b/packages/system/cozystack-controller/Makefile index d1cc1871..9bbfb5a6 100644 --- a/packages/system/cozystack-controller/Makefile +++ b/packages/system/cozystack-controller/Makefile @@ -1,15 +1,14 @@ NAME=cozystack-controller NAMESPACE=cozy-system -include ../../../hack/common-envs.mk -include ../../../hack/package.mk +include ../../../scripts/common-envs.mk +include ../../../scripts/package.mk -image: image-cozystack-controller +image: image-cozystack-controller update-version image-cozystack-controller: docker buildx build -f images/cozystack-controller/Dockerfile ../../.. \ --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 \ @@ -17,3 +16,7 @@ image-cozystack-controller: 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/definitions/dashboard.cozystack.io_cfomappings.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_cfomappings.yaml deleted file mode 100644 index a46f6a23..00000000 --- a/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_cfomappings.yaml +++ /dev/null @@ -1,118 +0,0 @@ ---- -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/images/cozystack-controller/Dockerfile b/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile index ea475317..bd6cfb38 100644 --- a/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile +++ b/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile @@ -2,7 +2,6 @@ FROM golang:1.25-alpine AS builder ARG TARGETOS ARG TARGETARCH -ARG VERSION=dev WORKDIR /workspace @@ -14,9 +13,7 @@ COPY pkg pkg/ COPY cmd cmd/ COPY internal internal/ -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 +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -ldflags="-extldflags=-static" -o /cozystack-controller cmd/cozystack-controller/main.go FROM scratch diff --git a/packages/system/cozystack-controller/templates/deployment.yaml b/packages/system/cozystack-controller/templates/deployment.yaml index aab7bbe1..6dc21b1c 100644 --- a/packages/system/cozystack-controller/templates/deployment.yaml +++ b/packages/system/cozystack-controller/templates/deployment.yaml @@ -19,6 +19,7 @@ spec: - name: cozystack-controller image: "{{ .Values.cozystackController.image }}" args: + - --cozystack-version={{ .Values.cozystackController.cozystackVersion }} {{- if .Values.cozystackController.debug }} - --zap-log-level=debug {{- else }} @@ -27,3 +28,6 @@ spec: {{- if .Values.cozystackController.disableTelemetry }} - --disable-telemetry {{- end }} + {{- if eq .Values.cozystackController.cozystackAPIKind "Deployment" }} + - --reconcile-deployment + {{- end }} diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index 4d0d0fde..1b365a43 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,4 +1,6 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v1.3.0@sha256:d03d19b78c4c98f970ac549a68b01ef6bd1ad755f5e0dcb9e08503511cdf2fdc + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.38.2@sha256:468b2eccbc0aa00bd3d72d56624a46e6ba178fa279cdd19248af74d32ea7d319 debug: false disableTelemetry: false + cozystackVersion: "v0.38.2" + cozystackAPIKind: "DaemonSet" diff --git a/packages/system/clustersecret-operator/Chart.yaml b/packages/system/cozystack-resource-definition-crd/Chart.yaml similarity index 74% rename from packages/system/clustersecret-operator/Chart.yaml rename to packages/system/cozystack-resource-definition-crd/Chart.yaml index bc9ef8e7..9924c7fa 100644 --- a/packages/system/clustersecret-operator/Chart.yaml +++ b/packages/system/cozystack-resource-definition-crd/Chart.yaml @@ -1,3 +1,3 @@ apiVersion: v2 -name: cozy-clustersecret-operator +name: cozystack-resource-definition-crd version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/cozystack-resource-definition-crd/Makefile b/packages/system/cozystack-resource-definition-crd/Makefile new file mode 100644 index 00000000..ddb24aef --- /dev/null +++ b/packages/system/cozystack-resource-definition-crd/Makefile @@ -0,0 +1,4 @@ +export NAME=cozystack-resource-definition-crd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/application-definition-crd/definition/cozystack.io_applicationdefinitions.yaml b/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml similarity index 72% rename from packages/system/application-definition-crd/definition/cozystack.io_applicationdefinitions.yaml rename to packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml index 44d33865..685d4ac5 100644 --- a/packages/system/application-definition-crd/definition/cozystack.io_applicationdefinitions.yaml +++ b/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml @@ -4,20 +4,20 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.16.4 - name: applicationdefinitions.cozystack.io + name: cozystackresourcedefinitions.cozystack.io spec: group: cozystack.io names: - kind: ApplicationDefinition - listKind: ApplicationDefinitionList - plural: applicationdefinitions - singular: applicationdefinition + kind: CozystackResourceDefinition + listKind: CozystackResourceDefinitionList + plural: cozystackresourcedefinitions + singular: cozystackresourcedefinition scope: Cluster versions: - name: v1alpha1 schema: openAPIV3Schema: - description: ApplicationDefinition is the Schema for the applicationdefinitions + description: CozystackResourceDefinition is the Schema for the cozystackresourcedefinitions API properties: apiVersion: @@ -135,22 +135,29 @@ spec: 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\"" + description: |- + CozystackResourceDefinitionResourceSelector 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" properties: matchExpressions: description: matchExpressions is a list of label selector @@ -210,22 +217,29 @@ spec: 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\"" + description: |- + CozystackResourceDefinitionResourceSelector 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" properties: matchExpressions: description: matchExpressions is a list of label selector @@ -282,34 +296,34 @@ spec: release: description: Release configuration properties: - chartRef: - description: Reference to the chart source + chart: + description: Helm chart configuration 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 + description: Name of the Helm chart type: string + sourceRef: + description: Source reference for the Helm chart + properties: + kind: + default: HelmRepository + description: Kind of the source reference + type: string + name: + description: Name of the source reference + type: string + namespace: + default: cozy-public + description: Namespace of the source reference + type: string + required: + - kind + - name + - namespace + type: object required: - - kind - name + - sourceRef type: object labels: additionalProperties: @@ -320,7 +334,7 @@ spec: description: Prefix for the release name type: string required: - - chartRef + - chart - prefix type: object secrets: @@ -332,22 +346,29 @@ spec: 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\"" + description: |- + CozystackResourceDefinitionResourceSelector 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" properties: matchExpressions: description: matchExpressions is a list of label selector @@ -407,22 +428,29 @@ spec: 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\"" + description: |- + CozystackResourceDefinitionResourceSelector 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" properties: matchExpressions: description: matchExpressions is a list of label selector @@ -485,22 +513,29 @@ spec: 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\"" + description: |- + CozystackResourceDefinitionResourceSelector 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" properties: matchExpressions: description: matchExpressions is a list of label selector @@ -560,22 +595,29 @@ spec: 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\"" + description: |- + CozystackResourceDefinitionResourceSelector 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" properties: matchExpressions: description: matchExpressions is a list of label selector diff --git a/packages/system/cozystack-resource-definition-crd/templates/crd.yaml b/packages/system/cozystack-resource-definition-crd/templates/crd.yaml new file mode 100644 index 00000000..40a93ad3 --- /dev/null +++ b/packages/system/cozystack-resource-definition-crd/templates/crd.yaml @@ -0,0 +1,2 @@ +--- +{{ .Files.Get "definition/cozystack.io_cozystackresourcedefinitions.yaml" }} diff --git a/packages/system/application-definition-crd/values.yaml b/packages/system/cozystack-resource-definition-crd/values.yaml similarity index 100% rename from packages/system/application-definition-crd/values.yaml rename to packages/system/cozystack-resource-definition-crd/values.yaml diff --git a/packages/system/cozystack-scheduler/Chart.yaml b/packages/system/cozystack-scheduler/Chart.yaml deleted file mode 100644 index f2dd13ee..00000000 --- a/packages/system/cozystack-scheduler/Chart.yaml +++ /dev/null @@ -1,3 +0,0 @@ -apiVersion: v2 -name: cozy-cozystack-scheduler -version: 0.3.0 diff --git a/packages/system/cozystack-scheduler/Makefile b/packages/system/cozystack-scheduler/Makefile deleted file mode 100644 index d075ec63..00000000 --- a/packages/system/cozystack-scheduler/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index f2dd13ee..00000000 --- a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/Chart.yaml +++ /dev/null @@ -1,3 +0,0 @@ -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 deleted file mode 100644 index d6b60d8b..00000000 --- a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/crds/cozystack.io_schedulingclasses.yaml +++ /dev/null @@ -1,1123 +0,0 @@ ---- -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 deleted file mode 100644 index 22f196a5..00000000 --- a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/clusterrole.yaml +++ /dev/null @@ -1,9 +0,0 @@ -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 deleted file mode 100644 index 00fcd968..00000000 --- a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/clusterrolebinding.yaml +++ /dev/null @@ -1,38 +0,0 @@ -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 deleted file mode 100644 index 24e0bc6f..00000000 --- a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/configmap.yaml +++ /dev/null @@ -1,58 +0,0 @@ -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 deleted file mode 100644 index 0365f0de..00000000 --- a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/deployment.yaml +++ /dev/null @@ -1,40 +0,0 @@ -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 deleted file mode 100644 index 796bf55c..00000000 --- a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/rolebinding.yaml +++ /dev/null @@ -1,40 +0,0 @@ -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 deleted file mode 100644 index 876e5f01..00000000 --- a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/serviceaccount.yaml +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index 55b6faff..00000000 --- a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/values.yaml +++ /dev/null @@ -1,23 +0,0 @@ -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 deleted file mode 100644 index a7b8fd21..00000000 --- a/packages/system/cozystack-scheduler/templates/tenant-clusterroles.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -# == 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 deleted file mode 100644 index ce8f372d..00000000 --- a/packages/system/cozystack-scheduler/tests/configmap_test.yaml +++ /dev/null @@ -1,26 +0,0 @@ -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 deleted file mode 100644 index ab16ca57..00000000 --- a/packages/system/cozystack-scheduler/values-linstor.yaml +++ /dev/null @@ -1,10 +0,0 @@ -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 a9f680a3..f89cba0d 100644 --- a/packages/system/dashboard/Makefile +++ b/packages/system/dashboard/Makefile @@ -1,8 +1,8 @@ export NAME=dashboard export NAMESPACE=cozy-$(NAME) -include ../../../hack/common-envs.mk -include ../../../hack/package.mk +include ../../../scripts/common-envs.mk +include ../../../scripts/package.mk update: update-crd update-dockerfiles image: image-openapi-ui image-openapi-ui-k8s-bff image-token-proxy update-tenant-text diff --git a/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile b/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile index ea0c900d..ef698698 100644 --- a/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile +++ b/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile @@ -1,10 +1,9 @@ -# imported from https://github.com/PRO-Robotech/openapi-ui-k8s-bff +# imported from https://github.com/cozystack/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 +ARG COMMIT_REF=183dc9dcbb0f8a1833dad642c35faa385c71e58d 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 diff --git a/packages/system/dashboard/images/openapi-ui/Dockerfile b/packages/system/dashboard/images/openapi-ui/Dockerfile index 82cc6db0..f430f8e6 100644 --- a/packages/system/dashboard/images/openapi-ui/Dockerfile +++ b/packages/system/dashboard/images/openapi-ui/Dockerfile @@ -1,13 +1,12 @@ ARG NODE_VERSION=20.18.1 # openapi-k8s-toolkit -# imported from https://github.com/PRO-Robotech/openapi-k8s-toolkit +# imported from https://github.com/cozystack/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 +ARG COMMIT=cb2f122caafaa2fd5455750213d9e633017ec555 +RUN wget -O- https://github.com/cozystack/openapi-k8s-toolkit/archive/${COMMIT}.tar.gz | tar -xzvf- --strip-components=1 COPY openapi-k8s-toolkit/patches /patches RUN git apply /patches/*.diff @@ -18,13 +17,12 @@ RUN npm run build # openapi-ui -# imported from https://github.com/PRO-Robotech/openapi-ui +# imported from https://github.com/cozystack/openapi-ui FROM node:${NODE_VERSION}-alpine AS builder #RUN apk add git WORKDIR /src -# release/1.4.0 -ARG COMMIT_REF=6addca6939264ef2e39801baa88c1460cc1aa53e +ARG COMMIT_REF=3cfbbf2156b6a5e4a1f283a032019530c0c2d37d 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 @@ -58,12 +56,5 @@ 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 deleted file mode 100644 index e98861a3..00000000 --- a/packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/flatmap-unresolved-placeholder.diff +++ /dev/null @@ -1,17 +0,0 @@ -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 deleted file mode 100644 index 1c83df7c..00000000 --- a/packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/formlistinput-allow-empty.diff +++ /dev/null @@ -1,37 +0,0 @@ -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 -+ }} - > -