From da6c053d3fee2c6cdad2d880772fd7587c04e3e3 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 9 Dec 2025 13:23:53 +0100 Subject: [PATCH 01/78] Fix: Add missing components to `distro-full` bundle (#1620) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `distro-full` bundle was missing critical components that exist in paas-full, causing multiple pod failures during installation. This PR adds the missing packages and fixes dependency issues. When installing cozystack with bundle-name: "distro-full", several pods failed to start: 1. CozystackResourceDefinition CRD missing - cozystack-controller pod: CrashLoopBackOff - lineage-controller-webhook pods: CrashLoopBackOff - Error: no matches for kind "CozystackResourceDefinition" in version "cozystack.io/v1alpha1" https://github.com/cozystack/cozystack/blob/a861814c241e38360f03f89ef44eb1791e4800fd/packages/system/cozystack-resource-definition-crd/definition/cozystack.io_cozystackresourcedefinitions.yaml#L1-L14 2. selfsigned-cluster-issuer ClusterIssuer missing - snapshot-validation-webhook pods: ContainerCreating (waiting for TLS secret) - snapshot-controller HelmRelease: Failed to install (timeout) - Error: clusterissuer.cert-manager.io "selfsigned-cluster-issuer" not found https://github.com/cozystack/cozystack/blob/a861814c241e38360f03f89ef44eb1791e4800fd/packages/system/cert-manager-issuers/templates/cluster-issuers.yaml#L52-L57 https://github.com/cozystack/cozystack/blob/a861814c241e38360f03f89ef44eb1791e4800fd/packages/system/snapshot-controller/template/clusterissuer.yaml#L1-L8 3. Cascading failures - linstor HelmRelease: Blocked (depends on snapshot-controller) ## Summary by CodeRabbit * **New Features** * Added two new resource-definition components to the platform distribution for enhanced configuration management. * **Improvements** * Made certificate issuer components required during deployment (no longer optional). * Adjusted snapshot controller startup order to wait for certificate issuers, improving startup reliability. ✏️ Tip: You can customize this high-level summary in your review settings. --- packages/core/platform/bundles/distro-full.yaml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/core/platform/bundles/distro-full.yaml b/packages/core/platform/bundles/distro-full.yaml index 3cd0df96..107cbb23 100644 --- a/packages/core/platform/bundles/distro-full.yaml +++ b/packages/core/platform/bundles/distro-full.yaml @@ -74,6 +74,18 @@ releases: 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: cozystack-resource-definitions + releaseName: cozystack-resource-definitions + chart: cozystack-resource-definitions + namespace: cozy-system + dependsOn: [cilium,cozystack-controller,cozystack-resource-definition-crd] + - name: cert-manager releaseName: cert-manager chart: cozy-cert-manager @@ -84,7 +96,6 @@ releases: releaseName: cert-manager-issuers chart: cozy-cert-manager-issuers namespace: cozy-cert-manager - optional: true dependsOn: [cilium,cert-manager] - name: prometheus-operator-crds @@ -204,7 +215,7 @@ releases: releaseName: snapshot-controller chart: cozy-snapshot-controller namespace: cozy-snapshot-controller - dependsOn: [cilium] + dependsOn: [cilium,cert-manager-issuers] - name: objectstorage-controller releaseName: objectstorage-controller From a4a432e2aaae658706d763a8e331227edbbb94d1 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 9 Dec 2025 14:25:32 +0100 Subject: [PATCH 02/78] [ci] Improve backport workflow with merge_commits skip and conflict resolution (#1694) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR improves the backport workflow by: - Adding `merge_commits: skip` to skip merge commits during backport - Adding `conflict_resolution: draft_commit_conflicts` to create draft PRs when conflicts occur instead of failing - Removing the 'Report if backport failed' step as it's no longer needed with the new conflict resolution strategy These changes ensure that backports handle merge commits and conflicts more gracefully. ## Summary by CodeRabbit * **Chores** * Enhanced the backport workflow to support simultaneous backporting to current and previous release branches based on PR labels * Added validation to ensure target branches exist before attempting backports * Improved workflow reliability by separating preparation and execution stages ✏️ Tip: You can customize this high-level summary in your review settings. --- .github/workflows/backport.yaml | 102 ++++++++++++++++++++++++++++---- 1 file changed, 89 insertions(+), 13 deletions(-) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index 10968e38..5a1ca990 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -2,7 +2,7 @@ name: Automatic Backport on: pull_request_target: - types: [closed] # fires when PR is closed (merged) + types: [closed, labeled] # fires when PR is closed (merged) or labeled concurrency: group: backport-${{ github.workflow }}-${{ github.event.pull_request.number }} @@ -13,22 +13,46 @@ permissions: pull-requests: write jobs: - backport: + # Determine which backports are needed + prepare: if: | github.event.pull_request.merged == true && - contains(github.event.pull_request.labels.*.name, 'backport') + ( + contains(github.event.pull_request.labels.*.name, 'backport') || + contains(github.event.pull_request.labels.*.name, 'backport-previous') || + (github.event.action == 'labeled' && (github.event.label.name == 'backport' || github.event.label.name == 'backport-previous')) + ) runs-on: [self-hosted] - + outputs: + backport_current: ${{ steps.labels.outputs.backport }} + backport_previous: ${{ steps.labels.outputs.backport_previous }} + current_branch: ${{ steps.branches.outputs.current_branch }} + previous_branch: ${{ steps.branches.outputs.previous_branch }} steps: - # 1. Decide which maintenance branch should receive the back‑port - - name: Determine target maintenance branch - id: target + - name: Check which labels are present + id: labels uses: actions/github-script@v7 with: script: | - let rel; + const pr = context.payload.pull_request; + const labels = pr.labels.map(l => l.name); + const isBackport = labels.includes('backport'); + const isBackportPrevious = labels.includes('backport-previous'); + + core.setOutput('backport', isBackport ? 'true' : 'false'); + core.setOutput('backport_previous', isBackportPrevious ? 'true' : 'false'); + + console.log(`backport label: ${isBackport}, backport-previous label: ${isBackportPrevious}`); + + - name: Determine target branches + id: branches + uses: actions/github-script@v7 + with: + script: | + // Get latest release + let latestRelease; try { - rel = await github.rest.repos.getLatestRelease({ + latestRelease = await github.rest.repos.getLatestRelease({ owner: context.repo.owner, repo: context.repo.repo }); @@ -36,18 +60,70 @@ jobs: core.setFailed('No existing releases found; cannot determine backport target.'); return; } - const [maj, min] = rel.data.tag_name.replace(/^v/, '').split('.'); - const branch = `release-${maj}.${min}`; - core.setOutput('branch', branch); - console.log(`Latest release ${rel.data.tag_name}; backporting to ${branch}`); + + const [maj, min] = latestRelease.data.tag_name.replace(/^v/, '').split('.'); + const currentBranch = `release-${maj}.${min}`; + const prevMin = parseInt(min) - 1; + const previousBranch = prevMin >= 0 ? `release-${maj}.${prevMin}` : ''; + + core.setOutput('current_branch', currentBranch); + core.setOutput('previous_branch', previousBranch); + + console.log(`Current branch: ${currentBranch}, Previous branch: ${previousBranch || 'N/A'}`); + + // Verify previous branch exists if we need it + if (previousBranch && '${{ steps.labels.outputs.backport_previous }}' === 'true') { + try { + await github.rest.repos.getBranch({ + owner: context.repo.owner, + repo: context.repo.repo, + branch: previousBranch + }); + console.log(`Previous branch ${previousBranch} exists`); + } catch (e) { + core.setFailed(`Previous branch ${previousBranch} does not exist.`); + return; + } + } + + backport: + needs: prepare + if: | + github.event.pull_request.merged == true && + (needs.prepare.outputs.backport_current == 'true' || needs.prepare.outputs.backport_previous == 'true') + runs-on: [self-hosted] + strategy: + matrix: + backport_type: [current, previous] + steps: + # 1. Determine target branch based on matrix + - name: Set target branch + id: target + if: | + (matrix.backport_type == 'current' && needs.prepare.outputs.backport_current == 'true') || + (matrix.backport_type == 'previous' && needs.prepare.outputs.backport_previous == 'true') + run: | + if [ "${{ matrix.backport_type }}" == "current" ]; then + echo "branch=${{ needs.prepare.outputs.current_branch }}" >> $GITHUB_OUTPUT + echo "Target branch: ${{ needs.prepare.outputs.current_branch }}" + else + echo "branch=${{ needs.prepare.outputs.previous_branch }}" >> $GITHUB_OUTPUT + echo "Target branch: ${{ needs.prepare.outputs.previous_branch }}" + fi + # 2. Checkout (required by backport‑action) - name: Checkout repository + if: steps.target.outcome == 'success' uses: actions/checkout@v4 # 3. Create the back‑port pull request - name: Create back‑port PR + id: backport + if: steps.target.outcome == 'success' uses: korthout/backport-action@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} label_pattern: '' # don't read labels for targets target_branches: ${{ steps.target.outputs.branch }} + merge_commits: skip + conflict_resolution: draft_commit_conflicts From 2c3761113601fc4e54063469e7bd7f8c4ae290fe Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 9 Dec 2025 14:33:03 +0100 Subject: [PATCH 03/78] [ci] Update korthout/backport-action@v3.2.1 Signed-off-by: Andrei Kvapil --- .github/workflows/backport.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index 5a1ca990..ed427827 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -120,7 +120,7 @@ jobs: - name: Create back‑port PR id: backport if: steps.target.outcome == 'success' - uses: korthout/backport-action@v3 + uses: korthout/backport-action@v3.2.1 with: github_token: ${{ secrets.GITHUB_TOKEN }} label_pattern: '' # don't read labels for targets From bd443bd578de2c686390a1f40200a0208bc7a418 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 9 Dec 2025 14:38:02 +0100 Subject: [PATCH 04/78] [linstor] Update piraeus-operator v2.10.2 (#1689) Signed-off-by: Andrei Kvapil ## What this PR does This release updates LINSTOR CSI to fix issues with the new fsck behaviour. ``` MountVolume.SetUp failed for volume "pvc-37245cc3-bf28-4da4-a127-e5c9c03cc088" : rpc error: code = Internal desc = NodePublishVolume failed for pvc-37245cc3-bf28-4da4-a127-e5c9c03cc088: failed to run fsck on device '/dev/zvol/data/pvc-37245cc3-bf28-4da4-a127-e5c9c03cc088_00000': failed to run fsck: output: "fsck from util-linux 2.41 /dev/zd832 is mounted. e2fsck: Cannot continue, aborting. ``` ### Release note ```release-note [linstor] Update piraeus-operator v2.10.2 ``` --- .../charts/piraeus/Chart.yaml | 4 +-- .../charts/piraeus/templates/config.yaml | 8 ++--- .../charts/piraeus/templates/crds.yaml | 35 +++++++++++++++++++ 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/packages/system/piraeus-operator/charts/piraeus/Chart.yaml b/packages/system/piraeus-operator/charts/piraeus/Chart.yaml index 38bd15db..777722f3 100644 --- a/packages/system/piraeus-operator/charts/piraeus/Chart.yaml +++ b/packages/system/piraeus-operator/charts/piraeus/Chart.yaml @@ -3,8 +3,8 @@ name: piraeus description: | The Piraeus Operator manages software defined storage clusters using LINSTOR in Kubernetes. type: application -version: 2.10.1 -appVersion: "v2.10.1" +version: 2.10.2 +appVersion: "v2.10.2" maintainers: - name: Piraeus Datastore url: https://piraeus.io diff --git a/packages/system/piraeus-operator/charts/piraeus/templates/config.yaml b/packages/system/piraeus-operator/charts/piraeus/templates/config.yaml index a57dffd3..2e6963f0 100644 --- a/packages/system/piraeus-operator/charts/piraeus/templates/config.yaml +++ b/packages/system/piraeus-operator/charts/piraeus/templates/config.yaml @@ -23,10 +23,10 @@ data: tag: v1.32.3 image: piraeus-server linstor-csi: - tag: v1.10.2 + tag: v1.10.3 image: piraeus-csi nfs-server: - tag: v1.10.2 + tag: v1.10.3 image: piraeus-csi-nfs-server drbd-reactor: tag: v1.10.0 @@ -44,7 +44,7 @@ data: tag: v1.3.0 image: linstor-affinity-controller drbd-module-loader: - tag: v9.2.15 + tag: v9.2.16 # The special "match" attribute is used to select an image based on the node's reported OS. # The operator will first check the k8s node's ".status.nodeInfo.osImage" field, and compare it against the list # here. If one matches, that specific image name will be used instead of the fallback image. @@ -99,7 +99,7 @@ data: tag: v2.17.0 image: livenessprobe csi-provisioner: - tag: v6.0.0 + tag: v6.1.0 image: csi-provisioner csi-snapshotter: tag: v8.4.0 diff --git a/packages/system/piraeus-operator/charts/piraeus/templates/crds.yaml b/packages/system/piraeus-operator/charts/piraeus/templates/crds.yaml index 1821cb61..5bd9212c 100644 --- a/packages/system/piraeus-operator/charts/piraeus/templates/crds.yaml +++ b/packages/system/piraeus-operator/charts/piraeus/templates/crds.yaml @@ -993,6 +993,24 @@ spec: - Retain - Delete type: string + evacuationStrategy: + description: EvacuationStrategy configures the evacuation of volumes + from a Satellite when DeletionPolicy "Evacuate" is used. + nullable: true + properties: + attachedVolumeReattachTimeout: + default: 5m + description: |- + AttachedVolumeReattachTimeout configures how long evacuation waits for attached volumes to reattach on + different nodes. Setting this to 0 disable this evacuation step. + type: string + unattachedVolumeAttachTimeout: + default: 5m + description: |- + UnattachedVolumeAttachTimeout configures how long evacuation waits for unattached volumes to attach on + different nodes. Setting this to 0 disable this evacuation step. + type: string + type: object internalTLS: description: |- InternalTLS configures secure communication for the LINSTOR Satellite. @@ -1683,6 +1701,23 @@ spec: - Retain - Delete type: string + evacuationStrategy: + description: EvacuationStrategy configures the evacuation of volumes + from a Satellite when DeletionPolicy "Evacuate" is used. + properties: + attachedVolumeReattachTimeout: + default: 5m + description: |- + AttachedVolumeReattachTimeout configures how long evacuation waits for attached volumes to reattach on + different nodes. Setting this to 0 disable this evacuation step. + type: string + unattachedVolumeAttachTimeout: + default: 5m + description: |- + UnattachedVolumeAttachTimeout configures how long evacuation waits for unattached volumes to attach on + different nodes. Setting this to 0 disable this evacuation step. + type: string + type: object internalTLS: description: |- InternalTLS configures secure communication for the LINSTOR Satellite. From 66b68e379892e395148db7ddd999da0e13eff460 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 9 Dec 2025 17:04:41 +0100 Subject: [PATCH 05/78] [dashboard] Fix CustomFormsOverride schema to nest properties under spec.properties (#1692) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does Fixes the logic for generating CustomFormsOverride schema to properly nest properties under `spec.properties` instead of directly under `properties`. Changes: - Updated `buildMultilineStringSchema` to check for `spec` property in OpenAPI schema - Process `spec.properties` instead of root `properties` - Create schema structure as `schema.properties.spec.properties.*` - Updated tests to reflect the new nested structure ### Release note ```release-note [dashboard] Fix CustomFormsOverride schema generation to nest properties under spec.properties ``` ## Summary by CodeRabbit * **Refactor** * Updated custom form schema generation to organize form fields within a nested structure for improved organization. * **Tests** * Expanded test coverage to validate the new schema organization and field type handling across nested levels. ✏️ Tip: You can customize this high-level summary in your review settings. --- .../dashboard/customformsoverride.go | 20 +++- .../dashboard/customformsoverride_test.go | 94 +++++++++++-------- 2 files changed, 74 insertions(+), 40 deletions(-) diff --git a/internal/controller/dashboard/customformsoverride.go b/internal/controller/dashboard/customformsoverride.go index f88202bc..2b0daa08 100644 --- a/internal/controller/dashboard/customformsoverride.go +++ b/internal/controller/dashboard/customformsoverride.go @@ -105,8 +105,26 @@ func buildMultilineStringSchema(openAPISchema string) (map[string]any, error) { "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 + } + + specProps, ok := specProp["properties"].(map[string]any) + if !ok { + return map[string]any{}, nil + } + + // Create spec.properties structure in schema + schemaProps := schema["properties"].(map[string]any) + specSchema := map[string]any{ + "properties": map[string]any{}, + } + schemaProps["spec"] = specSchema + // Process spec properties recursively - processSpecProperties(props, schema["properties"].(map[string]any)) + processSpecProperties(specProps, specSchema["properties"].(map[string]any)) return schema, nil } diff --git a/internal/controller/dashboard/customformsoverride_test.go b/internal/controller/dashboard/customformsoverride_test.go index 2766bf17..9f7babe9 100644 --- a/internal/controller/dashboard/customformsoverride_test.go +++ b/internal/controller/dashboard/customformsoverride_test.go @@ -9,41 +9,46 @@ func TestBuildMultilineStringSchema(t *testing.T) { // Test OpenAPI schema with various field types openAPISchema := `{ "properties": { - "simpleString": { - "type": "string", - "description": "A simple string field" - }, - "stringWithEnum": { - "type": "string", - "enum": ["option1", "option2"], - "description": "String with enum should be skipped" - }, - "numberField": { - "type": "number", - "description": "Number field should be skipped" - }, - "nestedObject": { + "spec": { "type": "object", "properties": { - "nestedString": { + "simpleString": { "type": "string", - "description": "Nested string should get multilineString" + "description": "A simple string field" }, - "nestedStringWithEnum": { + "stringWithEnum": { "type": "string", - "enum": ["a", "b"], - "description": "Nested string with enum should be skipped" - } - } - }, - "arrayOfObjects": { - "type": "array", - "items": { - "type": "object", - "properties": { - "itemString": { - "type": "string", - "description": "String in array item" + "enum": ["option1", "option2"], + "description": "String with enum should be skipped" + }, + "numberField": { + "type": "number", + "description": "Number field should be skipped" + }, + "nestedObject": { + "type": "object", + "properties": { + "nestedString": { + "type": "string", + "description": "Nested string should get multilineString" + }, + "nestedStringWithEnum": { + "type": "string", + "enum": ["a", "b"], + "description": "Nested string with enum should be skipped" + } + } + }, + "arrayOfObjects": { + "type": "array", + "items": { + "type": "object", + "properties": { + "itemString": { + "type": "string", + "description": "String in array item" + } + } } } } @@ -70,33 +75,44 @@ func TestBuildMultilineStringSchema(t *testing.T) { t.Fatal("schema.properties is not a map") } - // Check simpleString - simpleString, ok := props["simpleString"].(map[string]any) + // Check spec property exists + spec, ok := props["spec"].(map[string]any) if !ok { - t.Fatal("simpleString not found in properties") + t.Fatal("spec not found in properties") + } + + specProps, ok := spec["properties"].(map[string]any) + if !ok { + t.Fatal("spec.properties is not a map") + } + + // Check simpleString + simpleString, ok := specProps["simpleString"].(map[string]any) + if !ok { + t.Fatal("simpleString not found in spec.properties") } if simpleString["type"] != "multilineString" { t.Errorf("simpleString should have type multilineString, got %v", simpleString["type"]) } // Check stringWithEnum should not be present (or should not have multilineString) - if stringWithEnum, ok := props["stringWithEnum"].(map[string]any); ok { + if stringWithEnum, ok := specProps["stringWithEnum"].(map[string]any); ok { if stringWithEnum["type"] == "multilineString" { t.Error("stringWithEnum should not have multilineString type") } } // Check numberField should not be present - if numberField, ok := props["numberField"].(map[string]any); ok { + if numberField, ok := specProps["numberField"].(map[string]any); ok { if numberField["type"] != nil { t.Error("numberField should not have any type override") } } // Check nested object - nestedObject, ok := props["nestedObject"].(map[string]any) + nestedObject, ok := specProps["nestedObject"].(map[string]any) if !ok { - t.Fatal("nestedObject not found in properties") + t.Fatal("nestedObject not found in spec.properties") } nestedProps, ok := nestedObject["properties"].(map[string]any) if !ok { @@ -113,9 +129,9 @@ func TestBuildMultilineStringSchema(t *testing.T) { } // Check array of objects - arrayOfObjects, ok := props["arrayOfObjects"].(map[string]any) + arrayOfObjects, ok := specProps["arrayOfObjects"].(map[string]any) if !ok { - t.Fatal("arrayOfObjects not found in properties") + t.Fatal("arrayOfObjects not found in spec.properties") } items, ok := arrayOfObjects["items"].(map[string]any) if !ok { From 9b5f3726b614c09e52721259cff6088b9a5ac8d7 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 9 Dec 2025 17:08:39 +0100 Subject: [PATCH 06/78] [virtual-machine] Improve check for resizing job (#1688) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andrei Kvapil ## What this PR does PVC resizing now only occurs when storage is being increased, preventing unintended storage reduction operations ### Release note ```release-note [virtual-machine] Improve check for resizing job ``` ## Summary by CodeRabbit * **Bug Fixes** * PVC resizing now only triggers when the requested storage increases, preventing unintended shrink attempts. * **Enhancements** * More robust storage-size comparison and validation to accurately detect growth. * Resize operations now run only when needed, reducing unnecessary jobs. * **New Features** * Added conditional pre-install/pre-upgrade hook workflow to perform controlled PVC resize jobs. * **Chores** * Minor template formatting cleanup. ✏️ Tip: You can customize this high-level summary in your review settings. --- .../virtual-machine/templates/vm-update-hook.yaml | 6 +++++- .../apps/vm-disk/templates/pvc-resize-hook.yaml | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/apps/virtual-machine/templates/vm-update-hook.yaml b/packages/apps/virtual-machine/templates/vm-update-hook.yaml index 74f76cc5..1197c027 100644 --- a/packages/apps/virtual-machine/templates/vm-update-hook.yaml +++ b/packages/apps/virtual-machine/templates/vm-update-hook.yaml @@ -27,7 +27,11 @@ {{- if and $existingPVC $desiredStorage -}} {{- $currentStorage := $existingPVC.spec.resources.requests.storage | toString -}} {{- if not (eq $currentStorage $desiredStorage) -}} - {{- $needResizePVC = true -}} + {{- $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 -}} diff --git a/packages/apps/vm-disk/templates/pvc-resize-hook.yaml b/packages/apps/vm-disk/templates/pvc-resize-hook.yaml index 2619ed15..2454c599 100644 --- a/packages/apps/vm-disk/templates/pvc-resize-hook.yaml +++ b/packages/apps/vm-disk/templates/pvc-resize-hook.yaml @@ -1,5 +1,17 @@ {{- $existingPVC := lookup "v1" "PersistentVolumeClaim" .Release.Namespace .Release.Name }} -{{- if and $existingPVC (ne ($existingPVC.spec.resources.requests.storage | toString) .Values.storage) -}} +{{- $shouldResize := false -}} +{{- if and $existingPVC .Values.storage -}} + {{- $currentStorage := $existingPVC.spec.resources.requests.storage | toString -}} + {{- if ne $currentStorage .Values.storage -}} + {{- $oldSize := (include "cozy-lib.resources.toFloat" $currentStorage) | float64 -}} + {{- $newSize := (include "cozy-lib.resources.toFloat" .Values.storage) | float64 -}} + {{- if gt $newSize $oldSize -}} + {{- $shouldResize = true -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- if $shouldResize -}} apiVersion: batch/v1 kind: Job metadata: @@ -23,6 +35,7 @@ spec: command: ["sh", "-xec"] args: - | + echo "Resizing PVC to {{ .Values.storage }}..." kubectl patch pvc {{ .Release.Name }} -p '{"spec":{"resources":{"requests":{"storage":"{{ .Values.storage }}"}}}}' --- apiVersion: v1 From c44b198a60b262f85df0cb10a187401e87abc19f Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 10 Dec 2025 13:22:41 +0100 Subject: [PATCH 07/78] [apps] Refactor apiserver to use typed objects and fix UnstructuredList GVK (#1679) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does This PR refactors 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, it fixes 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 is a more comprehensive fix for the problem addressed in https://github.com/cozystack/cozystack/pull/1630, which was reverted in https://github.com/cozystack/cozystack/pull/1677. The fix includes the upstream fix from kubernetes/kubernetes#135537, which enables short-circuit path for `UnstructuredList` similar to regular `Unstructured` objects, using GVK from the object field instead of `typeToGVK`. ### Changes - Refactored `rest.go` handlers to use typed `Application` objects - Removed `unstructured.Unstructured` conversions - Fixed `UnstructuredList` GVK handling - Updated dependencies in `go.mod`/`go.sum` - Added e2e test for OpenAPI validation - Updated Dockerfile ### Release note ```release-note [apps] Refactor apiserver to use typed objects and fix UnstructuredList GVK handling This change refactors the apiserver REST handlers to use typed Application objects instead of unstructured.Unstructured, eliminating runtime conversions and simplifying the codebase. Additionally, it fixes an issue where UnstructuredList objects were incorrectly 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. ``` ## Summary by CodeRabbit * **Chores** * Added a module replacement in dependency configuration to ensure reproducible builds. * **Refactor** * REST internals now use strongly-typed Application and TenantModule resources and return typed API objects with consistent metadata. * **Tests** * Strengthened end-to-end checks for resource kinds and added a create/delete namespace scenario. ✏️ Tip: You can customize this high-level summary in your review settings. --- go.mod | 3 + go.sum | 4 +- hack/e2e-test-openapi.bats | 19 +++ pkg/registry/apps/application/rest.go | 178 +++++-------------------- pkg/registry/core/tenantmodule/rest.go | 101 +++++--------- 5 files changed, 91 insertions(+), 214 deletions(-) diff --git a/go.mod b/go.mod index 041aa96a..30ec5f7f 100644 --- a/go.mod +++ b/go.mod @@ -119,3 +119,6 @@ require ( sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) + +// See: issues.k8s.io/135537 +replace k8s.io/apimachinery => github.com/cozystack/apimachinery v0.0.0-20251201201312-18e522a87614 diff --git a/go.sum b/go.sum index a1090f31..a32e6b3b 100644 --- a/go.sum +++ b/go.sum @@ -18,6 +18,8 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cozystack/apimachinery v0.0.0-20251201201312-18e522a87614 h1:jH9elECUvhiIs3IMv3oS5k1JgCLVsSK6oU4dmq5gyW8= +github.com/cozystack/apimachinery v0.0.0-20251201201312-18e522a87614/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -291,8 +293,6 @@ k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= k8s.io/apiextensions-apiserver v0.31.2 h1:W8EwUb8+WXBLu56ser5IudT2cOho0gAKeTOnywBLxd0= k8s.io/apiextensions-apiserver v0.31.2/go.mod h1:i+Geh+nGCJEGiCGR3MlBDkS7koHIIKWVfWeRFiOsUcM= -k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= -k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= k8s.io/apiserver v0.31.2 h1:VUzOEUGRCDi6kX1OyQ801m4A7AUPglpsmGvdsekmcI4= k8s.io/apiserver v0.31.2/go.mod h1:o3nKZR7lPlJqkU5I3Ove+Zx3JuoFjQobGX1Gctw6XuE= k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= diff --git a/hack/e2e-test-openapi.bats b/hack/e2e-test-openapi.bats index d94cb422..88ed734b 100644 --- a/hack/e2e-test-openapi.bats +++ b/hack/e2e-test-openapi.bats @@ -21,14 +21,33 @@ } @test "Test kinds" { + val=$(kubectl get --raw /apis/apps.cozystack.io/v1alpha1/tenants | jq -r '.kind') + if [ "$val" != "TenantList" ]; then + echo "Expected kind to be TenantList, got $val" + exit 1 + fi val=$(kubectl get --raw /apis/apps.cozystack.io/v1alpha1/tenants | jq -r '.items[0].kind') if [ "$val" != "Tenant" ]; then echo "Expected kind to be Tenant, got $val" exit 1 fi + val=$(kubectl get --raw /apis/apps.cozystack.io/v1alpha1/ingresses | jq -r '.kind') + if [ "$val" != "IngressList" ]; then + echo "Expected kind to be IngressList, got $val" + exit 1 + fi val=$(kubectl get --raw /apis/apps.cozystack.io/v1alpha1/ingresses | jq -r '.items[0].kind') if [ "$val" != "Ingress" ]; then echo "Expected kind to be Ingress, got $val" exit 1 fi } + +@test "Create and delete namespace" { + kubectl create ns cozy-test-create-and-delete-namespace --dry-run=client -o yaml | kubectl apply -f - + if ! kubectl delete ns cozy-test-create-and-delete-namespace; then + echo "Failed to delete namespace" + kubectl describe ns cozy-test-create-and-delete-namespace + exit 1 + fi +} diff --git a/pkg/registry/apps/application/rest.go b/pkg/registry/apps/application/rest.go index 03de7c08..704cd709 100644 --- a/pkg/registry/apps/application/rest.go +++ b/pkg/registry/apps/application/rest.go @@ -28,7 +28,6 @@ import ( helmv2 "github.com/fluxcd/helm-controller/api/v2" metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" fields "k8s.io/apimachinery/pkg/fields" labels "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" @@ -142,17 +141,9 @@ func (r *REST) GetSingularName() string { // Create handles the creation of a new Application by converting it to a HelmRelease func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) { // Assert the object is of type Application - us, ok := obj.(*unstructured.Unstructured) + app, ok := obj.(*appsv1alpha1.Application) if !ok { - return nil, fmt.Errorf("expected unstructured.Unstructured object, got %T", obj) - } - - app := &appsv1alpha1.Application{} - - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(us.Object, app); err != nil { - errMsg := fmt.Sprintf("returned unstructured.Unstructured object was not an Application") - klog.Errorf(errMsg) - return nil, fmt.Errorf(errMsg) + return nil, fmt.Errorf("expected *appsv1alpha1.Application object, got %T", obj) } // Convert Application to HelmRelease @@ -186,15 +177,8 @@ func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation klog.V(6).Infof("Successfully created and converted HelmRelease %s to Application", helmRelease.GetName()) - // Convert Application to unstructured format - unstructuredApp, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&convertedApp) - if err != nil { - klog.Errorf("Failed to convert Application to unstructured for resource %s: %v", convertedApp.GetName(), err) - return nil, fmt.Errorf("failed to convert Application to unstructured: %v", err) - } - - klog.V(6).Infof("Successfully retrieved and converted resource %s of type %s to unstructured", convertedApp.GetName(), r.gvr.Resource) - return &unstructured.Unstructured{Object: unstructuredApp}, nil + klog.V(6).Infof("Successfully retrieved and converted resource %s of type %s", convertedApp.GetName(), r.gvr.Resource) + return &convertedApp, nil } // Get retrieves an Application by converting the corresponding HelmRelease @@ -238,25 +222,8 @@ func (r *REST) Get(ctx context.Context, name string, options *metav1.GetOptions) return nil, fmt.Errorf("conversion error: %v", err) } - // Explicitly set apiVersion and kind for Application - convertedApp.TypeMeta = metav1.TypeMeta{ - APIVersion: "apps.cozystack.io/v1alpha1", - Kind: r.kindName, - } - - // Convert Application to unstructured format - unstructuredApp, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&convertedApp) - if err != nil { - klog.Errorf("Failed to convert Application to unstructured for resource %s: %v", name, err) - return nil, fmt.Errorf("failed to convert Application to unstructured: %v", err) - } - - // Explicitly set apiVersion and kind in unstructured object - unstructuredApp["apiVersion"] = "apps.cozystack.io/v1alpha1" - unstructuredApp["kind"] = r.kindName - - klog.V(6).Infof("Successfully retrieved and converted resource %s of kind %s to unstructured", name, r.gvr.Resource) - return &unstructured.Unstructured{Object: unstructuredApp}, nil + klog.V(6).Infof("Successfully retrieved and converted resource %s of kind %s", name, r.gvr.Resource) + return &convertedApp, nil } // List retrieves a list of Applications by converting HelmReleases @@ -339,8 +306,8 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption return nil, err } - // Initialize unstructured items array - items := make([]unstructured.Unstructured, 0) + // Initialize Application items array + items := make([]appsv1alpha1.Application, 0, len(hrList.Items)) // Iterate over HelmReleases and convert to Applications for i := range hrList.Items { @@ -387,17 +354,11 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption } } - // Convert Application to unstructured - unstructuredApp, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&app) - if err != nil { - klog.Errorf("Error converting Application %s to unstructured: %v", app.Name, err) - continue - } - items = append(items, unstructured.Unstructured{Object: unstructuredApp}) + items = append(items, app) } - // Explicitly set apiVersion and kind in unstructured object - appList := r.NewList().(*unstructured.UnstructuredList) + // Create ApplicationList with proper kind + appList := r.NewList().(*appsv1alpha1.ApplicationList) appList.SetResourceVersion(hrList.GetResourceVersion()) appList.Items = items @@ -447,16 +408,9 @@ func (r *REST) Update(ctx context.Context, name string, objInfo rest.UpdatedObje } // Assert the new object is of type Application - us, ok := newObj.(*unstructured.Unstructured) + app, ok := newObj.(*appsv1alpha1.Application) if !ok { - errMsg := fmt.Sprintf("expected unstructured.Unstructured object, got %T", newObj) - klog.Errorf(errMsg) - return nil, false, fmt.Errorf(errMsg) - } - app := &appsv1alpha1.Application{} - - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(us.Object, app); err != nil { - errMsg := fmt.Sprintf("returned unstructured.Unstructured object was not an Application") + errMsg := fmt.Sprintf("expected *appsv1alpha1.Application object, got %T", newObj) klog.Errorf(errMsg) return nil, false, fmt.Errorf(errMsg) } @@ -517,24 +471,9 @@ func (r *REST) Update(ctx context.Context, name string, objInfo rest.UpdatedObje klog.V(6).Infof("Successfully updated and converted HelmRelease %s to Application", helmRelease.GetName()) - // Explicitly set apiVersion and kind for Application - convertedApp.TypeMeta = metav1.TypeMeta{ - APIVersion: "apps.cozystack.io/v1alpha1", - Kind: r.kindName, - } + klog.V(6).Infof("Returning updated Application object: %+v", convertedApp) - // Convert Application to unstructured format - unstructuredApp, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&convertedApp) - if err != nil { - klog.Errorf("Failed to convert Application to unstructured for resource %s: %v", convertedApp.GetName(), err) - return nil, false, fmt.Errorf("failed to convert Application to unstructured: %v", err) - } - obj := &unstructured.Unstructured{Object: unstructuredApp} - obj.SetGroupVersionKind(r.gvk) - - klog.V(6).Infof("Returning patched Application object: %+v", unstructuredApp) - - return obj, false, nil + return &convertedApp, false, nil } // Delete removes an Application by deleting the corresponding HelmRelease @@ -728,19 +667,10 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio } } - // Convert Application to unstructured - unstructuredApp, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&app) - if err != nil { - klog.Errorf("Failed to convert Application to unstructured: %v", err) - continue - } - obj := &unstructured.Unstructured{Object: unstructuredApp} - obj.SetGroupVersionKind(r.gvk) - // Create watch event with Application object appEvent := watch.Event{ Type: event.Type, - Object: obj, + Object: &app, } // Send event to custom watcher @@ -766,8 +696,8 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio // Helper function to get HelmRelease name from object func helmReleaseName(obj runtime.Object) string { - if u, ok := obj.(*unstructured.Unstructured); ok { - return u.GetName() + if app, ok := obj.(*appsv1alpha1.Application); ok { + return app.GetName() } return "" } @@ -1059,56 +989,6 @@ func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableO case *appsv1alpha1.Application: table = r.buildTableFromApplication(*obj) table.ListMeta.ResourceVersion = obj.GetResourceVersion() - case *unstructured.UnstructuredList: - apps := make([]appsv1alpha1.Application, 0, len(obj.Items)) - for _, u := range obj.Items { - var a appsv1alpha1.Application - err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &a) - if err != nil { - klog.Errorf("Failed to convert Unstructured to Application: %v", err) - continue - } - apps = append(apps, a) - } - table = r.buildTableFromApplications(apps) - table.ListMeta.ResourceVersion = obj.GetResourceVersion() - case *unstructured.Unstructured: - var apps []appsv1alpha1.Application - for { - var items interface{} - var ok bool - var objects []unstructured.Unstructured - if items, ok = obj.Object["items"]; !ok { - break - } - if objects, ok = items.([]unstructured.Unstructured); !ok { - break - } - apps = make([]appsv1alpha1.Application, 0, len(objects)) - var a appsv1alpha1.Application - for i := range objects { - err := runtime.DefaultUnstructuredConverter.FromUnstructured(objects[i].Object, &a) - if err != nil { - klog.Errorf("Failed to convert Unstructured to Application: %v", err) - continue - } - apps = append(apps, a) - } - break - } - if apps != nil { - table = r.buildTableFromApplications(apps) - table.ListMeta.ResourceVersion = obj.GetResourceVersion() - break - } - var app appsv1alpha1.Application - err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &app) - if err != nil { - klog.Errorf("Failed to convert Unstructured to Application: %v", err) - return nil, fmt.Errorf("failed to convert Unstructured to Application: %v", err) - } - table = r.buildTableFromApplication(app) - table.ListMeta.ResourceVersion = obj.GetResourceVersion() default: resource := schema.GroupResource{} if info, ok := request.RequestInfoFrom(ctx); ok { @@ -1147,10 +1027,11 @@ func (r *REST) buildTableFromApplications(apps []appsv1alpha1.Application) metav } now := time.Now() - for _, app := range apps { + for i := range apps { + app := &apps[i] row := metav1.TableRow{ Cells: []interface{}{app.GetName(), getReadyStatus(app.Status.Conditions), computeAge(app.GetCreationTimestamp().Time, now), getVersion(app.Status.Version)}, - Object: runtime.RawExtension{Object: &app}, + Object: runtime.RawExtension{Object: app}, } table.Rows = append(table.Rows, row) } @@ -1171,9 +1052,10 @@ func (r *REST) buildTableFromApplication(app appsv1alpha1.Application) metav1.Ta } now := time.Now() + a := app row := metav1.TableRow{ Cells: []interface{}{app.GetName(), getReadyStatus(app.Status.Conditions), computeAge(app.GetCreationTimestamp().Time, now), getVersion(app.Status.Version)}, - Object: runtime.RawExtension{Object: &app}, + Object: runtime.RawExtension{Object: &a}, } table.Rows = append(table.Rows, row) @@ -1237,15 +1119,21 @@ func (r *REST) Destroy() { // New creates a new instance of Application func (r *REST) New() runtime.Object { - obj := &unstructured.Unstructured{} - obj.SetGroupVersionKind(r.gvk) + obj := &appsv1alpha1.Application{} + obj.TypeMeta = metav1.TypeMeta{ + APIVersion: r.gvk.GroupVersion().String(), + Kind: r.kindName, + } return obj } // NewList returns an empty list of Application objects func (r *REST) NewList() runtime.Object { - obj := &unstructured.UnstructuredList{} - obj.SetGroupVersionKind(r.gvk.GroupVersion().WithKind(r.kindName + "List")) + obj := &appsv1alpha1.ApplicationList{} + obj.TypeMeta = metav1.TypeMeta{ + APIVersion: r.gvk.GroupVersion().String(), + Kind: r.kindName + "List", + } return obj } diff --git a/pkg/registry/core/tenantmodule/rest.go b/pkg/registry/core/tenantmodule/rest.go index 852a0b64..8ca27dde 100644 --- a/pkg/registry/core/tenantmodule/rest.go +++ b/pkg/registry/core/tenantmodule/rest.go @@ -26,7 +26,6 @@ import ( helmv2 "github.com/fluxcd/helm-controller/api/v2" metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" fields "k8s.io/apimachinery/pkg/fields" labels "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" @@ -147,25 +146,8 @@ func (r *REST) Get(ctx context.Context, name string, options *metav1.GetOptions) return nil, fmt.Errorf("conversion error: %v", err) } - // Explicitly set apiVersion and kind for TenantModule - convertedModule.TypeMeta = metav1.TypeMeta{ - APIVersion: "core.cozystack.io/v1alpha1", - Kind: r.kindName, - } - - // Convert TenantModule to unstructured format - unstructuredModule, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&convertedModule) - if err != nil { - klog.Errorf("Failed to convert TenantModule to unstructured for resource %s: %v", name, err) - return nil, fmt.Errorf("failed to convert TenantModule to unstructured: %v", err) - } - - // Explicitly set apiVersion and kind in unstructured object - unstructuredModule["apiVersion"] = "core.cozystack.io/v1alpha1" - unstructuredModule["kind"] = r.kindName - - klog.V(6).Infof("Successfully retrieved and converted resource %s of kind %s to unstructured", name, r.gvr.Resource) - return &unstructured.Unstructured{Object: unstructuredModule}, nil + klog.V(6).Infof("Successfully retrieved and converted resource %s of kind %s", name, r.gvr.Resource) + return &convertedModule, nil } // List retrieves a list of TenantModules by converting HelmReleases @@ -245,8 +227,8 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption return nil, err } - // Initialize unstructured items array - items := make([]unstructured.Unstructured, 0) + // Initialize TenantModule items array + items := make([]corev1alpha1.TenantModule, 0, len(hrList.Items)) // Iterate over HelmReleases and convert to TenantModules for i := range hrList.Items { @@ -294,19 +276,15 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption } } - // Convert TenantModule to unstructured - unstructuredModule, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&module) - if err != nil { - klog.Errorf("Error converting TenantModule %s to unstructured: %v", module.Name, err) - continue - } - items = append(items, unstructured.Unstructured{Object: unstructuredModule}) + items = append(items, module) } - // Explicitly set apiVersion and kind in unstructured object - moduleList := &unstructured.UnstructuredList{} - moduleList.SetAPIVersion("core.cozystack.io/v1alpha1") - moduleList.SetKind(r.kindName + "List") + // Create TenantModuleList with proper kind + moduleList := &corev1alpha1.TenantModuleList{} + moduleList.TypeMeta = metav1.TypeMeta{ + APIVersion: "core.cozystack.io/v1alpha1", + Kind: r.kindName + "List", + } moduleList.SetResourceVersion(hrList.GetResourceVersion()) moduleList.Items = items @@ -455,17 +433,10 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio } } - // Convert TenantModule to unstructured - unstructuredModule, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&module) - if err != nil { - klog.Errorf("Failed to convert TenantModule to unstructured: %v", err) - continue - } - // Create watch event with TenantModule object moduleEvent := watch.Event{ Type: event.Type, - Object: &unstructured.Unstructured{Object: unstructuredModule}, + Object: &module, } // Send event to custom watcher @@ -620,27 +591,11 @@ func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableO var table metav1.Table switch obj := object.(type) { - case *unstructured.UnstructuredList: - modules := make([]corev1alpha1.TenantModule, 0, len(obj.Items)) - for _, u := range obj.Items { - var m corev1alpha1.TenantModule - err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &m) - if err != nil { - klog.Errorf("Failed to convert Unstructured to TenantModule: %v", err) - continue - } - modules = append(modules, m) - } - table = r.buildTableFromTenantModules(modules) - table.ListMeta.ResourceVersion = obj.GetResourceVersion() - case *unstructured.Unstructured: - var module corev1alpha1.TenantModule - err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &module) - if err != nil { - klog.Errorf("Failed to convert Unstructured to TenantModule: %v", err) - return nil, fmt.Errorf("failed to convert Unstructured to TenantModule: %v", err) - } - table = r.buildTableFromTenantModule(module) + case *corev1alpha1.TenantModuleList: + table = r.buildTableFromTenantModules(obj.Items) + table.ListMeta.ResourceVersion = obj.ListMeta.ResourceVersion + case *corev1alpha1.TenantModule: + table = r.buildTableFromTenantModule(*obj) table.ListMeta.ResourceVersion = obj.GetResourceVersion() default: resource := schema.GroupResource{} @@ -680,10 +635,11 @@ func (r *REST) buildTableFromTenantModules(modules []corev1alpha1.TenantModule) } now := time.Now() - for _, module := range modules { + for i := range modules { + module := &modules[i] row := metav1.TableRow{ Cells: []interface{}{module.GetName(), getReadyStatus(module.Status.Conditions), computeAge(module.GetCreationTimestamp().Time, now), getVersion(module.Status.Version)}, - Object: runtime.RawExtension{Object: &module}, + Object: runtime.RawExtension{Object: module}, } table.Rows = append(table.Rows, row) } @@ -704,9 +660,10 @@ func (r *REST) buildTableFromTenantModule(module corev1alpha1.TenantModule) meta } now := time.Now() + m := module row := metav1.TableRow{ Cells: []interface{}{module.GetName(), getReadyStatus(module.Status.Conditions), computeAge(module.GetCreationTimestamp().Time, now), getVersion(module.Status.Version)}, - Object: runtime.RawExtension{Object: &module}, + Object: runtime.RawExtension{Object: &m}, } table.Rows = append(table.Rows, row) @@ -751,12 +708,22 @@ func (r *REST) Destroy() { // New creates a new instance of TenantModule func (r *REST) New() runtime.Object { - return &corev1alpha1.TenantModule{} + obj := &corev1alpha1.TenantModule{} + obj.TypeMeta = metav1.TypeMeta{ + APIVersion: r.gvk.GroupVersion().String(), + Kind: r.kindName, + } + return obj } // NewList returns an empty list of TenantModule objects func (r *REST) NewList() runtime.Object { - return &corev1alpha1.TenantModuleList{} + obj := &corev1alpha1.TenantModuleList{} + obj.TypeMeta = metav1.TypeMeta{ + APIVersion: r.gvk.GroupVersion().String(), + Kind: r.kindName + "List", + } + return obj } // Kind returns the resource kind used for API discovery From f5eb21131205226d01fe2a20b1988fada50cddb2 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 10 Dec 2025 19:26:35 +0100 Subject: [PATCH 08/78] [platform] Separate assets server into dedicated deployment (#1705) ## What this PR does Separates the assets server from the main cozystack installer into a dedicated StatefulSet deployment. This improves separation of concerns and allows the assets server to run independently from the installer. Changes: - Created new `cozystack-assets` StatefulSet in the platform package - Added dedicated Dockerfile for assets server image (`packages/core/platform/images/cozystack-assets/Dockerfile`) - Removed assets server container and Service from installer deployment - Updated HelmRepository URLs to point to new `cozystack-assets` service - Updated dashboard URLs in monitoring package to use new service - Added image build target to platform Makefile - Configured assets server with hostNetwork and proper RBAC permissions ### Release note ```release-note [platform] Separate assets server into dedicated StatefulSet deployment ``` --- Makefile | 1 + .../installer/images/cozystack/Dockerfile | 7 -- .../core/installer/templates/cozystack.yaml | 23 ------ packages/core/platform/Makefile | 14 ++++ .../images/cozystack-assets/Dockerfile | 25 +++++++ .../platform/templates/cozystack-assets.yaml | 75 +++++++++++++++++++ .../core/platform/templates/helmrepos.yaml | 6 +- packages/core/platform/values.yaml | 2 + .../monitoring/templates/dashboards.yaml | 2 +- 9 files changed, 121 insertions(+), 34 deletions(-) create mode 100644 packages/core/platform/images/cozystack-assets/Dockerfile create mode 100644 packages/core/platform/templates/cozystack-assets.yaml create mode 100644 packages/core/platform/values.yaml diff --git a/Makefile b/Makefile index 31a947c4..290928d7 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ build: build-deps make -C packages/system/bucket image make -C packages/system/objectstorage-controller image make -C packages/core/testing image + make -C packages/core/platform image make -C packages/core/installer image make manifests diff --git a/packages/core/installer/images/cozystack/Dockerfile b/packages/core/installer/images/cozystack/Dockerfile index c964c027..a4d27a1a 100644 --- a/packages/core/installer/images/cozystack/Dockerfile +++ b/packages/core/installer/images/cozystack/Dockerfile @@ -26,10 +26,6 @@ WORKDIR /src RUN go mod download -RUN go build -o /cozystack-assets-server -ldflags '-extldflags "-static" -w -s' ./cmd/cozystack-assets-server - -RUN make repos - FROM alpine:3.22 RUN wget -O- https://github.com/cozystack/cozypkg/raw/refs/heads/main/hack/install.sh | sh -s -- -v 1.2.0 @@ -39,10 +35,7 @@ RUN apk add --no-cache make kubectl helm coreutils git jq COPY --from=builder /src/scripts /cozystack/scripts COPY --from=builder /src/packages/core /cozystack/packages/core COPY --from=builder /src/packages/system /cozystack/packages/system -COPY --from=builder /src/_out/repos /cozystack/assets/repos -COPY --from=builder /cozystack-assets-server /usr/bin/cozystack-assets-server COPY --from=k8s-await-election-builder /k8s-await-election /usr/bin/k8s-await-election -COPY --from=builder /src/dashboards /cozystack/assets/dashboards WORKDIR /cozystack ENTRYPOINT ["/usr/bin/k8s-await-election", "/cozystack/scripts/installer.sh" ] diff --git a/packages/core/installer/templates/cozystack.yaml b/packages/core/installer/templates/cozystack.yaml index 10ebdc1f..0f084b90 100644 --- a/packages/core/installer/templates/cozystack.yaml +++ b/packages/core/installer/templates/cozystack.yaml @@ -68,15 +68,6 @@ spec: valueFrom: fieldRef: fieldPath: metadata.name - - name: assets - image: "{{ .Values.cozystack.image }}" - command: - - /usr/bin/cozystack-assets-server - - "-dir=/cozystack/assets" - - "-address=:8123" - ports: - - name: http - containerPort: 8123 tolerations: - key: "node.kubernetes.io/not-ready" operator: "Exists" @@ -84,17 +75,3 @@ spec: - key: "node.cilium.io/agent-not-ready" operator: "Exists" effect: "NoSchedule" ---- -apiVersion: v1 -kind: Service -metadata: - name: cozystack - namespace: cozy-system -spec: - ports: - - name: http - port: 80 - targetPort: 8123 - selector: - app: cozystack - type: ClusterIP diff --git a/packages/core/platform/Makefile b/packages/core/platform/Makefile index ab0e17bf..5c0b4786 100644 --- a/packages/core/platform/Makefile +++ b/packages/core/platform/Makefile @@ -1,6 +1,8 @@ NAME=platform NAMESPACE=cozy-system +include ../../../scripts/common-envs.mk + show: cozypkg show -n $(NAMESPACE) $(NAME) --plain @@ -18,3 +20,15 @@ namespaces-apply: diff: cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f- + +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/cozystack-assets.json \ + $(BUILDX_ARGS) + 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/images/cozystack-assets/Dockerfile b/packages/core/platform/images/cozystack-assets/Dockerfile new file mode 100644 index 00000000..cc28b0a8 --- /dev/null +++ b/packages/core/platform/images/cozystack-assets/Dockerfile @@ -0,0 +1,25 @@ +FROM golang:1.24-alpine AS builder + +ARG TARGETOS +ARG TARGETARCH + +RUN apk add --no-cache make git +RUN apk add helm --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community + +COPY . /src/ +WORKDIR /src + +RUN go mod download + +RUN go build -o /cozystack-assets-server -ldflags '-extldflags "-static" -w -s' ./cmd/cozystack-assets-server + +RUN make repos + +FROM alpine:3.22 + +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/templates/cozystack-assets.yaml b/packages/core/platform/templates/cozystack-assets.yaml new file mode 100644 index 00000000..76906155 --- /dev/null +++ b/packages/core/platform/templates/cozystack-assets.yaml @@ -0,0 +1,75 @@ +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 + - create + - update +--- +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/helmrepos.yaml b/packages/core/platform/templates/helmrepos.yaml index 69f77534..90bf1d1c 100644 --- a/packages/core/platform/templates/helmrepos.yaml +++ b/packages/core/platform/templates/helmrepos.yaml @@ -8,7 +8,7 @@ metadata: cozystack.io/repository: system spec: interval: 5m0s - url: http://cozystack.cozy-system.svc/repos/system + url: http://cozystack-assets.cozy-system.svc/repos/system --- apiVersion: source.toolkit.fluxcd.io/v1 kind: HelmRepository @@ -20,7 +20,7 @@ metadata: cozystack.io/repository: apps spec: interval: 5m0s - url: http://cozystack.cozy-system.svc/repos/apps + url: http://cozystack-assets.cozy-system.svc/repos/apps --- apiVersion: source.toolkit.fluxcd.io/v1 kind: HelmRepository @@ -31,4 +31,4 @@ metadata: cozystack.io/repository: extra spec: interval: 5m0s - url: http://cozystack.cozy-system.svc/repos/extra + url: http://cozystack-assets.cozy-system.svc/repos/extra diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml new file mode 100644 index 00000000..363d1921 --- /dev/null +++ b/packages/core/platform/values.yaml @@ -0,0 +1,2 @@ +assets: + image: ghcr.io/cozystack/cozystack/cozystack-assets:latest@sha256:19b166819d0205293c85d8351a3e038dc4c146b876a8e2ae21dce1d54f0b9e33 diff --git a/packages/extra/monitoring/templates/dashboards.yaml b/packages/extra/monitoring/templates/dashboards.yaml index 3facf66c..522df88b 100644 --- a/packages/extra/monitoring/templates/dashboards.yaml +++ b/packages/extra/monitoring/templates/dashboards.yaml @@ -11,6 +11,6 @@ spec: instanceSelector: matchLabels: dashboards: grafana - url: http://cozystack.cozy-system.svc/dashboards/{{ . }}.json + url: http://cozystack-assets.cozy-system.svc/dashboards/{{ . }}.json {{- end }} {{- end }} From 17138d825d90ca57e9459e5b2f111dec021aa55e Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 10 Dec 2025 19:28:01 +0100 Subject: [PATCH 09/78] [fluxcd] Enable source-watcher (#1706) This change is extracted from - https://github.com/cozystack/cozystack/pull/1641 and reworked to work standalone Signed-off-by: Andrei Kvapil ## What this PR does ### Release note ```release-note [fluxcd] Enable source-watcher ``` --- packages/system/fluxcd/values.yaml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/system/fluxcd/values.yaml b/packages/system/fluxcd/values.yaml index 3559a330..7f5af0ff 100644 --- a/packages/system/fluxcd/values.yaml +++ b/packages/system/fluxcd/values.yaml @@ -9,6 +9,7 @@ flux-instance: registry: ghcr.io/fluxcd components: - source-controller + - source-watcher - kustomize-controller - helm-controller - notification-controller @@ -38,12 +39,16 @@ flux-instance: - op: add path: /spec/template/spec/containers/0/args/- value: --storage-adv-addr=source-controller.cozy-fluxcd.svc - - op: add - path: /spec/template/spec/containers/0/args/- - value: --events-addr=http://notification-controller.cozy-fluxcd.svc/ - target: kind: Deployment - name: (kustomize-controller|helm-controller|image-reflector-controller|image-automation-controller) + name: source-watcher + patch: | + - op: add + path: /spec/template/spec/containers/0/args/- + value: --storage-adv-addr=source-watcher.cozy-fluxcd.svc + - target: + kind: Deployment + name: (kustomize-controller|helm-controller|image-reflector-controller|image-automation-controller|source-controller|source-watcher) patch: | - op: add path: /spec/template/spec/containers/0/args/- From aba147571b0fae836a542ca3d94718eca4b519d2 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 10 Dec 2025 20:56:13 +0100 Subject: [PATCH 10/78] [fluxcd] Add flux-aio module and migration (#1698) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change is extracted from - https://github.com/cozystack/cozystack/pull/1641 and reworked to work standalone requires: - https://github.com/cozystack/cozystack/pull/1705 ## What this PR does Adds a new `flux-aio` module and migration script to upgrade FluxCD to version 22. This introduces a new modular approach to FluxCD installation using the flux-aio OCI module. Changes: - Created new `flux-aio` package with Chart.yaml, Makefile, and CUE configuration - Added flux-aio module configuration using OCI module from `ghcr.io/stefanprodan/modules/flux-aio` - Generated large fluxcd.yaml template (11956+ lines) for FluxCD resources - Added migration script (migrations/21) to handle upgrade from version 21 to 22 - Updated installer to include flux-aio module - Added script `issue-flux-certificates.sh` for managing TLS certificates for cozystack-assets - Updated platform templates to support flux-aio module - Updated cozystack-assets service references ### Release note ```release-note [fluxcd] Add flux-aio module and migration ``` ## Summary by CodeRabbit ## Release Notes * **New Features** * Added TLS certificate support for Helm package repositories with automatic certificate provisioning. * **Chores** * Refactored FluxCD integration using Helm chart-based deployment. * Updated system to version 22 with automatic migration support. * Enhanced security dependencies (OpenSSL). ✏️ Tip: You can customize this high-level summary in your review settings. --- packages/core/flux-aio/Chart.yaml | 3 + packages/core/flux-aio/Makefile | 22 + packages/core/flux-aio/flux-aio.cue | 16 + packages/core/flux-aio/templates/_helpers.tpl | 13 + packages/core/flux-aio/templates/fluxcd.yaml | 11957 ++++++++++++++++ .../installer/images/cozystack/Dockerfile | 2 +- .../core/installer/templates/cozystack.yaml | 2 + .../core/platform/bundles/distro-full.yaml | 18 - .../core/platform/bundles/distro-hosted.yaml | 18 - packages/core/platform/bundles/paas-full.yaml | 18 - .../core/platform/bundles/paas-hosted.yaml | 18 - packages/core/platform/templates/_helpers.tpl | 30 + .../platform/templates/cozystack-assets.yaml | 2 - .../core/platform/templates/helmrepos.yaml | 12 +- scripts/installer.sh | 43 +- scripts/issue-flux-certificates.sh | 63 + scripts/migrations/21 | 10 + 17 files changed, 12133 insertions(+), 114 deletions(-) create mode 100644 packages/core/flux-aio/Chart.yaml create mode 100644 packages/core/flux-aio/Makefile create mode 100644 packages/core/flux-aio/flux-aio.cue create mode 100644 packages/core/flux-aio/templates/_helpers.tpl create mode 100644 packages/core/flux-aio/templates/fluxcd.yaml create mode 100755 scripts/issue-flux-certificates.sh create mode 100755 scripts/migrations/21 diff --git a/packages/core/flux-aio/Chart.yaml b/packages/core/flux-aio/Chart.yaml new file mode 100644 index 00000000..2e625a16 --- /dev/null +++ b/packages/core/flux-aio/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-fluxcd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/core/flux-aio/Makefile b/packages/core/flux-aio/Makefile new file mode 100644 index 00000000..d50f317d --- /dev/null +++ b/packages/core/flux-aio/Makefile @@ -0,0 +1,22 @@ +NAME=flux-aio +NAMESPACE=cozy-$(NAME) + +include ../../../scripts/common-envs.mk + +show: + cozypkg show -n $(NAMESPACE) $(NAME) --plain + +apply: + cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- --server-side --force-conflicts + +diff: + cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f- + +update: + 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 '/value: .svc/a \ {{- include "cozy.kubernetes_envs" . | nindent 12 }}' \ + -e '/hostNetwork: true/i \ dnsPolicy: ClusterFirstWithHostNet' diff --git a/packages/core/flux-aio/flux-aio.cue b/packages/core/flux-aio/flux-aio.cue new file mode 100644 index 00000000..8c067c3b --- /dev/null +++ b/packages/core/flux-aio/flux-aio.cue @@ -0,0 +1,16 @@ +bundle: { + apiVersion: "v1alpha1" + name: "flux-aio" + instances: { + "flux": { + module: { + url: "oci://ghcr.io/stefanprodan/modules/flux-aio" + version: "latest" + } + namespace: "cozy-fluxcd" + values: { + securityProfile: "privileged" + } + } + } +} 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/images/cozystack/Dockerfile b/packages/core/installer/images/cozystack/Dockerfile index a4d27a1a..606505ba 100644 --- a/packages/core/installer/images/cozystack/Dockerfile +++ b/packages/core/installer/images/cozystack/Dockerfile @@ -30,7 +30,7 @@ FROM alpine:3.22 RUN wget -O- https://github.com/cozystack/cozypkg/raw/refs/heads/main/hack/install.sh | sh -s -- -v 1.2.0 -RUN apk add --no-cache make kubectl helm coreutils git jq +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 diff --git a/packages/core/installer/templates/cozystack.yaml b/packages/core/installer/templates/cozystack.yaml index 0f084b90..c43b0425 100644 --- a/packages/core/installer/templates/cozystack.yaml +++ b/packages/core/installer/templates/cozystack.yaml @@ -54,6 +54,8 @@ spec: env: - name: KUBERNETES_SERVICE_HOST value: localhost + - name: INSTALL_FLUX + value: "true" - name: KUBERNETES_SERVICE_PORT value: "7445" - name: K8S_AWAIT_ELECTION_ENABLED diff --git a/packages/core/platform/bundles/distro-full.yaml b/packages/core/platform/bundles/distro-full.yaml index 107cbb23..b3079891 100644 --- a/packages/core/platform/bundles/distro-full.yaml +++ b/packages/core/platform/bundles/distro-full.yaml @@ -2,24 +2,6 @@ {{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} releases: -- name: fluxcd-operator - releaseName: fluxcd-operator - chart: cozy-fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - -- name: fluxcd - releaseName: fluxcd - chart: cozy-fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator,cilium] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - - name: cilium releaseName: cilium chart: cozy-cilium diff --git a/packages/core/platform/bundles/distro-hosted.yaml b/packages/core/platform/bundles/distro-hosted.yaml index 02653a21..e2aa5b03 100644 --- a/packages/core/platform/bundles/distro-hosted.yaml +++ b/packages/core/platform/bundles/distro-hosted.yaml @@ -2,24 +2,6 @@ {{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} releases: -- name: fluxcd-operator - releaseName: fluxcd-operator - chart: cozy-fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - -- name: fluxcd - releaseName: fluxcd - chart: cozy-fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - - name: cert-manager-crds releaseName: cert-manager-crds chart: cozy-cert-manager-crds diff --git a/packages/core/platform/bundles/paas-full.yaml b/packages/core/platform/bundles/paas-full.yaml index 96a7078f..ab618deb 100644 --- a/packages/core/platform/bundles/paas-full.yaml +++ b/packages/core/platform/bundles/paas-full.yaml @@ -11,24 +11,6 @@ {{- end }} releases: -- name: fluxcd-operator - releaseName: fluxcd-operator - chart: cozy-fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - -- name: fluxcd - releaseName: fluxcd - chart: cozy-fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator,cilium,kubeovn] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - - name: cilium releaseName: cilium chart: cozy-cilium diff --git a/packages/core/platform/bundles/paas-hosted.yaml b/packages/core/platform/bundles/paas-hosted.yaml index bc7f33d3..87430468 100644 --- a/packages/core/platform/bundles/paas-hosted.yaml +++ b/packages/core/platform/bundles/paas-hosted.yaml @@ -11,24 +11,6 @@ {{- end }} releases: -- name: fluxcd-operator - releaseName: fluxcd-operator - chart: cozy-fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - -- name: fluxcd - releaseName: fluxcd - chart: cozy-fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - - name: cert-manager-crds releaseName: cert-manager-crds chart: cozy-cert-manager-crds diff --git a/packages/core/platform/templates/_helpers.tpl b/packages/core/platform/templates/_helpers.tpl index 73a4574c..c656c7f8 100644 --- a/packages/core/platform/templates/_helpers.tpl +++ b/packages/core/platform/templates/_helpers.tpl @@ -17,6 +17,36 @@ Get IP-addresses of master nodes {{ join "," $ips }} {{- end -}} +{{/* +Get Kubernetes API Endpoint from cozystack deployment +Returns host:port format +*/}} +{{- 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" }} diff --git a/packages/core/platform/templates/cozystack-assets.yaml b/packages/core/platform/templates/cozystack-assets.yaml index 76906155..61ab8dca 100644 --- a/packages/core/platform/templates/cozystack-assets.yaml +++ b/packages/core/platform/templates/cozystack-assets.yaml @@ -43,8 +43,6 @@ rules: - cozystack-assets-0 verbs: - get - - create - - update --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding diff --git a/packages/core/platform/templates/helmrepos.yaml b/packages/core/platform/templates/helmrepos.yaml index 90bf1d1c..47954869 100644 --- a/packages/core/platform/templates/helmrepos.yaml +++ b/packages/core/platform/templates/helmrepos.yaml @@ -8,7 +8,9 @@ metadata: cozystack.io/repository: system spec: interval: 5m0s - url: http://cozystack-assets.cozy-system.svc/repos/system + 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 @@ -20,7 +22,9 @@ metadata: cozystack.io/repository: apps spec: interval: 5m0s - url: http://cozystack-assets.cozy-system.svc/repos/apps + 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 @@ -31,4 +35,6 @@ metadata: cozystack.io/repository: extra spec: interval: 5m0s - url: http://cozystack-assets.cozy-system.svc/repos/extra + 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/scripts/installer.sh b/scripts/installer.sh index 8dfa68ee..042e895a 100755 --- a/scripts/installer.sh +++ b/scripts/installer.sh @@ -19,29 +19,11 @@ run_migrations() { done } -flux_is_ok() { - kubectl wait --for=condition=available -n cozy-fluxcd deploy/source-controller deploy/helm-controller --timeout=1s - kubectl wait --for=condition=ready -n cozy-fluxcd helmrelease/fluxcd --timeout=1s # to call "apply resume" below -} - -ensure_fluxcd() { - if flux_is_ok; then +install_flux() { + if [ "$INSTALL_FLUX" != "true" ]; then return fi - # Install fluxcd-operator - if kubectl get helmreleases.helm.toolkit.fluxcd.io -n cozy-fluxcd fluxcd-operator; then - make -C packages/system/fluxcd-operator apply resume - else - make -C packages/system/fluxcd-operator apply-locally - fi - wait_for_crds fluxinstances.fluxcd.controlplane.io - - # Install fluxcd - if kubectl get helmreleases.helm.toolkit.fluxcd.io -n cozy-fluxcd fluxcd; then - make -C packages/system/fluxcd apply resume - else - make -C packages/system/fluxcd apply-locally - fi + make -C packages/core/flux-aio apply wait_for_crds helmreleases.helm.toolkit.fluxcd.io helmrepositories.source.toolkit.fluxcd.io } @@ -49,15 +31,6 @@ wait_for_crds() { timeout 60 sh -c "until kubectl get crd $*; do sleep 1; done" } -install_basic_charts() { - if [ "$BUNDLE" = "paas-full" ] || [ "$BUNDLE" = "distro-full" ]; then - make -C packages/system/cilium apply resume - fi - if [ "$BUNDLE" = "paas-full" ]; then - make -C packages/system/kubeovn apply resume - fi -} - cd "$(dirname "$0")/.." # Run migrations @@ -67,16 +40,14 @@ run_migrations make -C packages/core/platform namespaces-apply # Install fluxcd -ensure_fluxcd +install_flux + +# Install fluxcd certificates +./scripts/issue-flux-certificates.sh # Install platform chart make -C packages/core/platform reconcile -# Install basic charts -if ! flux_is_ok; then - install_basic_charts -fi - # Reconcile Helm repositories kubectl annotate helmrepositories.source.toolkit.fluxcd.io -A -l cozystack.io/repository reconcile.fluxcd.io/requestedAt=$(date +"%Y-%m-%dT%H:%M:%SZ") --overwrite diff --git a/scripts/issue-flux-certificates.sh b/scripts/issue-flux-certificates.sh new file mode 100755 index 00000000..825447e2 --- /dev/null +++ b/scripts/issue-flux-certificates.sh @@ -0,0 +1,63 @@ +#!/bin/sh +set -e + +if kubectl get secret -n cozy-system cozystack-assets-tls >/dev/null 2>&1 && kubectl get secret -n cozy-public cozystack-assets-tls >/dev/null 2>&1; then + echo "Secret cozystack-assets-tls already exists in both cozy-system and cozy-public namespaces. Exiting." + exit 0 +fi + +USER_CN="cozystack-assets-reader" +CSR_NAME="csr-${USER_CN}-$(date +%s)" + +# make temp directory and cleanup handler +TMPDIR=$(mktemp -d) +trap 'rm -rf "$TMPDIR"' EXIT + +# move into tmpdir +cd "$TMPDIR" + +openssl genrsa -out tls.key 2048 +openssl req -new -key tls.key -subj "/CN=${USER_CN}" -out tls.csr + +CSR_B64=$(base64 < tls.csr | tr -d '\n') + +cat < tls.crt + +kubectl get -n kube-public configmap kube-root-ca.crt \ + -o jsonpath='{.data.ca\.crt}' > ca.crt + +kubectl create secret generic "cozystack-assets-tls" \ + --namespace='cozy-system' \ + --type='kubernetes.io/tls' \ + --from-file=tls.crt \ + --from-file=tls.key \ + --from-file=ca.crt \ + --dry-run=client -o yaml | kubectl apply -f - + +kubectl create secret generic "cozystack-assets-tls" \ + --namespace='cozy-public' \ + --type='kubernetes.io/tls' \ + --from-file=tls.crt \ + --from-file=tls.key \ + --from-file=ca.crt \ + --dry-run=client -o yaml | kubectl apply -f - diff --git a/scripts/migrations/21 b/scripts/migrations/21 new file mode 100755 index 00000000..7a367668 --- /dev/null +++ b/scripts/migrations/21 @@ -0,0 +1,10 @@ +#!/bin/sh +# Migration 21 --> 22 + +set -euo pipefail + +kubectl delete hr -n cozy-fluxcd fluxcd --ignore-not-found + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=22 --dry-run=client -o yaml | kubectl apply -f- From 35c57798a60f248c7435179fec77a49863983a3d Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 18 Dec 2025 09:13:35 +0100 Subject: [PATCH 11/78] [monitoring] Add SLACK_SEVERITY_FILTER field and VMAgent for tenant monitoring (#1712) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [monitoring] Add SLACK_SEVERITY_FILTER field and VMAgent for tenant monitoring What this PR does This PR introduces 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, it adds a VMAgent resource template for scraping metrics within tenant namespaces, improving monitoring granularity and control. ```release-note [monitoring] Add SLACK_SEVERITY_FILTER for filtering Slack alert severities and VMAgent configuration for tenant-specific metrics scraping. ``` ## Summary by CodeRabbit * **New Features** * Added configurable severity filtering for Telegram alerts. * Extended Slack severity filtering to accept lists of severities. * **Bug Fixes / Behavior** * Severity settings now accept arrays (multiple severities) instead of single comma-separated strings. * **Documentation** * Updated configuration docs and examples to show list-style severity settings. ✏️ Tip: You can customize this high-level summary in your review settings. --- packages/extra/monitoring/README.md | 39 ++++++++++--------- .../monitoring/templates/alerta/alerta.yaml | 8 +++- packages/extra/monitoring/values.schema.json | 17 ++++++-- packages/extra/monitoring/values.yaml | 6 ++- .../cozyrds/monitoring.yaml | 4 +- 5 files changed, 47 insertions(+), 27 deletions(-) diff --git a/packages/extra/monitoring/README.md b/packages/extra/monitoring/README.md index 20327fd9..ed7df4f6 100644 --- a/packages/extra/monitoring/README.md +++ b/packages/extra/monitoring/README.md @@ -55,25 +55,26 @@ ### Alerta configuration -| Name | Description | Type | Value | -| ----------------------------------------- | ----------------------------------------------------------------- | ---------- | ------- | -| `alerta` | Configuration for the Alerta service. | `object` | `{}` | -| `alerta.storage` | Persistent volume size for the database. | `string` | `10Gi` | -| `alerta.storageClassName` | StorageClass used for the database. | `string` | `""` | -| `alerta.resources` | Resource configuration. | `object` | `{}` | -| `alerta.resources.requests` | Resource requests. | `object` | `{}` | -| `alerta.resources.requests.cpu` | CPU request. | `quantity` | `100m` | -| `alerta.resources.requests.memory` | Memory request. | `quantity` | `256Mi` | -| `alerta.resources.limits` | Resource limits. | `object` | `{}` | -| `alerta.resources.limits.cpu` | CPU limit. | `quantity` | `1` | -| `alerta.resources.limits.memory` | Memory limit. | `quantity` | `1Gi` | -| `alerta.alerts` | Alert routing configuration. | `object` | `{}` | -| `alerta.alerts.telegram` | Configuration for Telegram alerts. | `object` | `{}` | -| `alerta.alerts.telegram.token` | Telegram bot token. | `string` | `""` | -| `alerta.alerts.telegram.chatID` | Telegram chat ID(s), separated by commas. | `string` | `""` | -| `alerta.alerts.telegram.disabledSeverity` | List of severities without alerts (e.g. "informational,warning"). | `string` | `""` | -| `alerta.alerts.slack` | Configuration for Slack alerts. | `object` | `{}` | -| `alerta.alerts.slack.url` | Configuration uri for Slack alerts. | `string` | `""` | +| Name | Description | Type | Value | +| ----------------------------------------- | --------------------------------------------------------------------- | ---------- | ------- | +| `alerta` | Configuration for the Alerta service. | `object` | `{}` | +| `alerta.storage` | Persistent volume size for the database. | `string` | `10Gi` | +| `alerta.storageClassName` | StorageClass used for the database. | `string` | `""` | +| `alerta.resources` | Resource configuration. | `object` | `{}` | +| `alerta.resources.requests` | Resource requests. | `object` | `{}` | +| `alerta.resources.requests.cpu` | CPU request. | `quantity` | `100m` | +| `alerta.resources.requests.memory` | Memory request. | `quantity` | `256Mi` | +| `alerta.resources.limits` | Resource limits. | `object` | `{}` | +| `alerta.resources.limits.cpu` | CPU limit. | `quantity` | `1` | +| `alerta.resources.limits.memory` | Memory limit. | `quantity` | `1Gi` | +| `alerta.alerts` | Alert routing configuration. | `object` | `{}` | +| `alerta.alerts.telegram` | Configuration for Telegram alerts. | `object` | `{}` | +| `alerta.alerts.telegram.token` | Telegram bot token. | `string` | `""` | +| `alerta.alerts.telegram.chatID` | Telegram chat ID(s), separated by commas. | `string` | `""` | +| `alerta.alerts.telegram.disabledSeverity` | List of severities without alerts (e.g. ["informational","warning"]). | `[]string` | `[]` | +| `alerta.alerts.slack` | Configuration for Slack alerts. | `object` | `{}` | +| `alerta.alerts.slack.url` | Configuration uri for Slack alerts. | `string` | `""` | +| `alerta.alerts.slack.disabledSeverity` | List of severities without alerts (e.g. ["informational","warning"]). | `[]string` | `[]` | ### Grafana configuration diff --git a/packages/extra/monitoring/templates/alerta/alerta.yaml b/packages/extra/monitoring/templates/alerta/alerta.yaml index 71336286..72500948 100644 --- a/packages/extra/monitoring/templates/alerta/alerta.yaml +++ b/packages/extra/monitoring/templates/alerta/alerta.yaml @@ -129,13 +129,19 @@ spec: value: "{{ .Values.alerta.alerts.telegram.token }}" - name: TELEGRAM_WEBHOOK_URL value: "https://{{ printf "alerta.%s" (.Values.host | default $host) }}/api/webhooks/telegram?api-key={{ $apiKey }}" + {{- if .Values.alerta.alerts.telegram.disabledSeverity }} - name: TELEGRAM_DISABLE_NOTIFICATION_SEVERITY - value: "{{ .Values.alerta.alerts.telegram.disabledSeverity }}" + value: {{ .Values.alerta.alerts.telegram.disabledSeverity | toJson | quote }} + {{- end }} {{- end }} {{- if .Values.alerta.alerts.slack.url }} - name: "SLACK_WEBHOOK_URL" value: "{{ .Values.alerta.alerts.slack.url }}" + {{- if .Values.alerta.alerts.slack.disabledSeverity }} + - name: SLACK_SEVERITY_FILTER + value: {{ .Values.alerta.alerts.slack.disabledSeverity | toJson | quote }} + {{- end }} {{- end }} ports: diff --git a/packages/extra/monitoring/values.schema.json b/packages/extra/monitoring/values.schema.json index 21b3b798..0a6f0e64 100644 --- a/packages/extra/monitoring/values.schema.json +++ b/packages/extra/monitoring/values.schema.json @@ -20,6 +20,14 @@ "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", @@ -42,9 +50,12 @@ "default": "" }, "disabledSeverity": { - "description": "List of severities without alerts (e.g. \"informational,warning\").", - "type": "string", - "default": "" + "description": "List of severities without alerts (e.g. [\"informational\",\"warning\"]).", + "type": "array", + "default": [], + "items": { + "type": "string" + } }, "token": { "description": "Telegram bot token.", diff --git a/packages/extra/monitoring/values.yaml b/packages/extra/monitoring/values.yaml index f4e1043e..ab32b1b2 100644 --- a/packages/extra/monitoring/values.yaml +++ b/packages/extra/monitoring/values.yaml @@ -99,10 +99,11 @@ logsStorages: ## @typedef {struct} TelegramAlerts - Telegram alert configuration. ## @field {string} token - Telegram bot token. ## @field {string} chatID - Telegram chat ID(s), separated by commas. -## @field {string} [disabledSeverity] - List of severities without alerts (e.g. "informational,warning"). +## @field {[]string} [disabledSeverity] - List of severities without alerts (e.g. ["informational","warning"]). ## @typedef {struct} SlackAlerts - Slack alert configuration. ## @field {string} url - Configuration uri for Slack alerts. +## @field {[]string} [disabledSeverity] - List of severities without alerts (e.g. ["informational","warning"]). ## @typedef {struct} Alerts - Alert routing configuration. ## @field {TelegramAlerts} [telegram] - Configuration for Telegram alerts. @@ -129,9 +130,10 @@ alerta: telegram: token: "" chatID: "" - disabledSeverity: "" + disabledSeverity: [] slack: url: "" + disabledSeverity: [] ## ## @section Grafana configuration ## diff --git a/packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml b/packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml index 720dc161..e3f098e4 100644 --- a/packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml +++ b/packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml @@ -8,7 +8,7 @@ spec: singular: monitoring plural: monitorings openAPISchema: |- - {"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":{"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":"string","default":""},"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","default":[{"deduplicationInterval":"15s","name":"shortterm","retentionPeriod":"3d","storage":"10Gi","storageClassName":""},{"deduplicationInterval":"5m","name":"longterm","retentionPeriod":"14d","storage":"10Gi","storageClassName":""}],"items":{"type":"object","required":["deduplicationInterval","name","retentionPeriod","storage"],"properties":{"deduplicationInterval":{"description":"Deduplication interval for metrics.","type":"string"},"name":{"description":"Name of the storage instance.","type":"string"},"retentionPeriod":{"description":"Retention period for metrics.","type":"string"},"storage":{"description":"Persistent volume size.","type":"string","default":"10Gi"},"storageClassName":{"description":"StorageClass used for the data.","type":"string"},"vminsert":{"description":"Configuration for vminsert.","type":"object","properties":{"maxAllowed":{"description":"Maximum allowed resources.","type":"object","properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"minAllowed":{"description":"Minimum guaranteed resources.","type":"object","properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}},"vmselect":{"description":"Configuration for vmselect.","type":"object","properties":{"maxAllowed":{"description":"Maximum allowed resources.","type":"object","properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"minAllowed":{"description":"Minimum guaranteed resources.","type":"object","properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}},"vmstorage":{"description":"Configuration for vmstorage.","type":"object","properties":{"maxAllowed":{"description":"Maximum allowed resources.","type":"object","properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"minAllowed":{"description":"Minimum guaranteed resources.","type":"object","properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}}}}},"vmagent":{"description":"Configuration for VictoriaMetrics Agent.","type":"object","default":{},"properties":{"externalLabels":{"description":"External labels applied to all metrics.","default":{"cluster":"cozystack"}},"remoteWrite":{"description":"Remote write configuration.","default":{"urls":["http://vminsert-shortterm:8480/insert/0/prometheus","http://vminsert-longterm:8480/insert/0/prometheus"]}}}}}} + {"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","default":[{"deduplicationInterval":"15s","name":"shortterm","retentionPeriod":"3d","storage":"10Gi","storageClassName":""},{"deduplicationInterval":"5m","name":"longterm","retentionPeriod":"14d","storage":"10Gi","storageClassName":""}],"items":{"type":"object","required":["deduplicationInterval","name","retentionPeriod","storage"],"properties":{"deduplicationInterval":{"description":"Deduplication interval for metrics.","type":"string"},"name":{"description":"Name of the storage instance.","type":"string"},"retentionPeriod":{"description":"Retention period for metrics.","type":"string"},"storage":{"description":"Persistent volume size.","type":"string","default":"10Gi"},"storageClassName":{"description":"StorageClass used for the data.","type":"string"},"vminsert":{"description":"Configuration for vminsert.","type":"object","properties":{"maxAllowed":{"description":"Maximum allowed resources.","type":"object","properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"minAllowed":{"description":"Minimum guaranteed resources.","type":"object","properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}},"vmselect":{"description":"Configuration for vmselect.","type":"object","properties":{"maxAllowed":{"description":"Maximum allowed resources.","type":"object","properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"minAllowed":{"description":"Minimum guaranteed resources.","type":"object","properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}},"vmstorage":{"description":"Configuration for vmstorage.","type":"object","properties":{"maxAllowed":{"description":"Maximum allowed resources.","type":"object","properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"minAllowed":{"description":"Minimum guaranteed resources.","type":"object","properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}}}}},"vmagent":{"description":"Configuration for VictoriaMetrics Agent.","type":"object","default":{},"properties":{"externalLabels":{"description":"External labels applied to all metrics.","default":{"cluster":"cozystack"}},"remoteWrite":{"description":"Remote write configuration.","default":{"urls":["http://vminsert-shortterm:8480/insert/0/prometheus","http://vminsert-longterm:8480/insert/0/prometheus"]}}}}}} release: prefix: "" labels: @@ -28,7 +28,7 @@ spec: description: Monitoring and observability stack module: true icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODdfMzI2OCkiLz4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzY4N18zMjY4KSI+CjxwYXRoIGQ9Ik04OS41MDM5IDExMS43MDdINTQuNDk3QzU0LjE3MjcgMTExLjcwNyA1NC4wMTA4IDExMS4yMjEgNTQuMzM0OSAxMTEuMDU5TDU3LjI1MjIgMTA4Ljk1MkM2MC4zMzE0IDEwNi42ODMgNjEuOTUyMiAxMDIuNjMxIDYwLjk3OTcgOTguNzQxMkg4My4wMjFDODIuMDQ4NSAxMDIuNjMxIDgzLjY2OTMgMTA2LjY4MyA4Ni43NDg1IDEwOC45NTJMODkuNjY1OCAxMTEuMDU5Qzg5Ljk5IDExMS4yMjEgODkuODI3OSAxMTEuNzA3IDg5LjUwMzkgMTExLjcwN1oiIGZpbGw9IiNCMEI2QkIiLz4KPHBhdGggZD0iTTExMy4zMjggOTguNzQxSDMwLjY3MjVDMjcuNTkzMSA5OC43NDEgMjUgOTYuMTQ4IDI1IDkzLjA2ODdWMzMuMTAzMkMyNSAzMC4wMjM5IDI3LjU5MzEgMjcuNDMwNyAzMC42NzI1IDI3LjQzMDdIMTEzLjMyOEMxMTYuNDA3IDI3LjQzMDcgMTE5IDMwLjAyMzcgMTE5IDMzLjEwMzJWOTMuMDY4N0MxMTkgOTYuMTQ4IDExNi40MDcgOTguNzQxIDExMy4zMjggOTguNzQxWiIgZmlsbD0iI0U4RURFRSIvPgo8cGF0aCBkPSJNMTE5IDg0LjE1NDlIMjVWMzMuMTAzMkMyNSAzMC4wMjM5IDI3LjU5MzEgMjcuNDMwNyAzMC42NzI1IDI3LjQzMDdIMTEzLjMyOEMxMTYuNDA3IDI3LjQzMDcgMTE5IDMwLjAyMzcgMTE5IDMzLjEwMzJMMTE5IDg0LjE1NDlaIiBmaWxsPSIjMzg0NTRGIi8+CjxwYXRoIGQ9Ik05MC42Mzc0IDExNi41NjlINTMuMzYxNkM1Mi4wNjUxIDExNi41NjkgNTAuOTMwNyAxMTUuNDM1IDUwLjkzMDcgMTE0LjEzOEM1MC45MzA3IDExMi44NDEgNTIuMDY1MSAxMTEuNzA3IDUzLjM2MTYgMTExLjcwN0g5MC42Mzc0QzkxLjkzMzkgMTExLjcwNyA5My4wNjg0IDExMi44NDEgOTMuMDY4NCAxMTQuMTM4QzkzLjA2ODQgMTE1LjQzNSA5MS45MzM5IDExNi41NjkgOTAuNjM3NCAxMTYuNTY5WiIgZmlsbD0iI0U4RURFRSIvPgo8cGF0aCBkPSJNNTQuMTcyMiAzOC43NzU3SDMzLjEwMzJDMzIuMTMwNyAzOC43NzU3IDMxLjQ4MjQgMzguMTI3NCAzMS40ODI0IDM3LjE1NDlDMzEuNDgyNCAzNi4xODI0IDMyLjEzMDcgMzUuNTM0MiAzMy4xMDMyIDM1LjUzNDJINTQuMTcyMkM1NS4xNDQ3IDM1LjUzNDIgNTUuNzkzIDM2LjE4MjQgNTUuNzkzIDM3LjE1NDlDNTUuNzkyOCAzOC4xMjc0IDU1LjE0NDUgMzguNzc1NyA1NC4xNzIyIDM4Ljc3NTdaIiBmaWxsPSIjREQzNDJFIi8+CjxwYXRoIGQ9Ik02My44OTYzIDQ1LjI1OTFINDEuMjA2N0M0MC4yMzQyIDQ1LjI1OTEgMzkuNTg1OSA0NC42MTA4IDM5LjU4NTkgNDMuNjM4M0MzOS41ODU5IDQyLjY2NTggNDAuMjM0MiA0Mi4wMTc2IDQxLjIwNjcgNDIuMDE3Nkg2My44OTYzQzY0Ljg2ODggNDIuMDE3NiA2NS41MTcxIDQyLjY2NTggNjUuNTE3MSA0My42MzgzQzY1LjUxNzEgNDQuNjEwOCA2NC44Njg4IDQ1LjI1OTEgNjMuODk2MyA0NS4yNTkxWiIgZmlsbD0iIzczODNCRiIvPgo8cGF0aCBkPSJNMzQuNzI0IDQ1LjI1OTFIMzMuMTAzMkMzMi4xMzA3IDQ1LjI1OTEgMzEuNDgyNCA0NC42MTA4IDMxLjQ4MjQgNDMuNjM4M0MzMS40ODI0IDQyLjY2NTggMzIuMTMwNyA0Mi4wMTc2IDMzLjEwMzIgNDIuMDE3NkgzNC43MjRDMzUuNjk2NCA0Mi4wMTc2IDM2LjM0NDcgNDIuNjY1OCAzNi4zNDQ3IDQzLjYzODNDMzYuMzQ0NyA0NC42MTA4IDM1LjY5NjMgNDUuMjU5MSAzNC43MjQgNDUuMjU5MVoiIGZpbGw9IiM0MkIwNUMiLz4KPHBhdGggZD0iTTYzLjg5NjMgMzguNzc1N0g2MC42NTQ5QzU5LjY4MjQgMzguNzc1NyA1OS4wMzQyIDM4LjEyNzQgNTkuMDM0MiAzNy4xNTQ5QzU5LjAzNDIgMzYuMTgyNCA1OS42ODI0IDM1LjUzNDIgNjAuNjU0OSAzNS41MzQySDYzLjg5NjNDNjQuODY4OCAzNS41MzQyIDY1LjUxNzEgMzYuMTgyNCA2NS41MTcxIDM3LjE1NDlDNjUuNTE3MSAzOC4xMjc0IDY0Ljg2ODggMzguNzc1NyA2My44OTYzIDM4Ljc3NTdaIiBmaWxsPSIjRUNCQTE2Ii8+CjxwYXRoIGQ9Ik00Ny42ODkzIDUxLjc0MTNIMzMuMTAzMkMzMi4xMzA3IDUxLjc0MTMgMzEuNDgyNCA1MS4wOTMxIDMxLjQ4MjQgNTAuMTIwNkMzMS40ODI0IDQ5LjE0ODEgMzIuMTMwNyA0OC41IDMzLjEwMzIgNDguNUg0Ny42ODkzQzQ4LjY2MTggNDguNSA0OS4zMTAxIDQ5LjE0ODMgNDkuMzEwMSA1MC4xMjA4QzQ5LjMxMDEgNTEuMDkzMyA0OC42NjE4IDUxLjc0MTMgNDcuNjg5MyA1MS43NDEzWiIgZmlsbD0iI0REMzQyRSIvPgo8cGF0aCBkPSJNNjMuODk2OCA1MS43NDEzSDU0LjE3MjVDNTMuMiA1MS43NDEzIDUyLjU1MTggNTEuMDkzMSA1Mi41NTE4IDUwLjEyMDZDNTIuNTUxOCA0OS4xNDgxIDUzLjIwMDIgNDguNSA1NC4xNzI3IDQ4LjVINjMuODk2OUM2NC44Njk0IDQ4LjUgNjUuNTE3NyA0OS4xNDgzIDY1LjUxNzcgNTAuMTIwOEM2NS41MTc3IDUxLjA5MzMgNjQuODY5MiA1MS43NDEzIDYzLjg5NjggNTEuNzQxM1oiIGZpbGw9IiNFQ0JBMTYiLz4KPHBhdGggZD0iTTU0LjE3MjIgNTguMjI0SDMzLjEwMzJDMzIuMTMwNyA1OC4yMjQgMzEuNDgyNCA1Ny41NzU3IDMxLjQ4MjQgNTYuNjAzMkMzMS40ODI0IDU1LjYzMDcgMzIuMTMwNyA1NC45ODI0IDMzLjEwMzIgNTQuOTgyNEg1NC4xNzIyQzU1LjE0NDcgNTQuOTgyNCA1NS43OTMgNTUuNjMwNyA1NS43OTMgNTYuNjAzMkM1NS43OTMgNTcuNTc1NyA1NS4xNDQ1IDU4LjIyNCA1NC4xNzIyIDU4LjIyNFoiIGZpbGw9IiM0MkIwNUMiLz4KPHBhdGggZD0iTTYzLjg5NjMgNjQuNzA3NEg0MS4yMDY3QzQwLjIzNDIgNjQuNzA3NCAzOS41ODU5IDY0LjA1OTEgMzkuNTg1OSA2My4wODY2QzM5LjU4NTkgNjIuMTE0MSA0MC4yMzQyIDYxLjQ2NTggNDEuMjA2NyA2MS40NjU4SDYzLjg5NjNDNjQuODY4OCA2MS40NjU4IDY1LjUxNzEgNjIuMTE0MSA2NS41MTcxIDYzLjA4NjZDNjUuNTE3MSA2NC4wNTkxIDY0Ljg2ODggNjQuNzA3NCA2My44OTYzIDY0LjcwNzRaIiBmaWxsPSIjRUNCQTE2Ii8+CjxwYXRoIGQ9Ik0zNC43MjQgNjQuNzA3NEgzMy4xMDMyQzMyLjEzMDcgNjQuNzA3NCAzMS40ODI0IDY0LjA1OTEgMzEuNDgyNCA2My4wODY2QzMxLjQ4MjQgNjIuMTE0MSAzMi4xMzA3IDYxLjQ2NTggMzMuMTAzMiA2MS40NjU4SDM0LjcyNEMzNS42OTY0IDYxLjQ2NTggMzYuMzQ0NyA2Mi4xMTQxIDM2LjM0NDcgNjMuMDg2NkMzNi4zNDQ3IDY0LjA1OTEgMzUuNjk2MyA2NC43MDc0IDM0LjcyNCA2NC43MDc0WiIgZmlsbD0iI0REMzQyRSIvPgo8cGF0aCBkPSJNNDcuNjg5MyA3MS4xODk4SDMzLjEwMzJDMzIuMTMwNyA3MS4xODk4IDMxLjQ4MjQgNzAuNTQxNSAzMS40ODI0IDY5LjU2OUMzMS40ODI0IDY4LjU5NjUgMzIuMTMwNyA2Ny45NDgyIDMzLjEwMzIgNjcuOTQ4Mkg0Ny42ODkzQzQ4LjY2MTggNjcuOTQ4MiA0OS4zMTAxIDY4LjU5NjUgNDkuMzEwMSA2OS41NjlDNDkuMzEwMSA3MC41NDE1IDQ4LjY2MTggNzEuMTg5OCA0Ny42ODkzIDcxLjE4OThaIiBmaWxsPSIjNDJCMDVDIi8+CjxwYXRoIGQ9Ik02My44OTY4IDcxLjE4OThINTQuMTcyNUM1My4yIDcxLjE4OTggNTIuNTUxOCA3MC41NDE1IDUyLjU1MTggNjkuNTY5QzUyLjU1MTggNjguNTk2NSA1My4yIDY3Ljk0ODIgNTQuMTcyNSA2Ny45NDgySDYzLjg5NjhDNjQuODY5MiA2Ny45NDgyIDY1LjUxNzUgNjguNTk2NSA2NS41MTc1IDY5LjU2OUM2NS41MTc1IDcwLjU0MTUgNjQuODY5MiA3MS4xODk4IDYzLjg5NjggNzEuMTg5OFoiIGZpbGw9IiM3MzgzQkYiLz4KPHBhdGggZD0iTTU0LjE3MjIgNzcuNjcyMkgzMy4xMDMyQzMyLjEzMDcgNzcuNjcyMiAzMS40ODI0IDc3LjAyMzkgMzEuNDgyNCA3Ni4wNTE0QzMxLjQ4MjQgNzUuMDc4OSAzMi4xMzA3IDc0LjQzMDcgMzMuMTAzMiA3NC40MzA3SDU0LjE3MjJDNTUuMTQ0NyA3NC40MzA3IDU1Ljc5MyA3NS4wNzg5IDU1Ljc5MyA3Ni4wNTE0QzU1Ljc5MjggNzcuMDIzOSA1NS4xNDQ1IDc3LjY3MjIgNTQuMTcyMiA3Ny42NzIyWiIgZmlsbD0iI0VDQkExNiIvPgo8cGF0aCBkPSJNNjMuODk2MyA3Ny42NzIySDYwLjY1NDlDNTkuNjgyNCA3Ny42NzIyIDU5LjAzNDIgNzcuMDIzOSA1OS4wMzQyIDc2LjA1MTRDNTkuMDM0MiA3NS4wNzg5IDU5LjY4MjQgNzQuNDMwNyA2MC42NTQ5IDc0LjQzMDdINjMuODk2M0M2NC44Njg4IDc0LjQzMDcgNjUuNTE3MSA3NS4wNzg5IDY1LjUxNzEgNzYuMDUxNEM2NS41MTcxIDc3LjAyMzkgNjQuODY4OCA3Ny42NzIyIDYzLjg5NjMgNzcuNjcyMloiIGZpbGw9IiM0MkIwNUMiLz4KPHBhdGggZD0iTTEwMS4xNzIgNzcuNjcyMkg4MC4xMDMyQzc5LjEzMDcgNzcuNjcyMiA3OC40ODI0IDc3LjAyMzkgNzguNDgyNCA3Ni4wNTE0Qzc4LjQ4MjQgNzUuMDc4OSA3OS4xMzA3IDc0LjQzMDcgODAuMTAzMiA3NC40MzA3SDEwMS4xNzJDMTAyLjE0NSA3NC40MzA3IDEwMi43OTMgNzUuMDc4OSAxMDIuNzkzIDc2LjA1MTRDMTAyLjc5MyA3Ny4wMjM5IDEwMi4xNDUgNzcuNjcyMiAxMDEuMTcyIDc3LjY3MjJaIiBmaWxsPSIjREQzNDJFIi8+CjxwYXRoIGQ9Ik0xMTAuODk2IDc3LjY3MjJIMTA3LjY1NUMxMDYuNjgyIDc3LjY3MjIgMTA2LjAzNCA3Ny4wMjM5IDEwNi4wMzQgNzYuMDUxNEMxMDYuMDM0IDc1LjA3ODkgMTA2LjY4MiA3NC40MzA3IDEwNy42NTUgNzQuNDMwN0gxMTAuODk2QzExMS44NjkgNzQuNDMwNyAxMTIuNTE3IDc1LjA3ODkgMTEyLjUxNyA3Ni4wNTE0QzExMi41MTcgNzcuMDIzOSAxMTEuODY5IDc3LjY3MjIgMTEwLjg5NiA3Ny42NzIyWiIgZmlsbD0iIzQyQjA1QyIvPgo8cGF0aCBkPSJNNjMuODk2MyA1OC4yMjRINjAuNjU0OUM1OS42ODI0IDU4LjIyNCA1OS4wMzQyIDU3LjU3NTcgNTkuMDM0MiA1Ni42MDMyQzU5LjAzNDIgNTUuNjMwNyA1OS42ODI0IDU0Ljk4MjQgNjAuNjU0OSA1NC45ODI0SDYzLjg5NjNDNjQuODY4OCA1NC45ODI0IDY1LjUxNzEgNTUuNjMwNyA2NS41MTcxIDU2LjYwMzJDNjUuNTE3MSA1Ny41NzU3IDY0Ljg2ODggNTguMjI0IDYzLjg5NjMgNTguMjI0WiIgZmlsbD0iIzczODNCRiIvPgo8cGF0aCBkPSJNMTEyLjUxNyA1MS43NDExQzExMi41MTcgNjAuNjU0OSAxMDUuMjI0IDY3Ljk0OCA5Ni4zMTA0IDY3Ljk0OEM4Ny4zOTY2IDY3Ljk0OCA4MC4xMDM1IDYwLjY1NDkgODAuMTAzNSA1MS43NDExQzgwLjEwMzUgNDIuODI3MyA4Ny4zOTY2IDM1LjUzNDIgOTYuMzEwNCAzNS41MzQyQzEwNS4yMjQgMzUuNTM0MiAxMTIuNTE3IDQyLjgyNzMgMTEyLjUxNyA1MS43NDExWiIgZmlsbD0iI0VDQkExNiIvPgo8cGF0aCBkPSJNODAuMTAzNSA1MS43NDExQzgwLjEwMzUgNTIuMjI3MyA4MC4xMDM1IDUyLjg3NTUgODAuMTAzNSA1My4zNjE5SDk2LjMxMDRWMzUuNTM0MkM4Ny4zOTY2IDM1LjUzNDIgODAuMTAzNSA0Mi44MjczIDgwLjEwMzUgNTEuNzQxMVoiIGZpbGw9IiM0MkIwNUMiLz4KPC9nPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4N18zMjY4IiB4MT0iMS4yMzIzOWUtMDYiIHkxPSItOS41MDAwMSIgeDI9IjE2OCIgeTI9IjE2MiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjOEZEREZGIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzAwNzVGRiIvPgo8L2xpbmVhckdyYWRpZW50Pgo8Y2xpcFBhdGggaWQ9ImNsaXAwXzY4N18zMjY4Ij4KPHJlY3Qgd2lkdGg9Ijk0IiBoZWlnaHQ9Ijk0IiBmaWxsPSJ3aGl0ZSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjUgMjUpIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg== - keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "host"], ["spec", "metricsStorages"], ["spec", "logsStorages"], ["spec", "alerta"], ["spec", "alerta", "storage"], ["spec", "alerta", "storageClassName"], ["spec", "alerta", "resources"], ["spec", "alerta", "resources", "limits"], ["spec", "alerta", "resources", "limits", "cpu"], ["spec", "alerta", "resources", "limits", "memory"], ["spec", "alerta", "resources", "requests"], ["spec", "alerta", "resources", "requests", "cpu"], ["spec", "alerta", "resources", "requests", "memory"], ["spec", "alerta", "alerts"], ["spec", "alerta", "alerts", "telegram"], ["spec", "alerta", "alerts", "telegram", "token"], ["spec", "alerta", "alerts", "telegram", "chatID"], ["spec", "alerta", "alerts", "telegram", "disabledSeverity"], ["spec", "alerta", "alerts", "slack"], ["spec", "alerta", "alerts", "slack", "url"], ["spec", "grafana"], ["spec", "grafana", "db"], ["spec", "grafana", "db", "size"], ["spec", "grafana", "resources"], ["spec", "grafana", "resources", "limits"], ["spec", "grafana", "resources", "limits", "cpu"], ["spec", "grafana", "resources", "limits", "memory"], ["spec", "grafana", "resources", "requests"], ["spec", "grafana", "resources", "requests", "cpu"], ["spec", "grafana", "resources", "requests", "memory"], ["spec", "vmagent"], ["spec", "vmagent", "externalLabels"], ["spec", "vmagent", "externalLabels", "cluster"], ["spec", "vmagent", "remoteWrite"], ["spec", "vmagent", "remoteWrite", "urls"]] + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "host"], ["spec", "metricsStorages"], ["spec", "logsStorages"], ["spec", "alerta"], ["spec", "alerta", "storage"], ["spec", "alerta", "storageClassName"], ["spec", "alerta", "resources"], ["spec", "alerta", "resources", "limits"], ["spec", "alerta", "resources", "limits", "cpu"], ["spec", "alerta", "resources", "limits", "memory"], ["spec", "alerta", "resources", "requests"], ["spec", "alerta", "resources", "requests", "cpu"], ["spec", "alerta", "resources", "requests", "memory"], ["spec", "alerta", "alerts"], ["spec", "alerta", "alerts", "telegram"], ["spec", "alerta", "alerts", "telegram", "token"], ["spec", "alerta", "alerts", "telegram", "chatID"], ["spec", "alerta", "alerts", "telegram", "disabledSeverity"], ["spec", "alerta", "alerts", "slack"], ["spec", "alerta", "alerts", "slack", "url"], ["spec", "alerta", "alerts", "slack", "disabledSeverity"], ["spec", "grafana"], ["spec", "grafana", "db"], ["spec", "grafana", "db", "size"], ["spec", "grafana", "resources"], ["spec", "grafana", "resources", "limits"], ["spec", "grafana", "resources", "limits", "cpu"], ["spec", "grafana", "resources", "limits", "memory"], ["spec", "grafana", "resources", "requests"], ["spec", "grafana", "resources", "requests", "cpu"], ["spec", "grafana", "resources", "requests", "memory"], ["spec", "vmagent"], ["spec", "vmagent", "externalLabels"], ["spec", "vmagent", "externalLabels", "cluster"], ["spec", "vmagent", "remoteWrite"], ["spec", "vmagent", "remoteWrite", "urls"]] secrets: exclude: [] include: From f7c6a54b0c5ea98e82766c5d3dc8d2c29916cb5e Mon Sep 17 00:00:00 2001 From: Nikita <166552198+nbykov0@users.noreply.github.com> Date: Thu, 18 Dec 2025 13:39:38 +0300 Subject: [PATCH 12/78] Update SeaweedFS v4.02 (#1725) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andrei Kvapil ## What this PR does This PR includes new seaweedfs with improved perfomance for S3 daemon and fixes issue https://github.com/seaweedfs/seaweedfs/issues/7757 ### Release note ```release-note Update SeaweedFS v4.02 ``` ## Summary by CodeRabbit * **New Features** * Added all-in-one deployment mode with configurable replicas and update strategy * Expanded storage configuration supporting PersistentVolumeClaims with customizable access modes and size * Introduced configurable certificate duration and renewal periods * Enhanced monitoring configuration with gateway host/port and additional labels * **Bug Fixes** * Fixed probe endpoint scheme references across components * **Chores** * Updated to SeaweedFS 4.02 * Updated default ingress class configuration * S3 disabled by default ✏️ Tip: You can customize this high-level summary in your review settings. --- packages/system/seaweedfs/Makefile | 1 - .../seaweedfs/charts/seaweedfs/Chart.yaml | 4 +- .../all-in-one/all-in-one-deployment.yaml | 116 +++++++---- .../templates/all-in-one/all-in-one-pvc.yaml | 25 ++- .../all-in-one/all-in-one-service.yml | 18 +- .../seaweedfs/templates/cert/ca-cert.yaml | 8 +- .../templates/filer/filer-ingress.yaml | 13 +- .../templates/filer/filer-statefulset.yaml | 21 +- .../templates/master/master-statefulset.yaml | 12 +- .../seaweedfs/templates/s3/s3-deployment.yaml | 7 +- .../seaweedfs/templates/s3/s3-ingress.yaml | 16 +- .../shared/post-install-bucket-hook.yaml | 71 +++++-- .../templates/volume/volume-statefulset.yaml | 4 +- .../seaweedfs/charts/seaweedfs/values.yaml | 187 ++++++++++++------ .../seaweedfs/images/seaweedfs/Dockerfile | 2 +- .../seaweedfs/patches/long-term-ca.diff | 13 -- 16 files changed, 333 insertions(+), 185 deletions(-) delete mode 100644 packages/system/seaweedfs/patches/long-term-ca.diff diff --git a/packages/system/seaweedfs/Makefile b/packages/system/seaweedfs/Makefile index 2344f6b5..9d1f47cd 100644 --- a/packages/system/seaweedfs/Makefile +++ b/packages/system/seaweedfs/Makefile @@ -12,7 +12,6 @@ update: sed -i.bak "/ARG VERSION/ s|=.*|=$${version}|g" images/seaweedfs/Dockerfile && \ rm -f images/seaweedfs/Dockerfile.bak patch --no-backup-if-mismatch -p4 < patches/resize-api-server-annotation.diff - patch --no-backup-if-mismatch -p4 < patches/long-term-ca.diff #patch --no-backup-if-mismatch -p4 < patches/retention-policy-delete.yaml image: diff --git a/packages/system/seaweedfs/charts/seaweedfs/Chart.yaml b/packages/system/seaweedfs/charts/seaweedfs/Chart.yaml index c595d65e..6ea31115 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/Chart.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v1 description: SeaweedFS name: seaweedfs -appVersion: "3.99" +appVersion: "4.02" # Dev note: Trigger a helm chart release by `git tag -a helm-` -version: 4.0.399 +version: 4.0.402 diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-deployment.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-deployment.yaml index 8700a8a6..f6237bb7 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-deployment.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-deployment.yaml @@ -15,9 +15,9 @@ metadata: {{- toYaml .Values.allInOne.annotations | nindent 4 }} {{- end }} spec: - replicas: 1 + replicas: {{ .Values.allInOne.replicas | default 1 }} strategy: - type: Recreate + type: {{ .Values.allInOne.updateStrategy.type | default "Recreate" }} selector: matchLabels: app.kubernetes.io/name: {{ template "seaweedfs.name" . }} @@ -130,12 +130,23 @@ spec: value: {{ include "seaweedfs.cluster.masterAddress" . | quote }} - name: {{ $clusterFilerKey }} value: {{ include "seaweedfs.cluster.filerAddress" . | quote }} + {{- if .Values.allInOne.secretExtraEnvironmentVars }} + {{- range $key, $value := .Values.allInOne.secretExtraEnvironmentVars }} + - name: {{ $key }} + valueFrom: + {{ toYaml $value | nindent 16 }} + {{- end }} + {{- end }} command: - "/bin/sh" - "-ec" - | /usr/bin/weed \ + {{- if .Values.allInOne.loggingOverrideLevel }} + -v={{ .Values.allInOne.loggingOverrideLevel }} \ + {{- else }} -v={{ .Values.global.loggingLevel }} \ + {{- end }} server \ -dir=/data \ -master \ @@ -191,6 +202,9 @@ spec: {{- else if .Values.master.metricsPort }} -metricsPort={{ .Values.master.metricsPort }} \ {{- end }} + {{- if .Values.allInOne.metricsIp }} + -metricsIp={{ .Values.allInOne.metricsIp }} \ + {{- end }} -filer \ -filer.port={{ .Values.filer.port }} \ {{- if .Values.filer.disableDirListing }} @@ -219,61 +233,75 @@ spec: {{- end }} {{- if .Values.allInOne.s3.enabled }} -s3 \ - -s3.port={{ .Values.s3.port }} \ - {{- if .Values.s3.domainName }} - -s3.domainName={{ .Values.s3.domainName }} \ + -s3.port={{ .Values.allInOne.s3.port | default .Values.s3.port }} \ + {{- $domainName := .Values.allInOne.s3.domainName | default .Values.s3.domainName }} + {{- if $domainName }} + -s3.domainName={{ $domainName }} \ {{- end }} {{- if .Values.global.enableSecurity }} - {{- if .Values.s3.httpsPort }} - -s3.port.https={{ .Values.s3.httpsPort }} \ + {{- $httpsPort := .Values.allInOne.s3.httpsPort | default .Values.s3.httpsPort }} + {{- if $httpsPort }} + -s3.port.https={{ $httpsPort }} \ {{- end }} -s3.cert.file=/usr/local/share/ca-certificates/client/tls.crt \ -s3.key.file=/usr/local/share/ca-certificates/client/tls.key \ {{- end }} - {{- if eq (typeOf .Values.s3.allowEmptyFolder) "bool" }} - -s3.allowEmptyFolder={{ .Values.s3.allowEmptyFolder }} \ - {{- end }} - {{- if .Values.s3.enableAuth }} + {{- if or .Values.allInOne.s3.enableAuth .Values.s3.enableAuth .Values.filer.s3.enableAuth }} -s3.config=/etc/sw/s3/seaweedfs_s3_config \ {{- end }} - {{- if .Values.s3.auditLogConfig }} + {{- $auditLogConfig := .Values.allInOne.s3.auditLogConfig | default .Values.s3.auditLogConfig }} + {{- if $auditLogConfig }} -s3.auditLogConfig=/etc/sw/s3/s3_auditLogConfig.json \ {{- end }} {{- end }} {{- if .Values.allInOne.sftp.enabled }} -sftp \ - -sftp.port={{ .Values.sftp.port }} \ - {{- if .Values.sftp.sshPrivateKey }} - -sftp.sshPrivateKey={{ .Values.sftp.sshPrivateKey }} \ + -sftp.port={{ .Values.allInOne.sftp.port | default .Values.sftp.port }} \ + {{- $sshPrivateKey := .Values.allInOne.sftp.sshPrivateKey | default .Values.sftp.sshPrivateKey }} + {{- if $sshPrivateKey }} + -sftp.sshPrivateKey={{ $sshPrivateKey }} \ {{- end }} - {{- if .Values.sftp.hostKeysFolder }} - -sftp.hostKeysFolder={{ .Values.sftp.hostKeysFolder }} \ + {{- $hostKeysFolder := .Values.allInOne.sftp.hostKeysFolder | default .Values.sftp.hostKeysFolder }} + {{- if $hostKeysFolder }} + -sftp.hostKeysFolder={{ $hostKeysFolder }} \ {{- end }} - {{- if .Values.sftp.authMethods }} - -sftp.authMethods={{ .Values.sftp.authMethods }} \ + {{- $authMethods := .Values.allInOne.sftp.authMethods | default .Values.sftp.authMethods }} + {{- if $authMethods }} + -sftp.authMethods={{ $authMethods }} \ {{- end }} - {{- if .Values.sftp.maxAuthTries }} - -sftp.maxAuthTries={{ .Values.sftp.maxAuthTries }} \ + {{- $maxAuthTries := .Values.allInOne.sftp.maxAuthTries | default .Values.sftp.maxAuthTries }} + {{- if $maxAuthTries }} + -sftp.maxAuthTries={{ $maxAuthTries }} \ {{- end }} - {{- if .Values.sftp.bannerMessage }} - -sftp.bannerMessage="{{ .Values.sftp.bannerMessage }}" \ + {{- $bannerMessage := .Values.allInOne.sftp.bannerMessage | default .Values.sftp.bannerMessage }} + {{- if $bannerMessage }} + -sftp.bannerMessage="{{ $bannerMessage }}" \ {{- end }} - {{- if .Values.sftp.loginGraceTime }} - -sftp.loginGraceTime={{ .Values.sftp.loginGraceTime }} \ + {{- $loginGraceTime := .Values.allInOne.sftp.loginGraceTime | default .Values.sftp.loginGraceTime }} + {{- if $loginGraceTime }} + -sftp.loginGraceTime={{ $loginGraceTime }} \ {{- end }} - {{- if .Values.sftp.clientAliveInterval }} - -sftp.clientAliveInterval={{ .Values.sftp.clientAliveInterval }} \ + {{- $clientAliveInterval := .Values.allInOne.sftp.clientAliveInterval | default .Values.sftp.clientAliveInterval }} + {{- if $clientAliveInterval }} + -sftp.clientAliveInterval={{ $clientAliveInterval }} \ {{- end }} - {{- if .Values.sftp.clientAliveCountMax }} - -sftp.clientAliveCountMax={{ .Values.sftp.clientAliveCountMax }} \ + {{- $clientAliveCountMax := .Values.allInOne.sftp.clientAliveCountMax | default .Values.sftp.clientAliveCountMax }} + {{- if $clientAliveCountMax }} + -sftp.clientAliveCountMax={{ $clientAliveCountMax }} \ {{- end }} + {{- if or .Values.allInOne.sftp.enableAuth .Values.sftp.enableAuth }} -sftp.userStoreFile=/etc/sw/sftp/seaweedfs_sftp_config \ {{- end }} + {{- end }} + {{- $extraArgsCount := len .Values.allInOne.extraArgs }} + {{- range $i, $arg := .Values.allInOne.extraArgs }} + {{ $arg | quote }}{{ if ne (add1 $i) $extraArgsCount }} \{{ end }} + {{- end }} volumeMounts: - name: data mountPath: /data - {{- if and .Values.allInOne.s3.enabled (or .Values.s3.enableAuth .Values.filer.s3.enableAuth) }} + {{- if and .Values.allInOne.s3.enabled (or .Values.allInOne.s3.enableAuth .Values.s3.enableAuth .Values.filer.s3.enableAuth) }} - name: config-s3-users mountPath: /etc/sw/s3 readOnly: true @@ -282,10 +310,12 @@ spec: - name: config-ssh mountPath: /etc/sw/ssh readOnly: true + {{- if or .Values.allInOne.sftp.enableAuth .Values.sftp.enableAuth }} - mountPath: /etc/sw/sftp name: config-users readOnly: true {{- end }} + {{- end }} {{- if .Values.filer.notificationConfig }} - name: notification-config mountPath: /etc/seaweedfs/notification.toml @@ -332,15 +362,16 @@ spec: - containerPort: {{ .Values.filer.grpcPort }} name: swfs-fil-grpc {{- if .Values.allInOne.s3.enabled }} - - containerPort: {{ .Values.s3.port }} + - containerPort: {{ .Values.allInOne.s3.port | default .Values.s3.port }} name: swfs-s3 - {{- if .Values.s3.httpsPort }} - - containerPort: {{ .Values.s3.httpsPort }} + {{- $httpsPort := .Values.allInOne.s3.httpsPort | default .Values.s3.httpsPort }} + {{- if $httpsPort }} + - containerPort: {{ $httpsPort }} name: swfs-s3-tls {{- end }} {{- end }} {{- if .Values.allInOne.sftp.enabled }} - - containerPort: {{ .Values.sftp.port }} + - containerPort: {{ .Values.allInOne.sftp.port | default .Values.sftp.port }} name: swfs-sftp {{- end }} {{- if .Values.allInOne.metricsPort }} @@ -352,7 +383,7 @@ spec: httpGet: path: {{ .Values.allInOne.readinessProbe.httpGet.path }} port: {{ .Values.master.port }} - scheme: {{ .Values.allInOne.readinessProbe.scheme }} + scheme: {{ .Values.allInOne.readinessProbe.httpGet.scheme }} initialDelaySeconds: {{ .Values.allInOne.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.allInOne.readinessProbe.periodSeconds }} successThreshold: {{ .Values.allInOne.readinessProbe.successThreshold }} @@ -364,7 +395,7 @@ spec: httpGet: path: {{ .Values.allInOne.livenessProbe.httpGet.path }} port: {{ .Values.master.port }} - scheme: {{ .Values.allInOne.livenessProbe.scheme }} + scheme: {{ .Values.allInOne.livenessProbe.httpGet.scheme }} initialDelaySeconds: {{ .Values.allInOne.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.allInOne.livenessProbe.periodSeconds }} successThreshold: {{ .Values.allInOne.livenessProbe.successThreshold }} @@ -389,26 +420,31 @@ spec: path: {{ .Values.allInOne.data.hostPathPrefix }}/seaweedfs-all-in-one-data/ type: DirectoryOrCreate {{- else if eq .Values.allInOne.data.type "persistentVolumeClaim" }} + persistentVolumeClaim: + claimName: {{ template "seaweedfs.name" . }}-all-in-one-data + {{- else if eq .Values.allInOne.data.type "existingClaim" }} persistentVolumeClaim: claimName: {{ .Values.allInOne.data.claimName }} {{- else if eq .Values.allInOne.data.type "emptyDir" }} emptyDir: {} {{- end }} - {{- if and .Values.allInOne.s3.enabled (or .Values.s3.enableAuth .Values.filer.s3.enableAuth) }} + {{- if and .Values.allInOne.s3.enabled (or .Values.allInOne.s3.enableAuth .Values.s3.enableAuth .Values.filer.s3.enableAuth) }} - name: config-s3-users secret: defaultMode: 420 - secretName: {{ default (printf "%s-s3-secret" (include "seaweedfs.name" .)) (or .Values.s3.existingConfigSecret .Values.filer.s3.existingConfigSecret) }} + secretName: {{ default (printf "%s-s3-secret" (include "seaweedfs.name" .)) (or .Values.allInOne.s3.existingConfigSecret .Values.s3.existingConfigSecret .Values.filer.s3.existingConfigSecret) }} {{- end }} {{- if .Values.allInOne.sftp.enabled }} - name: config-ssh secret: defaultMode: 420 - secretName: {{ default (printf "%s-sftp-ssh-secret" (include "seaweedfs.name" .)) .Values.sftp.existingSshConfigSecret }} + secretName: {{ default (printf "%s-sftp-ssh-secret" (include "seaweedfs.name" .)) (or .Values.allInOne.sftp.existingSshConfigSecret .Values.sftp.existingSshConfigSecret) }} + {{- if or .Values.allInOne.sftp.enableAuth .Values.sftp.enableAuth }} - name: config-users secret: defaultMode: 420 - secretName: {{ default (printf "%s-sftp-secret" (include "seaweedfs.name" .)) .Values.sftp.existingConfigSecret }} + secretName: {{ default (printf "%s-sftp-secret" (include "seaweedfs.name" .)) (or .Values.allInOne.sftp.existingConfigSecret .Values.sftp.existingConfigSecret) }} + {{- end }} {{- end }} {{- if .Values.filer.notificationConfig }} - name: notification-config diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-pvc.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-pvc.yaml index 49ac2014..a62450c3 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-pvc.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-pvc.yaml @@ -1,21 +1,28 @@ -{{- if and .Values.allInOne.enabled (eq .Values.allInOne.data.type "persistentVolumeClaim") }} +{{- if .Values.allInOne.enabled }} +{{- if eq .Values.allInOne.data.type "persistentVolumeClaim" }} apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: {{ .Values.allInOne.data.claimName }} + name: {{ template "seaweedfs.name" . }}-all-in-one-data + namespace: {{ .Release.Namespace }} labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/component: seaweedfs-all-in-one - {{- if .Values.allInOne.annotations }} + {{- with .Values.allInOne.data.annotations }} annotations: - {{- toYaml .Values.allInOne.annotations | nindent 4 }} + {{- toYaml . | nindent 4 }} {{- end }} spec: accessModes: - - ReadWriteOnce - resources: - requests: - storage: {{ .Values.allInOne.data.size }} + {{- toYaml (.Values.allInOne.data.accessModes | default (list "ReadWriteOnce")) | nindent 4 }} {{- if .Values.allInOne.data.storageClass }} storageClassName: {{ .Values.allInOne.data.storageClass }} {{- end }} -{{- end }} \ No newline at end of file + resources: + requests: + storage: {{ .Values.allInOne.data.size | default "10Gi" }} +{{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-service.yml b/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-service.yml index 14076a9c..b13f5789 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-service.yml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-service.yml @@ -15,6 +15,7 @@ metadata: {{- toYaml .Values.allInOne.service.annotations | nindent 4 }} {{- end }} spec: + type: {{ .Values.allInOne.service.type | default "ClusterIP" }} internalTrafficPolicy: {{ .Values.allInOne.service.internalTrafficPolicy | default "Cluster" }} ports: # Master ports @@ -50,13 +51,14 @@ spec: # S3 ports (if enabled) {{- if .Values.allInOne.s3.enabled }} - name: "swfs-s3" - port: {{ if .Values.allInOne.s3.enabled }}{{ .Values.s3.port }}{{ else }}{{ .Values.filer.s3.port }}{{ end }} - targetPort: {{ if .Values.allInOne.s3.enabled }}{{ .Values.s3.port }}{{ else }}{{ .Values.filer.s3.port }}{{ end }} + port: {{ .Values.allInOne.s3.port | default .Values.s3.port }} + targetPort: {{ .Values.allInOne.s3.port | default .Values.s3.port }} protocol: TCP - {{- if and .Values.allInOne.s3.enabled .Values.s3.httpsPort }} + {{- $httpsPort := .Values.allInOne.s3.httpsPort | default .Values.s3.httpsPort }} + {{- if $httpsPort }} - name: "swfs-s3-tls" - port: {{ .Values.s3.httpsPort }} - targetPort: {{ .Values.s3.httpsPort }} + port: {{ $httpsPort }} + targetPort: {{ $httpsPort }} protocol: TCP {{- end }} {{- end }} @@ -64,8 +66,8 @@ spec: # SFTP ports (if enabled) {{- if .Values.allInOne.sftp.enabled }} - name: "swfs-sftp" - port: {{ .Values.sftp.port }} - targetPort: {{ .Values.sftp.port }} + port: {{ .Values.allInOne.sftp.port | default .Values.sftp.port }} + targetPort: {{ .Values.allInOne.sftp.port | default .Values.sftp.port }} protocol: TCP {{- end }} @@ -80,4 +82,4 @@ spec: selector: app.kubernetes.io/name: {{ template "seaweedfs.name" . }} app.kubernetes.io/component: seaweedfs-all-in-one -{{- end }} \ No newline at end of file +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml index f2572558..b01a8dcc 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml @@ -13,8 +13,12 @@ spec: secretName: {{ template "seaweedfs.name" . }}-ca-cert commonName: "{{ template "seaweedfs.name" . }}-root-ca" isCA: true - duration: 87600h - renewBefore: 720h + {{- if .Values.certificates.ca.duration }} + duration: {{ .Values.certificates.ca.duration }} + {{- end }} + {{- if .Values.certificates.ca.renewBefore }} + renewBefore: {{ .Values.certificates.ca.renewBefore }} + {{- end }} issuerRef: name: {{ template "seaweedfs.name" . }}-issuer kind: Issuer diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-ingress.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-ingress.yaml index 9ce15ae9..b185a58b 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-ingress.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-ingress.yaml @@ -1,5 +1,8 @@ -{{- if .Values.filer.enabled }} -{{- if .Values.filer.ingress.enabled }} +{{- /* Filer ingress works for both normal mode (filer.enabled) and all-in-one mode (allInOne.enabled) */}} +{{- $filerEnabled := or .Values.filer.enabled .Values.allInOne.enabled }} +{{- if and $filerEnabled .Values.filer.ingress.enabled }} +{{- /* Determine service name based on deployment mode */}} +{{- $serviceName := ternary (printf "%s-all-in-one" (include "seaweedfs.name" .)) (printf "%s-filer" (include "seaweedfs.name" .)) .Values.allInOne.enabled }} {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} apiVersion: networking.k8s.io/v1 {{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion }} @@ -33,16 +36,14 @@ spec: backend: {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} service: - name: {{ template "seaweedfs.name" . }}-filer + name: {{ $serviceName }} port: number: {{ .Values.filer.port }} - #name: {{- else }} - serviceName: {{ template "seaweedfs.name" . }}-filer + serviceName: {{ $serviceName }} servicePort: {{ .Values.filer.port }} {{- end }} {{- if .Values.filer.ingress.host }} host: {{ .Values.filer.ingress.host }} {{- end }} {{- end }} -{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-statefulset.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-statefulset.yaml index 5c1a0950..2b8c2744 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-statefulset.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-statefulset.yaml @@ -213,9 +213,6 @@ spec: -s3.cert.file=/usr/local/share/ca-certificates/client/tls.crt \ -s3.key.file=/usr/local/share/ca-certificates/client/tls.key \ {{- end }} - {{- if eq (typeOf .Values.filer.s3.allowEmptyFolder) "bool" }} - -s3.allowEmptyFolder={{ .Values.filer.s3.allowEmptyFolder }} \ - {{- end }} {{- if .Values.filer.s3.enableAuth }} -s3.config=/etc/sw/seaweedfs_s3_config \ {{- end }} @@ -289,7 +286,7 @@ spec: httpGet: path: {{ .Values.filer.readinessProbe.httpGet.path }} port: {{ .Values.filer.port }} - scheme: {{ .Values.filer.readinessProbe.scheme }} + scheme: {{ .Values.filer.readinessProbe.httpGet.scheme }} initialDelaySeconds: {{ .Values.filer.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.filer.readinessProbe.periodSeconds }} successThreshold: {{ .Values.filer.readinessProbe.successThreshold }} @@ -301,7 +298,7 @@ spec: httpGet: path: {{ .Values.filer.livenessProbe.httpGet.path }} port: {{ .Values.filer.port }} - scheme: {{ .Values.filer.livenessProbe.scheme }} + scheme: {{ .Values.filer.livenessProbe.httpGet.scheme }} initialDelaySeconds: {{ .Values.filer.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.filer.livenessProbe.periodSeconds }} successThreshold: {{ .Values.filer.livenessProbe.successThreshold }} @@ -392,10 +389,12 @@ spec: nodeSelector: {{ tpl .Values.filer.nodeSelector . | indent 8 | trim }} {{- end }} - {{- if and (.Values.filer.enablePVC) (eq .Values.filer.data.type "persistentVolumeClaim") }} + {{- if and (.Values.filer.enablePVC) (not .Values.filer.data) }} # DEPRECATION: Deprecate in favor of filer.data section below volumeClaimTemplates: - - metadata: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: name: data-filer spec: accessModes: @@ -411,7 +410,9 @@ spec: {{- if $pvc_exists }} volumeClaimTemplates: {{- if eq .Values.filer.data.type "persistentVolumeClaim" }} - - metadata: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: name: data-filer {{- with .Values.filer.data.annotations }} annotations: @@ -425,7 +426,9 @@ spec: storage: {{ .Values.filer.data.size }} {{- end }} {{- if eq .Values.filer.logs.type "persistentVolumeClaim" }} - - metadata: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: name: seaweedfs-filer-log-volume {{- with .Values.filer.logs.annotations }} annotations: diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-statefulset.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-statefulset.yaml index 01387fc9..a7067345 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-statefulset.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-statefulset.yaml @@ -235,7 +235,7 @@ spec: httpGet: path: {{ .Values.master.readinessProbe.httpGet.path }} port: {{ .Values.master.port }} - scheme: {{ .Values.master.readinessProbe.scheme }} + scheme: {{ .Values.master.readinessProbe.httpGet.scheme }} initialDelaySeconds: {{ .Values.master.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.master.readinessProbe.periodSeconds }} successThreshold: {{ .Values.master.readinessProbe.successThreshold }} @@ -247,7 +247,7 @@ spec: httpGet: path: {{ .Values.master.livenessProbe.httpGet.path }} port: {{ .Values.master.port }} - scheme: {{ .Values.master.livenessProbe.scheme }} + scheme: {{ .Values.master.livenessProbe.httpGet.scheme }} initialDelaySeconds: {{ .Values.master.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.master.livenessProbe.periodSeconds }} successThreshold: {{ .Values.master.livenessProbe.successThreshold }} @@ -327,7 +327,9 @@ spec: {{- if $pvc_exists }} volumeClaimTemplates: {{- if eq .Values.master.data.type "persistentVolumeClaim"}} - - metadata: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: name: data-{{ .Release.Namespace }} {{- with .Values.master.data.annotations }} annotations: @@ -341,7 +343,9 @@ spec: storage: {{ .Values.master.data.size }} {{- end }} {{- if eq .Values.master.logs.type "persistentVolumeClaim"}} - - metadata: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: name: seaweedfs-master-log-volume {{- with .Values.master.logs.annotations }} annotations: diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-deployment.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-deployment.yaml index 0c6d52c3..29dd2d43 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-deployment.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-deployment.yaml @@ -143,9 +143,6 @@ spec: {{- if .Values.s3.domainName }} -domainName={{ .Values.s3.domainName }} \ {{- end }} - {{- if eq (typeOf .Values.s3.allowEmptyFolder) "bool" }} - -allowEmptyFolder={{ .Values.s3.allowEmptyFolder }} \ - {{- end }} {{- if .Values.s3.enableAuth }} -config=/etc/sw/seaweedfs_s3_config \ {{- end }} @@ -204,7 +201,7 @@ spec: httpGet: path: {{ .Values.s3.readinessProbe.httpGet.path }} port: {{ .Values.s3.port }} - scheme: {{ .Values.s3.readinessProbe.scheme }} + scheme: {{ .Values.s3.readinessProbe.httpGet.scheme }} initialDelaySeconds: {{ .Values.s3.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.s3.readinessProbe.periodSeconds }} successThreshold: {{ .Values.s3.readinessProbe.successThreshold }} @@ -216,7 +213,7 @@ spec: httpGet: path: {{ .Values.s3.livenessProbe.httpGet.path }} port: {{ .Values.s3.port }} - scheme: {{ .Values.s3.livenessProbe.scheme }} + scheme: {{ .Values.s3.livenessProbe.httpGet.scheme }} initialDelaySeconds: {{ .Values.s3.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.s3.livenessProbe.periodSeconds }} successThreshold: {{ .Values.s3.livenessProbe.successThreshold }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-ingress.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-ingress.yaml index a856923e..899773ae 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-ingress.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-ingress.yaml @@ -1,4 +1,9 @@ -{{- if .Values.s3.ingress.enabled }} +{{- /* S3 ingress works for standalone S3 gateway (s3.enabled), S3 on Filer (filer.s3.enabled), and all-in-one mode (allInOne.s3.enabled) */}} +{{- $s3Enabled := or .Values.s3.enabled (and .Values.filer.s3.enabled (not .Values.allInOne.enabled)) (and .Values.allInOne.enabled .Values.allInOne.s3.enabled) }} +{{- if and $s3Enabled .Values.s3.ingress.enabled }} +{{- /* Determine service name based on deployment mode */}} +{{- $serviceName := ternary (printf "%s-all-in-one" (include "seaweedfs.name" .)) (printf "%s-s3" (include "seaweedfs.name" .)) .Values.allInOne.enabled }} +{{- $s3Port := .Values.allInOne.s3.port | default .Values.s3.port }} {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} apiVersion: networking.k8s.io/v1 {{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion }} @@ -32,13 +37,12 @@ spec: backend: {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} service: - name: {{ template "seaweedfs.name" . }}-s3 + name: {{ $serviceName }} port: - number: {{ .Values.s3.port }} - #name: + number: {{ $s3Port }} {{- else }} - serviceName: {{ template "seaweedfs.name" . }}-s3 - servicePort: {{ .Values.s3.port }} + serviceName: {{ $serviceName }} + servicePort: {{ $s3Port }} {{- end }} {{- if .Values.s3.ingress.host }} host: {{ .Values.s3.ingress.host | quote }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/shared/post-install-bucket-hook.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/post-install-bucket-hook.yaml index 44d65089..a0c56edc 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/shared/post-install-bucket-hook.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/post-install-bucket-hook.yaml @@ -1,6 +1,32 @@ -{{- if .Values.master.enabled }} -{{- if .Values.filer.s3.enabled }} -{{- if .Values.filer.s3.createBuckets }} +{{- /* Support bucket creation for both standalone filer.s3 and allInOne modes */}} +{{- $createBuckets := list }} +{{- $s3Enabled := false }} +{{- $enableAuth := false }} +{{- $existingConfigSecret := "" }} + +{{- /* Check allInOne mode first */}} +{{- if .Values.allInOne.enabled }} + {{- if .Values.allInOne.s3.enabled }} + {{- $s3Enabled = true }} + {{- if .Values.allInOne.s3.createBuckets }} + {{- $createBuckets = .Values.allInOne.s3.createBuckets }} + {{- end }} + {{- $enableAuth = or .Values.allInOne.s3.enableAuth .Values.s3.enableAuth .Values.filer.s3.enableAuth }} + {{- $existingConfigSecret = or .Values.allInOne.s3.existingConfigSecret .Values.s3.existingConfigSecret .Values.filer.s3.existingConfigSecret }} + {{- end }} +{{- else if .Values.master.enabled }} + {{- /* Check standalone filer.s3 mode */}} + {{- if .Values.filer.s3.enabled }} + {{- $s3Enabled = true }} + {{- if .Values.filer.s3.createBuckets }} + {{- $createBuckets = .Values.filer.s3.createBuckets }} + {{- end }} + {{- $enableAuth = .Values.filer.s3.enableAuth }} + {{- $existingConfigSecret = .Values.filer.s3.existingConfigSecret }} + {{- end }} +{{- end }} + +{{- if and $s3Enabled $createBuckets }} --- apiVersion: batch/v1 kind: Job @@ -32,9 +58,9 @@ spec: - name: WEED_CLUSTER_DEFAULT value: "sw" - name: WEED_CLUSTER_SW_MASTER - value: "{{ template "seaweedfs.name" . }}-master.{{ .Release.Namespace }}:{{ .Values.master.port }}" + value: {{ include "seaweedfs.cluster.masterAddress" . | quote }} - name: WEED_CLUSTER_SW_FILER - value: "{{ template "seaweedfs.name" . }}-filer-client.{{ .Release.Namespace }}:{{ .Values.filer.port }}" + value: {{ include "seaweedfs.cluster.filerAddress" . | quote }} - name: POD_IP valueFrom: fieldRef: @@ -71,24 +97,29 @@ spec: echo "Service at $url failed to become ready within 5 minutes" exit 1 } + {{- if .Values.allInOne.enabled }} + wait_for_service "http://$WEED_CLUSTER_SW_MASTER{{ .Values.allInOne.readinessProbe.httpGet.path }}" + wait_for_service "http://$WEED_CLUSTER_SW_FILER{{ .Values.filer.readinessProbe.httpGet.path }}" + {{- else }} wait_for_service "http://$WEED_CLUSTER_SW_MASTER{{ .Values.master.readinessProbe.httpGet.path }}" wait_for_service "http://$WEED_CLUSTER_SW_FILER{{ .Values.filer.readinessProbe.httpGet.path }}" - {{- range $reg, $props := $.Values.filer.s3.createBuckets }} - exec /bin/echo \ - "s3.bucket.create --name {{ $props.name }}" |\ + {{- end }} + {{- range $createBuckets }} + /bin/echo \ + "s3.bucket.create --name {{ .name }}" |\ /usr/bin/weed shell {{- end }} - {{- range $reg, $props := $.Values.filer.s3.createBuckets }} - {{- if $props.anonymousRead }} - exec /bin/echo \ + {{- range $createBuckets }} + {{- if .anonymousRead }} + /bin/echo \ "s3.configure --user anonymous \ - --buckets {{ $props.name }} \ + --buckets {{ .name }} \ --actions Read \ --apply true" |\ /usr/bin/weed shell {{- end }} {{- end }} - {{- if .Values.filer.s3.enableAuth }} + {{- if $enableAuth }} volumeMounts: - name: config-users mountPath: /etc/sw @@ -106,17 +137,15 @@ spec: {{- if .Values.filer.containerSecurityContext.enabled }} securityContext: {{- omit .Values.filer.containerSecurityContext "enabled" | toYaml | nindent 12 }} {{- end }} - {{- if .Values.filer.s3.enableAuth }} + {{- if $enableAuth }} volumes: - name: config-users secret: defaultMode: 420 - {{- if not (empty .Values.filer.s3.existingConfigSecret) }} - secretName: {{ .Values.filer.s3.existingConfigSecret }} + {{- if $existingConfigSecret }} + secretName: {{ $existingConfigSecret }} {{- else }} - secretName: seaweedfs-s3-secret + secretName: {{ template "seaweedfs.name" . }}-s3-secret {{- end }} - {{- end }}{{/** if .Values.filer.s3.enableAuth **/}} -{{- end }}{{/** if .Values.master.enabled **/}} -{{- end }}{{/** if .Values.filer.s3.enabled **/}} -{{- end }}{{/** if .Values.filer.s3.createBuckets **/}} + {{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml index 29a035a2..1a8964a5 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml @@ -251,7 +251,7 @@ spec: httpGet: path: {{ $volume.readinessProbe.httpGet.path }} port: {{ $volume.port }} - scheme: {{ $volume.readinessProbe.scheme }} + scheme: {{ $volume.readinessProbe.httpGet.scheme }} initialDelaySeconds: {{ $volume.readinessProbe.initialDelaySeconds }} periodSeconds: {{ $volume.readinessProbe.periodSeconds }} successThreshold: {{ $volume.readinessProbe.successThreshold }} @@ -263,7 +263,7 @@ spec: httpGet: path: {{ $volume.livenessProbe.httpGet.path }} port: {{ $volume.port }} - scheme: {{ $volume.livenessProbe.scheme }} + scheme: {{ $volume.livenessProbe.httpGet.scheme }} initialDelaySeconds: {{ $volume.livenessProbe.initialDelaySeconds }} periodSeconds: {{ $volume.livenessProbe.periodSeconds }} successThreshold: {{ $volume.livenessProbe.successThreshold }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/values.yaml b/packages/system/seaweedfs/charts/seaweedfs/values.yaml index cf16623c..b71e1071 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/values.yaml @@ -22,6 +22,8 @@ global: serviceAccountName: "seaweedfs" automountServiceAccountToken: true certificates: + duration: 87600h + renewBefore: 720h alphacrds: false monitoring: enabled: false @@ -235,27 +237,27 @@ master: ingress: enabled: false - className: "nginx" + className: "" # host: false for "*" hostname host: "master.seaweedfs.local" path: "/sw-master/?(.*)" pathType: ImplementationSpecific - annotations: - nginx.ingress.kubernetes.io/auth-type: "basic" - nginx.ingress.kubernetes.io/auth-secret: "default/ingress-basic-auth-secret" - nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - SW-Master' - nginx.ingress.kubernetes.io/service-upstream: "true" - nginx.ingress.kubernetes.io/rewrite-target: /$1 - nginx.ingress.kubernetes.io/use-regex: "true" - nginx.ingress.kubernetes.io/enable-rewrite-log: "true" - nginx.ingress.kubernetes.io/ssl-redirect: "false" - nginx.ingress.kubernetes.io/force-ssl-redirect: "false" - nginx.ingress.kubernetes.io/configuration-snippet: | - sub_filter '' ' '; #add base url - sub_filter '="/' '="./'; #make absolute paths to relative - sub_filter '=/' '=./'; - sub_filter '/seaweedfsstatic' './seaweedfsstatic'; - sub_filter_once off; + annotations: {} + # nginx.ingress.kubernetes.io/auth-type: "basic" + # nginx.ingress.kubernetes.io/auth-secret: "default/ingress-basic-auth-secret" + # nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - SW-Master' + # nginx.ingress.kubernetes.io/service-upstream: "true" + # nginx.ingress.kubernetes.io/rewrite-target: /$1 + # nginx.ingress.kubernetes.io/use-regex: "true" + # nginx.ingress.kubernetes.io/enable-rewrite-log: "true" + # nginx.ingress.kubernetes.io/ssl-redirect: "false" + # nginx.ingress.kubernetes.io/force-ssl-redirect: "false" + # nginx.ingress.kubernetes.io/configuration-snippet: | + # sub_filter '' ' '; #add base url + # sub_filter '="/' '="./'; #make absolute paths to relative + # sub_filter '=/' '=./'; + # sub_filter '/seaweedfsstatic' './seaweedfsstatic'; + # sub_filter_once off; tls: [] extraEnvironmentVars: @@ -308,7 +310,7 @@ volume: # limit file size to avoid out of memory, default 256mb fileSizeLimitMB: null # minimum free disk space(in percents). If free disk space lower this value - all volumes marks as ReadOnly - minFreeSpacePercent: 7 + minFreeSpacePercent: 1 # Custom command line arguments to add to the volume command # Example to fix IPv6 metrics connectivity issues: @@ -769,28 +771,28 @@ filer: ingress: enabled: false - className: "nginx" + className: "" # host: false for "*" hostname host: "seaweedfs.cluster.local" path: "/sw-filer/?(.*)" pathType: ImplementationSpecific - annotations: - nginx.ingress.kubernetes.io/backend-protocol: GRPC - nginx.ingress.kubernetes.io/auth-type: "basic" - nginx.ingress.kubernetes.io/auth-secret: "default/ingress-basic-auth-secret" - nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - SW-Filer' - nginx.ingress.kubernetes.io/service-upstream: "true" - nginx.ingress.kubernetes.io/rewrite-target: /$1 - nginx.ingress.kubernetes.io/use-regex: "true" - nginx.ingress.kubernetes.io/enable-rewrite-log: "true" - nginx.ingress.kubernetes.io/ssl-redirect: "false" - nginx.ingress.kubernetes.io/force-ssl-redirect: "false" - nginx.ingress.kubernetes.io/configuration-snippet: | - sub_filter '' ' '; #add base url - sub_filter '="/' '="./'; #make absolute paths to relative - sub_filter '=/' '=./'; - sub_filter '/seaweedfsstatic' './seaweedfsstatic'; - sub_filter_once off; + annotations: {} + # nginx.ingress.kubernetes.io/backend-protocol: GRPC + # nginx.ingress.kubernetes.io/auth-type: "basic" + # nginx.ingress.kubernetes.io/auth-secret: "default/ingress-basic-auth-secret" + # nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - SW-Filer' + # nginx.ingress.kubernetes.io/service-upstream: "true" + # nginx.ingress.kubernetes.io/rewrite-target: /$1 + # nginx.ingress.kubernetes.io/use-regex: "true" + # nginx.ingress.kubernetes.io/enable-rewrite-log: "true" + # nginx.ingress.kubernetes.io/ssl-redirect: "false" + # nginx.ingress.kubernetes.io/force-ssl-redirect: "false" + # nginx.ingress.kubernetes.io/configuration-snippet: | + # sub_filter '' ' '; #add base url + # sub_filter '="/' '="./'; #make absolute paths to relative + # sub_filter '=/' '=./'; + # sub_filter '/seaweedfsstatic' './seaweedfsstatic'; + # sub_filter_once off; # extraEnvVars is a list of extra environment variables to set with the stateful set. extraEnvironmentVars: @@ -854,8 +856,6 @@ filer: port: 8333 # add additional https port httpsPort: 0 - # allow empty folders - allowEmptyFolder: false # Suffix of the host name, {bucket}.{domainName} domainName: "" # enable user & permission to s3 (need to inject to all services) @@ -873,7 +873,7 @@ filer: # anonymousRead: false s3: - enabled: true + enabled: false imageOverride: null restartPolicy: null replicas: 1 @@ -883,8 +883,6 @@ s3: httpsPort: 0 metricsPort: 9327 loggingOverrideLevel: null - # allow empty folders - allowEmptyFolder: true # enable user & permission to s3 (need to inject to all services) enableAuth: false # set to the name of an existing kubernetes Secret with the s3 json config file @@ -977,9 +975,9 @@ s3: extraEnvironmentVars: # Custom command line arguments to add to the s3 command - # Example to fix connection idle seconds: - extraArgs: ["-idleTimeout=30"] - # extraArgs: [] + # Default idleTimeout is 120 seconds. Example to customize: + # extraArgs: ["-idleTimeout=300"] + extraArgs: [] # used to configure livenessProbe on s3 containers # @@ -1009,7 +1007,7 @@ s3: ingress: enabled: false - className: "nginx" + className: "" # host: false for "*" hostname host: "seaweedfs.cluster.local" path: "/" @@ -1095,6 +1093,7 @@ allInOne: enabled: false imageOverride: null restartPolicy: Always + replicas: 1 # Number of replicas (note: multiple replicas may require shared storage) # Core configuration idleTimeout: 30 # Connection idle seconds @@ -1106,24 +1105,85 @@ allInOne: metricsIp: "" # Metrics listen IP. If empty, defaults to bindAddress loggingOverrideLevel: null # Override logging level - # Service configuration + # Custom command line arguments to add to the server command + # Example to fix IPv6 metrics connectivity issues: + # extraArgs: ["-metricsIp", "0.0.0.0"] + # Example with multiple args: + # extraArgs: ["-customFlag", "value", "-anotherFlag"] + extraArgs: [] + + # Update strategy configuration + # type: Recreate or RollingUpdate + # For single replica, Recreate is recommended to avoid data conflicts. + # For multiple replicas with RollingUpdate, you MUST use shared storage + # (e.g., data.type: persistentVolumeClaim with ReadWriteMany access mode) + # to avoid data loss or inconsistency between pods. + updateStrategy: + type: Recreate + + # S3 gateway configuration + # Note: Most parameters below default to null, which means they inherit from + # the global s3.* settings. Set explicit values here to override for allInOne only. s3: enabled: false # Whether to enable S3 gateway + port: null # S3 gateway port (null inherits from s3.port) + httpsPort: null # S3 gateway HTTPS port (null inherits from s3.httpsPort) + domainName: null # Suffix of the host name (null inherits from s3.domainName) + enableAuth: false # Enable user & permission to S3 + # Set to the name of an existing kubernetes Secret with the s3 json config file + # should have a secret key called seaweedfs_s3_config with an inline json config + existingConfigSecret: null + auditLogConfig: null # S3 audit log configuration (null inherits from s3.auditLogConfig) + # You may specify buckets to be created during the install process. + # Buckets may be exposed publicly by setting `anonymousRead` to `true` + # createBuckets: + # - name: bucket-a + # anonymousRead: true + # - name: bucket-b + # anonymousRead: false + + # SFTP server configuration + # Note: Most parameters below default to null, which means they inherit from + # the global sftp.* settings. Set explicit values here to override for allInOne only. sftp: enabled: false # Whether to enable SFTP server + port: null # SFTP port (null inherits from sftp.port) + sshPrivateKey: null # Path to SSH private key (null inherits from sftp.sshPrivateKey) + hostKeysFolder: null # Path to SSH host keys folder (null inherits from sftp.hostKeysFolder) + authMethods: null # Comma-separated auth methods (null inherits from sftp.authMethods) + maxAuthTries: null # Maximum authentication attempts (null inherits from sftp.maxAuthTries) + bannerMessage: null # Banner message (null inherits from sftp.bannerMessage) + loginGraceTime: null # Login grace time (null inherits from sftp.loginGraceTime) + clientAliveInterval: null # Client keep-alive interval (null inherits from sftp.clientAliveInterval) + clientAliveCountMax: null # Maximum missed keep-alive messages (null inherits from sftp.clientAliveCountMax) + enableAuth: false # Enable SFTP authentication + # Set to the name of an existing kubernetes Secret with the sftp json config file + existingConfigSecret: null + # Set to the name of an existing kubernetes Secret with the SSH keys + existingSshConfigSecret: null # Service settings service: annotations: {} # Annotations for the service type: ClusterIP # Service type (ClusterIP, NodePort, LoadBalancer) + internalTrafficPolicy: Cluster # Internal traffic policy + + # Note: For ingress in all-in-one mode, use the standard s3.ingress and + # filer.ingress settings. The templates automatically detect all-in-one mode + # and point to the correct service (seaweedfs-all-in-one instead of + # seaweedfs-s3 or seaweedfs-filer). # Storage configuration data: - type: "emptyDir" # Options: "hostPath", "persistentVolumeClaim", "emptyDir" + type: "emptyDir" # Options: "hostPath", "persistentVolumeClaim", "emptyDir", "existingClaim" hostPathPrefix: /mnt/data # Path prefix for hostPath volumes - claimName: seaweedfs-data-pvc # Name of the PVC to use - size: "" # Size of the PVC - storageClass: "" # Storage class for the PVC + claimName: seaweedfs-data-pvc # Name of the PVC to use (for existingClaim type) + size: null # Size of the PVC (null defaults to 10Gi for persistentVolumeClaim type) + storageClass: null # Storage class for the PVC (null uses cluster default) + # accessModes for the PVC. Default is ["ReadWriteOnce"]. + # For multi-replica deployments, use ["ReadWriteMany"] with a compatible storage class. + accessModes: [] + annotations: {} # Annotations for the PVC # Health checks readinessProbe: @@ -1131,7 +1191,7 @@ allInOne: httpGet: path: /cluster/status port: 9333 - scheme: HTTP + scheme: HTTP initialDelaySeconds: 10 periodSeconds: 15 successThreshold: 1 @@ -1143,7 +1203,7 @@ allInOne: httpGet: path: /cluster/status port: 9333 - scheme: HTTP + scheme: HTTP initialDelaySeconds: 20 periodSeconds: 30 successThreshold: 1 @@ -1152,6 +1212,18 @@ allInOne: # Additional resources extraEnvironmentVars: {} # Additional environment variables + # Secret environment variables (for database credentials, etc.) + # Example: + # secretExtraEnvironmentVars: + # WEED_POSTGRES_USERNAME: + # secretKeyRef: + # name: postgres-credentials + # key: username + # WEED_POSTGRES_PASSWORD: + # secretKeyRef: + # name: postgres-credentials + # key: password + secretExtraEnvironmentVars: {} extraVolumeMounts: "" # Additional volume mounts extraVolumes: "" # Additional volumes initContainers: "" # Init containers @@ -1171,7 +1243,7 @@ allInOne: matchLabels: app.kubernetes.io/name: {{ template "seaweedfs.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/component: master + app.kubernetes.io/component: seaweedfs-all-in-one topologyKey: kubernetes.io/hostname # Topology Spread Constraints Settings @@ -1179,16 +1251,16 @@ allInOne: # for a PodSpec. By Default no constraints are set. topologySpreadConstraints: "" - # Toleration Settings for master pods + # Toleration Settings for pods # This should be a multi-line string matching the Toleration array # in a PodSpec. tolerations: "" - # nodeSelector labels for master pod assignment, formatted as a muli-line string. + # nodeSelector labels for pod assignment, formatted as a muli-line string. # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector nodeSelector: "" - # Used to assign priority to master pods + # Used to assign priority to pods # ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ priorityClassName: "" @@ -1268,6 +1340,9 @@ certificates: keySize: 2048 duration: 2160h # 90d renewBefore: 360h # 15d + ca: + duration: 87600h # 10 years + renewBefore: 720h # 30d externalCertificates: # This will avoid the need to use cert-manager and will rely on providing your own external certificates and CA # you will need to store your provided certificates in the secret read by the different services: diff --git a/packages/system/seaweedfs/images/seaweedfs/Dockerfile b/packages/system/seaweedfs/images/seaweedfs/Dockerfile index 48776a56..7177c70f 100644 --- a/packages/system/seaweedfs/images/seaweedfs/Dockerfile +++ b/packages/system/seaweedfs/images/seaweedfs/Dockerfile @@ -1,2 +1,2 @@ -ARG VERSION=3.99 +ARG VERSION=4.02 FROM chrislusf/seaweedfs:${VERSION} diff --git a/packages/system/seaweedfs/patches/long-term-ca.diff b/packages/system/seaweedfs/patches/long-term-ca.diff deleted file mode 100644 index a53d697d..00000000 --- a/packages/system/seaweedfs/patches/long-term-ca.diff +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml -index 0fd6615e..f2572558 100644 ---- a/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml -+++ b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml -@@ -13,6 +13,8 @@ spec: - secretName: {{ template "seaweedfs.name" . }}-ca-cert - commonName: "{{ template "seaweedfs.name" . }}-root-ca" - isCA: true -+ duration: 87600h -+ renewBefore: 720h - issuerRef: - name: {{ template "seaweedfs.name" . }}-issuer - kind: Issuer From 1beb11a6a937523945cb69e8c71b24646c27c9dd Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 18 Dec 2025 17:06:00 +0100 Subject: [PATCH 13/78] Add Cloupard to ADOPTERS.md (#1733) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does This PR adds Cloupard as new adopter to the list. ### Release note ```release-note Add Cloupard to ADOPTERS.md ``` ## Summary by CodeRabbit * **Documentation** * Updated the list of project adopters with recent entries. ✏️ Tip: You can customize this high-level summary in your review settings. --- ADOPTERS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ADOPTERS.md b/ADOPTERS.md index 542e984b..d6cacdc5 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -32,4 +32,4 @@ This list is sorted in chronological order, based on the submission date. | [Urmanac](https://urmanac.com) | @kingdonb | 2024-12-04 | Urmanac is the future home of a hosting platform for the knowledge base of a community of personal server enthusiasts. We use Cozystack to provide support services for web sites hosted using both conventional deployments and on SpinKube, with WASM. | | [Hidora](https://hikube.cloud) | @matthieu-robin | 2025-09-17 | Hidora is a Swiss cloud provider delivering managed services and infrastructure solutions through datacenters located in Switzerland, ensuring data sovereignty and reliability. Its sovereign cloud platform, Hikube, is designed to run workloads with high availability across multiple datacenters, providing enterprises with a secure and scalable foundation for their applications based on Cozystack. | | [QOSI](https://qosi.kz) | @tabu-a | 2025-10-04 | QOSI is a non-profit organization driving open-source adoption and digital sovereignty across Kazakhstan and Central Asia. We use Cozystack as a platform for deploying sovereign, GPU-enabled clouds and educational environments under the National AI Program. Our goal is to accelerate the region’s transition toward open, self-hosted cloud-native technologies | -| \ No newline at end of file +| [Cloupard](https://cloupard.kz/) | @serjiott | 2025-12-18 | Cloupard is a public cloud provider offering IaaS and PaaS services via datacenters in Kazakhstan and Uzbekistan. Uses CozyStack on bare metal to extend its managed PaaS offerings. | From f9bfcfd125c92bab3c0f4d828d6b16748e540c3d Mon Sep 17 00:00:00 2001 From: Nikita <166552198+nbykov0@users.noreply.github.com> Date: Tue, 23 Dec 2025 15:39:19 +0300 Subject: [PATCH 14/78] [virtual-machine,vm-instance] Add nodeAffinity for Windows VMs based on scheduling config (#1693) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds nodeAffinity configuration to virtual-machine and vm-instance charts to support dedicated nodes for Windows VMs. ## Changes - Added logic to check `cozystack-scheduling` ConfigMap in `cozy-system` namespace - If `dedicatedNodesForWindowsVMs` is enabled, adds appropriate nodeAffinity: - **Windows VMs**: Strong affinity (required) to nodes with label `scheduling.cozystack.io/vm-windows=true` - **Non-Windows VMs**: Soft affinity (preferred) to nodes without the Windows label ## Implementation - Windows detection based on `instanceProfile` value starting with "windows" - Strong affinity uses `requiredDuringSchedulingIgnoredDuringExecution` - Soft affinity uses `preferredDuringSchedulingIgnoredDuringExecution` with weight 100 ## Summary by CodeRabbit * **New Features** * Added configurable node-affinity for VM scheduling: when the cluster scheduling flag is enabled, Windows VMs are placed on dedicated Windows nodes (required rule), while non-Windows VMs are preferred to avoid those nodes (soft preference). * Change is gated by the cluster scheduling configuration and only affects placement rules; no other VM specs were altered. ✏️ Tip: You can customize this high-level summary in your review settings. --- .../virtual-machine/templates/_helpers.tpl | 33 +++++++++++++++++++ .../apps/virtual-machine/templates/vm.yaml | 2 ++ .../apps/vm-instance/templates/_helpers.tpl | 33 +++++++++++++++++++ packages/apps/vm-instance/templates/vm.yaml | 3 ++ 4 files changed, 71 insertions(+) diff --git a/packages/apps/virtual-machine/templates/_helpers.tpl b/packages/apps/virtual-machine/templates/_helpers.tpl index f3ade695..7b6929ac 100644 --- a/packages/apps/virtual-machine/templates/_helpers.tpl +++ b/packages/apps/virtual-machine/templates/_helpers.tpl @@ -69,3 +69,36 @@ Generate a stable UUID for cloud-init re-initialization upon upgrade. {{- end }} {{- $uuid }} {{- end }} + +{{/* +Node Affinity for Windows VMs +*/}} +{{- define "virtual-machine.nodeAffinity" -}} +{{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" -}} +{{- if $configMap -}} +{{- $dedicatedNodesForWindowsVMs := get $configMap.data "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/virtual-machine/templates/vm.yaml b/packages/apps/virtual-machine/templates/vm.yaml index 92084acb..efadf3af 100644 --- a/packages/apps/virtual-machine/templates/vm.yaml +++ b/packages/apps/virtual-machine/templates/vm.yaml @@ -124,6 +124,8 @@ spec: terminationGracePeriodSeconds: 30 + {{- include "virtual-machine.nodeAffinity" . | nindent 6 }} + volumes: - name: systemdisk dataVolume: diff --git a/packages/apps/vm-instance/templates/_helpers.tpl b/packages/apps/vm-instance/templates/_helpers.tpl index f3ade695..7b6929ac 100644 --- a/packages/apps/vm-instance/templates/_helpers.tpl +++ b/packages/apps/vm-instance/templates/_helpers.tpl @@ -69,3 +69,36 @@ Generate a stable UUID for cloud-init re-initialization upon upgrade. {{- end }} {{- $uuid }} {{- end }} + +{{/* +Node Affinity for Windows VMs +*/}} +{{- define "virtual-machine.nodeAffinity" -}} +{{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" -}} +{{- if $configMap -}} +{{- $dedicatedNodesForWindowsVMs := get $configMap.data "dedicatedNodesForWindowsVMs" -}} +{{- if eq $dedicatedNodesForWindowsVMs "true" -}} +{{- $isWindows := hasPrefix "windows" (toString .Values.instanceProfile) -}} +affinity: + nodeAffinity: + {{- if $isWindows }} + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: scheduling.cozystack.io/vm-windows + operator: In + values: + - "true" + {{- else }} + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + preference: + matchExpressions: + - key: scheduling.cozystack.io/vm-windows + operator: NotIn + values: + - "true" + {{- end }} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/packages/apps/vm-instance/templates/vm.yaml b/packages/apps/vm-instance/templates/vm.yaml index 61fc65a7..acad3475 100644 --- a/packages/apps/vm-instance/templates/vm.yaml +++ b/packages/apps/vm-instance/templates/vm.yaml @@ -95,6 +95,9 @@ spec: noCloud: {} {{- end }} terminationGracePeriodSeconds: 30 + + {{- include "virtual-machine.nodeAffinity" . | nindent 6 }} + volumes: {{- range .Values.disks }} - name: disk-{{ .name }} From 67109c33b1e51b3f7ba353b6ebe237601133d8a7 Mon Sep 17 00:00:00 2001 From: Nikita <166552198+nbykov0@users.noreply.github.com> Date: Tue, 23 Dec 2025 15:41:12 +0300 Subject: [PATCH 15/78] [cilium] Enable automatic pod rollout on configmap updates (#1728) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable automatic restart of cilium and cilium-operator pods when cilium-config ConfigMap is updated. This change adds: - `rollOutCiliumPods: true` - enables automatic rollout of cilium-agent pods - `operator.rollOutPods: true` - enables automatic rollout of cilium-operator pods When the ConfigMap is updated, pods will automatically restart due to the `cilium.io/cilium-configmap-checksum` annotation that contains the SHA256 hash of the configmap. ## Summary by CodeRabbit * **Chores** * Updated Cilium configuration settings to enable pod rollout behavior for Cilium and operator pods by default. ✏️ Tip: You can customize this high-level summary in your review settings. --- packages/system/cilium/values.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/system/cilium/values.yaml b/packages/system/cilium/values.yaml index 72263556..abadcc36 100644 --- a/packages/system/cilium/values.yaml +++ b/packages/system/cilium/values.yaml @@ -18,3 +18,6 @@ cilium: digest: "sha256:81262986a41487bfa3d0465091d3a386def5bd1ab476350bd4af2fdee5846fe6" envoy: enabled: false + rollOutCiliumPods: true + operator: + rollOutPods: true From 66cfbe7c0e95a148e99f69a90a5af8abe3afe33d Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Tue, 23 Dec 2025 17:04:05 +0400 Subject: [PATCH 16/78] Add changelogs for v0.38.3 and v.0.38.4 (#1743) --- docs/changelogs/v0.38.3.md | 14 ++++++++++++++ docs/changelogs/v0.38.4.md | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 docs/changelogs/v0.38.3.md create mode 100644 docs/changelogs/v0.38.4.md diff --git a/docs/changelogs/v0.38.3.md b/docs/changelogs/v0.38.3.md new file mode 100644 index 00000000..5aa44d30 --- /dev/null +++ b/docs/changelogs/v0.38.3.md @@ -0,0 +1,14 @@ + + +## Improvements + +* **[core:installer] Address buildx warnings for installer image builds**: Aligns Dockerfile syntax casing to remove buildx warnings, keeping installer builds clean ([**@nbykov0**](https://github.com/nbykov0) in #1682). +* **[system:coredns] Align CoreDNS app labels with Talos defaults**: Matches CoreDNS labels to Talos conventions so services select pods consistently across platform and tenant clusters ([**@nbykov0**](https://github.com/nbykov0) in #1675). +* **[system:monitoring-agents] Rename CoreDNS metrics service to avoid conflicts**: Renames the metrics service so it no longer clashes with the CoreDNS service used for name resolution in tenant clusters ([**@nbykov0**](https://github.com/nbykov0) in #1676). + +--- + +**Full Changelog**: [v0.38.2...v0.38.3](https://github.com/cozystack/cozystack/compare/v0.38.2...v0.38.3) + diff --git a/docs/changelogs/v0.38.4.md b/docs/changelogs/v0.38.4.md new file mode 100644 index 00000000..94ea46fe --- /dev/null +++ b/docs/changelogs/v0.38.4.md @@ -0,0 +1,18 @@ + + +## Fixes + +* **[linstor] Update piraeus-operator v2.10.2 to handle fsck checks reliably**: Upgrades LINSTOR CSI to avoid failed mounts when fsck sees mounted volumes, improving volume publish reliability ([**@kvaps**](https://github.com/kvaps) in #1689, #1697). +* **[dashboard] Nest CustomFormsOverride properties under spec.properties**: Fixes schema generation so custom form properties are placed under `spec.properties`, preventing mis-rendered or missing form fields ([**@kvaps**](https://github.com/kvaps) in #1692, #1700). +* **[virtual-machine] Guard PVC resize to only expand storage**: Ensures resize jobs run only when storage size increases, avoiding unintended shrink attempts during VM updates ([**@kvaps**](https://github.com/kvaps) in #1688, #1701). + +## Documentation + +* **[website] Clarify GPU check command**: Makes the kubectl command for validating GPU binding more explicit, including namespace context ([**@nbykov0**](https://github.com/nbykov0) in cozystack/website#379). + +--- + +**Full Changelog**: [v0.38.3...v0.38.4](https://github.com/cozystack/cozystack/compare/v0.38.3...v0.38.4) + From 682f83e71c874920502b143241a8c41fd8f3d4e8 Mon Sep 17 00:00:00 2001 From: Nikita <166552198+nbykov0@users.noreply.github.com> Date: Tue, 23 Dec 2025 17:11:22 +0300 Subject: [PATCH 17/78] [system/cilium] Enable topology-aware routing for services (#1734) --- packages/system/cilium/values.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/system/cilium/values.yaml b/packages/system/cilium/values.yaml index abadcc36..95159b1f 100644 --- a/packages/system/cilium/values.yaml +++ b/packages/system/cilium/values.yaml @@ -10,6 +10,7 @@ cilium: enabled: true loadBalancer: algorithm: maglev + serviceTopology: true ipam: mode: "kubernetes" image: From a939b2bbd0a3a39a078eba3426064728ca0233bb Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 24 Dec 2025 14:09:38 +0100 Subject: [PATCH 18/78] [registry] Add application labels and update filtering mechanism (#1707) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change is extracted from - https://github.com/cozystack/cozystack/pull/1641 and reworked to work standalone ## What this PR does This PR extracts changes from the https://github.com/cozystack/cozystack/pull/1641. It adds application metadata labels to HelmReleases and updates the filtering mechanism to use labels instead of chart/sourceRef matching. Changes: - Add three application metadata labels (`apps.cozystack.io/application.kind`, `apps.cozystack.io/application.group`, `apps.cozystack.io/application.name`) when creating/updating HelmRelease via Cozystack-API - Replace `shouldIncludeHelmRelease` filtering with label-based filtering in Get, List, and Update methods - Always add kind and group label requirements in List for precise filtering - Update CozystackResourceDefinitionController to watch only HelmReleases with `cozystack.io/ui=true` label - Update LineageControllerWebhook to extract metadata directly from HelmRelease labels instead of using chart mapping configuration - Add functionality to update HelmRelease chart from CozystackResourceDefinition using label selectors ### Release note ```release-note [registry] Add application labels and update filtering mechanism to use label-based filtering instead of chart/sourceRef matching ``` ## Summary by CodeRabbit * **New Features** * Added application metadata labels (kind, group, name) and exported label keys for HelmRelease identification. * New reconciler keeps HelmRelease charts in sync with application CRDs. * **Refactor** * Mapping, listing and selection moved to label-driven logic; reconciliation responsibilities split so core reconciler focuses on restart/debounce while a separate reconciler updates HelmReleases. * **Chores** * Migration script to backfill application labels on existing HelmReleases. ✏️ Tip: You can customize this high-level summary in your review settings. --- cmd/cozystack-controller/main.go | 8 + .../cozystackresource_controller.go | 2 + ...ystackresourcedefinition_helmreconciler.go | 166 +++++++++++++++ internal/lineagecontrollerwebhook/config.go | 65 ++++-- .../lineagecontrollerwebhook/controller.go | 12 +- packages/apps/tenant/templates/etcd.yaml | 3 + packages/apps/tenant/templates/info.yaml | 3 + packages/apps/tenant/templates/ingress.yaml | 3 + .../apps/tenant/templates/monitoring.yaml | 3 + packages/apps/tenant/templates/seaweedfs.yaml | 3 + packages/core/platform/templates/apps.yaml | 3 + .../system/bootbox/templates/bootbox.yaml | 3 + pkg/apis/apps/v1alpha1/types.go | 7 + pkg/registry/apps/application/rest.go | 201 ++++++++---------- scripts/migrations/22 | 163 ++++++++++++++ 15 files changed, 498 insertions(+), 147 deletions(-) create mode 100644 internal/controller/cozystackresourcedefinition_helmreconciler.go create mode 100755 scripts/migrations/22 diff --git a/cmd/cozystack-controller/main.go b/cmd/cozystack-controller/main.go index fc18a778..91889224 100644 --- a/cmd/cozystack-controller/main.go +++ b/cmd/cozystack-controller/main.go @@ -229,6 +229,14 @@ func main() { os.Exit(1) } + if err = (&controller.CozystackResourceDefinitionHelmReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "CozystackResourceDefinitionHelmReconciler") + os.Exit(1) + } + dashboardManager := &dashboard.Manager{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), diff --git a/internal/controller/cozystackresource_controller.go b/internal/controller/cozystackresource_controller.go index 46884418..5492a4a8 100644 --- a/internal/controller/cozystackresource_controller.go +++ b/internal/controller/cozystackresource_controller.go @@ -37,6 +37,8 @@ type CozystackResourceDefinitionReconciler struct { } func (r *CozystackResourceDefinitionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + // Only handle debounced restart logic + // HelmRelease reconciliation is handled by CozystackResourceDefinitionHelmReconciler return r.debouncedRestart(ctx) } diff --git a/internal/controller/cozystackresourcedefinition_helmreconciler.go b/internal/controller/cozystackresourcedefinition_helmreconciler.go new file mode 100644 index 00000000..c086b56f --- /dev/null +++ b/internal/controller/cozystackresourcedefinition_helmreconciler.go @@ -0,0 +1,166 @@ +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 +} + +// updateHelmReleaseChart updates the chart 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 + } + } + + 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/lineagecontrollerwebhook/config.go b/internal/lineagecontrollerwebhook/config.go index 4ca45c13..7204ab66 100644 --- a/internal/lineagecontrollerwebhook/config.go +++ b/internal/lineagecontrollerwebhook/config.go @@ -2,49 +2,72 @@ package lineagecontrollerwebhook import ( "fmt" + "strings" cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" helmv2 "github.com/fluxcd/helm-controller/api/v2" ) -type chartRef struct { - repo string - chart string -} - type appRef struct { group string kind string } type runtimeConfig struct { - chartAppMap map[chartRef]*cozyv1alpha1.CozystackResourceDefinition - appCRDMap map[appRef]*cozyv1alpha1.CozystackResourceDefinition + appCRDMap map[appRef]*cozyv1alpha1.CozystackResourceDefinition } func (l *LineageControllerWebhook) initConfig() { l.initOnce.Do(func() { if l.config.Load() == nil { l.config.Store(&runtimeConfig{ - chartAppMap: make(map[chartRef]*cozyv1alpha1.CozystackResourceDefinition), - appCRDMap: make(map[appRef]*cozyv1alpha1.CozystackResourceDefinition), + appCRDMap: make(map[appRef]*cozyv1alpha1.CozystackResourceDefinition), }) } }) } -func (l *LineageControllerWebhook) Map(hr *helmv2.HelmRelease) (string, string, string, error) { - cfg, ok := l.config.Load().(*runtimeConfig) +// getApplicationLabel safely extracts an application label from HelmRelease +func getApplicationLabel(hr *helmv2.HelmRelease, key string) (string, error) { + if hr.Labels == nil { + return "", fmt.Errorf("cannot map helm release %s/%s to dynamic app: labels are nil", hr.Namespace, hr.Name) + } + val, ok := hr.Labels[key] if !ok { - return "", "", "", fmt.Errorf("failed to load chart-app mapping from config") + return "", fmt.Errorf("cannot map helm release %s/%s to dynamic app: missing %s label", hr.Namespace, hr.Name, key) } - if hr.Spec.Chart == nil { - return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app", hr.Namespace, hr.Name) - } - s := hr.Spec.Chart.Spec - val, ok := cfg.chartAppMap[chartRef{s.SourceRef.Name, s.Chart}] - if !ok { - return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app", hr.Namespace, hr.Name) - } - return "apps.cozystack.io/v1alpha1", val.Spec.Application.Kind, val.Spec.Release.Prefix, nil + return val, nil +} + +func (l *LineageControllerWebhook) Map(hr *helmv2.HelmRelease) (string, string, string, error) { + // Extract application metadata from labels + appKind, err := getApplicationLabel(hr, "apps.cozystack.io/application.kind") + if err != nil { + return "", "", "", err + } + + appGroup, err := getApplicationLabel(hr, "apps.cozystack.io/application.group") + if err != nil { + return "", "", "", err + } + + appName, err := getApplicationLabel(hr, "apps.cozystack.io/application.name") + if err != nil { + return "", "", "", err + } + + // Construct API version from group + apiVersion := fmt.Sprintf("%s/v1alpha1", appGroup) + + // Extract prefix from HelmRelease name by removing the application name + // HelmRelease name format: + prefix := strings.TrimSuffix(hr.Name, appName) + + // Validate the derived prefix + // This ensures correctness when appName appears multiple times in hr.Name + if prefix+appName != hr.Name { + return "", "", "", fmt.Errorf("cannot derive prefix from helm release %s/%s: name does not end with application name %s", hr.Namespace, hr.Name, appName) + } + + return apiVersion, appKind, prefix, nil } diff --git a/internal/lineagecontrollerwebhook/controller.go b/internal/lineagecontrollerwebhook/controller.go index e7522f62..092d16e7 100644 --- a/internal/lineagecontrollerwebhook/controller.go +++ b/internal/lineagecontrollerwebhook/controller.go @@ -24,25 +24,15 @@ func (c *LineageControllerWebhook) Reconcile(ctx context.Context, req ctrl.Reque return ctrl.Result{}, err } cfg := &runtimeConfig{ - chartAppMap: make(map[chartRef]*cozyv1alpha1.CozystackResourceDefinition), - appCRDMap: make(map[appRef]*cozyv1alpha1.CozystackResourceDefinition), + appCRDMap: make(map[appRef]*cozyv1alpha1.CozystackResourceDefinition), } for _, crd := range crds.Items { - chRef := chartRef{ - crd.Spec.Release.Chart.SourceRef.Name, - crd.Spec.Release.Chart.Name, - } appRef := appRef{ "apps.cozystack.io", crd.Spec.Application.Kind, } newRef := crd - if _, exists := cfg.chartAppMap[chRef]; exists { - l.Info("duplicate chart mapping detected; ignoring subsequent entry", "key", chRef) - } else { - cfg.chartAppMap[chRef] = &newRef - } if _, exists := cfg.appCRDMap[appRef]; exists { l.Info("duplicate app mapping detected; ignoring subsequent entry", "key", appRef) } else { diff --git a/packages/apps/tenant/templates/etcd.yaml b/packages/apps/tenant/templates/etcd.yaml index 9db6ff6c..8cd720cc 100644 --- a/packages/apps/tenant/templates/etcd.yaml +++ b/packages/apps/tenant/templates/etcd.yaml @@ -9,6 +9,9 @@ metadata: internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} + apps.cozystack.io/application.kind: Etcd + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.name: etcd spec: chart: spec: diff --git a/packages/apps/tenant/templates/info.yaml b/packages/apps/tenant/templates/info.yaml index 4b6f2640..4a66e422 100644 --- a/packages/apps/tenant/templates/info.yaml +++ b/packages/apps/tenant/templates/info.yaml @@ -8,6 +8,9 @@ metadata: internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} + apps.cozystack.io/application.kind: Info + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.name: info spec: chart: spec: diff --git a/packages/apps/tenant/templates/ingress.yaml b/packages/apps/tenant/templates/ingress.yaml index b866300f..beb07342 100644 --- a/packages/apps/tenant/templates/ingress.yaml +++ b/packages/apps/tenant/templates/ingress.yaml @@ -9,6 +9,9 @@ metadata: internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} + apps.cozystack.io/application.kind: Ingress + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.name: ingress spec: chart: spec: diff --git a/packages/apps/tenant/templates/monitoring.yaml b/packages/apps/tenant/templates/monitoring.yaml index edcc66d9..4986fc21 100644 --- a/packages/apps/tenant/templates/monitoring.yaml +++ b/packages/apps/tenant/templates/monitoring.yaml @@ -9,6 +9,9 @@ metadata: internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} + apps.cozystack.io/application.kind: Monitoring + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.name: monitoring spec: chart: spec: diff --git a/packages/apps/tenant/templates/seaweedfs.yaml b/packages/apps/tenant/templates/seaweedfs.yaml index 936e294b..9a714b79 100644 --- a/packages/apps/tenant/templates/seaweedfs.yaml +++ b/packages/apps/tenant/templates/seaweedfs.yaml @@ -9,6 +9,9 @@ metadata: internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} + apps.cozystack.io/application.kind: SeaweedFS + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.name: seaweedfs spec: chart: spec: diff --git a/packages/core/platform/templates/apps.yaml b/packages/core/platform/templates/apps.yaml index c7653e03..514dcffb 100644 --- a/packages/core/platform/templates/apps.yaml +++ b/packages/core/platform/templates/apps.yaml @@ -36,6 +36,9 @@ metadata: 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 diff --git a/packages/system/bootbox/templates/bootbox.yaml b/packages/system/bootbox/templates/bootbox.yaml index 496e42e5..45cd07ce 100644 --- a/packages/system/bootbox/templates/bootbox.yaml +++ b/packages/system/bootbox/templates/bootbox.yaml @@ -5,6 +5,9 @@ metadata: helm.sh/resource-policy: keep labels: 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: diff --git a/pkg/apis/apps/v1alpha1/types.go b/pkg/apis/apps/v1alpha1/types.go index 8e756779..0118b0de 100644 --- a/pkg/apis/apps/v1alpha1/types.go +++ b/pkg/apis/apps/v1alpha1/types.go @@ -21,6 +21,13 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +// Application label keys used to identify and filter HelmReleases +const ( + ApplicationKindLabel = "apps.cozystack.io/application.kind" + ApplicationGroupLabel = "apps.cozystack.io/application.group" + ApplicationNameLabel = "apps.cozystack.io/application.name" +) + // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // ApplicationList is a list of Application objects. diff --git a/pkg/registry/apps/application/rest.go b/pkg/registry/apps/application/rest.go index 704cd709..78ff8dbc 100644 --- a/pkg/registry/apps/application/rest.go +++ b/pkg/registry/apps/application/rest.go @@ -32,6 +32,7 @@ import ( labels "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/selection" "k8s.io/apimachinery/pkg/util/duration" "k8s.io/apimachinery/pkg/watch" "k8s.io/apiserver/pkg/endpoints/request" @@ -66,6 +67,13 @@ const ( AnnotationPrefix = "apps.cozystack.io-" ) +// Application label keys - use constants from API package +const ( + ApplicationKindLabel = appsv1alpha1.ApplicationKindLabel + ApplicationGroupLabel = appsv1alpha1.ApplicationGroupLabel + ApplicationNameLabel = appsv1alpha1.ApplicationNameLabel +) + // Define the GroupVersionResource for HelmRelease var helmReleaseGVR = schema.GroupVersionResource{ Group: "helm.toolkit.fluxcd.io", @@ -157,6 +165,13 @@ func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation helmRelease.Labels = mergeMaps(r.releaseConfig.Labels, helmRelease.Labels) // Merge user labels with prefix helmRelease.Labels = mergeMaps(helmRelease.Labels, addPrefixedMap(app.Labels, LabelPrefix)) + // Add application metadata labels + if helmRelease.Labels == nil { + helmRelease.Labels = make(map[string]string) + } + helmRelease.Labels[ApplicationKindLabel] = r.kindName + helmRelease.Labels[ApplicationGroupLabel] = r.gvk.Group + helmRelease.Labels[ApplicationNameLabel] = app.Name // Note: Annotations from config are not handled as r.releaseConfig.Annotations is undefined klog.V(6).Infof("Creating HelmRelease %s in namespace %s", helmRelease.Name, app.Namespace) @@ -208,9 +223,9 @@ func (r *REST) Get(ctx context.Context, name string, options *metav1.GetOptions) return nil, err } - // Check if HelmRelease meets the required chartName and sourceRef criteria - if !r.shouldIncludeHelmRelease(helmRelease) { - klog.Errorf("HelmRelease %s does not match the required chartName and sourceRef criteria", helmReleaseName) + // Check if HelmRelease has required labels + if !r.hasRequiredApplicationLabels(helmRelease) { + klog.Errorf("HelmRelease %s does not match the required application labels", helmReleaseName) // Return a NotFound error for the Application resource return nil, apierrors.NewNotFound(r.gvr.GroupResource(), name) } @@ -266,6 +281,19 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption } // Process label.selector + // Always add application metadata label requirements + appKindReq, err := labels.NewRequirement(ApplicationKindLabel, selection.Equals, []string{r.kindName}) + if err != nil { + klog.Errorf("Error creating application kind label requirement: %v", err) + return nil, fmt.Errorf("error creating application kind label requirement: %v", err) + } + appGroupReq, err := labels.NewRequirement(ApplicationGroupLabel, selection.Equals, []string{r.gvk.Group}) + if err != nil { + klog.Errorf("Error creating application group label requirement: %v", err) + return nil, fmt.Errorf("error creating application group label requirement: %v", err) + } + labelRequirements := []labels.Requirement{*appKindReq, *appGroupReq} + if options.LabelSelector != nil { ls := options.LabelSelector.String() parsedLabels, err := labels.Parse(ls) @@ -285,9 +313,12 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption } prefixedReqs = append(prefixedReqs, *prefixedReq) } - helmLabelSelector = labels.NewSelector().Add(prefixedReqs...).String() + labelRequirements = append(labelRequirements, prefixedReqs...) } } + helmLabelSelector = labels.NewSelector().Add(labelRequirements...).String() + + klog.V(6).Infof("Using label selector: %s for kind: %s, group: %s", helmLabelSelector, r.kindName, r.gvk.Group) // Set ListOptions for HelmRelease with selector mapping metaOptions := metav1.ListOptions{ @@ -306,18 +337,19 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption return nil, err } + klog.V(6).Infof("Found %d HelmReleases with label selector", len(hrList.Items)) + // Initialize Application items array items := make([]appsv1alpha1.Application, 0, len(hrList.Items)) // Iterate over HelmReleases and convert to Applications + // Note: All HelmReleases already match the required labels due to server-side label selector filtering for i := range hrList.Items { - if !r.shouldIncludeHelmRelease(&hrList.Items[i]) { - continue - } + hr := &hrList.Items[i] - app, err := r.ConvertHelmReleaseToApplication(&hrList.Items[i]) + app, err := r.ConvertHelmReleaseToApplication(hr) if err != nil { - klog.Errorf("Error converting HelmRelease %s to Application: %v", hrList.Items[i].GetName(), err) + klog.Errorf("Error converting HelmRelease %s to Application: %v", hr.GetName(), err) continue } @@ -436,18 +468,17 @@ func (r *REST) Update(ctx context.Context, name string, objInfo rest.UpdatedObje helmRelease.Labels = mergeMaps(r.releaseConfig.Labels, helmRelease.Labels) // Merge user labels with prefix helmRelease.Labels = mergeMaps(helmRelease.Labels, addPrefixedMap(app.Labels, LabelPrefix)) + // Add application metadata labels + if helmRelease.Labels == nil { + helmRelease.Labels = make(map[string]string) + } + helmRelease.Labels[ApplicationKindLabel] = r.kindName + helmRelease.Labels[ApplicationGroupLabel] = r.gvk.Group + helmRelease.Labels[ApplicationNameLabel] = app.Name // Note: Annotations from config are not handled as r.releaseConfig.Annotations is undefined klog.V(6).Infof("Updating HelmRelease %s in namespace %s", helmRelease.Name, helmRelease.Namespace) - // Before updating, ensure the HelmRelease meets the inclusion criteria - // This prevents updating HelmReleases that should not be managed as Applications - if !r.shouldIncludeHelmRelease(helmRelease) { - klog.Errorf("HelmRelease %s does not match the required chartName and sourceRef criteria", helmRelease.Name) - // Return a NotFound error for the Application resource - return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) - } - // Update the HelmRelease in Kubernetes err = r.c.Update(ctx, helmRelease, &client.UpdateOptions{Raw: &metav1.UpdateOptions{}}) if err != nil { @@ -455,13 +486,6 @@ func (r *REST) Update(ctx context.Context, name string, objInfo rest.UpdatedObje return nil, false, fmt.Errorf("failed to update HelmRelease: %v", err) } - // After updating, ensure the updated HelmRelease still meets the inclusion criteria - if !r.shouldIncludeHelmRelease(helmRelease) { - klog.Errorf("Updated HelmRelease %s does not match the required chartName and sourceRef criteria", helmRelease.GetName()) - // Return a NotFound error for the Application resource - return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) - } - // Convert the updated HelmRelease back to Application convertedApp, err := r.ConvertHelmReleaseToApplication(helmRelease) if err != nil { @@ -503,9 +527,9 @@ func (r *REST) Delete(ctx context.Context, name string, deleteValidation rest.Va return nil, false, err } - // Validate that the HelmRelease meets the inclusion criteria - if !r.shouldIncludeHelmRelease(helmRelease) { - klog.Errorf("HelmRelease %s does not match the required chartName and sourceRef criteria", helmReleaseName) + // Validate that the HelmRelease has required labels + if !r.hasRequiredApplicationLabelsWithName(helmRelease, name) { + klog.Errorf("HelmRelease %s does not match the required application labels", helmReleaseName) // Return NotFound error for Application resource return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) } @@ -523,7 +547,7 @@ func (r *REST) Delete(ctx context.Context, name string, deleteValidation rest.Va return nil, true, nil } -// Watch sets up a watch on HelmReleases, filters them based on sourceRef and prefix, and converts events to Applications +// Watch sets up a watch on HelmReleases, filters them based on application labels, and converts events to Applications func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptions) (watch.Interface, error) { namespace, err := r.getNamespace(ctx) if err != nil { @@ -564,6 +588,19 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio } // Process label.selector + // Always add application metadata label requirements + appKindReq, err := labels.NewRequirement(ApplicationKindLabel, selection.Equals, []string{r.kindName}) + if err != nil { + klog.Errorf("Error creating application kind label requirement: %v", err) + return nil, fmt.Errorf("error creating application kind label requirement: %v", err) + } + appGroupReq, err := labels.NewRequirement(ApplicationGroupLabel, selection.Equals, []string{r.gvk.Group}) + if err != nil { + klog.Errorf("Error creating application group label requirement: %v", err) + return nil, fmt.Errorf("error creating application group label requirement: %v", err) + } + labelRequirements := []labels.Requirement{*appKindReq, *appGroupReq} + if options.LabelSelector != nil { ls := options.LabelSelector.String() parsedLabels, err := labels.Parse(ls) @@ -583,9 +620,10 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio } prefixedReqs = append(prefixedReqs, *prefixedReq) } - helmLabelSelector = labels.NewSelector().Add(prefixedReqs...).String() + labelRequirements = append(labelRequirements, prefixedReqs...) } } + helmLabelSelector = labels.NewSelector().Add(labelRequirements...).String() // Set ListOptions for HelmRelease with selector mapping metaOptions := metav1.ListOptions{ @@ -639,10 +677,7 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio continue } - if !r.shouldIncludeHelmRelease(hr) { - continue - } - + // Note: All HelmReleases already match the required labels due to server-side label selector filtering // Convert HelmRelease to Application app, err := r.ConvertHelmReleaseToApplication(hr) if err != nil { @@ -694,14 +729,6 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio return customW, nil } -// Helper function to get HelmRelease name from object -func helmReleaseName(obj runtime.Object) string { - if app, ok := obj.(*appsv1alpha1.Application); ok { - return app.GetName() - } - return "" -} - // customWatcher wraps the original watcher and filters/converts events type customWatcher struct { resultChan chan watch.Event @@ -725,74 +752,6 @@ func (cw *customWatcher) ResultChan() <-chan watch.Event { return cw.resultChan } -// shouldIncludeHelmRelease determines if a HelmRelease should be included based on filtering criteria -func (r *REST) shouldIncludeHelmRelease(hr *helmv2.HelmRelease) bool { - // Nil check for Chart field - if hr.Spec.Chart == nil { - klog.V(6).Infof("HelmRelease %s has nil spec.chart field", hr.GetName()) - return false - } - - // Filter by Chart Name - chartName := hr.Spec.Chart.Spec.Chart - if chartName == "" { - klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.chart field", hr.GetName()) - return false - } - if chartName != r.releaseConfig.Chart.Name { - klog.V(6).Infof("HelmRelease %s chart name %s does not match expected %s", hr.GetName(), chartName, r.releaseConfig.Chart.Name) - return false - } - - // Filter by SourceRefConfig and Prefix - return r.matchesSourceRefAndPrefix(hr) -} - -// matchesSourceRefAndPrefix checks both SourceRefConfig and Prefix criteria -func (r *REST) matchesSourceRefAndPrefix(hr *helmv2.HelmRelease) bool { - // Nil check for Chart field (defensive) - if hr.Spec.Chart == nil { - klog.V(6).Infof("HelmRelease %s has nil spec.chart field", hr.GetName()) - return false - } - - // Extract SourceRef fields - sourceRef := hr.Spec.Chart.Spec.SourceRef - sourceRefKind := sourceRef.Kind - sourceRefName := sourceRef.Name - sourceRefNamespace := sourceRef.Namespace - - if sourceRefKind == "" { - klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.sourceRef.kind field", hr.GetName()) - return false - } - if sourceRefName == "" { - klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.sourceRef.name field", hr.GetName()) - return false - } - if sourceRefNamespace == "" { - klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.sourceRef.namespace field", hr.GetName()) - return false - } - - // Check if SourceRef matches the configuration - if sourceRefKind != r.releaseConfig.Chart.SourceRef.Kind || - sourceRefName != r.releaseConfig.Chart.SourceRef.Name || - sourceRefNamespace != r.releaseConfig.Chart.SourceRef.Namespace { - klog.V(6).Infof("HelmRelease %s sourceRef does not match expected values", hr.GetName()) - return false - } - - // Additional filtering by Prefix - name := hr.GetName() - if !strings.HasPrefix(name, r.releaseConfig.Prefix) { - klog.V(6).Infof("HelmRelease %s does not have the expected prefix %s", name, r.releaseConfig.Prefix) - return false - } - - return true -} - // getNamespace extracts the namespace from the context func (r *REST) getNamespace(ctx context.Context) (string, error) { namespace, ok := request.NamespaceFrom(ctx) @@ -804,13 +763,25 @@ func (r *REST) getNamespace(ctx context.Context) (string, error) { return namespace, nil } -// buildLabelSelector constructs a label selector string from a map of labels -func buildLabelSelector(labels map[string]string) string { - var selectors []string - for k, v := range labels { - selectors = append(selectors, fmt.Sprintf("%s=%s", k, v)) +// hasRequiredApplicationLabels checks if a HelmRelease has the required application labels +// matching the REST instance's kind and group +func (r *REST) hasRequiredApplicationLabels(hr *helmv2.HelmRelease) bool { + if hr.Labels == nil { + return false } - return strings.Join(selectors, ",") + return hr.Labels[ApplicationKindLabel] == r.kindName && + hr.Labels[ApplicationGroupLabel] == r.gvk.Group +} + +// hasRequiredApplicationLabelsWithName checks if a HelmRelease has the required application labels +// matching the REST instance's kind, group, and the specified application name +func (r *REST) hasRequiredApplicationLabelsWithName(hr *helmv2.HelmRelease, appName string) bool { + if hr.Labels == nil { + return false + } + return hr.Labels[ApplicationKindLabel] == r.kindName && + hr.Labels[ApplicationGroupLabel] == r.gvk.Group && + hr.Labels[ApplicationNameLabel] == appName } // mergeMaps combines two maps of labels or annotations diff --git a/scripts/migrations/22 b/scripts/migrations/22 new file mode 100755 index 00000000..192e431c --- /dev/null +++ b/scripts/migrations/22 @@ -0,0 +1,163 @@ +#!/bin/sh +# Migration 22 --> 23 + +set -euo pipefail + +echo "Migrating HelmReleases: adding application labels for tenant-* namespaces" + +# Function to determine application type from HelmRelease name +determine_app_type() { + local name="$1" + local app_kind="" + local app_name="" + + # Try to match by prefix (longest match first) + case "$name" in + virtual-machine-*) + app_kind="VirtualMachine" + app_name="${name#virtual-machine-}" + ;; + vm-instance-*) + app_kind="VMInstance" + app_name="${name#vm-instance-}" + ;; + vm-disk-*) + app_kind="VMDisk" + app_name="${name#vm-disk-}" + ;; + virtualprivatecloud-*) + app_kind="VirtualPrivateCloud" + app_name="${name#virtualprivatecloud-}" + ;; + http-cache-*) + app_kind="HTTPCache" + app_name="${name#http-cache-}" + ;; + tcp-balancer-*) + app_kind="TCPBalancer" + app_name="${name#tcp-balancer-}" + ;; + clickhouse-*) + app_kind="ClickHouse" + app_name="${name#clickhouse-}" + ;; + foundationdb-*) + app_kind="FoundationDB" + app_name="${name#foundationdb-}" + ;; + ferretdb-*) + app_kind="FerretDB" + app_name="${name#ferretdb-}" + ;; + rabbitmq-*) + app_kind="RabbitMQ" + app_name="${name#rabbitmq-}" + ;; + kubernetes-*) + app_kind="Kubernetes" + app_name="${name#kubernetes-}" + ;; + bucket-*) + app_kind="Bucket" + app_name="${name#bucket-}" + ;; + kafka-*) + app_kind="Kafka" + app_name="${name#kafka-}" + ;; + mysql-*) + app_kind="MySQL" + app_name="${name#mysql-}" + ;; + nats-*) + app_kind="NATS" + app_name="${name#nats-}" + ;; + postgres-*) + app_kind="PostgreSQL" + app_name="${name#postgres-}" + ;; + redis-*) + app_kind="Redis" + app_name="${name#redis-}" + ;; + tenant-*) + app_kind="Tenant" + app_name="${name#tenant-}" + ;; + vpn-*) + app_kind="VPN" + app_name="${name#vpn-}" + ;; + bootbox) + app_kind="BootBox" + app_name="bootbox" + ;; + etcd) + app_kind="Etcd" + app_name="etcd" + ;; + info) + app_kind="Info" + app_name="info" + ;; + ingress|ingress-*) + app_kind="Ingress" + if [ "$name" = "ingress" ]; then + app_name="ingress" + else + app_name="${name#ingress-}" + fi + ;; + monitoring) + app_kind="Monitoring" + app_name="monitoring" + ;; + seaweedfs) + app_kind="SeaweedFS" + app_name="seaweedfs" + ;; + *) + # Unknown type + return 1 + ;; + esac + + echo "$app_kind|$app_name" + return 0 +} + +# Process all HelmReleases in tenant-* namespaces with cozystack.io/ui=true label +kubectl get helmreleases --all-namespaces -l cozystack.io/ui=true -o json | \ + jq -r '.items[] | select(.metadata.namespace | startswith("tenant-")) | "\(.metadata.namespace)|\(.metadata.name)"' | \ + while IFS='|' read -r namespace name; do + echo "Processing HelmRelease $namespace/$name" + + # Determine application type + app_type=$(determine_app_type "$name") + status=$? + if [ $status -ne 0 ] || [ -z "$app_type" ]; then + echo "Warning: Could not determine application type for $namespace/$name, skipping" + continue + fi + + app_kind=$(echo "$app_type" | cut -d'|' -f1) + app_name=$(echo "$app_type" | cut -d'|' -f2) + app_group="apps.cozystack.io" + + # Build labels string + labels="apps.cozystack.io/application.kind=$app_kind" + labels="$labels apps.cozystack.io/application.group=$app_group" + labels="$labels apps.cozystack.io/application.name=$app_name" + + # Apply labels using kubectl label --overwrite + kubectl label helmrelease -n "$namespace" "$name" --overwrite $labels + echo "Added application labels to $namespace/$name: $labels" + done + +echo "Migration completed" + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=23 --dry-run=client -o yaml | kubectl apply -f- + From b3179d032aa98db70a8b302bad24aff09af9214c Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Wed, 24 Dec 2025 17:10:02 +0400 Subject: [PATCH 19/78] [vm] Always expose VMs with a service (#1738) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does When VMs are created without a public IP, no service is created for them and they have no in-cluster DNS name. This PR fixes this and resolves #1731. ### Release note ```release-note [vm] Always expose VMs with at least a ClusterIP service. ``` ## Summary by CodeRabbit * **Improvements** * Service templates now conditionally enable external-specific annotations and settings when external mode is enabled. * External LoadBalancer deployments support richer port configuration (including whole-IP fallback), while internal services retain a single default port (65535). * External traffic policy and node port allocation are applied only in external mode to preserve internal behavior. ✏️ Tip: You can customize this high-level summary in your review settings. --- packages/apps/virtual-machine/templates/service.yaml | 10 +++++++++- packages/apps/vm-instance/templates/service.yaml | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/apps/virtual-machine/templates/service.yaml b/packages/apps/virtual-machine/templates/service.yaml index f212db62..b12f7612 100644 --- a/packages/apps/virtual-machine/templates/service.yaml +++ b/packages/apps/virtual-machine/templates/service.yaml @@ -1,4 +1,3 @@ -{{- if .Values.external }} --- apiVersion: v1 kind: Service @@ -7,17 +6,24 @@ metadata: 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 }} @@ -27,4 +33,6 @@ spec: targetPort: {{ . }} {{- end }} {{- end }} +{{- else }} + - port: 65535 {{- end }} diff --git a/packages/apps/vm-instance/templates/service.yaml b/packages/apps/vm-instance/templates/service.yaml index f212db62..b12f7612 100644 --- a/packages/apps/vm-instance/templates/service.yaml +++ b/packages/apps/vm-instance/templates/service.yaml @@ -1,4 +1,3 @@ -{{- if .Values.external }} --- apiVersion: v1 kind: Service @@ -7,17 +6,24 @@ metadata: 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 }} @@ -27,4 +33,6 @@ spec: targetPort: {{ . }} {{- end }} {{- end }} +{{- else }} + - port: 65535 {{- end }} From 77de2bdda079e1455ba29a3b7eedc0b2582aed73 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 24 Dec 2025 14:10:37 +0100 Subject: [PATCH 20/78] Update go modules (#1736) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change is extracted from - https://github.com/cozystack/cozystack/pull/1641 and reworked to work standalone Signed-off-by: Andrei Kvapil ```release-note [cozystack] Update go modules ``` * **Chores** * Updated Go toolchain to 1.25.0 and upgraded core Kubernetes libraries, OpenTelemetry, Prometheus, gRPC/protobuf and many indirect dependencies. Bumped builder base images to golang:1.25-alpine across multiple components. * **Refactor** * Removed legacy component versioning/emulation and simplified server startup and configuration paths. * **Tests** * Removed tests related to the legacy versioning/emulation behavior. ✏️ Tip: You can customize this high-level summary in your review settings. --- go.mod | 147 ++++---- go.sum | 341 +++++++++--------- .../installer/images/cozystack/Dockerfile | 2 +- .../images/cozystack-assets/Dockerfile | 2 +- .../images/cozystack-api/Dockerfile | 2 +- .../images/cozystack-controller/Dockerfile | 2 +- .../images/kubeovn-plunger/Dockerfile | 2 +- .../lineage-controller-webhook/Dockerfile | 2 +- pkg/cmd/server/start.go | 81 +---- pkg/cmd/server/start_test.go | 52 +-- 10 files changed, 275 insertions(+), 358 deletions(-) diff --git a/go.mod b/go.mod index 30ec5f7f..f211d737 100644 --- a/go.mod +++ b/go.mod @@ -2,33 +2,37 @@ module github.com/cozystack/cozystack -go 1.23.0 +go 1.25.0 require ( - github.com/fluxcd/helm-controller/api v1.1.0 + github.com/fluxcd/helm-controller/api v1.4.3 + github.com/go-logr/logr v1.4.3 + github.com/go-logr/zapr v1.3.0 github.com/google/gofuzz v1.2.0 - github.com/onsi/ginkgo/v2 v2.19.0 - github.com/onsi/gomega v1.33.1 - github.com/spf13/cobra v1.8.1 - github.com/stretchr/testify v1.9.0 + github.com/onsi/ginkgo/v2 v2.23.3 + github.com/onsi/gomega v1.37.0 + github.com/prometheus/client_golang v1.22.0 + github.com/robfig/cron/v3 v3.0.1 + github.com/spf13/cobra v1.9.1 + go.uber.org/zap v1.27.0 gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.31.2 - k8s.io/apiextensions-apiserver v0.31.2 - k8s.io/apimachinery v0.31.2 - k8s.io/apiserver v0.31.2 - k8s.io/client-go v0.31.2 - k8s.io/component-base v0.31.2 + k8s.io/api v0.34.1 + k8s.io/apiextensions-apiserver v0.34.1 + k8s.io/apimachinery v0.34.1 + k8s.io/apiserver v0.34.1 + k8s.io/client-go v0.34.1 + k8s.io/component-base v0.34.1 k8s.io/klog/v2 v2.130.1 - k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 - k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 - sigs.k8s.io/controller-runtime v0.19.0 - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 + k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b + k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d + sigs.k8s.io/controller-runtime v0.22.2 + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 ) require ( + cel.dev/expr v0.24.0 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect - github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect @@ -36,89 +40,90 @@ require ( github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/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.0 // indirect + github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fluxcd/pkg/apis/kustomize v1.6.1 // indirect - github.com/fluxcd/pkg/apis/meta v1.6.1 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/fluxcd/pkg/apis/kustomize v1.13.0 // indirect + github.com/fluxcd/pkg/apis/meta v1.22.0 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/cel-go v0.21.0 // indirect - github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.6.0 // indirect - github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect + github.com/google/btree v1.1.3 // indirect + github.com/google/cel-go v0.26.0 // indirect + github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect - github.com/imdario/mergo v0.3.6 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/moby/spdystream v0.4.0 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect + github.com/mailru/easyjson v0.9.0 // indirect + github.com/moby/spdystream v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/pflag v1.0.7 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect github.com/x448/float16 v0.8.4 // indirect - go.etcd.io/etcd/api/v3 v3.5.16 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.16 // indirect - go.etcd.io/etcd/client/v3 v3.5.16 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/sdk v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect - go.opentelemetry.io/proto/otlp v1.3.1 // indirect + go.etcd.io/etcd/api/v3 v3.6.4 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect + go.etcd.io/etcd/client/v3 v3.6.4 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.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.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.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.31.0 // indirect + go.yaml.in/yaml/v2 v2.4.2 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/crypto v0.42.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/oauth2 v0.23.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/term v0.27.0 // indirect - golang.org/x/text v0.21.0 // indirect - golang.org/x/time v0.7.0 // indirect - golang.org/x/tools v0.26.0 // indirect + golang.org/x/net v0.45.0 // indirect + golang.org/x/oauth2 v0.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.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-20240528184218-531527333157 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/grpc v1.65.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-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 gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/kms v0.31.2 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 // indirect - sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect + k8s.io/kms v0.34.1 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect ) // See: issues.k8s.io/135537 -replace k8s.io/apimachinery => github.com/cozystack/apimachinery v0.0.0-20251201201312-18e522a87614 +replace k8s.io/apimachinery => github.com/cozystack/apimachinery v0.0.0-20251219010959-1f91eabae46c diff --git a/go.sum b/go.sum index a32e6b3b..2e0df1a0 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,11 @@ +cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= @@ -18,47 +18,44 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cozystack/apimachinery v0.0.0-20251201201312-18e522a87614 h1:jH9elECUvhiIs3IMv3oS5k1JgCLVsSK6oU4dmq5gyW8= -github.com/cozystack/apimachinery v0.0.0-20251201201312-18e522a87614/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cozystack/apimachinery v0.0.0-20251219010959-1f91eabae46c h1:C2wIfH/OzhU9XOK/e6Ik9cg7nZ1z6fN4lf6a3yFdik8= +github.com/cozystack/apimachinery v0.0.0-20251219010959-1f91eabae46c/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= +github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= -github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= +github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fluxcd/helm-controller/api v1.1.0 h1:NS5Wm3U6Kv4w7Cw2sDOV++vf2ecGfFV00x1+2Y3QcOY= -github.com/fluxcd/helm-controller/api v1.1.0/go.mod h1:BgHMgMY6CWynzl4KIbHpd6Wpn3FN9BqgkwmvoKCp6iE= -github.com/fluxcd/pkg/apis/kustomize v1.6.1 h1:22FJc69Mq4i8aCxnKPlddHhSMyI4UPkQkqiAdWFcqe0= -github.com/fluxcd/pkg/apis/kustomize v1.6.1/go.mod h1:5dvQ4IZwz0hMGmuj8tTWGtarsuxW0rWsxJOwC6i+0V8= -github.com/fluxcd/pkg/apis/meta v1.6.1 h1:maLhcRJ3P/70ArLCY/LF/YovkxXbX+6sTWZwZQBeNq0= -github.com/fluxcd/pkg/apis/meta v1.6.1/go.mod h1:YndB/gxgGZmKfqpAfFxyCDNFJFP0ikpeJzs66jwq280= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/fluxcd/helm-controller/api v1.4.3 h1:CdZwjL1liXmYCWyk2jscmFEB59tICIlnWB9PfDDW5q4= +github.com/fluxcd/helm-controller/api v1.4.3/go.mod h1:0XrBhKEaqvxyDj/FziG1Q8Fmx2UATdaqLgYqmZh6wW4= +github.com/fluxcd/pkg/apis/kustomize v1.13.0 h1:GGf0UBVRIku+gebY944icVeEIhyg1P/KE3IrhOyJJnE= +github.com/fluxcd/pkg/apis/kustomize v1.13.0/go.mod h1:TLKVqbtnzkhDuhWnAsN35977HvRfIjs+lgMuNro/LEc= +github.com/fluxcd/pkg/apis/meta v1.22.0 h1:EHWQH5ZWml7i8eZ/AMjm1jxid3j/PQ31p+hIwCt6crM= +github.com/fluxcd/pkg/apis/meta v1.22.0/go.mod h1:Kc1+bWe5p0doROzuV9XiTfV/oL3ddsemYXt8ZYWdVVg= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= @@ -66,162 +63,171 @@ github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/cel-go v0.21.0 h1:cl6uW/gxN+Hy50tNYvI691+sXxioCnstFzLp2WO4GCI= -github.com/google/cel-go v0.21.0/go.mod h1:rHUlWCcBKgyEk+eV03RPdZUekPp6YcJwV0FxuUksYxc= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/cel-go v0.26.0 h1:DPGjXackMpJWH680oGY4lZhYjIameYmR+/6RBdDGmaI= +github.com/google/cel-go v0.26.0/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= +github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= +github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmp v0.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/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= -github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0 h1:FbSCl+KggFl+Ocym490i/EyXF4lPgLoUtcSWquBM0Rs= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0/go.mod h1:qOchhhIlmRcqk/O9uCo/puJlyo07YINaIqdZfZG3Jkc= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= -github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= -github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= +github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= -github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= +github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= +github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= +github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= +github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_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.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/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/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk= +github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= -go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= -go.etcd.io/etcd/api/v3 v3.5.16 h1:WvmyJVbjWqK4R1E+B12RRHz3bRGy9XVfh++MgbN+6n0= -go.etcd.io/etcd/api/v3 v3.5.16/go.mod h1:1P4SlIP/VwkDmGo3OlOD7faPeP8KDIFhqvciH5EfN28= -go.etcd.io/etcd/client/pkg/v3 v3.5.16 h1:ZgY48uH6UvB+/7R9Yf4x574uCO3jIx0TRDyetSfId3Q= -go.etcd.io/etcd/client/pkg/v3 v3.5.16/go.mod h1:V8acl8pcEK0Y2g19YlOV9m9ssUe6MgiDSobSoaBAM0E= -go.etcd.io/etcd/client/v2 v2.305.13 h1:RWfV1SX5jTU0lbCvpVQe3iPQeAHETWdOTb6pxhd77C8= -go.etcd.io/etcd/client/v2 v2.305.13/go.mod h1:iQnL7fepbiomdXMb3om1rHq96htNNGv2sJkEcZGDRRg= -go.etcd.io/etcd/client/v3 v3.5.16 h1:sSmVYOAHeC9doqi0gv7v86oY/BTld0SEFGaxsU9eRhE= -go.etcd.io/etcd/client/v3 v3.5.16/go.mod h1:X+rExSGkyqxvu276cr2OwPLBaeqFu1cIl4vmRjAD/50= -go.etcd.io/etcd/pkg/v3 v3.5.13 h1:st9bDWNsKkBNpP4PR1MvM/9NqUPfvYZx/YXegsYEH8M= -go.etcd.io/etcd/pkg/v3 v3.5.13/go.mod h1:N+4PLrp7agI/Viy+dUYpX7iRtSPvKq+w8Y14d1vX+m0= -go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA= -go.etcd.io/etcd/raft/v3 v3.5.13/go.mod h1:uUFibGLn2Ksm2URMxN1fICGhk8Wu96EfDQyuLhAcAmw= -go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok= -go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= -go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= -go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.etcd.io/bbolt v1.4.2 h1:IrUHp260R8c+zYx/Tm8QZr04CX+qWS5PGfPdevhdm1I= +go.etcd.io/bbolt v1.4.2/go.mod h1:Is8rSHO/b4f3XigBC0lL0+4FwAQv3HXEEIgFMuKHceM= +go.etcd.io/etcd/api/v3 v3.6.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo= +go.etcd.io/etcd/api/v3 v3.6.4/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk= +go.etcd.io/etcd/client/pkg/v3 v3.6.4 h1:9HBYrjppeOfFjBjaMTRxT3R7xT0GLK8EJMVC4xg6ok0= +go.etcd.io/etcd/client/pkg/v3 v3.6.4/go.mod h1:sbdzr2cl3HzVmxNw//PH7aLGVtY4QySjQFuaCgcRFAI= +go.etcd.io/etcd/client/v3 v3.6.4 h1:YOMrCfMhRzY8NgtzUsHl8hC2EBSnuqbR3dh84Uryl7A= +go.etcd.io/etcd/client/v3 v3.6.4/go.mod h1:jaNNHCyg2FdALyKWnd7hxZXZxZANb0+KGY+YQaEMISo= +go.etcd.io/etcd/pkg/v3 v3.6.4 h1:fy8bmXIec1Q35/jRZ0KOes8vuFxbvdN0aAFqmEfJZWA= +go.etcd.io/etcd/pkg/v3 v3.6.4/go.mod h1:kKcYWP8gHuBRcteyv6MXWSN0+bVMnfgqiHueIZnKMtE= +go.etcd.io/etcd/server/v3 v3.6.4 h1:LsCA7CzjVt+8WGrdsnh6RhC0XqCsLkBly3ve5rTxMAU= +go.etcd.io/etcd/server/v3 v3.6.4/go.mod h1:aYCL/h43yiONOv0QIR82kH/2xZ7m+IWYjzRmyQfnCAg= +go.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ= +go.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.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.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= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -230,50 +236,48 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= +golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/oauth2 v0.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= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= +golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= -golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= +golang.org/x/time v0.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= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= -golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= +golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/genproto/googleapis/api v0.0.0-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= @@ -283,37 +287,42 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= -k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= -k8s.io/apiextensions-apiserver v0.31.2 h1:W8EwUb8+WXBLu56ser5IudT2cOho0gAKeTOnywBLxd0= -k8s.io/apiextensions-apiserver v0.31.2/go.mod h1:i+Geh+nGCJEGiCGR3MlBDkS7koHIIKWVfWeRFiOsUcM= -k8s.io/apiserver v0.31.2 h1:VUzOEUGRCDi6kX1OyQ801m4A7AUPglpsmGvdsekmcI4= -k8s.io/apiserver v0.31.2/go.mod h1:o3nKZR7lPlJqkU5I3Ove+Zx3JuoFjQobGX1Gctw6XuE= -k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= -k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs= -k8s.io/component-base v0.31.2 h1:Z1J1LIaC0AV+nzcPRFqfK09af6bZ4D1nAOpWsy9owlA= -k8s.io/component-base v0.31.2/go.mod h1:9PeyyFN/drHjtJZMCTkSpQJS3U9OXORnHQqMLDz0sUQ= +k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM= +k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk= +k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI= +k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc= +k8s.io/apiserver v0.34.1 h1:U3JBGdgANK3dfFcyknWde1G6X1F4bg7PXuvlqt8lITA= +k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0= +k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY= +k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8= +k8s.io/component-base v0.34.1 h1:v7xFgG+ONhytZNFpIz5/kecwD+sUhVE6HU7qQUiRM4A= +k8s.io/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kms v0.31.2 h1:pyx7l2qVOkClzFMIWMVF/FxsSkgd+OIGH7DecpbscJI= -k8s.io/kms v0.31.2/go.mod h1:OZKwl1fan3n3N5FFxnW5C4V3ygrah/3YXeJWS3O6+94= -k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 h1:GKE9U8BH16uynoxQii0auTjmmmuZ3O0LFMN6S0lPPhI= -k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 h1:CPT0ExVicCzcpeN4baWEV2ko2Z/AsiZgEdwgcfwLgMo= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= -sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= -sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +k8s.io/kms v0.34.1 h1:iCFOvewDPzWM9fMTfyIPO+4MeuZ0tcZbugxLNSHFG4w= +k8s.io/kms v0.34.1/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM= +k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA= +k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts= +k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d h1:wAhiDyZ4Tdtt7e46e9M5ZSAJ/MnPGPs+Ki1gHw4w1R0= +k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/controller-runtime v0.22.2 h1:cK2l8BGWsSWkXz09tcS4rJh95iOLney5eawcK5A33r4= +sigs.k8s.io/controller-runtime v0.22.2/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/packages/core/installer/images/cozystack/Dockerfile b/packages/core/installer/images/cozystack/Dockerfile index 606505ba..beeed70b 100644 --- a/packages/core/installer/images/cozystack/Dockerfile +++ b/packages/core/installer/images/cozystack/Dockerfile @@ -13,7 +13,7 @@ RUN git clone ${K8S_AWAIT_ELECTION_GITREPO} /usr/local/go/k8s-await-election/ \ && make \ && mv ./out/k8s-await-election-${TARGETARCH} /k8s-await-election -FROM golang:1.24-alpine AS builder +FROM golang:1.25-alpine AS builder ARG TARGETOS ARG TARGETARCH diff --git a/packages/core/platform/images/cozystack-assets/Dockerfile b/packages/core/platform/images/cozystack-assets/Dockerfile index cc28b0a8..bf284de3 100644 --- a/packages/core/platform/images/cozystack-assets/Dockerfile +++ b/packages/core/platform/images/cozystack-assets/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24-alpine AS builder +FROM golang:1.25-alpine AS builder ARG TARGETOS ARG TARGETARCH diff --git a/packages/system/cozystack-api/images/cozystack-api/Dockerfile b/packages/system/cozystack-api/images/cozystack-api/Dockerfile index ea7bdc10..b4b206a6 100644 --- a/packages/system/cozystack-api/images/cozystack-api/Dockerfile +++ b/packages/system/cozystack-api/images/cozystack-api/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24-alpine AS builder +FROM golang:1.25-alpine AS builder ARG TARGETOS ARG TARGETARCH diff --git a/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile b/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile index c7ada9ef..bd6cfb38 100644 --- a/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile +++ b/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24-alpine AS builder +FROM golang:1.25-alpine AS builder ARG TARGETOS ARG TARGETARCH diff --git a/packages/system/kubeovn-plunger/images/kubeovn-plunger/Dockerfile b/packages/system/kubeovn-plunger/images/kubeovn-plunger/Dockerfile index a6264ae1..b0473244 100644 --- a/packages/system/kubeovn-plunger/images/kubeovn-plunger/Dockerfile +++ b/packages/system/kubeovn-plunger/images/kubeovn-plunger/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24-alpine AS builder +FROM golang:1.25-alpine AS builder ARG TARGETOS ARG TARGETARCH diff --git a/packages/system/lineage-controller-webhook/images/lineage-controller-webhook/Dockerfile b/packages/system/lineage-controller-webhook/images/lineage-controller-webhook/Dockerfile index e043e472..d9232d98 100644 --- a/packages/system/lineage-controller-webhook/images/lineage-controller-webhook/Dockerfile +++ b/packages/system/lineage-controller-webhook/images/lineage-controller-webhook/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24-alpine AS builder +FROM golang:1.25-alpine AS builder ARG TARGETOS ARG TARGETARCH diff --git a/pkg/cmd/server/start.go b/pkg/cmd/server/start.go index 3427e61d..5da8254e 100644 --- a/pkg/cmd/server/start.go +++ b/pkg/cmd/server/start.go @@ -35,14 +35,11 @@ import ( "github.com/spf13/cobra" "k8s.io/apimachinery/pkg/runtime" utilerrors "k8s.io/apimachinery/pkg/util/errors" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apimachinery/pkg/util/version" "k8s.io/apiserver/pkg/endpoints/openapi" genericapiserver "k8s.io/apiserver/pkg/server" genericoptions "k8s.io/apiserver/pkg/server/options" utilfeature "k8s.io/apiserver/pkg/util/feature" - utilversionpkg "k8s.io/apiserver/pkg/util/version" - "k8s.io/component-base/featuregate" + basecompatibility "k8s.io/component-base/compatibility" baseversion "k8s.io/component-base/version" netutils "k8s.io/utils/net" "sigs.k8s.io/controller-runtime/pkg/client" @@ -86,9 +83,6 @@ func NewCommandStartCozyServer(ctx context.Context, defaults *CozyServerOptions) cmd := &cobra.Command{ Short: "Launch an Cozystack API server", Long: "Launch an Cozystack API server", - PersistentPreRunE: func(*cobra.Command, []string) error { - return utilversionpkg.DefaultComponentGlobalsRegistry.Set() - }, RunE: func(c *cobra.Command, args []string) error { if err := o.Complete(); err != nil { return err @@ -107,38 +101,8 @@ func NewCommandStartCozyServer(ctx context.Context, defaults *CozyServerOptions) flags := cmd.Flags() o.RecommendedOptions.AddFlags(flags) - // The following lines demonstrate how to configure version compatibility and feature gates - // for the "Cozy" component according to KEP-4330. - - // Create a default version object for the "Cozy" component. - defaultCozyVersion := "1.1" - // Register the "Cozy" component in the global component registry, - // associating it with its effective version and feature gate configuration. - _, appsFeatureGate := utilversionpkg.DefaultComponentGlobalsRegistry.ComponentGlobalsOrRegister( - apiserver.CozyComponentName, utilversionpkg.NewEffectiveVersion(defaultCozyVersion), - featuregate.NewVersionedFeatureGate(version.MustParse(defaultCozyVersion)), - ) - - // Add feature gate specifications for the "Cozy" component. - utilruntime.Must(appsFeatureGate.AddVersioned(map[featuregate.Feature]featuregate.VersionedSpecs{ - // Example of adding feature gates: - // "FeatureName": {{"v1", true}, {"v2", false}}, - })) - - // Register the standard kube component if it is not already registered in the global registry. - _, _ = utilversionpkg.DefaultComponentGlobalsRegistry.ComponentGlobalsOrRegister( - utilversionpkg.DefaultKubeComponent, - utilversionpkg.NewEffectiveVersion(baseversion.DefaultKubeBinaryVersion), - utilfeature.DefaultMutableFeatureGate, - ) - - // Set the version emulation mapping from the "Cozy" component to the kube component. - utilruntime.Must(utilversionpkg.DefaultComponentGlobalsRegistry.SetEmulationVersionMapping( - apiserver.CozyComponentName, utilversionpkg.DefaultKubeComponent, CozyVersionToKubeVersion, - )) - - // Add flags from the global component registry. - utilversionpkg.DefaultComponentGlobalsRegistry.AddFlags(flags) + // Note: KEP-4330 component versioning functionality (k8s.io/apiserver/pkg/util/version) + // is not available in Kubernetes v0.34.1. The component versioning code has been removed. return cmd } @@ -225,7 +189,6 @@ func (o *CozyServerOptions) Complete() error { func (o CozyServerOptions) Validate(args []string) error { var allErrors []error allErrors = append(allErrors, o.RecommendedOptions.Validate()...) - allErrors = append(allErrors, utilversionpkg.DefaultComponentGlobalsRegistry.Validate()...) return utilerrors.NewAggregate(allErrors) } @@ -253,14 +216,14 @@ func (o *CozyServerOptions) Config() (*apiserver.Config, error) { sampleopenapi.GetOpenAPIDefinitions, openapi.NewDefinitionNamer(apiserver.Scheme), ) - version := "0.1" + apiVersion := "0.1" if o.ResourceConfig != nil { raw, err := json.Marshal(o.ResourceConfig) if err != nil { return nil, fmt.Errorf("failed to marshal resource config: %v", err) } sum := sha256.Sum256(raw) - version = "0.1-" + hex.EncodeToString(sum[:8]) + apiVersion = "0.1-" + hex.EncodeToString(sum[:8]) } // capture schemas from config once for fast lookup inside the closure @@ -270,23 +233,26 @@ func (o *CozyServerOptions) Config() (*apiserver.Config, error) { } serverConfig.OpenAPIConfig.Info.Title = "Cozy" - serverConfig.OpenAPIConfig.Info.Version = version + serverConfig.OpenAPIConfig.Info.Version = apiVersion serverConfig.OpenAPIConfig.PostProcessSpec = buildPostProcessV2(kindSchemas) serverConfig.OpenAPIV3Config = genericapiserver.DefaultOpenAPIV3Config( sampleopenapi.GetOpenAPIDefinitions, openapi.NewDefinitionNamer(apiserver.Scheme), ) serverConfig.OpenAPIV3Config.Info.Title = "Cozy" - serverConfig.OpenAPIV3Config.Info.Version = version + serverConfig.OpenAPIV3Config.Info.Version = apiVersion serverConfig.OpenAPIV3Config.PostProcessSpec = buildPostProcessV3(kindSchemas) - serverConfig.FeatureGate = utilversionpkg.DefaultComponentGlobalsRegistry.FeatureGateFor( - utilversionpkg.DefaultKubeComponent, - ) - serverConfig.EffectiveVersion = utilversionpkg.DefaultComponentGlobalsRegistry.EffectiveVersionFor( - apiserver.CozyComponentName, - ) + // Set FeatureGate and EffectiveVersion - required for Complete() in Kubernetes v0.34.1 + // Following the pattern from sample-apiserver, but creating EffectiveVersion directly + // without ComponentGlobalsRegistry + serverConfig.FeatureGate = utilfeature.DefaultMutableFeatureGate + // Create EffectiveVersion directly using compatibility package + // This is needed even without ComponentGlobalsRegistry + if baseversion.DefaultKubeBinaryVersion != "" { + serverConfig.EffectiveVersion = basecompatibility.NewEffectiveVersionFromString(baseversion.DefaultKubeBinaryVersion, "", "") + } if err := o.RecommendedOptions.ApplyTo(serverConfig); err != nil { return nil, err @@ -318,18 +284,3 @@ func (o CozyServerOptions) RunCozyServer(ctx context.Context) error { return server.GenericAPIServer.PrepareRun().RunWithContext(ctx) } - -// CozyVersionToKubeVersion defines the version mapping between the Cozy component and kube -func CozyVersionToKubeVersion(ver *version.Version) *version.Version { - if ver.Major() != 1 { - return nil - } - kubeVer := utilversionpkg.DefaultKubeEffectiveVersion().BinaryVersion() - // "1.2" corresponds to kubeVer - offset := int(ver.Minor()) - 2 - mappedVer := kubeVer.OffsetMinor(offset) - if mappedVer.GreaterThan(kubeVer) { - return kubeVer - } - return mappedVer -} diff --git a/pkg/cmd/server/start_test.go b/pkg/cmd/server/start_test.go index da96ed31..df7c3547 100644 --- a/pkg/cmd/server/start_test.go +++ b/pkg/cmd/server/start_test.go @@ -16,53 +16,5 @@ limitations under the License. package server -import ( - "testing" - - "k8s.io/apimachinery/pkg/util/version" - utilversion "k8s.io/apiserver/pkg/util/version" - - "github.com/stretchr/testify/assert" -) - -func TestCozyEmulationVersionToKubeEmulationVersion(t *testing.T) { - defaultKubeEffectiveVersion := utilversion.DefaultKubeEffectiveVersion() - - testCases := []struct { - desc string - appsEmulationVer *version.Version - expectedKubeEmulationVer *version.Version - }{ - { - desc: "same version as than kube binary", - appsEmulationVer: version.MajorMinor(1, 2), - expectedKubeEmulationVer: defaultKubeEffectiveVersion.BinaryVersion(), - }, - { - desc: "1 version lower than kube binary", - appsEmulationVer: version.MajorMinor(1, 1), - expectedKubeEmulationVer: defaultKubeEffectiveVersion.BinaryVersion().OffsetMinor(-1), - }, - { - desc: "2 versions lower than kube binary", - appsEmulationVer: version.MajorMinor(1, 0), - expectedKubeEmulationVer: defaultKubeEffectiveVersion.BinaryVersion().OffsetMinor(-2), - }, - { - desc: "capped at kube binary", - appsEmulationVer: version.MajorMinor(1, 3), - expectedKubeEmulationVer: defaultKubeEffectiveVersion.BinaryVersion(), - }, - { - desc: "no mapping", - appsEmulationVer: version.MajorMinor(2, 10), - }, - } - - for _, tc := range testCases { - t.Run(tc.desc, func(t *testing.T) { - mappedKubeEmulationVer := CozyVersionToKubeVersion(tc.appsEmulationVer) - assert.True(t, mappedKubeEmulationVer.EqualTo(tc.expectedKubeEmulationVer)) - }) - } -} +// Note: Tests for KEP-4330 component versioning functionality have been removed +// as the functionality is not available in Kubernetes v0.34.1. From ecb9a223aacb36fbd8001f712d1972321571a48b Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 24 Dec 2025 14:11:24 +0100 Subject: [PATCH 21/78] Add changelogs to v.0.39.1 (#1750) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does ### Release note ```release-note Add changelogs for v.0.39.0 and v.0.39.1 ``` ## Summary by CodeRabbit * **New Features** * Topology-aware routing for services * Automatic pod rollouts on configuration changes * Windows VM scheduling support * SLACK_SEVERITY_FILTER for notification filtering * VMAgent resource for metrics scraping * **Improvements** * Enhanced networking and storage capabilities * Configuration management enhancements * Updated dependencies * **Bug Fixes** * Schema nesting and resizing validation * Namespace deletion regression ✏️ Tip: You can customize this high-level summary in your review settings. --- docs/changelogs/v0.39.0.md | 73 ++++++++++++++++++++++++++++++++++++++ docs/changelogs/v0.39.1.md | 12 +++++++ 2 files changed, 85 insertions(+) create mode 100644 docs/changelogs/v0.39.0.md create mode 100644 docs/changelogs/v0.39.1.md diff --git a/docs/changelogs/v0.39.0.md b/docs/changelogs/v0.39.0.md new file mode 100644 index 00000000..9630b6c5 --- /dev/null +++ b/docs/changelogs/v0.39.0.md @@ -0,0 +1,73 @@ +# Cozystack v0.39 — "Enhanced Networking & Monitoring" + +This release introduces topology-aware routing for Cilium services, automatic pod rollouts on configuration changes, improved monitoring capabilities, and numerous bug fixes and improvements across the platform. + +## Highlights + +* **Topology-Aware Routing**: Enabled topology-aware routing for Cilium services, improving traffic distribution and reducing latency by routing traffic to endpoints in the same zone when possible ([**@nbykov0**](https://github.com/nbykov0) in #1734). +* **Automatic Pod Rollouts**: Cilium and Cilium operator pods now automatically restart when configuration changes, ensuring configuration updates are applied immediately ([**@kvaps**](https://github.com/kvaps) in #1728, #1745). +* **Windows VM Scheduling**: Added nodeAffinity configuration for Windows VMs based on scheduling config, enabling dedicated nodes for Windows workloads ([**@kvaps**](https://github.com/kvaps) in #1693, #1744). +* **SeaweedFS Updates**: Updated to SeaweedFS v4.02 with improved S3 daemon performance and fixes ([**@kvaps**](https://github.com/kvaps) in #1725, #1732). + +--- + +## Major Features and Improvements + +### Networking + +* **[system/cilium] Enable topology-aware routing for services**: Enabled topology-aware routing for services, improving traffic distribution and reducing latency by routing traffic to endpoints in the same zone when possible. This feature helps optimize network performance in multi-zone deployments ([**@nbykov0**](https://github.com/nbykov0) in #1734). +* **[cilium] Enable automatic pod rollout on configmap updates**: Cilium and Cilium operator pods now automatically restart when the cilium-config ConfigMap is updated, ensuring configuration changes are applied immediately without manual intervention ([**@kvaps**](https://github.com/kvaps) in #1728, #1745). + +### Virtual Machines + +* **[virtual-machine,vm-instance] Add nodeAffinity for Windows VMs based on scheduling config**: Added nodeAffinity configuration to virtual-machine and vm-instance charts to support dedicated nodes for Windows VMs. When `dedicatedNodesForWindowsVMs` is enabled in the `cozystack-scheduling` ConfigMap, Windows VMs are scheduled on nodes with label `scheduling.cozystack.io/vm-windows=true`, while non-Windows VMs prefer nodes without this label ([**@kvaps**](https://github.com/kvaps) in #1693, #1744). + +### Storage + +* **Update SeaweedFS v4.02**: Updated SeaweedFS to version 4.02 with improved performance for S3 daemon and fixes for known issues. This update includes better S3 compatibility and performance improvements ([**@kvaps**](https://github.com/kvaps) in #1725, #1732). + +## Improvements + +* **[seaweedfs] Extended CA certificate duration to reduce disruptive CA rotations**: Extended CA certificate duration to reduce disruptive CA rotations, improving long-term certificate management and reducing operational overhead ([**@IvanHunters**](https://github.com/IvanHunters) in #1657). +* **[dashboard] Add config hash annotations to restart pods on config changes**: Added config hash annotations to dashboard deployment templates to ensure pods are automatically restarted when their configuration changes, ensuring configuration updates are applied immediately ([**@kvaps**](https://github.com/kvaps) in #1662). +* **[tenant][kubernetes] Introduce better cleanup logic**: Improved cleanup logic for tenant Kubernetes resources, ensuring proper resource cleanup when tenants are deleted or updated. Added automated pre-delete cleanup job for tenant namespaces to remove tenant-related releases during uninstall ([**@kvaps**](https://github.com/kvaps) in #1661). +* **[system:coredns] update coredns app labels to match Talos coredns labels**: Updated coredns app labels to match Talos coredns labels, ensuring consistency across the platform ([**@nbykov0**](https://github.com/nbykov0) in #1675). +* **[system:monitoring-agents] rename coredns metrics service**: Renamed coredns metrics service to avoid interference with coredns service used for name resolution in tenant k8s clusters ([**@nbykov0**](https://github.com/nbykov0) in #1676). +* **[core:installer] Address buildx warnings**: Fixed Dockerfile syntax warnings from buildx, ensuring clean builds without warnings ([**@nbykov0**](https://github.com/nbykov0) in #1682). + +## 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). +* **[dashboard] Fix CustomFormsOverride schema to nest properties under spec.properties**: Fixed the logic for generating CustomFormsOverride schema to properly nest properties under `spec.properties` instead of directly under `properties`, ensuring correct form schema generation ([**@kvaps**](https://github.com/kvaps) in #1692, #1700). +* **[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, #1701). +* **[linstor] Update piraeus-operator v2.10.2**: Updated LINSTOR CSI to fix issues with the new fsck behaviour, resolving mount failures when fsck attempts to run on mounted devices ([**@kvaps**](https://github.com/kvaps) in #1689, #1697). +* **[api] Revert dynamic list kinds representation fix (fixes namespace deletion regression)**: Reverted changes from #1630 that caused a regression affecting namespace deletion and upgrades from previous versions. The regression caused namespace deletion failures with errors like "content is not a list: []unstructured.Unstructured" during namespace finalization. This revert restores compatibility with namespace deletion controller and fixes upgrade issues from previous versions ([**@kvaps**](https://github.com/kvaps) in #1677). + +## Dependencies + +* **Update SeaweedFS v4.02**: Updated SeaweedFS to version 4.02 ([**@kvaps**](https://github.com/kvaps) in #1725, #1732). +* **[linstor] Update piraeus-operator v2.10.2**: Updated piraeus-operator to version 2.10.2 ([**@kvaps**](https://github.com/kvaps) in #1689, #1697). + +## Documentation + +* **[website] docs(talm): update talm init syntax for mandatory --preset and --name flags**: Updated documentation to reflect breaking changes in talm, adding mandatory `--preset` and `--name` flags to the talm init command ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#386). + +--- + +## Contributors + +We'd like to thank all contributors who made this release possible: + +* [**@IvanHunters**](https://github.com/IvanHunters) +* [**@kvaps**](https://github.com/kvaps) +* [**@lexfrei**](https://github.com/lexfrei) +* [**@nbykov0**](https://github.com/nbykov0) + +--- + +**Full Changelog**: [v0.38.0...v0.39.0](https://github.com/cozystack/cozystack/compare/v0.38.0...v0.39.0) + + + diff --git a/docs/changelogs/v0.39.1.md b/docs/changelogs/v0.39.1.md new file mode 100644 index 00000000..569271ee --- /dev/null +++ b/docs/changelogs/v0.39.1.md @@ -0,0 +1,12 @@ + + +## Features and Improvements + +* **[monitoring] Add SLACK_SEVERITY_FILTER field and VMAgent for tenant monitoring**: Introduced the SLACK_SEVERITY_FILTER environment variable in the Alerta deployment to enable filtering of alert severities for Slack notifications based on the disabledSeverity configuration. Additionally, added a VMAgent resource template for scraping metrics within tenant namespaces, improving monitoring granularity and control. This enhancement allows administrators to configure which alert severities are sent to Slack and enables tenant-specific metrics collection for better observability ([**@IvanHunters**](https://github.com/IvanHunters) in #1712). + +--- + +**Full Changelog**: [v0.39.0...v0.39.1](https://github.com/cozystack/cozystack/compare/v0.39.0...v0.39.1) + From eb042b4ef132e046b95ad90694ddae89f70024c2 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 24 Dec 2025 15:15:25 +0100 Subject: [PATCH 22/78] [core] Extract Talos package from installer (#1724) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does Extract Talos-related functionality from `packages/core/installer` into a separate `packages/core/talos` package. This refactoring separates concerns: - The `installer` package now focuses solely on the Cozystack installer - The `talos` package handles all Talos Linux image building and assets generation Changes: - Created new `packages/core/talos` package with Chart.yaml, Makefile, and values.yaml - Moved Talos profiles (initramfs, kernel, iso, installer, metal, nocloud) to talos package - Moved matchbox configuration and Dockerfile to talos package - Moved `hack/gen-profiles.sh` and `hack/gen-versions.sh` scripts to talos package - Updated installer Makefile to remove all Talos-related targets - Updated root Makefile to build talos package separately - Updated matchbox Dockerfile paths to reference talos package ### Release note ```release-note [core] Extract Talos package from installer into separate packages/core/talos package ``` ## Summary by CodeRabbit * **Chores** * Reorganized build system to add a dedicated Talos package with its own image and asset build workflow * Switched asset generation to the new Talos packaging path and simplified build dependency chain * Added Helm chart manifest and streamlined image build/publishing steps for Talos-related artifacts ✏️ Tip: You can customize this high-level summary in your review settings. --- .github/workflows/pull-requests.yaml | 2 +- Makefile | 3 +- packages/core/installer/Makefile | 33 +--------------- packages/core/talos/Chart.yaml | 4 ++ packages/core/talos/Makefile | 38 +++++++++++++++++++ .../{installer => talos}/hack/gen-profiles.sh | 0 .../{installer => talos}/hack/gen-versions.sh | 0 .../images/matchbox/Dockerfile | 4 +- .../images/matchbox/groups/default.json | 0 .../images/matchbox/profiles/default.json | 0 .../images/talos/profiles/initramfs.yaml | 0 .../images/talos/profiles/installer.yaml | 0 .../images/talos/profiles/iso.yaml | 0 .../images/talos/profiles/kernel.yaml | 0 .../images/talos/profiles/metal.yaml | 0 .../images/talos/profiles/nocloud.yaml | 0 packages/core/talos/values.yaml | 0 17 files changed, 48 insertions(+), 36 deletions(-) create mode 100644 packages/core/talos/Chart.yaml create mode 100644 packages/core/talos/Makefile rename packages/core/{installer => talos}/hack/gen-profiles.sh (100%) rename packages/core/{installer => talos}/hack/gen-versions.sh (100%) rename packages/core/{installer => talos}/images/matchbox/Dockerfile (53%) rename packages/core/{installer => talos}/images/matchbox/groups/default.json (100%) rename packages/core/{installer => talos}/images/matchbox/profiles/default.json (100%) rename packages/core/{installer => talos}/images/talos/profiles/initramfs.yaml (100%) rename packages/core/{installer => talos}/images/talos/profiles/installer.yaml (100%) rename packages/core/{installer => talos}/images/talos/profiles/iso.yaml (100%) rename packages/core/{installer => talos}/images/talos/profiles/kernel.yaml (100%) rename packages/core/{installer => talos}/images/talos/profiles/metal.yaml (100%) rename packages/core/{installer => talos}/images/talos/profiles/nocloud.yaml (100%) create mode 100644 packages/core/talos/values.yaml diff --git a/.github/workflows/pull-requests.yaml b/.github/workflows/pull-requests.yaml index 06b4f3d3..2de01160 100644 --- a/.github/workflows/pull-requests.yaml +++ b/.github/workflows/pull-requests.yaml @@ -58,7 +58,7 @@ jobs: DOCKER_CONFIG: ${{ runner.temp }}/.docker - name: Build Talos image - run: make -C packages/core/installer talos-nocloud + run: make -C packages/core/talos talos-nocloud - name: Save git diff as patch if: "!contains(github.event.pull_request.labels.*.name, 'release')" diff --git a/Makefile b/Makefile index 290928d7..c1de2a9f 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ build: build-deps make -C packages/system/bucket image make -C packages/system/objectstorage-controller 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 @@ -40,7 +41,7 @@ manifests: (cd packages/core/installer/; helm template -n cozy-installer installer .) > _out/assets/cozystack-installer.yaml assets: - make -C packages/core/installer assets + make -C packages/core/talos assets test: make -C packages/core/testing apply diff --git a/packages/core/installer/Makefile b/packages/core/installer/Makefile index a51e7b61..12a3e333 100644 --- a/packages/core/installer/Makefile +++ b/packages/core/installer/Makefile @@ -1,8 +1,6 @@ NAME=installer NAMESPACE=cozy-system -TALOS_VERSION=$(shell awk '/^version:/ {print $$2}' images/talos/profiles/installer.yaml) - include ../../../scripts/common-envs.mk pre-checks: @@ -17,10 +15,7 @@ apply: diff: cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f - -update: - hack/gen-profiles.sh - -image: pre-checks image-matchbox image-cozystack image-talos +image: pre-checks image-cozystack image-cozystack: docker buildx build -f images/cozystack/Dockerfile ../../.. \ @@ -32,29 +27,3 @@ image-cozystack: 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 - -image-talos: - test -f ../../../_out/assets/installer-amd64.tar || make talos-installer - skopeo copy docker-archive:../../../_out/assets/installer-amd64.tar docker://$(REGISTRY)/talos:$(call settag,$(TALOS_VERSION)) - -image-matchbox: - test -f ../../../_out/assets/kernel-amd64 || make talos-kernel - test -f ../../../_out/assets/initramfs-metal-amd64.xz || make talos-initramfs - docker buildx build -f images/matchbox/Dockerfile ../../.. \ - --tag $(REGISTRY)/matchbox:$(call settag,$(TAG)) \ - --tag $(REGISTRY)/matchbox:$(call settag,$(TALOS_VERSION)-$(TAG)) \ - --cache-from type=registry,ref=$(REGISTRY)/matchbox:latest \ - --cache-to type=inline \ - --metadata-file images/matchbox.json \ - $(BUILDX_ARGS) - echo "$(REGISTRY)/matchbox:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/matchbox.json -o json -r)" \ - > ../../extra/bootbox/images/matchbox.tag - rm -f images/matchbox.json - -assets: talos-iso talos-nocloud talos-metal talos-kernel talos-initramfs - -talos-initramfs talos-kernel talos-installer talos-iso talos-nocloud talos-metal: - mkdir -p ../../../_out/assets - cat images/talos/profiles/$(subst talos-,,$@).yaml | \ - docker run --rm -i -v /dev:/dev --privileged "ghcr.io/siderolabs/imager:$(TALOS_VERSION)" --tar-to-stdout - | \ - tar -C ../../../_out/assets -xzf- diff --git a/packages/core/talos/Chart.yaml b/packages/core/talos/Chart.yaml new file mode 100644 index 00000000..0ba301dc --- /dev/null +++ b/packages/core/talos/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v2 +name: cozy-talos +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process + diff --git a/packages/core/talos/Makefile b/packages/core/talos/Makefile new file mode 100644 index 00000000..24d9c9f2 --- /dev/null +++ b/packages/core/talos/Makefile @@ -0,0 +1,38 @@ +NAME=talos +NAMESPACE=cozy-system + +TALOS_VERSION=$(shell awk '/^version:/ {print $$2}' images/talos/profiles/installer.yaml) + +include ../../../scripts/common-envs.mk + +update: + hack/gen-profiles.sh + +image: image-matchbox image-talos + +image-talos: + test -f ../../../_out/assets/installer-amd64.tar || make talos-installer + skopeo copy docker-archive:../../../_out/assets/installer-amd64.tar docker://$(REGISTRY)/talos:$(call settag,$(TALOS_VERSION)) + +image-matchbox: + test -f ../../../_out/assets/kernel-amd64 || make talos-kernel + test -f ../../../_out/assets/initramfs-metal-amd64.xz || make talos-initramfs + docker buildx build -f images/matchbox/Dockerfile ../../.. \ + --tag $(REGISTRY)/matchbox:$(call settag,$(TAG)) \ + --tag $(REGISTRY)/matchbox:$(call settag,$(TALOS_VERSION)-$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/matchbox:latest \ + --cache-to type=inline \ + --metadata-file images/matchbox.json \ + $(BUILDX_ARGS) + echo "$(REGISTRY)/matchbox:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/matchbox.json -o json -r)" \ + > ../../extra/bootbox/images/matchbox.tag + rm -f images/matchbox.json + +assets: talos-iso talos-nocloud talos-metal talos-kernel talos-initramfs + +talos-initramfs talos-kernel talos-installer talos-iso talos-nocloud talos-metal: + mkdir -p ../../../_out/assets + cat images/talos/profiles/$(subst talos-,,$@).yaml | \ + docker run --rm -i -v /dev:/dev --privileged "ghcr.io/siderolabs/imager:$(TALOS_VERSION)" --tar-to-stdout - | \ + tar -C ../../../_out/assets -xzf- + diff --git a/packages/core/installer/hack/gen-profiles.sh b/packages/core/talos/hack/gen-profiles.sh similarity index 100% rename from packages/core/installer/hack/gen-profiles.sh rename to packages/core/talos/hack/gen-profiles.sh diff --git a/packages/core/installer/hack/gen-versions.sh b/packages/core/talos/hack/gen-versions.sh similarity index 100% rename from packages/core/installer/hack/gen-versions.sh rename to packages/core/talos/hack/gen-versions.sh diff --git a/packages/core/installer/images/matchbox/Dockerfile b/packages/core/talos/images/matchbox/Dockerfile similarity index 53% rename from packages/core/installer/images/matchbox/Dockerfile rename to packages/core/talos/images/matchbox/Dockerfile index 1083ab26..fbb6f3bf 100644 --- a/packages/core/installer/images/matchbox/Dockerfile +++ b/packages/core/talos/images/matchbox/Dockerfile @@ -2,5 +2,5 @@ FROM quay.io/poseidon/matchbox:v0.10.0 COPY _out/assets/initramfs-metal-amd64.xz /var/lib/matchbox/assets/initramfs.xz COPY _out/assets/kernel-amd64 /var/lib/matchbox/assets/vmlinuz -COPY packages/core/installer/images/matchbox/groups /var/lib/matchbox/groups -COPY packages/core/installer/images/matchbox/profiles /var/lib/matchbox/profiles +COPY packages/core/talos/images/matchbox/groups /var/lib/matchbox/groups +COPY packages/core/talos/images/matchbox/profiles /var/lib/matchbox/profiles diff --git a/packages/core/installer/images/matchbox/groups/default.json b/packages/core/talos/images/matchbox/groups/default.json similarity index 100% rename from packages/core/installer/images/matchbox/groups/default.json rename to packages/core/talos/images/matchbox/groups/default.json diff --git a/packages/core/installer/images/matchbox/profiles/default.json b/packages/core/talos/images/matchbox/profiles/default.json similarity index 100% rename from packages/core/installer/images/matchbox/profiles/default.json rename to packages/core/talos/images/matchbox/profiles/default.json diff --git a/packages/core/installer/images/talos/profiles/initramfs.yaml b/packages/core/talos/images/talos/profiles/initramfs.yaml similarity index 100% rename from packages/core/installer/images/talos/profiles/initramfs.yaml rename to packages/core/talos/images/talos/profiles/initramfs.yaml diff --git a/packages/core/installer/images/talos/profiles/installer.yaml b/packages/core/talos/images/talos/profiles/installer.yaml similarity index 100% rename from packages/core/installer/images/talos/profiles/installer.yaml rename to packages/core/talos/images/talos/profiles/installer.yaml diff --git a/packages/core/installer/images/talos/profiles/iso.yaml b/packages/core/talos/images/talos/profiles/iso.yaml similarity index 100% rename from packages/core/installer/images/talos/profiles/iso.yaml rename to packages/core/talos/images/talos/profiles/iso.yaml diff --git a/packages/core/installer/images/talos/profiles/kernel.yaml b/packages/core/talos/images/talos/profiles/kernel.yaml similarity index 100% rename from packages/core/installer/images/talos/profiles/kernel.yaml rename to packages/core/talos/images/talos/profiles/kernel.yaml diff --git a/packages/core/installer/images/talos/profiles/metal.yaml b/packages/core/talos/images/talos/profiles/metal.yaml similarity index 100% rename from packages/core/installer/images/talos/profiles/metal.yaml rename to packages/core/talos/images/talos/profiles/metal.yaml diff --git a/packages/core/installer/images/talos/profiles/nocloud.yaml b/packages/core/talos/images/talos/profiles/nocloud.yaml similarity index 100% rename from packages/core/installer/images/talos/profiles/nocloud.yaml rename to packages/core/talos/images/talos/profiles/nocloud.yaml diff --git a/packages/core/talos/values.yaml b/packages/core/talos/values.yaml new file mode 100644 index 00000000..e69de29b From d1c0af1db4c2ffd1e784626ec381bfe91542cad3 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 24 Dec 2025 21:10:53 +0100 Subject: [PATCH 23/78] [workflow] Add GitHub Action to update release notes from changelogs (#1752) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds a GitHub Actions workflow that automatically updates release notes from changelog files when changes are merged to main. The workflow: - Triggers on push to main branch - Processes up to 30 releases from the first page - For each release, checks if a corresponding changelog file exists in `docs/changelogs/` - Updates the release notes with the changelog content if it exists and differs from the current content - Skips releases that are already up to date to avoid unnecessary API calls This automates the process of keeping release notes synchronized with changelog files. ## Summary by CodeRabbit * **Chores** * Automated workflow added to synchronize GitHub releases with local changelog files, updating release notes only when content differs. * **Documentation** * Changelogs and release notes reorganized and expanded with improved sectioning and new tooling/documentation entries. * **New Features** * Added VM disk SVG icon entry under Features/Improvements. * **Bug Fixes** * Pinned CoreDNS image tag for reproducible deployments. * Fixed a documentation typo that prevented a component from displaying in the web UI. ✏️ Tip: You can customize this high-level summary in your review settings. --- .github/workflows/update-releasenotes.yaml | 92 ++++++++++++++++++++++ docs/changelogs/v0.36.2.md | 5 +- docs/changelogs/v0.39.0.md | 46 ++++++++--- 3 files changed, 130 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/update-releasenotes.yaml diff --git a/.github/workflows/update-releasenotes.yaml b/.github/workflows/update-releasenotes.yaml new file mode 100644 index 00000000..b475511f --- /dev/null +++ b/.github/workflows/update-releasenotes.yaml @@ -0,0 +1,92 @@ +name: Update Release Notes + +on: + push: + branches: + - main + +concurrency: + group: update-releasenotes-${{ github.workflow }} + cancel-in-progress: false + +jobs: + update-releasenotes: + name: Update Release Notes + runs-on: [self-hosted] + permissions: + contents: write + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Update release notes from changelogs + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const path = require('path'); + + const changelogDir = 'docs/changelogs'; + + // Get releases from first page + const releases = await github.rest.repos.listReleases({ + owner: context.repo.owner, + repo: context.repo.repo, + per_page: 30 + }); + + console.log(`Found ${releases.data.length} releases (first page only)`); + + // Process each release + for (const release of releases.data) { + const tag = release.tag_name; + const changelogFile = `${tag}.md`; + const changelogPath = path.join(changelogDir, changelogFile); + + console.log(`\nProcessing release: ${tag}`); + + // Check if changelog file exists + if (!fs.existsSync(changelogPath)) { + console.log(` ⚠️ Changelog file ${changelogFile} does not exist, skipping...`); + continue; + } + + // Read changelog file content + let changelogContent; + try { + changelogContent = fs.readFileSync(changelogPath, 'utf8'); + } catch (error) { + console.log(` ❌ Error reading file ${changelogPath}: ${error.message}`); + continue; + } + + if (!changelogContent.trim()) { + console.log(` ⚠️ Changelog file ${changelogFile} is empty, skipping...`); + continue; + } + + // Check if content is already up to date + const currentBody = release.body || ''; + if (currentBody.trim() === changelogContent.trim()) { + console.log(` ✓ Content is already up to date, skipping...`); + continue; + } + + // Update release notes + try { + await github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release.id, + body: changelogContent + }); + console.log(` ✅ Successfully updated release notes for ${tag}`); + } catch (error) { + console.log(` ❌ Error updating release ${tag}: ${error.message}`); + core.setFailed(`Failed to update release notes for ${tag}`); + } + } + diff --git a/docs/changelogs/v0.36.2.md b/docs/changelogs/v0.36.2.md index 9e912e69..cb44308a 100644 --- a/docs/changelogs/v0.36.2.md +++ b/docs/changelogs/v0.36.2.md @@ -5,10 +5,13 @@ https://github.com/cozystack/cozystack/releases/tag/v0.36.2 ## Features and Improvements -## Security +* [vm-disk] New SVG icon for VM disk application. (@kvaps and @kvapsova in https://github.com/cozystack/cozystack/pull/1435) ## Fixes +* [kubernetes] Pin CoreDNS image tag to v1.12.4 for consistent, reproducible deployments. (@kvaps in https://github.com/cozystack/cozystack/pull/1469) +* [dashboard] Fix FerretDB spec typo that prevented deploy/display in the web UI. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1440) + ## Dependencies ## Development, Testing, and CI/CD diff --git a/docs/changelogs/v0.39.0.md b/docs/changelogs/v0.39.0.md index 9630b6c5..ff498258 100644 --- a/docs/changelogs/v0.39.0.md +++ b/docs/changelogs/v0.39.0.md @@ -5,9 +5,9 @@ This release introduces topology-aware routing for Cilium services, automatic po ## Highlights * **Topology-Aware Routing**: Enabled topology-aware routing for Cilium services, improving traffic distribution and reducing latency by routing traffic to endpoints in the same zone when possible ([**@nbykov0**](https://github.com/nbykov0) in #1734). -* **Automatic Pod Rollouts**: Cilium and Cilium operator pods now automatically restart when configuration changes, ensuring configuration updates are applied immediately ([**@kvaps**](https://github.com/kvaps) in #1728, #1745). -* **Windows VM Scheduling**: Added nodeAffinity configuration for Windows VMs based on scheduling config, enabling dedicated nodes for Windows workloads ([**@kvaps**](https://github.com/kvaps) in #1693, #1744). -* **SeaweedFS Updates**: Updated to SeaweedFS v4.02 with improved S3 daemon performance and fixes ([**@kvaps**](https://github.com/kvaps) in #1725, #1732). +* **Automatic Pod Rollouts**: Cilium and Cilium operator pods now automatically restart when configuration changes, ensuring configuration updates are applied immediately ([**@kvaps**](https://github.com/kvaps) in #1728). +* **Windows VM Scheduling**: Added nodeAffinity configuration for Windows VMs based on scheduling config, enabling dedicated nodes for Windows workloads ([**@kvaps**](https://github.com/kvaps) in #1693). +* **SeaweedFS Updates**: Updated to SeaweedFS v4.02 with improved S3 daemon performance and fixes ([**@kvaps**](https://github.com/kvaps) in #1725). --- @@ -16,15 +16,27 @@ This release introduces topology-aware routing for Cilium services, automatic po ### Networking * **[system/cilium] Enable topology-aware routing for services**: Enabled topology-aware routing for services, improving traffic distribution and reducing latency by routing traffic to endpoints in the same zone when possible. This feature helps optimize network performance in multi-zone deployments ([**@nbykov0**](https://github.com/nbykov0) in #1734). -* **[cilium] Enable automatic pod rollout on configmap updates**: Cilium and Cilium operator pods now automatically restart when the cilium-config ConfigMap is updated, ensuring configuration changes are applied immediately without manual intervention ([**@kvaps**](https://github.com/kvaps) in #1728, #1745). +* **[cilium] Enable automatic pod rollout on configmap updates**: Cilium and Cilium operator pods now automatically restart when the cilium-config ConfigMap is updated, ensuring configuration changes are applied immediately without manual intervention ([**@kvaps**](https://github.com/kvaps) in #1728). ### Virtual Machines -* **[virtual-machine,vm-instance] Add nodeAffinity for Windows VMs based on scheduling config**: Added nodeAffinity configuration to virtual-machine and vm-instance charts to support dedicated nodes for Windows VMs. When `dedicatedNodesForWindowsVMs` is enabled in the `cozystack-scheduling` ConfigMap, Windows VMs are scheduled on nodes with label `scheduling.cozystack.io/vm-windows=true`, while non-Windows VMs prefer nodes without this label ([**@kvaps**](https://github.com/kvaps) in #1693, #1744). +* **[virtual-machine,vm-instance] Add nodeAffinity for Windows VMs based on scheduling config**: Added nodeAffinity configuration to virtual-machine and vm-instance charts to support dedicated nodes for Windows VMs. When `dedicatedNodesForWindowsVMs` is enabled in the `cozystack-scheduling` ConfigMap, Windows VMs are scheduled on nodes with label `scheduling.cozystack.io/vm-windows=true`, while non-Windows VMs prefer nodes without this label ([**@kvaps**](https://github.com/kvaps) in #1693). ### Storage -* **Update SeaweedFS v4.02**: Updated SeaweedFS to version 4.02 with improved performance for S3 daemon and fixes for known issues. This update includes better S3 compatibility and performance improvements ([**@kvaps**](https://github.com/kvaps) in #1725, #1732). +* **Update SeaweedFS v4.02**: Updated SeaweedFS to version 4.02 with improved performance for S3 daemon and fixes for known issues. This update includes better S3 compatibility and performance improvements ([**@kvaps**](https://github.com/kvaps) in #1725). + +### Tools + +* **[talm] feat(init)!: require --name flag for cluster name**: Breaking change: The `talm init` command now requires the `--name` flag to specify the cluster name. This ensures consistent cluster naming and prevents accidental initialization without a name ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm#86). +* **[talm] feat(template): preserve extra YAML documents in output**: Templates now preserve extra YAML documents in the output, allowing for more flexible template processing ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm#87). +* **[talm] feat: add directory expansion for -f flag**: Added directory expansion support for the `-f` flag, allowing users to specify directories instead of individual files ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@ca5713e). +* **[talm] Introduce automatic root detection**: Added automatic root detection logic to simplify talm usage and reduce manual configuration ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@d165162). +* **[talm] Introduce talm kubeconfig --login command**: Added new `talm kubeconfig --login` command for easier kubeconfig management ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@5f7e05b). +* **[talm] Introduce encryption**: Added encryption support to talm for secure configuration management ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#81). +* **[talm] Replace code-generation with wrapper on talosctl**: Refactored talm to use a wrapper on talosctl instead of code generation, simplifying the codebase and improving maintainability ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#80). +* **[talm] Use go embed instead of code generation**: Migrated from code generation to go embed for better build performance and simpler dependency management ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#79). +* **[boot-to-talos] Cozystack: Update Talos Linux v1.11.3**: Updated boot-to-talos to use Talos Linux v1.11.3 ([**@kvaps**](https://github.com/kvaps) in cozystack/boot-to-talos#7). ## Improvements @@ -34,22 +46,32 @@ This release introduces topology-aware routing for Cilium services, automatic po * **[system:coredns] update coredns app labels to match Talos coredns labels**: Updated coredns app labels to match Talos coredns labels, ensuring consistency across the platform ([**@nbykov0**](https://github.com/nbykov0) in #1675). * **[system:monitoring-agents] rename coredns metrics service**: Renamed coredns metrics service to avoid interference with coredns service used for name resolution in tenant k8s clusters ([**@nbykov0**](https://github.com/nbykov0) in #1676). * **[core:installer] Address buildx warnings**: Fixed Dockerfile syntax warnings from buildx, ensuring clean builds without warnings ([**@nbykov0**](https://github.com/nbykov0) in #1682). +* **[talm] Refactor root detection logic into single file**: Improved code organization by consolidating root detection logic into a single file ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@487b479). +* **[talm] Refactor init logic, better upgrade**: Improved initialization logic and upgrade process for better reliability ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@c512777). +* **[talm] Sugar for kubeconfig command**: Added convenience features to the kubeconfig command for improved usability ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@a4010b3). +* **[talm] wrap upgrade command**: Wrapped upgrade command for better integration and error handling ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@2e1afbf). +* **[talm] docs(readme): add Homebrew installation option**: Added Homebrew installation option to the README for easier installation on macOS ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm@12bd4f2). +* **[talm] cozystack: disable nodeCIDRs allocation**: Disabled nodeCIDRs allocation in talm for better network configuration control ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#82). +* **[talm] Update license to Apache2.0**: Updated license to Apache 2.0 for better compatibility and clarity ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@eda1032). ## Fixes -* **[apps] Refactor apiserver to use typed objects and fix UnstructuredList GVK**: Refactored the apiserver REST handlers to use typed objects (`appsv1alpha1.Application`) instead of `unstructured.Unstructured`, eliminating the need for runtime conversions and simplifying the codebase. Additionally, fixed an issue where `UnstructuredList` objects were using the first registered kind from `typeToGVK` instead of the kind from the object's field when multiple kinds are registered with the same Go type. This fix includes the upstream fix from kubernetes/kubernetes#135537 ([**@kvaps**](https://github.com/kvaps) in #1679, #1709). -* **[dashboard] Fix CustomFormsOverride schema to nest properties under spec.properties**: Fixed the logic for generating CustomFormsOverride schema to properly nest properties under `spec.properties` instead of directly under `properties`, ensuring correct form schema generation ([**@kvaps**](https://github.com/kvaps) in #1692, #1700). -* **[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, #1701). -* **[linstor] Update piraeus-operator v2.10.2**: Updated LINSTOR CSI to fix issues with the new fsck behaviour, resolving mount failures when fsck attempts to run on mounted devices ([**@kvaps**](https://github.com/kvaps) in #1689, #1697). +* **[apps] Refactor apiserver to use typed objects and fix UnstructuredList GVK**: Refactored the apiserver REST handlers to use typed objects (`appsv1alpha1.Application`) instead of `unstructured.Unstructured`, eliminating the need for runtime conversions and simplifying the codebase. Additionally, fixed an issue where `UnstructuredList` objects were using the first registered kind from `typeToGVK` instead of the kind from the object's field when multiple kinds are registered with the same Go type. This fix includes the upstream fix from kubernetes/kubernetes#135537 ([**@kvaps**](https://github.com/kvaps) in #1679). +* **[dashboard] Fix CustomFormsOverride schema to nest properties under spec.properties**: Fixed the logic for generating CustomFormsOverride schema to properly nest properties under `spec.properties` instead of directly under `properties`, ensuring correct form schema generation ([**@kvaps**](https://github.com/kvaps) in #1692). +* **[virtual-machine] Improve check for resizing job**: Improved storage resize logic to only expand persistent volume claims when storage is being increased, preventing unintended storage reduction operations. Added validation to accurately compare current and desired storage sizes before triggering resize operations ([**@kvaps**](https://github.com/kvaps) in #1688). +* **[linstor] Update piraeus-operator v2.10.2**: Updated LINSTOR CSI to fix issues with the new fsck behaviour, resolving mount failures when fsck attempts to run on mounted devices ([**@kvaps**](https://github.com/kvaps) in #1689). * **[api] Revert dynamic list kinds representation fix (fixes namespace deletion regression)**: Reverted changes from #1630 that caused a regression affecting namespace deletion and upgrades from previous versions. The regression caused namespace deletion failures with errors like "content is not a list: []unstructured.Unstructured" during namespace finalization. This revert restores compatibility with namespace deletion controller and fixes upgrade issues from previous versions ([**@kvaps**](https://github.com/kvaps) in #1677). +* **[talm] fix: normalize template paths for Windows compatibility**: Fixed template path handling to ensure Windows compatibility by normalizing paths ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm#88). ## Dependencies -* **Update SeaweedFS v4.02**: Updated SeaweedFS to version 4.02 ([**@kvaps**](https://github.com/kvaps) in #1725, #1732). -* **[linstor] Update piraeus-operator v2.10.2**: Updated piraeus-operator to version 2.10.2 ([**@kvaps**](https://github.com/kvaps) in #1689, #1697). +* **Update SeaweedFS v4.02**: Updated SeaweedFS to version 4.02 ([**@kvaps**](https://github.com/kvaps) in #1725). +* **[linstor] Update piraeus-operator v2.10.2**: Updated piraeus-operator to version 2.10.2 ([**@kvaps**](https://github.com/kvaps) in #1689). +* **[talm] Cozystack: Update Talos Linux v1.11.3**: Updated talm to use Talos Linux v1.11.3 ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#83). ## Documentation +* **[website] Add article: Talm v0.17: Built-in Age Encryption for Secrets Management**: Added comprehensive blog post announcing Talm v0.17 and its built-in age-based encryption for secrets. Covers initial setup and key generation, encryption/decryption workflows, idempotent encryption behavior, automatic .gitignore handling, file permission safeguards, security best practices, and guidance for GitOps and CI/CD integration ([**@kvaps**](https://github.com/kvaps) in [cozystack/website#384](https://github.com/cozystack/website/pull/384)). * **[website] docs(talm): update talm init syntax for mandatory --preset and --name flags**: Updated documentation to reflect breaking changes in talm, adding mandatory `--preset` and `--name` flags to the talm init command ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#386). --- From 87fa8c93fcefa4a52e418d61eb89ccd89c3e14d0 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 24 Dec 2025 21:11:07 +0100 Subject: [PATCH 24/78] [workflows] Add auto patch release workflow (#1754) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds a new GitHub workflow that automatically creates patch releases for maintenance branches. ## What it does - Runs daily at 2:00 AM CET (1:00 UTC) - Checks all `release-X.Y` branches - For each branch, finds the latest published release with tag `vX.Y.Z` (without suffixes like -rc, -alpha, -beta) - If new commits exist after the release, creates a new tag `vX.Y.Z+1` and force-pushes it - This triggers the existing tag workflow to build and create a release PR ## Why releases instead of tags The workflow checks published releases (not just tags) because if a release PR hasn't been merged yet, the workflow should run again the next day and move the tag to newer commits if they exist. ## Summary by CodeRabbit * **Chores** * Automated patch release workflow configured for release branches, enabling automatic version tagging when new commits are detected. ✏️ Tip: You can customize this high-level summary in your review settings. --- .github/workflows/auto-release.yaml | 161 ++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 .github/workflows/auto-release.yaml diff --git a/.github/workflows/auto-release.yaml b/.github/workflows/auto-release.yaml new file mode 100644 index 00000000..c34c53b3 --- /dev/null +++ b/.github/workflows/auto-release.yaml @@ -0,0 +1,161 @@ +name: Auto Patch Release + +on: + schedule: + # Run daily at 2:00 AM CET (1:00 UTC in winter, 0:00 UTC in summer) + # Using 1:00 UTC to approximate 2:00 AM CET + - cron: '0 1 * * *' + workflow_dispatch: # Allow manual trigger + +concurrency: + group: auto-release-${{ github.workflow }} + cancel-in-progress: false + +jobs: + auto-release: + name: Auto Patch Release + runs-on: [self-hosted] + permissions: + contents: write + pull-requests: read + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Configure git + env: + GH_PAT: ${{ secrets.GH_PAT }} + run: | + git config user.name "cozystack-bot" + git config user.email "217169706+cozystack-bot@users.noreply.github.com" + git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY} + + - name: Process release branches + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GH_PAT }} + script: | + const { execSync } = require('child_process'); + + // Get all release-X.Y branches + const branches = execSync('git branch -r | grep -E "origin/release-[0-9]+\\.[0-9]+$" | sed "s|origin/||" | tr -d " "', { encoding: 'utf8' }) + .split('\n') + .filter(b => b.trim()) + .filter(b => /^release-\d+\.\d+$/.test(b)); + + console.log(`Found ${branches.length} release branches: ${branches.join(', ')}`); + + // Get all published releases (not draft) + const allReleases = await github.rest.repos.listReleases({ + owner: context.repo.owner, + repo: context.repo.repo, + per_page: 100 + }); + + // Filter to only published releases (not draft) with tags matching vX.Y.Z (no suffixes) + const publishedReleases = allReleases.data + .filter(r => !r.draft) + .filter(r => /^v\d+\.\d+\.\d+$/.test(r.tag_name)); + + console.log(`Found ${publishedReleases.length} published releases without suffixes`); + + for (const branch of branches) { + console.log(`\n=== Processing branch: ${branch} ===`); + + // Extract X.Y from branch name (release-X.Y) + const match = branch.match(/^release-(\d+\.\d+)$/); + if (!match) { + console.log(` ⚠️ Branch ${branch} doesn't match pattern, skipping`); + continue; + } + + const [major, minor] = match[1].split('.'); + const versionPrefix = `v${major}.${minor}.`; + + console.log(` Looking for releases with prefix: ${versionPrefix}`); + + // Find the latest published release for this branch (vX.Y.Z without suffixes) + const branchReleases = publishedReleases + .filter(r => r.tag_name.startsWith(versionPrefix)) + .filter(r => /^v\d+\.\d+\.\d+$/.test(r.tag_name)); // Ensure no suffixes + + if (branchReleases.length === 0) { + console.log(` ⚠️ No published releases found for ${branch}, skipping`); + continue; + } + + // Sort by version (descending) to get the latest + branchReleases.sort((a, b) => { + const aVersion = a.tag_name.match(/^v(\d+)\.(\d+)\.(\d+)$/); + const bVersion = b.tag_name.match(/^v(\d+)\.(\d+)\.(\d+)$/); + if (!aVersion || !bVersion) return 0; + + const aNum = parseInt(aVersion[1]) * 10000 + parseInt(aVersion[2]) * 100 + parseInt(aVersion[3]); + const bNum = parseInt(bVersion[1]) * 10000 + parseInt(bVersion[2]) * 100 + parseInt(bVersion[3]); + return bNum - aNum; + }); + + const latestRelease = branchReleases[0]; + console.log(` ✅ Latest published release: ${latestRelease.tag_name}`); + + // Get the commit SHA for this release tag + let releaseCommitSha; + try { + releaseCommitSha = execSync(`git rev-list -n 1 ${latestRelease.tag_name}`, { encoding: 'utf8' }).trim(); + console.log(` Release commit SHA: ${releaseCommitSha}`); + } catch (error) { + console.log(` ⚠️ Could not find commit for tag ${latestRelease.tag_name}, skipping`); + continue; + } + + // Checkout the branch + execSync(`git fetch origin ${branch}:${branch}`, { encoding: 'utf8' }); + execSync(`git checkout ${branch}`, { encoding: 'utf8' }); + + // Get the latest commit on the branch + const latestBranchCommit = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim(); + console.log(` Latest branch commit: ${latestBranchCommit}`); + + // Check if there are new commits after the release + const commitsAfterRelease = execSync( + `git rev-list ${releaseCommitSha}..HEAD --oneline`, + { encoding: 'utf8' } + ).trim(); + + if (!commitsAfterRelease) { + console.log(` ℹ️ No new commits after ${latestRelease.tag_name}, skipping`); + continue; + } + + console.log(` ✅ Found new commits after release:`); + console.log(commitsAfterRelease); + + // Calculate next version (Z+1) + const versionMatch = latestRelease.tag_name.match(/^v(\d+)\.(\d+)\.(\d+)$/); + if (!versionMatch) { + console.log(` ❌ Could not parse version from ${latestRelease.tag_name}, skipping`); + continue; + } + + const nextPatch = parseInt(versionMatch[3]) + 1; + const nextTag = `v${versionMatch[1]}.${versionMatch[2]}.${nextPatch}`; + + console.log(` 🏷️ Creating new tag: ${nextTag} on commit ${latestBranchCommit}`); + + // Create and push the tag (force push to update if exists) + try { + execSync(`git tag -f ${nextTag} ${latestBranchCommit}`, { encoding: 'utf8' }); + execSync(`git push -f origin ${nextTag}`, { encoding: 'utf8' }); + console.log(` ✅ Successfully created and pushed tag ${nextTag}`); + } catch (error) { + console.log(` ❌ Error creating/pushing tag ${nextTag}: ${error.message}`); + core.setFailed(`Failed to create tag ${nextTag} for branch ${branch}`); + } + } + + console.log(`\n✅ Finished processing all release branches`); + From 9ab7430cecc1d2be7d7a02cf929e1efef22ecac4 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 25 Dec 2025 10:39:21 +0100 Subject: [PATCH 25/78] [workflow] Push tags as cozystack-bot to trigger GitHub workflows Signed-off-by: Andrei Kvapil --- .github/workflows/pull-requests-release.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/pull-requests-release.yaml b/.github/workflows/pull-requests-release.yaml index 7b047474..1e13fa88 100644 --- a/.github/workflows/pull-requests-release.yaml +++ b/.github/workflows/pull-requests-release.yaml @@ -46,7 +46,12 @@ jobs: fetch-depth: 0 - name: Create tag on merge commit + env: + GH_PAT: ${{ secrets.GH_PAT }} run: | + git config user.name "cozystack-bot" + git config user.email "217169706+cozystack-bot@users.noreply.github.com" + git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY} git tag -f ${{ steps.get_tag.outputs.tag }} ${{ github.sha }} git push -f origin ${{ steps.get_tag.outputs.tag }} From f400310f285fbd456e8f47df686c272473680084 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 25 Dec 2025 10:45:02 +0100 Subject: [PATCH 26/78] [agents] Add instructions for working with unresolved code review comments (#1710) Signed-off-by: Andrei Kvapil ## What this PR does ### Release note ```release-note [agents] Add instructions for working with unresolved code review comments ``` --- AGENTS.md | 38 ++++++++++++++--- docs/agents/contributing.md | 85 +++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 7 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index d78d0d23..eb1febf7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,14 +3,38 @@ This file provides structured guidance for AI coding assistants and agents working with the **Cozystack** project. -## Agent Documentation +## Activation -| Agent | Purpose | -|-------|---------| -| [overview.md](./docs/agents/overview.md) | Project structure and conventions | -| [contributing.md](./docs/agents/contributing.md) | Commits, pull requests, and git workflow | -| [changelog.md](./docs/agents/changelog.md) | Changelog generation instructions | -| [releasing.md](./docs/agents/releasing.md) | Release process and workflow | +**CRITICAL**: When the user asks you to do something that matches the scope of a documented process, you MUST read the corresponding documentation file and follow the instructions exactly as written. + +- **Commits, PRs, git operations** (e.g., "create a commit", "make a PR", "fix review comments", "rebase", "cherry-pick") + - Read: [`contributing.md`](./docs/agents/contributing.md) + - Action: Read the entire file and follow ALL instructions step-by-step + +- **Changelog generation** (e.g., "generate changelog", "create changelog", "prepare changelog for version X") + - Read: [`changelog.md`](./docs/agents/changelog.md) + - Action: Read the entire file and follow ALL steps in the checklist. Do NOT skip any mandatory steps + +- **Release creation** (e.g., "create release", "prepare release", "tag release", "make a release") + - Read: [`releasing.md`](./docs/agents/releasing.md) + - Action: Read the file and follow the referenced release process in `docs/release.md` + +- **Project structure, conventions, code layout** (e.g., "where should I put X", "what's the convention for Y", "how is the project organized") + - Read: [`overview.md`](./docs/agents/overview.md) + - Action: Read relevant sections to understand project structure and conventions + +- **General questions about contributing** + - Read: [`contributing.md`](./docs/agents/contributing.md) + - Action: Read the file to understand git workflow, commit format, PR process + +**Important rules:** +- ✅ **ONLY read the file if the task matches the documented process scope** - do not read files for tasks that don't match their purpose +- ✅ **ALWAYS read the file FIRST** before starting the task (when applicable) +- ✅ **Follow instructions EXACTLY** as written in the documentation +- ✅ **Do NOT skip mandatory steps** (especially in changelog.md) +- ✅ **Do NOT assume** you know the process - always check the documentation when the task matches +- ❌ **Do NOT read files** for tasks that are outside their documented scope +- 📖 **Note**: [`overview.md`](./docs/agents/overview.md) can be useful as a reference to understand project structure and conventions, even when not explicitly required by the task ## Project Overview diff --git a/docs/agents/contributing.md b/docs/agents/contributing.md index e0519b5c..4a2a7ef9 100644 --- a/docs/agents/contributing.md +++ b/docs/agents/contributing.md @@ -155,6 +155,91 @@ 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=' +query($owner: String!, $repo: String!, $pr: Int!) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $pr) { + reviewThreads(first: 100) { + nodes { + isResolved + comments(first: 100) { + nodes { + id + path + line + author { login } + bodyText + url + createdAt + } + } + } + } + } + } +}' --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | .comments.nodes[]' +``` + +### 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=' +query($owner: String!, $repo: String!, $pr: Int!) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $pr) { + reviewThreads(first: 100) { + nodes { + isResolved + comments(first: 100) { + nodes { + path + line + author { login } + bodyText + } + } + } + } + } + } +}' --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | .comments.nodes[] | "\(.path):\(.line // "N/A") - \(.author.login): \(.bodyText[:150])"' +``` + +### 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 From ffd10e99f12b4cbb96c1d57af5514a7c026411a8 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Mon, 29 Dec 2025 12:52:13 +0400 Subject: [PATCH 27/78] [platform] Add alphabetical sorting to registry resource lists (#1764) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does Adds deterministic alphabetical sorting to all registry resource lists: - TenantNamespace (sorted by name) - TenantSecret (sorted by namespace/name) - TenantModule (sorted by namespace/name) - Application (sorted by namespace/name) Introduces a new `pkg/registry/sorting` package with generic helper functions to avoid code duplication. Also fixes pre-existing linter errors: - Unused `helmReleaseGVR` variables - Non-constant format strings in `klog.Errorf` calls - Redundant embedded field selectors ### Release note ```release-note [platform] Registry resource lists are now returned in alphabetical order ``` ## Summary by CodeRabbit * **New Features** * Added a reusable alphabetical sorting utility and applied consistent sorting across list endpoints. * **Bug Fixes** * Ensured ResourceVersion/UID are sourced correctly for accurate list/table responses. * Simplified and improved error logging and table ResourceVersion handling. * Made schema defaulting behavior more consistent. * **Tests** * Added unit tests validating alphabetical sorting for multiple resource types. ✏️ Tip: You can customize this high-level summary in your review settings. --- pkg/registry/apps/application/rest.go | 25 ++++---- .../apps/application/rest_defaulting.go | 18 +++--- .../apps/application/rest_sorting_test.go | 36 +++++++++++ pkg/registry/core/tenantmodule/rest.go | 16 ++--- pkg/registry/core/tenantmodule/rest_test.go | 36 +++++++++++ pkg/registry/core/tenantnamespace/rest.go | 8 ++- .../core/tenantnamespace/rest_test.go | 40 +++++++++++++ pkg/registry/core/tenantsecret/rest.go | 18 ++---- pkg/registry/sorting/sort.go | 47 +++++++++++++++ pkg/registry/sorting/sort_test.go | 60 +++++++++++++++++++ 10 files changed, 254 insertions(+), 50 deletions(-) create mode 100644 pkg/registry/apps/application/rest_sorting_test.go create mode 100644 pkg/registry/core/tenantmodule/rest_test.go create mode 100644 pkg/registry/core/tenantnamespace/rest_test.go create mode 100644 pkg/registry/sorting/sort.go create mode 100644 pkg/registry/sorting/sort_test.go diff --git a/pkg/registry/apps/application/rest.go b/pkg/registry/apps/application/rest.go index 78ff8dbc..ee189e26 100644 --- a/pkg/registry/apps/application/rest.go +++ b/pkg/registry/apps/application/rest.go @@ -42,6 +42,7 @@ import ( appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" "github.com/cozystack/cozystack/pkg/config" + "github.com/cozystack/cozystack/pkg/registry/sorting" internalapiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema" @@ -74,13 +75,6 @@ const ( ApplicationNameLabel = appsv1alpha1.ApplicationNameLabel ) -// Define the GroupVersionResource for HelmRelease -var helmReleaseGVR = schema.GroupVersionResource{ - Group: "helm.toolkit.fluxcd.io", - Version: "v2", - Resource: "helmreleases", -} - // REST implements the RESTStorage interface for Application resources type REST struct { c client.Client @@ -394,6 +388,8 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption appList.SetResourceVersion(hrList.GetResourceVersion()) appList.Items = items + sorting.ByNamespacedName[appsv1alpha1.Application, *appsv1alpha1.Application](appList.Items) + klog.V(6).Infof("Successfully listed %d Application resources in namespace %s", len(items), namespace) return appList, nil } @@ -442,9 +438,8 @@ func (r *REST) Update(ctx context.Context, name string, objInfo rest.UpdatedObje // Assert the new object is of type Application app, ok := newObj.(*appsv1alpha1.Application) if !ok { - errMsg := fmt.Sprintf("expected *appsv1alpha1.Application object, got %T", newObj) - klog.Errorf(errMsg) - return nil, false, fmt.Errorf(errMsg) + klog.Errorf("expected *appsv1alpha1.Application object, got %T", newObj) + return nil, false, fmt.Errorf("expected *appsv1alpha1.Application object, got %T", newObj) } // Convert Application to HelmRelease @@ -757,7 +752,7 @@ func (r *REST) getNamespace(ctx context.Context) (string, error) { namespace, ok := request.NamespaceFrom(ctx) if !ok { err := fmt.Errorf("namespace not found in context") - klog.Errorf(err.Error()) + klog.Error(err) return "", err } return namespace, nil @@ -913,8 +908,8 @@ func (r *REST) convertApplicationToHelmRelease(app *appsv1alpha1.Application) (* Namespace: app.Namespace, Labels: addPrefixedMap(app.Labels, LabelPrefix), Annotations: addPrefixedMap(app.Annotations, AnnotationPrefix), - ResourceVersion: app.ObjectMeta.ResourceVersion, - UID: app.ObjectMeta.UID, + ResourceVersion: app.ResourceVersion, + UID: app.UID, }, Spec: helmv2.HelmReleaseSpec{ Chart: &helmv2.HelmChartTemplate{ @@ -956,10 +951,10 @@ func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableO switch obj := object.(type) { case *appsv1alpha1.ApplicationList: table = r.buildTableFromApplications(obj.Items) - table.ListMeta.ResourceVersion = obj.ListMeta.ResourceVersion + table.ResourceVersion = obj.ResourceVersion case *appsv1alpha1.Application: table = r.buildTableFromApplication(*obj) - table.ListMeta.ResourceVersion = obj.GetResourceVersion() + table.ResourceVersion = obj.GetResourceVersion() default: resource := schema.GroupResource{} if info, ok := request.RequestInfoFrom(ctx); ok { diff --git a/pkg/registry/apps/application/rest_defaulting.go b/pkg/registry/apps/application/rest_defaulting.go index 6630a08b..36518af6 100644 --- a/pkg/registry/apps/application/rest_defaulting.go +++ b/pkg/registry/apps/application/rest_defaulting.go @@ -72,7 +72,7 @@ func applyDefaults(v any, s *structuralschema.Structural, top bool) (any, error) return v, nil } - effType := s.Generic.Type + effType := s.Type if effType == "" { switch { case len(s.Properties) > 0 || (s.AdditionalProperties != nil && s.AdditionalProperties.Structural != nil): @@ -88,8 +88,8 @@ func applyDefaults(v any, s *structuralschema.Structural, top bool) (any, error) case "object": mv, isMap := v.(map[string]any) if !isMap || v == nil { - if s.Generic.Default.Object != nil && !top { - if dm, ok := s.Generic.Default.Object.(map[string]any); ok { + if s.Default.Object != nil && !top { + if dm, ok := s.Default.Object.(map[string]any); ok { mv = cloneMap(dm) } } @@ -100,8 +100,8 @@ func applyDefaults(v any, s *structuralschema.Structural, top bool) (any, error) for name, ps := range s.Properties { if _, ok := mv[name]; !ok { - if ps.Generic.Default.Object != nil { - mv[name] = clone(ps.Generic.Default.Object) + if ps.Default.Object != nil { + mv[name] = clone(ps.Default.Object) } } if cur, ok := mv[name]; ok { @@ -131,8 +131,8 @@ func applyDefaults(v any, s *structuralschema.Structural, top bool) (any, error) case "array": sl, isSlice := v.([]any) if !isSlice || v == nil { - if s.Generic.Default.Object != nil { - if ds, ok := s.Generic.Default.Object.([]any); ok { + if s.Default.Object != nil { + if ds, ok := s.Default.Object.([]any); ok { sl = cloneSlice(ds) } } @@ -152,8 +152,8 @@ func applyDefaults(v any, s *structuralschema.Structural, top bool) (any, error) return sl, nil default: - if v == nil && s.Generic.Default.Object != nil { - return clone(s.Generic.Default.Object), nil + if v == nil && s.Default.Object != nil { + return clone(s.Default.Object), nil } return v, nil } diff --git a/pkg/registry/apps/application/rest_sorting_test.go b/pkg/registry/apps/application/rest_sorting_test.go new file mode 100644 index 00000000..6b3f6162 --- /dev/null +++ b/pkg/registry/apps/application/rest_sorting_test.go @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: Apache-2.0 + +package application + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + "github.com/cozystack/cozystack/pkg/registry/sorting" +) + +func TestApplicationListSortsAlphabetically(t *testing.T) { + items := []appsv1alpha1.Application{ + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-b", Name: "zebra"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-a", Name: "alpha"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-b", Name: "alpha"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-a", Name: "bravo"}}, + } + + sorting.ByNamespacedName[appsv1alpha1.Application, *appsv1alpha1.Application](items) + + expected := []struct{ ns, name string }{ + {"ns-a", "alpha"}, + {"ns-a", "bravo"}, + {"ns-b", "alpha"}, + {"ns-b", "zebra"}, + } + + for i, exp := range expected { + if items[i].Namespace != exp.ns || items[i].Name != exp.name { + t.Errorf("item %d: expected %s/%s, got %s/%s", i, exp.ns, exp.name, items[i].Namespace, items[i].Name) + } + } +} diff --git a/pkg/registry/core/tenantmodule/rest.go b/pkg/registry/core/tenantmodule/rest.go index 8ca27dde..12da0e0d 100644 --- a/pkg/registry/core/tenantmodule/rest.go +++ b/pkg/registry/core/tenantmodule/rest.go @@ -40,6 +40,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" + "github.com/cozystack/cozystack/pkg/registry/sorting" apierrors "k8s.io/apimachinery/pkg/api/errors" ) @@ -60,13 +61,6 @@ const ( singularName = "tenantmodule" ) -// Define the GroupVersionResource for HelmRelease -var helmReleaseGVR = schema.GroupVersionResource{ - Group: "helm.toolkit.fluxcd.io", - Version: "v2", - Resource: "helmreleases", -} - // REST implements the RESTStorage interface for TenantModule resources type REST struct { c client.Client @@ -288,6 +282,8 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption moduleList.SetResourceVersion(hrList.GetResourceVersion()) moduleList.Items = items + sorting.ByNamespacedName[corev1alpha1.TenantModule, *corev1alpha1.TenantModule](moduleList.Items) + klog.V(6).Infof("Successfully listed %d TenantModule resources in namespace %s", len(items), namespace) return moduleList, nil } @@ -514,7 +510,7 @@ func (r *REST) getNamespace(ctx context.Context) (string, error) { namespace, ok := request.NamespaceFrom(ctx) if !ok { err := fmt.Errorf("namespace not found in context") - klog.Errorf(err.Error()) + klog.Error(err) return "", err } return namespace, nil @@ -593,10 +589,10 @@ func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableO switch obj := object.(type) { case *corev1alpha1.TenantModuleList: table = r.buildTableFromTenantModules(obj.Items) - table.ListMeta.ResourceVersion = obj.ListMeta.ResourceVersion + table.ResourceVersion = obj.ResourceVersion case *corev1alpha1.TenantModule: table = r.buildTableFromTenantModule(*obj) - table.ListMeta.ResourceVersion = obj.GetResourceVersion() + table.ResourceVersion = obj.GetResourceVersion() default: resource := schema.GroupResource{} if info, ok := request.RequestInfoFrom(ctx); ok { diff --git a/pkg/registry/core/tenantmodule/rest_test.go b/pkg/registry/core/tenantmodule/rest_test.go new file mode 100644 index 00000000..ceed9e7b --- /dev/null +++ b/pkg/registry/core/tenantmodule/rest_test.go @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: Apache-2.0 + +package tenantmodule + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" + "github.com/cozystack/cozystack/pkg/registry/sorting" +) + +func TestTenantModuleListSortsAlphabetically(t *testing.T) { + items := []corev1alpha1.TenantModule{ + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-b", Name: "zebra"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-a", Name: "alpha"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-b", Name: "alpha"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-a", Name: "bravo"}}, + } + + sorting.ByNamespacedName[corev1alpha1.TenantModule, *corev1alpha1.TenantModule](items) + + expected := []struct{ ns, name string }{ + {"ns-a", "alpha"}, + {"ns-a", "bravo"}, + {"ns-b", "alpha"}, + {"ns-b", "zebra"}, + } + + for i, exp := range expected { + if items[i].Namespace != exp.ns || items[i].Name != exp.name { + t.Errorf("item %d: expected %s/%s, got %s/%s", i, exp.ns, exp.name, items[i].Namespace, items[i].Name) + } + } +} diff --git a/pkg/registry/core/tenantnamespace/rest.go b/pkg/registry/core/tenantnamespace/rest.go index 68d9fe3c..90d5920d 100644 --- a/pkg/registry/core/tenantnamespace/rest.go +++ b/pkg/registry/core/tenantnamespace/rest.go @@ -26,6 +26,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" + "github.com/cozystack/cozystack/pkg/registry/sorting" ) const ( @@ -206,10 +207,10 @@ func (r *REST) ConvertToTable(_ context.Context, obj runtime.Object, _ runtime.O for i := range v.Items { tbl.Rows = append(tbl.Rows, row(&v.Items[i])) } - tbl.ListMeta.ResourceVersion = v.ListMeta.ResourceVersion + tbl.ResourceVersion = v.ResourceVersion case *corev1alpha1.TenantNamespace: tbl.Rows = append(tbl.Rows, row(v)) - tbl.ListMeta.ResourceVersion = v.ResourceVersion + tbl.ResourceVersion = v.ResourceVersion default: return nil, notAcceptable{r.gvr.GroupResource(), fmt.Sprintf("unexpected %T", obj)} } @@ -254,6 +255,9 @@ func (r *REST) makeList(src *corev1.NamespaceList, allowed []string) *corev1alph }, }) } + + sorting.ByName[corev1alpha1.TenantNamespace, *corev1alpha1.TenantNamespace](out.Items) + return out } diff --git a/pkg/registry/core/tenantnamespace/rest_test.go b/pkg/registry/core/tenantnamespace/rest_test.go new file mode 100644 index 00000000..7f2979bc --- /dev/null +++ b/pkg/registry/core/tenantnamespace/rest_test.go @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 + +package tenantnamespace + +import ( + "testing" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestMakeListSortsAlphabetically(t *testing.T) { + r := &REST{} + + // Create namespaces in non-alphabetical order + src := &corev1.NamespaceList{ + Items: []corev1.Namespace{ + {ObjectMeta: metav1.ObjectMeta{Name: "tenant-zebra"}}, + {ObjectMeta: metav1.ObjectMeta{Name: "tenant-alpha"}}, + {ObjectMeta: metav1.ObjectMeta{Name: "tenant-mike"}}, + {ObjectMeta: metav1.ObjectMeta{Name: "tenant-bravo"}}, + }, + } + + allowed := []string{"tenant-zebra", "tenant-alpha", "tenant-mike", "tenant-bravo"} + + result := r.makeList(src, allowed) + + expected := []string{"tenant-alpha", "tenant-bravo", "tenant-mike", "tenant-zebra"} + + if len(result.Items) != len(expected) { + t.Fatalf("expected %d items, got %d", len(expected), len(result.Items)) + } + + for i, name := range expected { + if result.Items[i].Name != name { + t.Errorf("item %d: expected %q, got %q", i, name, result.Items[i].Name) + } + } +} diff --git a/pkg/registry/core/tenantsecret/rest.go b/pkg/registry/core/tenantsecret/rest.go index b1667c45..e5dbf9dd 100644 --- a/pkg/registry/core/tenantsecret/rest.go +++ b/pkg/registry/core/tenantsecret/rest.go @@ -9,7 +9,6 @@ import ( "encoding/base64" "fmt" "net/http" - "slices" "time" corev1 "k8s.io/api/core/v1" @@ -28,6 +27,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" + "github.com/cozystack/cozystack/pkg/registry/sorting" ) // ----------------------------------------------------------------------------- @@ -278,17 +278,7 @@ func (r *REST) List(ctx context.Context, opts *metainternal.ListOptions) (runtim for i := range list.Items { out.Items = append(out.Items, *secretToTenant(&list.Items[i])) } - slices.SortFunc(out.Items, func(a, b corev1alpha1.TenantSecret) int { - aKey := fmt.Sprintf("%s/%s", a.Namespace, a.Name) - bKey := fmt.Sprintf("%s/%s", b.Namespace, b.Name) - switch { - case aKey < bKey: - return -1 - case aKey > bKey: - return 1 - } - return 0 - }) + sorting.ByNamespacedName[corev1alpha1.TenantSecret, *corev1alpha1.TenantSecret](out.Items) return out, nil } @@ -481,10 +471,10 @@ func (r *REST) ConvertToTable(_ context.Context, obj runtime.Object, _ runtime.O for i := range v.Items { tbl.Rows = append(tbl.Rows, row(&v.Items[i])) } - tbl.ListMeta.ResourceVersion = v.ListMeta.ResourceVersion + tbl.ResourceVersion = v.ResourceVersion case *corev1alpha1.TenantSecret: tbl.Rows = append(tbl.Rows, row(v)) - tbl.ListMeta.ResourceVersion = v.ResourceVersion + tbl.ResourceVersion = v.ResourceVersion default: return nil, notAcceptable{r.gvr.GroupResource(), fmt.Sprintf("unexpected %T", obj)} } diff --git a/pkg/registry/sorting/sort.go b/pkg/registry/sorting/sort.go new file mode 100644 index 00000000..ff4b0ecb --- /dev/null +++ b/pkg/registry/sorting/sort.go @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: Apache-2.0 + +// Package sorting provides generic sorting utilities for registry resources. +package sorting + +import ( + "slices" + "strings" +) + +// NameGetter is an interface for objects that have a Name. +type NameGetter interface { + GetName() string +} + +// NamespaceGetter is an interface for objects that have both Name and Namespace. +type NamespaceGetter interface { + NameGetter + GetNamespace() string +} + +// ByName sorts a slice of objects by their Name in alphabetical order. +// Use this for cluster-scoped resources. +func ByName[T any, PT interface { + *T + NameGetter +}](items []T) { + slices.SortFunc(items, func(a, b T) int { + pa, pb := PT(&a), PT(&b) + return strings.Compare(pa.GetName(), pb.GetName()) + }) +} + +// ByNamespacedName sorts a slice of objects by Namespace/Name in alphabetical order. +// Use this for namespace-scoped resources. +func ByNamespacedName[T any, PT interface { + *T + NamespaceGetter +}](items []T) { + slices.SortFunc(items, func(a, b T) int { + pa, pb := PT(&a), PT(&b) + if res := strings.Compare(pa.GetNamespace(), pb.GetNamespace()); res != 0 { + return res + } + return strings.Compare(pa.GetName(), pb.GetName()) + }) +} diff --git a/pkg/registry/sorting/sort_test.go b/pkg/registry/sorting/sort_test.go new file mode 100644 index 00000000..d76f3865 --- /dev/null +++ b/pkg/registry/sorting/sort_test.go @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: Apache-2.0 + +package sorting + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type testClusterScoped struct { + metav1.ObjectMeta +} + +type testNamespaceScoped struct { + metav1.ObjectMeta +} + +func TestByName(t *testing.T) { + items := []testClusterScoped{ + {ObjectMeta: metav1.ObjectMeta{Name: "zebra"}}, + {ObjectMeta: metav1.ObjectMeta{Name: "alpha"}}, + {ObjectMeta: metav1.ObjectMeta{Name: "mike"}}, + {ObjectMeta: metav1.ObjectMeta{Name: "bravo"}}, + } + + ByName[testClusterScoped, *testClusterScoped](items) + + expected := []string{"alpha", "bravo", "mike", "zebra"} + + for i, name := range expected { + if items[i].Name != name { + t.Errorf("item %d: expected %q, got %q", i, name, items[i].Name) + } + } +} + +func TestByNamespacedName(t *testing.T) { + items := []testNamespaceScoped{ + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-b", Name: "zebra"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-a", Name: "alpha"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-b", Name: "alpha"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-a", Name: "bravo"}}, + } + + ByNamespacedName[testNamespaceScoped, *testNamespaceScoped](items) + + expected := []struct{ ns, name string }{ + {"ns-a", "alpha"}, + {"ns-a", "bravo"}, + {"ns-b", "alpha"}, + {"ns-b", "zebra"}, + } + + for i, exp := range expected { + if items[i].Namespace != exp.ns || items[i].Name != exp.name { + t.Errorf("item %d: expected %s/%s, got %s/%s", i, exp.ns, exp.name, items[i].Namespace, items[i].Name) + } + } +} From 654eb7c3f9a8f32eeda39b303083bb8aa9b4b1d9 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 29 Dec 2025 13:56:09 +0100 Subject: [PATCH 28/78] [cozystack-controller] Fix: move crds to definitions (#1759) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andrei Kvapil ## What this PR does ### Release note ```release-note [cozystack-controller] Fix: move crds to definitions ``` ## Summary by CodeRabbit * **Chores** * Updated the Custom Resource Definition generation template to source files from a new location, ensuring consistent configuration management. ✏️ Tip: You can customize this high-level summary in your review settings. --- .../{crds => definitions}/cozystack.io_workloadmonitors.yaml | 0 .../{crds => definitions}/cozystack.io_workloads.yaml | 0 .../dashboard.cozystack.io_breadcrumbs.yaml | 0 .../dashboard.cozystack.io_breadcrumbsinside.yaml | 0 .../dashboard.cozystack.io_customcolumnsoverrides.yaml | 0 .../dashboard.cozystack.io_customformsoverrides.yaml | 0 .../dashboard.cozystack.io_customformsprefills.yaml | 0 .../{crds => definitions}/dashboard.cozystack.io_factories.yaml | 0 .../dashboard.cozystack.io_marketplacepanels.yaml | 0 .../dashboard.cozystack.io_navigations.yaml | 0 .../{crds => definitions}/dashboard.cozystack.io_sidebars.yaml | 0 .../dashboard.cozystack.io_tableurimappings.yaml | 0 packages/system/cozystack-controller/templates/crds/crds.yaml | 2 +- 13 files changed, 1 insertion(+), 1 deletion(-) rename packages/system/cozystack-controller/{crds => definitions}/cozystack.io_workloadmonitors.yaml (100%) rename packages/system/cozystack-controller/{crds => definitions}/cozystack.io_workloads.yaml (100%) rename packages/system/cozystack-controller/{crds => definitions}/dashboard.cozystack.io_breadcrumbs.yaml (100%) rename packages/system/cozystack-controller/{crds => definitions}/dashboard.cozystack.io_breadcrumbsinside.yaml (100%) rename packages/system/cozystack-controller/{crds => definitions}/dashboard.cozystack.io_customcolumnsoverrides.yaml (100%) rename packages/system/cozystack-controller/{crds => definitions}/dashboard.cozystack.io_customformsoverrides.yaml (100%) rename packages/system/cozystack-controller/{crds => definitions}/dashboard.cozystack.io_customformsprefills.yaml (100%) rename packages/system/cozystack-controller/{crds => definitions}/dashboard.cozystack.io_factories.yaml (100%) rename packages/system/cozystack-controller/{crds => definitions}/dashboard.cozystack.io_marketplacepanels.yaml (100%) rename packages/system/cozystack-controller/{crds => definitions}/dashboard.cozystack.io_navigations.yaml (100%) rename packages/system/cozystack-controller/{crds => definitions}/dashboard.cozystack.io_sidebars.yaml (100%) rename packages/system/cozystack-controller/{crds => definitions}/dashboard.cozystack.io_tableurimappings.yaml (100%) diff --git a/packages/system/cozystack-controller/crds/cozystack.io_workloadmonitors.yaml b/packages/system/cozystack-controller/definitions/cozystack.io_workloadmonitors.yaml similarity index 100% rename from packages/system/cozystack-controller/crds/cozystack.io_workloadmonitors.yaml rename to packages/system/cozystack-controller/definitions/cozystack.io_workloadmonitors.yaml diff --git a/packages/system/cozystack-controller/crds/cozystack.io_workloads.yaml b/packages/system/cozystack-controller/definitions/cozystack.io_workloads.yaml similarity index 100% rename from packages/system/cozystack-controller/crds/cozystack.io_workloads.yaml rename to packages/system/cozystack-controller/definitions/cozystack.io_workloads.yaml diff --git a/packages/system/cozystack-controller/crds/dashboard.cozystack.io_breadcrumbs.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_breadcrumbs.yaml similarity index 100% rename from packages/system/cozystack-controller/crds/dashboard.cozystack.io_breadcrumbs.yaml rename to packages/system/cozystack-controller/definitions/dashboard.cozystack.io_breadcrumbs.yaml diff --git a/packages/system/cozystack-controller/crds/dashboard.cozystack.io_breadcrumbsinside.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_breadcrumbsinside.yaml similarity index 100% rename from packages/system/cozystack-controller/crds/dashboard.cozystack.io_breadcrumbsinside.yaml rename to packages/system/cozystack-controller/definitions/dashboard.cozystack.io_breadcrumbsinside.yaml diff --git a/packages/system/cozystack-controller/crds/dashboard.cozystack.io_customcolumnsoverrides.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_customcolumnsoverrides.yaml similarity index 100% rename from packages/system/cozystack-controller/crds/dashboard.cozystack.io_customcolumnsoverrides.yaml rename to packages/system/cozystack-controller/definitions/dashboard.cozystack.io_customcolumnsoverrides.yaml diff --git a/packages/system/cozystack-controller/crds/dashboard.cozystack.io_customformsoverrides.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_customformsoverrides.yaml similarity index 100% rename from packages/system/cozystack-controller/crds/dashboard.cozystack.io_customformsoverrides.yaml rename to packages/system/cozystack-controller/definitions/dashboard.cozystack.io_customformsoverrides.yaml diff --git a/packages/system/cozystack-controller/crds/dashboard.cozystack.io_customformsprefills.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_customformsprefills.yaml similarity index 100% rename from packages/system/cozystack-controller/crds/dashboard.cozystack.io_customformsprefills.yaml rename to packages/system/cozystack-controller/definitions/dashboard.cozystack.io_customformsprefills.yaml diff --git a/packages/system/cozystack-controller/crds/dashboard.cozystack.io_factories.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_factories.yaml similarity index 100% rename from packages/system/cozystack-controller/crds/dashboard.cozystack.io_factories.yaml rename to packages/system/cozystack-controller/definitions/dashboard.cozystack.io_factories.yaml diff --git a/packages/system/cozystack-controller/crds/dashboard.cozystack.io_marketplacepanels.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_marketplacepanels.yaml similarity index 100% rename from packages/system/cozystack-controller/crds/dashboard.cozystack.io_marketplacepanels.yaml rename to packages/system/cozystack-controller/definitions/dashboard.cozystack.io_marketplacepanels.yaml diff --git a/packages/system/cozystack-controller/crds/dashboard.cozystack.io_navigations.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_navigations.yaml similarity index 100% rename from packages/system/cozystack-controller/crds/dashboard.cozystack.io_navigations.yaml rename to packages/system/cozystack-controller/definitions/dashboard.cozystack.io_navigations.yaml diff --git a/packages/system/cozystack-controller/crds/dashboard.cozystack.io_sidebars.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_sidebars.yaml similarity index 100% rename from packages/system/cozystack-controller/crds/dashboard.cozystack.io_sidebars.yaml rename to packages/system/cozystack-controller/definitions/dashboard.cozystack.io_sidebars.yaml diff --git a/packages/system/cozystack-controller/crds/dashboard.cozystack.io_tableurimappings.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_tableurimappings.yaml similarity index 100% rename from packages/system/cozystack-controller/crds/dashboard.cozystack.io_tableurimappings.yaml rename to packages/system/cozystack-controller/definitions/dashboard.cozystack.io_tableurimappings.yaml diff --git a/packages/system/cozystack-controller/templates/crds/crds.yaml b/packages/system/cozystack-controller/templates/crds/crds.yaml index 0a98dd32..2cf3183b 100644 --- a/packages/system/cozystack-controller/templates/crds/crds.yaml +++ b/packages/system/cozystack-controller/templates/crds/crds.yaml @@ -1,4 +1,4 @@ -{{- range $path, $_ := .Files.Glob "crds/*" }} +{{- range $path, $_ := .Files.Glob "definitions/*" }} --- {{ $.Files.Get $path }} {{- end }} From f3c178e30ddaae0c1b202d2f72e9aebb8c28d293 Mon Sep 17 00:00:00 2001 From: Aleksei Sviridkin Date: Mon, 29 Dec 2025 16:04:02 +0300 Subject: [PATCH 29/78] [cilium] Update Cilium to v1.18.5 (#1769) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does - Update Cilium from v1.17.8 to v1.18.5 - Add `SED_INPLACE` variable to `scripts/common-envs.mk` for macOS compatibility - Remove deprecated `enableRuntimeDeviceDetection` option (now default behavior in 1.18) Cilium 1.18 requires Linux kernel 5.10+ (compatible with Talos). References: - [Cilium 1.18 Upgrade Guide](https://docs.cilium.io/en/stable/operations/upgrade/) - [Cilium 1.18 Release Blog](https://isovalent.com/blog/post/cilium-1-18/) ### Release note ```release-note [cilium] Update Cilium to v1.18.5 ``` ## Summary by CodeRabbit ## Release Notes * **New Features** * Added configurable Kubernetes service discovery with ConfigMap-based endpoint source * Introduced exponential backoff settings for Kubernetes API client connections * Added metrics sampling interval configuration for internal agent metrics * Implemented identity management mode options for endpoint slices and DNS proxy pre-allocation * Enhanced Prometheus scrape timeout configuration across monitoring components * **Improvements** * Upgraded core components to v1.18.5 * Strengthened security defaults by disabling privilege escalation across pods * Added startup and liveness probe configurations for improved health monitoring * Extended network policy correlation capabilities in Hubble ✏️ Tip: You can customize this high-level summary in your review settings. --- packages/system/cilium/Makefile | 6 +- .../system/cilium/charts/cilium/Chart.yaml | 128 +- .../system/cilium/charts/cilium/README.md | 160 +- .../dashboards/cilium-dashboard.json | 2228 +++++++---------- .../configmap/bootstrap-config.yaml | 6 +- .../cilium/charts/cilium/templates/NOTES.txt | 7 + .../charts/cilium/templates/_helpers.tpl | 9 +- .../templates/cilium-agent/clusterrole.yaml | 11 +- .../templates/cilium-agent/daemonset.yaml | 55 +- .../cilium/templates/cilium-agent/role.yaml | 2 +- .../templates/cilium-agent/rolebinding.yaml | 4 +- .../cilium-agent/servicemonitor.yaml | 4 + .../cilium/templates/cilium-ca-secret.yaml | 2 +- .../cilium/templates/cilium-configmap.yaml | 122 +- .../templates/cilium-envoy/configmap.yaml | 2 +- .../templates/cilium-envoy/daemonset.yaml | 13 + .../cilium-envoy/servicemonitor.yaml | 3 + .../templates/cilium-flowlog-configmap.yaml | 15 +- .../templates/cilium-ingress-service.yaml | 6 +- .../cilium-operator/clusterrole.yaml | 28 +- .../templates/cilium-operator/deployment.yaml | 13 + .../cilium-operator/poddisruptionbudget.yaml | 7 + .../cilium-operator/rolebinding.yaml | 2 +- .../cilium-operator/servicemonitor.yaml | 3 + .../cilium-preflight/clusterrole.yaml | 11 +- .../cilium-preflight/clusterrolebinding.yaml | 2 +- .../templates/cilium-preflight/daemonset.yaml | 80 +- .../cilium-preflight/deployment.yaml | 13 +- .../cilium-preflight/poddisruptionbudget.yaml | 7 + .../templates/cilium-secrets-namespace.yaml | 4 + .../clustermesh-apiserver/clusterrole.yaml | 31 +- .../clusterrolebinding.yaml | 2 +- .../clustermesh-apiserver/deployment.yaml | 68 +- .../metrics-service.yaml | 10 +- .../poddisruptionbudget.yaml | 9 +- .../clustermesh-apiserver/service.yaml | 2 +- .../clustermesh-apiserver/serviceaccount.yaml | 2 +- .../clustermesh-apiserver/servicemonitor.yaml | 16 +- .../tls-certmanager/admin-secret.yaml | 2 +- .../tls-certmanager/client-secret.yaml | 22 - .../tls-certmanager/local-secret.yaml | 2 +- .../tls-certmanager/remote-secret.yaml | 2 +- .../tls-certmanager/server-secret.yaml | 2 +- .../tls-cronjob/_job-spec.tpl | 14 +- .../tls-cronjob/cronjob.yaml | 2 +- .../tls-cronjob/job.yaml | 2 +- .../tls-cronjob/role.yaml | 2 +- .../tls-cronjob/rolebinding.yaml | 2 +- .../tls-cronjob/serviceaccount.yaml | 2 +- .../tls-helm/admin-secret.yaml | 2 +- .../tls-helm/client-secret.yaml | 24 - .../tls-helm/local-secret.yaml | 2 +- .../tls-helm/remote-secret.yaml | 2 +- .../tls-helm/server-secret.yaml | 2 +- .../tls-provided/admin-secret.yaml | 2 +- .../tls-provided/client-secret.yaml | 22 - .../tls-provided/remote-secret.yaml | 2 +- .../tls-provided/server-secret.yaml | 2 +- .../users-configmap.yaml | 2 +- .../templates/clustermesh-config/_helpers.tpl | 16 +- .../clustermesh-secret.yaml | 3 +- .../kvstoremesh-secret.yaml | 2 +- .../hubble-relay/poddisruptionbudget.yaml | 7 + .../hubble-relay/servicemonitor.yaml | 5 + .../cilium/templates/hubble-ui/_nginx.tpl | 3 +- .../hubble-ui/poddisruptionbudget.yaml | 7 + .../cilium/templates/hubble-ui/service.yaml | 3 + .../templates/hubble/servicemonitor.yaml | 5 +- .../hubble/tls-cronjob/_job-spec.tpl | 4 + .../hubble/tls-helm/relay-client-secret.yaml | 12 +- .../hubble/tls-helm/server-secret.yaml | 12 +- .../tls-provided/metrics-server-secret.yaml | 2 +- .../templates/spire/agent/daemonset.yaml | 2 +- .../templates/spire/server/statefulset.yaml | 4 +- .../charts/cilium/templates/validate.yaml | 66 +- .../charts/cilium/templates/warnings.txt | 13 + .../cilium/charts/cilium/values.schema.json | 454 +++- .../system/cilium/charts/cilium/values.yaml | 395 ++- .../cilium/charts/cilium/values.yaml.tmpl | 363 ++- .../system/cilium/images/cilium/Dockerfile | 2 +- packages/system/cilium/values-kubeovn.yaml | 1 - scripts/common-envs.mk | 7 + 82 files changed, 2605 insertions(+), 1992 deletions(-) delete mode 100644 packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/client-secret.yaml delete mode 100644 packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/client-secret.yaml delete mode 100644 packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/client-secret.yaml create mode 100644 packages/system/cilium/charts/cilium/templates/warnings.txt diff --git a/packages/system/cilium/Makefile b/packages/system/cilium/Makefile index 269fb285..4d1c6ae7 100644 --- a/packages/system/cilium/Makefile +++ b/packages/system/cilium/Makefile @@ -10,10 +10,10 @@ update: rm -rf charts helm repo add cilium https://helm.cilium.io/ helm repo update cilium - helm pull cilium/cilium --untar --untardir charts --version 1.17 - sed -i -e '/Used in iptables/d' -e '/SYS_MODULE/d' charts/cilium/values.yaml + helm pull cilium/cilium --untar --untardir charts --version 1.18 + $(SED_INPLACE) -e '/Used in iptables/d' -e '/SYS_MODULE/d' charts/cilium/values.yaml version=$$(awk '$$1 == "version:" {print $$2}' charts/cilium/Chart.yaml) && \ - sed -i "s/ARG VERSION=.*/ARG VERSION=v$${version}/" images/cilium/Dockerfile + $(SED_INPLACE) "s/ARG VERSION=.*/ARG VERSION=v$${version}/" images/cilium/Dockerfile image: docker buildx build images/cilium \ diff --git a/packages/system/cilium/charts/cilium/Chart.yaml b/packages/system/cilium/charts/cilium/Chart.yaml index 39cdd18a..479d2347 100644 --- a/packages/system/cilium/charts/cilium/Chart.yaml +++ b/packages/system/cilium/charts/cilium/Chart.yaml @@ -7,67 +7,64 @@ annotations: ciliumclusterwidenetworkpolicies.cilium.io\n displayName: Cilium Clusterwide Network Policy\n description: |\n Cilium Clusterwide Network Policies support configuring network traffic\n policiies across the entire cluster, including - applying node firewalls.\n- kind: CiliumExternalWorkload\n version: v2\n name: - ciliumexternalworkloads.cilium.io\n displayName: Cilium External Workload\n description: - |\n Cilium External Workload supports configuring the ability for external\n - \ non-Kubernetes workloads to join the cluster.\n- kind: CiliumLocalRedirectPolicy\n - \ version: v2\n name: ciliumlocalredirectpolicies.cilium.io\n displayName: Cilium - Local Redirect Policy\n description: |\n Cilium Local Redirect Policy allows - local redirects to be configured\n within a node to support use cases like - Node-Local DNS or KIAM.\n- kind: CiliumNode\n version: v2\n name: ciliumnodes.cilium.io\n - \ displayName: Cilium Node\n description: |\n Cilium Node represents a node - managed by Cilium. It contains a\n specification to control various node specific - configuration aspects\n and a status section to represent the status of the - node.\n- kind: CiliumIdentity\n version: v2\n name: ciliumidentities.cilium.io\n - \ displayName: Cilium Identity\n description: |\n Cilium Identity allows introspection - into security identities that\n Cilium allocates which identify sets of labels - that are assigned to\n individual endpoints in the cluster.\n- kind: CiliumEndpoint\n - \ version: v2\n name: ciliumendpoints.cilium.io\n displayName: Cilium Endpoint\n - \ description: |\n Cilium Endpoint represents the status of individual pods - or nodes in\n the cluster which are managed by Cilium, including enforcement - status,\n IP addressing and whether the networking is successfully operational.\n- - kind: CiliumEndpointSlice\n version: v2alpha1\n name: ciliumendpointslices.cilium.io\n - \ displayName: Cilium Endpoint Slice\n description: |\n Cilium Endpoint Slice - represents the status of groups of pods or nodes\n in the cluster which are - managed by Cilium, including enforcement status,\n IP addressing and whether - the networking is successfully operational.\n- kind: CiliumEgressGatewayPolicy\n - \ version: v2\n name: ciliumegressgatewaypolicies.cilium.io\n displayName: Cilium - Egress Gateway Policy\n description: |\n Cilium Egress Gateway Policy provides - control over the way that traffic\n leaves the cluster and which source addresses - to use for that traffic.\n- kind: CiliumClusterwideEnvoyConfig\n version: v2\n - \ name: ciliumclusterwideenvoyconfigs.cilium.io\n displayName: Cilium Clusterwide - Envoy Config\n description: |\n Cilium Clusterwide Envoy Config specifies - Envoy resources and K8s service mappings\n to be provisioned into Cilium host - proxy instances in cluster context.\n- kind: CiliumEnvoyConfig\n version: v2\n - \ name: ciliumenvoyconfigs.cilium.io\n displayName: Cilium Envoy Config\n description: - |\n Cilium Envoy Config specifies Envoy resources and K8s service mappings\n - \ to be provisioned into Cilium host proxy instances in namespace context.\n- - kind: CiliumNodeConfig\n version: v2\n name: ciliumnodeconfigs.cilium.io\n displayName: - Cilium Node Configuration\n description: |\n CiliumNodeConfig is a list of - configuration key-value pairs. It is applied to\n nodes indicated by a label - selector.\n- kind: CiliumBGPPeeringPolicy\n version: v2alpha1\n name: ciliumbgppeeringpolicies.cilium.io\n - \ displayName: Cilium BGP Peering Policy\n description: |\n Cilium BGP Peering - Policy instructs Cilium to create specific BGP peering\n configurations.\n- - kind: CiliumBGPClusterConfig\n version: v2alpha1\n name: ciliumbgpclusterconfigs.cilium.io\n - \ displayName: Cilium BGP Cluster Config\n description: |\n Cilium BGP Cluster - Config instructs Cilium operator to create specific BGP cluster\n configurations.\n- - kind: CiliumBGPPeerConfig\n version: v2alpha1\n name: ciliumbgppeerconfigs.cilium.io\n - \ displayName: Cilium BGP Peer Config\n description: |\n CiliumBGPPeerConfig - is a common set of BGP peer configurations. It can be referenced \n by multiple - peers from CiliumBGPClusterConfig.\n- kind: CiliumBGPAdvertisement\n version: - v2alpha1\n name: ciliumbgpadvertisements.cilium.io\n displayName: Cilium BGP - Advertisement\n description: |\n CiliumBGPAdvertisement is used to define - source of BGP advertisement as well as BGP attributes \n to be advertised with - those prefixes.\n- kind: CiliumBGPNodeConfig\n version: v2alpha1\n name: ciliumbgpnodeconfigs.cilium.io\n - \ displayName: Cilium BGP Node Config\n description: |\n CiliumBGPNodeConfig - is read only node specific BGP configuration. It is constructed by Cilium operator.\n - \ It will also contain node local BGP state information.\n- kind: CiliumBGPNodeConfigOverride\n - \ version: v2alpha1\n name: ciliumbgpnodeconfigoverrides.cilium.io\n displayName: - Cilium BGP Node Config Override\n description: |\n CiliumBGPNodeConfigOverride - can be used to override node specific BGP configuration.\n- kind: CiliumLoadBalancerIPPool\n - \ version: v2alpha1\n name: ciliumloadbalancerippools.cilium.io\n displayName: - Cilium Load Balancer IP Pool\n description: |\n Defining a Cilium Load Balancer - IP Pool instructs Cilium to assign IPs to LoadBalancer Services.\n- kind: CiliumCIDRGroup\n + applying node firewalls.\n- kind: CiliumLocalRedirectPolicy\n version: v2\n name: + ciliumlocalredirectpolicies.cilium.io\n displayName: Cilium Local Redirect Policy\n + \ description: |\n Cilium Local Redirect Policy allows local redirects to be + configured\n within a node to support use cases like Node-Local DNS.\n- kind: + CiliumNode\n version: v2\n name: ciliumnodes.cilium.io\n displayName: Cilium + Node\n description: |\n Cilium Node represents a node managed by Cilium. It + contains a\n specification to control various node specific configuration aspects\n + \ and a status section to represent the status of the node.\n- kind: CiliumIdentity\n + \ version: v2\n name: ciliumidentities.cilium.io\n displayName: Cilium Identity\n + \ description: |\n Cilium Identity allows introspection into security identities + that\n Cilium allocates which identify sets of labels that are assigned to\n + \ individual endpoints in the cluster.\n- kind: CiliumEndpoint\n version: v2\n + \ name: ciliumendpoints.cilium.io\n displayName: Cilium Endpoint\n description: + |\n Cilium Endpoint represents the status of individual pods or nodes in\n + \ the cluster which are managed by Cilium, including enforcement status,\n IP + addressing and whether the networking is successfully operational.\n- kind: CiliumEndpointSlice\n + \ version: v2alpha1\n name: ciliumendpointslices.cilium.io\n displayName: Cilium + Endpoint Slice\n description: |\n Cilium Endpoint Slice represents the status + of groups of pods or nodes\n in the cluster which are managed by Cilium, including + enforcement status,\n IP addressing and whether the networking is successfully + operational.\n- kind: CiliumEgressGatewayPolicy\n version: v2\n name: ciliumegressgatewaypolicies.cilium.io\n + \ displayName: Cilium Egress Gateway Policy\n description: |\n Cilium Egress + Gateway Policy provides control over the way that traffic\n leaves the cluster + and which source addresses to use for that traffic.\n- kind: CiliumClusterwideEnvoyConfig\n + \ version: v2\n name: ciliumclusterwideenvoyconfigs.cilium.io\n displayName: + Cilium Clusterwide Envoy Config\n description: |\n Cilium Clusterwide Envoy + Config specifies Envoy resources and K8s service mappings\n to be provisioned + into Cilium host proxy instances in cluster context.\n- kind: CiliumEnvoyConfig\n + \ version: v2\n name: ciliumenvoyconfigs.cilium.io\n displayName: Cilium Envoy + Config\n description: |\n Cilium Envoy Config specifies Envoy resources and + K8s service mappings\n to be provisioned into Cilium host proxy instances in + namespace context.\n- kind: CiliumNodeConfig\n version: v2\n name: ciliumnodeconfigs.cilium.io\n + \ displayName: Cilium Node Configuration\n description: |\n CiliumNodeConfig + is a list of configuration key-value pairs. It is applied to\n nodes indicated + by a label selector.\n- kind: CiliumBGPPeeringPolicy\n version: v2alpha1\n name: + ciliumbgppeeringpolicies.cilium.io\n displayName: Cilium BGP Peering Policy\n + \ description: |\n Cilium BGP Peering Policy instructs Cilium to create specific + BGP peering\n configurations.\n- kind: CiliumBGPClusterConfig\n version: v2alpha1\n + \ name: ciliumbgpclusterconfigs.cilium.io\n displayName: Cilium BGP Cluster Config\n + \ description: |\n Cilium BGP Cluster Config instructs Cilium operator to create + specific BGP cluster\n configurations.\n- kind: CiliumBGPPeerConfig\n version: + v2alpha1\n name: ciliumbgppeerconfigs.cilium.io\n displayName: Cilium BGP Peer + Config\n description: |\n CiliumBGPPeerConfig is a common set of BGP peer + configurations. It can be referenced \n by multiple peers from CiliumBGPClusterConfig.\n- + kind: CiliumBGPAdvertisement\n version: v2alpha1\n name: ciliumbgpadvertisements.cilium.io\n + \ displayName: Cilium BGP Advertisement\n description: |\n CiliumBGPAdvertisement + is used to define source of BGP advertisement as well as BGP attributes \n to + be advertised with those prefixes.\n- kind: CiliumBGPNodeConfig\n version: v2alpha1\n + \ name: ciliumbgpnodeconfigs.cilium.io\n displayName: Cilium BGP Node Config\n + \ description: |\n CiliumBGPNodeConfig is read only node specific BGP configuration. + It is constructed by Cilium operator.\n It will also contain node local BGP + state information.\n- kind: CiliumBGPNodeConfigOverride\n version: v2alpha1\n + \ name: ciliumbgpnodeconfigoverrides.cilium.io\n displayName: Cilium BGP Node + Config Override\n description: |\n CiliumBGPNodeConfigOverride can be used + to override node specific BGP configuration.\n- kind: CiliumLoadBalancerIPPool\n + \ version: v2\n name: ciliumloadbalancerippools.cilium.io\n displayName: Cilium + Load Balancer IP Pool\n description: |\n Defining a Cilium Load Balancer IP + Pool instructs Cilium to assign IPs to LoadBalancer Services.\n- kind: CiliumCIDRGroup\n \ version: v2alpha1\n name: ciliumcidrgroups.cilium.io\n displayName: Cilium CIDR Group\n description: |\n CiliumCIDRGroup is a list of CIDRs that can be referenced as a single entity from CiliumNetworkPolicies.\n- kind: CiliumL2AnnouncementPolicy\n @@ -77,9 +74,12 @@ annotations: area network, by which nodes, and via which interfaces.\n- kind: CiliumPodIPPool\n \ version: v2alpha1\n name: ciliumpodippools.cilium.io\n displayName: Cilium Pod IP Pool\n description: |\n CiliumPodIPPool defines an IP pool that can - be used for pooled IPAM (i.e. the multi-pool IPAM mode).\n" + be used for pooled IPAM (i.e. the multi-pool IPAM mode).\n- kind: CiliumGatewayClassConfig\n + \ version: v2alpha1\n name: ciliumgatewayclassconfigs.cilium.io\n displayName: + Cilium Gateway Class Config\n description: |\n CiliumGatewayClassConfig defines + a configuration for Gateway API GatewayClass.\n" apiVersion: v2 -appVersion: 1.17.8 +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 @@ -95,4 +95,4 @@ kubeVersion: '>= 1.21.0-0' name: cilium sources: - https://github.com/cilium/cilium -version: 1.17.8 +version: 1.18.5 diff --git a/packages/system/cilium/charts/cilium/README.md b/packages/system/cilium/charts/cilium/README.md index 40a133e6..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.17.8](https://img.shields.io/badge/Version-1.17.8-informational?style=flat-square) ![AppVersion: 1.17.8](https://img.shields.io/badge/AppVersion-1.17.8-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 @@ -73,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 | @@ -85,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:d82f458899c9696cb26a7c02d5568f81c8c8223f8661bb2a7988b269c8b9051e","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 | @@ -95,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 | @@ -114,11 +114,17 @@ contributors across the globe, there is almost always someone available to help. | authentication.rotatedIdentitiesQueueSize | int | `1024` | Buffer size of the channel Cilium uses to receive certificate expiration events from auth handlers. | | autoDirectNodeRoutes | bool | `false` | Enable installation of PodCIDR routes between worker nodes if worker nodes share a common L2 network segment. | | azure.enabled | bool | `false` | Enable Azure integration. Note that this is incompatible with AKS clusters created in BYOCNI mode: use AKS BYOCNI integration (`aksbyocni.enabled`) instead. | -| bandwidthManager | object | `{"bbr":false,"enabled":false}` | Enable bandwidth manager to optimize TCP and UDP workloads and allow for rate-limiting traffic from individual Pods with EDT (Earliest Departure Time) through the "kubernetes.io/egress-bandwidth" Pod annotation. | +| bandwidthManager | object | `{"bbr":false,"bbrHostNamespaceOnly":false,"enabled":false}` | Enable bandwidth manager to optimize TCP and UDP workloads and allow for rate-limiting traffic from individual Pods with EDT (Earliest Departure Time) through the "kubernetes.io/egress-bandwidth" Pod annotation. | | bandwidthManager.bbr | bool | `false` | Activate BBR TCP congestion control for Pods | +| bandwidthManager.bbrHostNamespaceOnly | bool | `false` | Activate BBR TCP congestion control for Pods in the host namespace only. | | bandwidthManager.enabled | bool | `false` | Enable bandwidth manager infrastructure (also prerequirement for BBR) | -| bgpControlPlane | object | `{"enabled":false,"secretsNamespace":{"create":false,"name":"kube-system"},"statusReport":{"enabled":true}}` | This feature set enables virtual BGP routers to be created via CiliumBGPPeeringPolicy CRDs. | +| bgpControlPlane | object | `{"enabled":false,"legacyOriginAttribute":{"enabled":false},"routerIDAllocation":{"ipPool":"","mode":"default"},"secretsNamespace":{"create":false,"name":"kube-system"},"statusReport":{"enabled":true}}` | This feature set enables virtual BGP routers to be created via CiliumBGPPeeringPolicy CRDs. | | bgpControlPlane.enabled | bool | `false` | Enables the BGP control plane. | +| 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. | +| bgpControlPlane.routerIDAllocation.mode | string | `"default"` | BGP router-id allocation mode. In default mode, the router-id is derived from the IPv4 address if it is available, or else it is determined by the lower 32 bits of the MAC address. | | bgpControlPlane.secretsNamespace | object | `{"create":false,"name":"kube-system"}` | SecretsNamespace is the namespace which BGP support will retrieve secrets from. | | bgpControlPlane.secretsNamespace.create | bool | `false` | Create secrets namespace for BGP secrets. | | bgpControlPlane.secretsNamespace.name | string | `"kube-system"` | The name of the secret namespace to which Cilium agents are given read access | @@ -129,7 +135,7 @@ contributors across the globe, there is almost always someone available to help. | bpf.ctAccounting | bool | `false` | Enable CT accounting for packets and bytes | | bpf.ctAnyMax | int | `262144` | Configure the maximum number of entries for the non-TCP connection tracking table. | | bpf.ctTcpMax | int | `524288` | Configure the maximum number of entries in the TCP connection tracking table. | -| bpf.datapathMode | string | `veth` | Mode for Pod devices for the core datapath (veth, netkit, netkit-l2, lb-only) | +| bpf.datapathMode | string | `veth` | Mode for Pod devices for the core datapath (veth, netkit, netkit-l2) | | 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. | @@ -156,12 +162,13 @@ contributors across the globe, there is almost always someone available to help. | 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.policyStatsMapMax | int | `65536` | Configure the maximum number of entries in global policy stats map. @schema type: [null, integer] @schema | | bpf.preallocateMaps | bool | `false` | Enables pre-allocation of eBPF map values. This increases memory usage but can reduce latency. | | bpf.root | string | `"/sys/fs/bpf"` | Configure the mount point for the BPF filesystem | | bpf.tproxy | bool | `false` | Configure the eBPF-based TPROXY (beta) to reduce reliance on iptables rules for implementing Layer 7 policy. | | bpf.vlanBypass | list | `[]` | Configure explicitly allowed VLAN id's for bpf logic bypass. [0] will allow all VLAN id's without any filtering. | | bpfClockProbe | bool | `false` | Enable BPF clock source probing for more efficient tick retrieval. | -| certgen | object | `{"affinity":{},"annotations":{"cronJob":{},"job":{}},"extraVolumeMounts":[],"extraVolumes":[],"generateCA":true,"image":{"digest":"sha256:ab6b1928e9c5f424f6b0f51c68065b9fd85e2f8d3e5f21fbd1a3cb27e6fb9321","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/certgen","tag":"v0.2.1","useDigest":true},"nodeSelector":{},"podLabels":{},"priorityClassName":"","tolerations":[],"ttlSecondsAfterFinished":1800}` | Configure certificate generation for Hubble integration. If hubble.tls.auto.method=cronJob, these values are used for the Kubernetes CronJob which will be scheduled regularly to (re)generate any certificates not provided manually. | +| certgen | object | `{"affinity":{},"annotations":{"cronJob":{},"job":{}},"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.extraVolumeMounts | list | `[]` | Additional certgen volumeMounts. | @@ -170,15 +177,16 @@ contributors across the globe, there is almost always someone available to help. | certgen.nodeSelector | object | `{}` | Node selector for certgen ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector | | certgen.podLabels | object | `{}` | Labels to be added to hubble-certgen pods | | certgen.priorityClassName | string | `""` | Priority class for certgen ref: https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#priorityclass | +| certgen.resources | object | `{}` | Resource limits for certgen ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers | | certgen.tolerations | list | `[]` | Node tolerations for pod assignment on nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ | | certgen.ttlSecondsAfterFinished | int | `1800` | Seconds after which the completed job pod will be deleted | | cgroup | object | `{"autoMount":{"enabled":true,"resources":{}},"hostRoot":"/run/cilium/cgroupv2"}` | Configure cgroup related configuration | | cgroup.autoMount.enabled | bool | `true` | Enable auto mount of cgroup2 filesystem. When `autoMount` is enabled, cgroup2 filesystem is mounted at `cgroup.hostRoot` path on the underlying host and inside the cilium agent pod. If users disable `autoMount`, it's expected that users have mounted cgroup2 filesystem at the specified `cgroup.hostRoot` volume, and then the volume will be mounted inside the cilium agent pod at the same path. | | cgroup.autoMount.resources | object | `{}` | Init Container Cgroup Automount resource limits & requests | | cgroup.hostRoot | string | `"/run/cilium/cgroupv2"` | Configure cgroup root where cgroup2 filesystem is mounted on the host (see also: `cgroup.autoMount`) | +| ciliumEndpointSlice | object | `{"enabled":false,"rateLimits":[{"burst":20,"limit":10,"nodes":0},{"burst":100,"limit":50,"nodes":100}]}` | CiliumEndpointSlice configuration options. | | ciliumEndpointSlice.enabled | bool | `false` | Enable Cilium EndpointSlice feature. | | ciliumEndpointSlice.rateLimits | list | `[{"burst":20,"limit":10,"nodes":0},{"burst":100,"limit":50,"nodes":100}]` | List of rate limit options to be used for the CiliumEndpointSlice controller. Each object in the list must have the following fields: nodes: Count of nodes at which to apply the rate limit. limit: The sustained request rate in requests per second. The maximum rate that can be configured is 50. burst: The burst request rate in requests per second. The maximum burst that can be configured is 100. | -| ciliumEndpointSlice.sliceMode | string | `"identity"` | The slicing mode to use for CiliumEndpointSlices. identity groups together CiliumEndpoints that share the same identity. fcfs groups together CiliumEndpoints in a first-come-first-serve basis, filling in the largest non-full slice first. | | cleanBpfState | bool | `false` | Clean all eBPF datapath state from the initContainer of the cilium-agent DaemonSet. WARNING: Use with care! | | cleanState | bool | `false` | Clean all local Cilium state from the initContainer of the cilium-agent DaemonSet. Implies cleanBpfState: true. WARNING: Use with care! | | cluster.id | int | `0` | Unique ID of the cluster. Must be unique across all connected clusters and in the range of 1 to 255. Only required for Cluster Mesh, may be 0 if Cluster Mesh is not used. | @@ -197,12 +205,13 @@ contributors across the globe, there is almost always someone available to help. | clustermesh.apiserver.extraVolumeMounts | list | `[]` | Additional clustermesh-apiserver volumeMounts. | | clustermesh.apiserver.extraVolumes | list | `[]` | Additional clustermesh-apiserver volumes. | | clustermesh.apiserver.healthPort | int | `9880` | TCP port for the clustermesh-apiserver health API. | -| clustermesh.apiserver.image | object | `{"digest":"sha256:3ac210d94d37a77ec010f9ac4c705edc8f15f22afa2b9a6f0e2a7d64d2360586","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/clustermesh-apiserver","tag":"v1.17.8","useDigest":true}` | Clustermesh API server image. | -| clustermesh.apiserver.kvstoremesh.enabled | bool | `true` | Enable KVStoreMesh. KVStoreMesh caches the information retrieved from the remote clusters in the local etcd instance. | +| clustermesh.apiserver.image | object | `{"digest":"sha256: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. | | clustermesh.apiserver.kvstoremesh.extraVolumeMounts | list | `[]` | Additional KVStoreMesh volumeMounts. | | clustermesh.apiserver.kvstoremesh.healthPort | int | `9881` | TCP port for the KVStoreMesh health API. | +| clustermesh.apiserver.kvstoremesh.kvstoreMode | string | `"internal"` | Specify the KVStore mode when running KVStoreMesh Supported values: - "internal": remote cluster identities are cached in etcd that runs as a sidecar within ``clustermesh-apiserver`` pod. - "external": ``clustermesh-apiserver`` will sync remote cluster information to the etcd used as kvstore. This can't be enabled with crd identity allocation mode. | | clustermesh.apiserver.kvstoremesh.lifecycle | object | `{}` | lifecycle setting for the KVStoreMesh container | | clustermesh.apiserver.kvstoremesh.readinessProbe | object | `{}` | Configuration for the KVStoreMesh readiness probe. | | clustermesh.apiserver.kvstoremesh.resources | object | `{}` | Resource requests and limits for the KVStoreMesh container | @@ -220,18 +229,22 @@ contributors across the globe, there is almost always someone available to help. | clustermesh.apiserver.metrics.serviceMonitor.etcd.interval | string | `"10s"` | Interval for scrape metrics (etcd metrics) | | clustermesh.apiserver.metrics.serviceMonitor.etcd.metricRelabelings | string | `nil` | Metrics relabeling configs for the ServiceMonitor clustermesh-apiserver (etcd metrics) | | clustermesh.apiserver.metrics.serviceMonitor.etcd.relabelings | string | `nil` | Relabeling configs for the ServiceMonitor clustermesh-apiserver (etcd metrics) | +| clustermesh.apiserver.metrics.serviceMonitor.etcd.scrapeTimeout | string | `nil` | Timeout after which scrape is considered to be failed. | | clustermesh.apiserver.metrics.serviceMonitor.interval | string | `"10s"` | Interval for scrape metrics (apiserver metrics) | | clustermesh.apiserver.metrics.serviceMonitor.kvstoremesh.interval | string | `"10s"` | Interval for scrape metrics (KVStoreMesh metrics) | | clustermesh.apiserver.metrics.serviceMonitor.kvstoremesh.metricRelabelings | string | `nil` | Metrics relabeling configs for the ServiceMonitor clustermesh-apiserver (KVStoreMesh metrics) | | clustermesh.apiserver.metrics.serviceMonitor.kvstoremesh.relabelings | string | `nil` | Relabeling configs for the ServiceMonitor clustermesh-apiserver (KVStoreMesh metrics) | +| clustermesh.apiserver.metrics.serviceMonitor.kvstoremesh.scrapeTimeout | string | `nil` | Timeout after which scrape is considered to be failed. | | clustermesh.apiserver.metrics.serviceMonitor.labels | object | `{}` | Labels to add to ServiceMonitor clustermesh-apiserver | | clustermesh.apiserver.metrics.serviceMonitor.metricRelabelings | string | `nil` | Metrics relabeling configs for the ServiceMonitor clustermesh-apiserver (apiserver metrics) | | clustermesh.apiserver.metrics.serviceMonitor.relabelings | string | `nil` | Relabeling configs for the ServiceMonitor clustermesh-apiserver (apiserver metrics) | +| clustermesh.apiserver.metrics.serviceMonitor.scrapeTimeout | string | `nil` | Timeout after which scrape is considered to be failed. | | clustermesh.apiserver.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for pod assignment ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector | | clustermesh.apiserver.podAnnotations | object | `{}` | Annotations to be added to clustermesh-apiserver pods | | clustermesh.apiserver.podDisruptionBudget.enabled | bool | `false` | enable PodDisruptionBudget ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ | | clustermesh.apiserver.podDisruptionBudget.maxUnavailable | int | `1` | Maximum number/percentage of pods that may be made unavailable | | clustermesh.apiserver.podDisruptionBudget.minAvailable | string | `nil` | Minimum number/percentage of pods that should remain scheduled. When it's set, maxUnavailable must be disabled by `maxUnavailable: null` | +| clustermesh.apiserver.podDisruptionBudget.unhealthyPodEvictionPolicy | string | `nil` | How are unhealthy, but running, pods counted for eviction | | clustermesh.apiserver.podLabels | object | `{}` | Labels to be added to clustermesh-apiserver pods | | clustermesh.apiserver.podSecurityContext | object | `{"fsGroup":65532,"runAsGroup":65532,"runAsNonRoot":true,"runAsUser":65532}` | Security context to be added to clustermesh-apiserver pods | | clustermesh.apiserver.priorityClassName | string | `""` | The priority class to use for clustermesh-apiserver | @@ -272,22 +285,26 @@ contributors across the globe, there is almost always someone available to help. | clustermesh.enableEndpointSliceSynchronization | bool | `false` | Enable the synchronization of Kubernetes EndpointSlices corresponding to the remote endpoints of appropriately-annotated global services through ClusterMesh | | clustermesh.enableMCSAPISupport | bool | `false` | Enable Multi-Cluster Services API support | | clustermesh.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.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. | | cni.confFileMountPath | string | `"/tmp/cni-configuration"` | Configure the path to where to mount the ConfigMap inside the agent pod. | | cni.confPath | string | `"/etc/cni/net.d"` | Configure the path to the CNI configuration directory on the host. | -| cni.configMapKey | string | `"cni-config"` | Configure the key in the CNI ConfigMap to read the contents of the CNI configuration from. | +| cni.configMap | string | `""` | When defined, configMap will mount the provided value as ConfigMap and interpret the 'cni.configMapKey' value as CNI configuration file and write it when the agent starts up. | +| cni.configMapKey | string | `"cni-config"` | Configure the key in the CNI ConfigMap to read the contents of the CNI configuration from. For this to be effective, the 'cni.configMap' parameter must be specified too. Note that the 'cni.configMap' parameter is the name of the ConfigMap, while 'cni.configMapKey' is the name of the key in the ConfigMap data containing the actual configuration. | | cni.customConf | bool | `false` | Skip writing of the CNI configuration. This can be used if writing of the CNI configuration is performed by external automation. | | cni.enableRouteMTUForCNIChaining | bool | `false` | Enable route MTU for pod netns when CNI chaining is used | | cni.exclusive | bool | `true` | Make Cilium take ownership over the `/etc/cni/net.d` directory on the node, renaming all non-Cilium CNI configurations to `*.cilium_bak`. This ensures no Pods can be scheduled using other CNI plugins during Cilium agent downtime. | | cni.hostConfDirMountPath | string | `"/host/etc/cni/net.d"` | Configure the path to where the CNI configuration directory is mounted inside the agent pod. | | cni.install | bool | `true` | Install the CNI configuration and binary files into the filesystem. | +| cni.iptablesRemoveAWSRules | bool | `true` | Enable the removal of iptables rules created by the AWS CNI VPC plugin. | | cni.logFile | string | `"/var/run/cilium/cilium-cni.log"` | Configure the log file for CNI logging with retention policy of 7 days. Disable CNI file logging by setting this field to empty explicitly. | | cni.resources | object | `{"requests":{"cpu":"100m","memory":"10Mi"}}` | Specifies the resources for the cni initContainer | | cni.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. | +| 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 | @@ -300,6 +317,7 @@ contributors across the globe, there is almost always someone available to help. | daemon.runPath | string | `"/var/run/cilium"` | Configure where Cilium runtime state should be stored. | | dashboards | object | `{"annotations":{},"enabled":false,"label":"grafana_dashboard","labelValue":"1","namespace":null}` | Grafana dashboards for cilium-agent grafana can import dashboards based on the label and value ref: https://github.com/grafana/helm-charts/tree/main/charts/grafana#sidecar-for-dashboards | | debug.enabled | bool | `false` | Enable debug logging | +| debug.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 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. | @@ -311,24 +329,22 @@ contributors across the globe, there is almost always someone available to help. | dnsProxy.idleConnectionGracePeriod | string | `"0s"` | Time during which idle but previously active connections with expired DNS lookups are still considered alive. | | dnsProxy.maxDeferredConnectionDeletes | int | `10000` | Maximum number of IPs to retain for expired DNS lookups with still-active connections. | | dnsProxy.minTtl | int | `0` | The minimum time, in seconds, to use DNS data for toFQDNs policies. If the upstream DNS server returns a DNS record with a shorter TTL, Cilium overwrites the TTL with this value. Setting this value to zero means that Cilium will honor the TTLs returned by the upstream DNS server. | +| dnsProxy.preAllocateIdentities | bool | `true` | Pre-allocate ToFQDN identities. This reduces DNS proxy tail latency, at the potential cost of some unnecessary policymap entries. Disable this if you have a large (200+) number of unique ToFQDN selectors. | | dnsProxy.preCache | string | `""` | DNS cache data at this path is preloaded on agent startup. | | dnsProxy.proxyPort | int | `0` | Global port on which the in-agent DNS proxy should listen. Default 0 is a OS-assigned port. | | dnsProxy.proxyResponseMaxDelay | string | `"100ms"` | The maximum time the DNS proxy holds an allowed DNS response before sending it along. Responses are sent as soon as the datapath is updated with the new IP information. | | dnsProxy.socketLingerTimeout | int | `10` | Timeout (in seconds) when closing the connection between the DNS proxy and the upstream server. If set to 0, the connection is closed immediately (with TCP RST). If set to -1, the connection is closed asynchronously in the background. | | egressGateway.enabled | bool | `false` | Enables egress gateway to redirect and SNAT the traffic that leaves the cluster. | | egressGateway.reconciliationTriggerInterval | string | `"1s"` | Time between triggers of egress gateway state reconciliations | -| enableCiliumEndpointSlice | bool | `false` | Enable CiliumEndpointSlice feature (deprecated, please use `ciliumEndpointSlice.enabled` instead). | | enableCriticalPriorityClass | bool | `true` | Explicitly enable or disable priority class. .Capabilities.KubeVersion is unsettable in `helm template` calls, it depends on k8s libraries version that Helm was compiled against. This option allows to explicitly disable setting the priority class, which is useful for rendering charts for gke clusters in advance. | | enableIPv4BIGTCP | bool | `false` | Enables IPv4 BIG TCP support which increases maximum IPv4 GSO/GRO limits for nodes and pods | -| enableIPv4Masquerade | bool | `true` | Enables masquerading of IPv4 traffic leaving the node from endpoints. | +| enableIPv4Masquerade | bool | `true` unless ipam eni mode is active | Enables masquerading of IPv4 traffic leaving the node from endpoints. | | enableIPv6BIGTCP | bool | `false` | Enables IPv6 BIG TCP support which increases maximum IPv6 GSO/GRO limits for nodes and pods | | enableIPv6Masquerade | bool | `true` | Enables masquerading of IPv6 traffic leaving the node from endpoints. | | enableInternalTrafficPolicy | bool | `true` | Enable Internal Traffic Policy | -| enableK8sTerminatingEndpoint | bool | `true` | Configure whether to enable auto detect of terminating state for endpoints in order to support graceful termination. | | enableLBIPAM | bool | `true` | Enable LoadBalancer IP Address Management | | enableMasqueradeRouteSource | bool | `false` | Enables masquerading to the source of the route for traffic leaving the node from endpoints. | | enableNonDefaultDenyPolicies | bool | `true` | Enable Non-Default-Deny policies | -| enableRuntimeDeviceDetection | bool | `true` | Enables experimental support for the detection of new and removed datapath devices. When devices change the eBPF datapath is reloaded and services updated. If "devices" is set then only those devices, or devices matching a wildcard will be considered. This option has been deprecated and is a no-op. | | enableXTSocketFallback | bool | `true` | Enables the fallback compatibility solution for when the xt_socket kernel module is missing and it is needed for the datapath L7 redirection to work properly. See documentation for details on when this can be disabled: https://docs.cilium.io/en/stable/operations/system_requirements/#linux-kernel. | | encryption.enabled | bool | `false` | Enable transparent network encryption. | | encryption.ipsec.encryptedOverlay | bool | `false` | Enable IPsec encrypted overlay | @@ -359,7 +375,6 @@ contributors across the globe, there is almost always someone available to help. | 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.subnetIDsFilter | list | `[]` | Filter via subnet IDs which will dictate which subnets are going to be used to create new ENIs Important note: This requires that each instance has an ENI with a matching subnet attached when Cilium is deployed. If you only want to control subnets for ENIs attached by Cilium, use the CNI configuration file settings (cni.customConf) instead. | | eni.subnetTagsFilter | list | `[]` | Filter via tags (k=v) which will dictate which subnets are going to be used to create new ENIs Important note: This requires that each instance has an ENI with a matching subnet attached when Cilium is deployed. If you only want to control subnets for ENIs attached by Cilium, use the CNI configuration file settings (cni.customConf) instead. | -| eni.updateEC2AdapterLimitViaAPI | bool | `true` | Update ENI Adapter limits from the EC2 API | | envoy.affinity | object | `{"nodeAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"cilium.io/no-schedule","operator":"NotIn","values":["true"]}]}]}},"podAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":[{"labelSelector":{"matchLabels":{"k8s-app":"cilium"}},"topologyKey":"kubernetes.io/hostname"}]},"podAntiAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":[{"labelSelector":{"matchLabels":{"k8s-app":"cilium-envoy"}},"topologyKey":"kubernetes.io/hostname"}]}}` | Affinity for cilium-envoy. | | envoy.annotations | object | `{}` | Annotations to be added to all top-level cilium-envoy objects (resources under templates/cilium-envoy) | | envoy.baseID | int | `0` | Set Envoy'--base-id' to use when allocating shared memory regions. Only needs to be changed if multiple Envoy instances will run on the same node and may have conflicts. Supported values: 0 - 4294967295. Defaults to '0' | @@ -377,9 +392,11 @@ contributors across the globe, there is almost always someone available to help. | envoy.extraVolumes | list | `[]` | Additional envoy volumes. | | envoy.healthPort | int | `9878` | TCP port for the health API. | | envoy.httpRetryCount | int | `3` | Maximum number of retries for each HTTP request | +| envoy.httpUpstreamLingerTimeout | string | `nil` | Time in seconds to block Envoy worker thread while an upstream HTTP connection is closing. If set to 0, the connection is closed immediately (with TCP RST). If set to -1, the connection is closed asynchronously in the background. | | envoy.idleTimeoutDurationSeconds | int | `60` | Set Envoy upstream HTTP idle connection timeout seconds. Does not apply to connections with pending requests. Default 60s | -| envoy.image | object | `{"digest":"sha256:06fbc4e55d926dd82ff2a0049919248dcc6be5354609b09012b01bc9c5b0ee28","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium-envoy","tag":"v1.33.9-1757932127-3c04e8f2f1027d106b96f8ef4a0215e81dbaaece","useDigest":true}` | Envoy container image. | +| 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 | | envoy.livenessProbe.periodSeconds | int | `30` | interval between checks of the liveness probe | | envoy.log.accessLogBufferSize | int | `4096` | Size of the Envoy access log buffer created within the agent in bytes. Tune this value up if you encounter "Envoy: Discarded truncated access log message" errors. Large request/response header sizes (e.g. 16KiB) will require a larger buffer size. | @@ -397,7 +414,7 @@ contributors across the globe, there is almost always someone available to help. | envoy.podSecurityContext.appArmorProfile | object | `{"type":"Unconfined"}` | AppArmorProfile options for the `cilium-agent` and init containers | | envoy.policyRestoreTimeoutDuration | string | `nil` | Max duration to wait for endpoint policies to be restored on restart. Default "3m". | | envoy.priorityClassName | string | `nil` | The priority class to use for cilium-envoy. | -| envoy.prometheus | object | `{"enabled":true,"port":"9964","serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","labels":{},"metricRelabelings":null,"relabelings":[{"replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}]}}` | Configure Cilium Envoy Prometheus options. Note that some of these apply to either cilium-agent or cilium-envoy. | +| envoy.prometheus | object | `{"enabled":true,"port":"9964","serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","labels":{},"metricRelabelings":null,"relabelings":[{"action":"replace","replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}],"scrapeTimeout":null}}` | Configure Cilium Envoy Prometheus options. Note that some of these apply to either cilium-agent or cilium-envoy. | | envoy.prometheus.enabled | bool | `true` | Enable prometheus metrics for cilium-envoy | | envoy.prometheus.port | string | `"9964"` | Serve prometheus metrics for cilium-envoy on the configured port | | envoy.prometheus.serviceMonitor.annotations | object | `{}` | Annotations to add to ServiceMonitor cilium-envoy | @@ -405,7 +422,8 @@ contributors across the globe, there is almost always someone available to help. | envoy.prometheus.serviceMonitor.interval | string | `"10s"` | Interval for scrape metrics. | | envoy.prometheus.serviceMonitor.labels | object | `{}` | Labels to add to ServiceMonitor cilium-envoy | | envoy.prometheus.serviceMonitor.metricRelabelings | string | `nil` | Metrics relabeling configs for the ServiceMonitor cilium-envoy or for cilium-agent with Envoy configured. | -| envoy.prometheus.serviceMonitor.relabelings | list | `[{"replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}]` | Relabeling configs for the ServiceMonitor cilium-envoy or for cilium-agent with Envoy configured. | +| envoy.prometheus.serviceMonitor.relabelings | list | `[{"action":"replace","replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}]` | Relabeling configs for the ServiceMonitor cilium-envoy or for cilium-agent with Envoy configured. | +| envoy.prometheus.serviceMonitor.scrapeTimeout | string | `nil` | Timeout after which scrape is considered to be failed. | | envoy.readinessProbe.failureThreshold | int | `3` | failure threshold of readiness probe | | envoy.readinessProbe.periodSeconds | int | `30` | interval between checks of the readiness probe | | envoy.resources | object | `{}` | Envoy resource limits & requests ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | @@ -414,8 +432,10 @@ contributors across the globe, there is almost always someone available to help. | envoy.securityContext.capabilities.keepCapNetBindService | bool | `false` | Keep capability `NET_BIND_SERVICE` for Envoy process. | | envoy.securityContext.privileged | bool | `false` | Run the pod with elevated privileges | | envoy.securityContext.seLinuxOptions | object | `{"level":"s0","type":"spc_t"}` | SELinux options for the `cilium-envoy` container | +| envoy.startupProbe.enabled | bool | `true` | Enable startup probe for cilium-envoy | | envoy.startupProbe.failureThreshold | int | `105` | failure threshold of startup probe. 105 x 2s translates to the old behaviour of the readiness probe (120s delay + 30 x 3s) | | envoy.startupProbe.periodSeconds | int | `2` | interval between checks of the startup probe | +| envoy.streamIdleTimeoutDurationSeconds | int | `300` | Set Envoy the amount of time that the connection manager will allow a stream to exist with no upstream or downstream activity. default 5 minutes | | envoy.terminationGracePeriodSeconds | int | `1` | Configure termination grace period for cilium-envoy DaemonSet. | | envoy.tolerations | list | `[{"operator":"Exists"}]` | Node tolerations for envoy scheduling to nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ | | envoy.updateStrategy | object | `{"rollingUpdate":{"maxUnavailable":2},"type":"RollingUpdate"}` | cilium-envoy update strategy ref: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/#updating-a-daemonset | @@ -429,8 +449,6 @@ contributors across the globe, there is almost always someone available to help. | etcd.enabled | bool | `false` | Enable etcd mode for the agent. | | etcd.endpoints | list | `["https://CHANGE-ME:2379"]` | List of etcd endpoints | | etcd.ssl | bool | `false` | Enable use of TLS/SSL for connectivity to etcd. | -| externalWorkloads | object | `{"enabled":false}` | Configure external workloads support | -| externalWorkloads.enabled | bool | `false` | Enable support for external workloads, such as VMs (false by default). | | extraArgs | list | `[]` | Additional agent container arguments. | | extraConfig | object | `{}` | extraConfig allows you to specify additional configuration parameters to be included in the cilium-config configmap. | | extraContainers | list | `[]` | Additional containers added to the cilium DaemonSet. | @@ -457,26 +475,24 @@ contributors across the globe, there is almost always someone available to help. | healthCheckICMPFailureThreshold | int | `3` | Number of ICMP requests sent for each health check before marking a node or endpoint unreachable. | | healthChecking | bool | `true` | Enable connectivity health checking. | | healthPort | int | `9879` | TCP port for the agent health API. This is not the port for cilium-health. | -| highScaleIPcache | object | `{"enabled":false}` | EnableHighScaleIPcache enables the special ipcache mode for high scale clusters. The ipcache content will be reduced to the strict minimum and traffic will be encapsulated to carry security identities. | -| highScaleIPcache.enabled | bool | `false` | Enable the high scale mode for the ipcache. | | hostFirewall | object | `{"enabled":false}` | Configure the host firewall. | | hostFirewall.enabled | bool | `false` | Enables the enforcement of host policies in the eBPF datapath. | -| hostPort.enabled | bool | `false` | Enable hostPort service support. | | hubble.annotations | object | `{}` | Annotations to be added to all top-level hubble objects (resources under templates/hubble) | | hubble.dropEventEmitter | object | `{"enabled":false,"interval":"2m","reasons":["auth_required","policy_denied"]}` | Emit v1.Events related to pods on detection of packet drops. This feature is alpha, please provide feedback at https://github.com/cilium/cilium/issues/33975. | | hubble.dropEventEmitter.interval | string | `"2m"` | - Minimum time between emitting same events. | | hubble.dropEventEmitter.reasons | list | `["auth_required","policy_denied"]` | - Drop reasons to emit events for. ref: https://docs.cilium.io/en/stable/_api/v1/flow/README/#dropreason | | hubble.enabled | bool | `true` | Enable Hubble (true by default). | -| hubble.export | object | `{"dynamic":{"config":{"configMapName":"cilium-flowlog-config","content":[{"excludeFilters":[],"fieldMask":[],"filePath":"/var/run/cilium/hubble/events.log","includeFilters":[],"name":"all"}],"createConfigMap":true},"enabled":false},"fileMaxBackups":5,"fileMaxSizeMb":10,"static":{"allowList":[],"denyList":[],"enabled":false,"fieldMask":[],"filePath":"/var/run/cilium/hubble/events.log"}}` | Hubble flows export. | -| hubble.export.dynamic | object | `{"config":{"configMapName":"cilium-flowlog-config","content":[{"excludeFilters":[],"fieldMask":[],"filePath":"/var/run/cilium/hubble/events.log","includeFilters":[],"name":"all"}],"createConfigMap":true},"enabled":false}` | - Dynamic exporters configuration. Dynamic exporters may be reconfigured without a need of agent restarts. | +| hubble.export | object | `{"dynamic":{"config":{"configMapName":"cilium-flowlog-config","content":[{"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 | `[{"excludeFilters":[],"fieldMask":[],"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.fileMaxBackups | int | `5` | - Defines max number of backup/rotated files. | -| hubble.export.fileMaxSizeMb | int | `10` | - Defines max file size of output file before it gets rotated. | -| hubble.export.static | object | `{"allowList":[],"denyList":[],"enabled":false,"fieldMask":[],"filePath":"/var/run/cilium/hubble/events.log"}` | - Static exporter configuration. Static exporter is bound to agent lifecycle. | +| hubble.export.static | object | `{"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. | | hubble.listenAddress | string | `":4244"` | An additional address for Hubble to listen to. Set this field ":4244" if you are enabling Hubble Relay, as it assumes that Hubble is listening on port 4244. | -| hubble.metrics | object | `{"dashboards":{"annotations":{},"enabled":false,"label":"grafana_dashboard","labelValue":"1","namespace":null},"dynamic":{"config":{"configMapName":"cilium-dynamic-metrics-config","content":[],"createConfigMap":true},"enabled":false},"enableOpenMetrics":false,"enabled":null,"port":9965,"serviceAnnotations":{},"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","jobLabel":"","labels":{},"metricRelabelings":null,"relabelings":[{"replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}],"tlsConfig":{}},"tls":{"enabled":false,"server":{"cert":"","existingSecret":"","extraDnsNames":[],"extraIpAddresses":[],"key":"","mtls":{"enabled":false,"key":"ca.crt","name":null,"useSecret":false}}}}` | Hubble metrics configuration. See https://docs.cilium.io/en/stable/observability/metrics/#hubble-metrics for more comprehensive documentation about Hubble metrics. | +| hubble.metrics | object | `{"dashboards":{"annotations":{},"enabled":false,"label":"grafana_dashboard","labelValue":"1","namespace":null},"dynamic":{"config":{"configMapName":"cilium-dynamic-metrics-config","content":[],"createConfigMap":true},"enabled":false},"enableOpenMetrics":false,"enabled":null,"port":9965,"serviceAnnotations":{},"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","jobLabel":"","labels":{},"metricRelabelings":null,"relabelings":[{"action":"replace","replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}],"scrapeTimeout":null,"tlsConfig":{}},"tls":{"enabled":false,"server":{"cert":"","existingSecret":"","extraDnsNames":[],"extraIpAddresses":[],"key":"","mtls":{"enabled":false,"key":"ca.crt","name":null,"useSecret":false}}}}` | Hubble metrics configuration. See https://docs.cilium.io/en/stable/observability/metrics/#hubble-metrics for more comprehensive documentation about Hubble metrics. | | hubble.metrics.dashboards | object | `{"annotations":{},"enabled":false,"label":"grafana_dashboard","labelValue":"1","namespace":null}` | Grafana dashboards for hubble grafana can import dashboards based on the label and value ref: https://github.com/grafana/helm-charts/tree/main/charts/grafana#sidecar-for-dashboards | | hubble.metrics.dynamic.config.configMapName | string | `"cilium-dynamic-metrics-config"` | -- Name of configmap with configuration that may be altered to reconfigure metric handlers within a running agent. | | hubble.metrics.dynamic.config.content | list | `[]` | -- Exporters configuration in YAML format. | @@ -491,7 +507,8 @@ contributors across the globe, there is almost always someone available to help. | hubble.metrics.serviceMonitor.jobLabel | string | `""` | jobLabel to add for ServiceMonitor hubble | | hubble.metrics.serviceMonitor.labels | object | `{}` | Labels to add to ServiceMonitor hubble | | hubble.metrics.serviceMonitor.metricRelabelings | string | `nil` | Metrics relabeling configs for the ServiceMonitor hubble | -| hubble.metrics.serviceMonitor.relabelings | list | `[{"replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}]` | Relabeling configs for the ServiceMonitor hubble | +| hubble.metrics.serviceMonitor.relabelings | list | `[{"action":"replace","replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}]` | Relabeling configs for the ServiceMonitor hubble | +| hubble.metrics.serviceMonitor.scrapeTimeout | string | `nil` | Timeout after which scrape is considered to be failed. | | hubble.metrics.tls.server.cert | string | `""` | base64 encoded PEM values for the Hubble metrics server certificate (deprecated). Use existingSecret instead. | | hubble.metrics.tls.server.existingSecret | string | `""` | Name of the Secret containing the certificate and key for the Hubble metrics server. If specified, cert and key are ignored. | | hubble.metrics.tls.server.extraDnsNames | list | `[]` | Extra DNS names added to certificate when it's auto generated | @@ -500,6 +517,7 @@ contributors across the globe, there is almost always someone available to help. | hubble.metrics.tls.server.mtls | object | `{"enabled":false,"key":"ca.crt","name":null,"useSecret":false}` | Configure mTLS for the Hubble metrics server. | | hubble.metrics.tls.server.mtls.key | string | `"ca.crt"` | Entry of the ConfigMap containing the CA. | | hubble.metrics.tls.server.mtls.name | string | `nil` | Name of the ConfigMap containing the CA to validate client certificates against. If mTLS is enabled and this is unspecified, it will default to the same CA used for Hubble metrics server certificates. | +| hubble.networkPolicyCorrelation | object | `{"enabled":true}` | Enables network policy correlation of Hubble flows, i.e. populating `egress_allowed_by`, `ingress_denied_by` fields with policy information. | | hubble.peerService.clusterDomain | string | `"cluster.local"` | The cluster domain to use to query the Hubble Peer service. It should be the local cluster. | | hubble.peerService.targetPort | int | `4244` | Target Port for the Peer service, must match the hubble.listenAddress' port. | | hubble.preferIpv6 | bool | `false` | Whether Hubble should prefer to announce IPv6 or IPv4 addresses if both are available. | @@ -508,17 +526,16 @@ contributors across the globe, there is almost always someone available to help. | hubble.redact.http.headers.deny | list | `[]` | List of HTTP headers to deny: matching headers will be redacted. Note: `allow` and `deny` lists cannot be used both at the same time, only one can be present. Example: redact: enabled: true http: headers: deny: - Authorization - Proxy-Authorization You can specify the options from the helm CLI: --set hubble.redact.enabled="true" --set hubble.redact.http.headers.deny="Authorization,Proxy-Authorization" | | hubble.redact.http.urlQuery | bool | `false` | Enables redacting URL query (GET) parameters. Example: redact: enabled: true http: urlQuery: true You can specify the options from the helm CLI: --set hubble.redact.enabled="true" --set hubble.redact.http.urlQuery="true" | | hubble.redact.http.userInfo | bool | `true` | Enables redacting user info, e.g., password when basic auth is used. Example: redact: enabled: true http: userInfo: true You can specify the options from the helm CLI: --set hubble.redact.enabled="true" --set hubble.redact.http.userInfo="true" | -| hubble.redact.kafka.apiKey | bool | `true` | Enables redacting Kafka's API key. Example: redact: enabled: true kafka: apiKey: true You can specify the options from the helm CLI: --set hubble.redact.enabled="true" --set hubble.redact.kafka.apiKey="true" | +| hubble.redact.kafka.apiKey | bool | `true` | Enables redacting Kafka's API key (deprecated, will be removed in v1.19). Example: redact: enabled: true kafka: apiKey: true You can specify the options from the helm CLI: --set hubble.redact.enabled="true" --set hubble.redact.kafka.apiKey="true" | | hubble.relay.affinity | object | `{"podAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":[{"labelSelector":{"matchLabels":{"k8s-app":"cilium"}},"topologyKey":"kubernetes.io/hostname"}]}}` | Affinity for hubble-replay | | hubble.relay.annotations | object | `{}` | Annotations to be added to all top-level hubble-relay objects (resources under templates/hubble-relay) | -| hubble.relay.dialTimeout | string | `nil` | Dial timeout to connect to the local hubble instance to receive peer information (e.g. "30s"). This option has been deprecated and is a no-op. | | hubble.relay.enabled | bool | `false` | Enable Hubble Relay (requires hubble.enabled=true) | | hubble.relay.extraEnv | list | `[]` | Additional hubble-relay environment variables. | | hubble.relay.extraVolumeMounts | list | `[]` | Additional hubble-relay volumeMounts. | | hubble.relay.extraVolumes | list | `[]` | Additional hubble-relay volumes. | | hubble.relay.gops.enabled | bool | `true` | Enable gops for hubble-relay | | hubble.relay.gops.port | int | `9893` | Configure gops listen port for hubble-relay | -| hubble.relay.image | object | `{"digest":"sha256:2e576bf7a02291c07bffbc1ca0a66a6c70f4c3eb155480e5b3ac027bedd2858b","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/hubble-relay","tag":"v1.17.8","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.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for pod assignment ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector | @@ -526,24 +543,26 @@ contributors across the globe, there is almost always someone available to help. | hubble.relay.podDisruptionBudget.enabled | bool | `false` | enable PodDisruptionBudget ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ | | hubble.relay.podDisruptionBudget.maxUnavailable | int | `1` | Maximum number/percentage of pods that may be made unavailable | | hubble.relay.podDisruptionBudget.minAvailable | string | `nil` | Minimum number/percentage of pods that should remain scheduled. When it's set, maxUnavailable must be disabled by `maxUnavailable: null` | +| hubble.relay.podDisruptionBudget.unhealthyPodEvictionPolicy | string | `nil` | How are unhealthy, but running, pods counted for eviction | | hubble.relay.podLabels | object | `{}` | Labels to be added to hubble-relay pods | -| hubble.relay.podSecurityContext | object | `{"fsGroup":65532}` | hubble-relay pod security context | +| hubble.relay.podSecurityContext | object | `{"fsGroup":65532,"seccompProfile":{"type":"RuntimeDefault"}}` | hubble-relay pod security context | | hubble.relay.pprof.address | string | `"localhost"` | Configure pprof listen address for hubble-relay | | hubble.relay.pprof.enabled | bool | `false` | Enable pprof for hubble-relay | | hubble.relay.pprof.port | int | `6062` | Configure pprof listen port for hubble-relay | | hubble.relay.priorityClassName | string | `""` | The priority class to use for hubble-relay | -| hubble.relay.prometheus | object | `{"enabled":false,"port":9966,"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","labels":{},"metricRelabelings":null,"relabelings":null}}` | Enable prometheus metrics for hubble-relay on the configured port at /metrics | +| hubble.relay.prometheus | object | `{"enabled":false,"port":9966,"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","labels":{},"metricRelabelings":null,"relabelings":null,"scrapeTimeout":null}}` | Enable prometheus metrics for hubble-relay on the configured port at /metrics | | hubble.relay.prometheus.serviceMonitor.annotations | object | `{}` | Annotations to add to ServiceMonitor hubble-relay | | hubble.relay.prometheus.serviceMonitor.enabled | bool | `false` | Enable service monitors. This requires the prometheus CRDs to be available (see https://github.com/prometheus-operator/prometheus-operator/blob/main/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml) | | hubble.relay.prometheus.serviceMonitor.interval | string | `"10s"` | Interval for scrape metrics. | | hubble.relay.prometheus.serviceMonitor.labels | object | `{}` | Labels to add to ServiceMonitor hubble-relay | | hubble.relay.prometheus.serviceMonitor.metricRelabelings | string | `nil` | Metrics relabeling configs for the ServiceMonitor hubble-relay | | hubble.relay.prometheus.serviceMonitor.relabelings | string | `nil` | Relabeling configs for the ServiceMonitor hubble-relay | +| hubble.relay.prometheus.serviceMonitor.scrapeTimeout | string | `nil` | Timeout after which scrape is considered to be failed. | | hubble.relay.replicas | int | `1` | Number of replicas run for the hubble-relay deployment. | | hubble.relay.resources | object | `{}` | Specifies the resources for the hubble-relay pods | | hubble.relay.retryTimeout | string | `nil` | Backoff duration to retry connecting to the local hubble instance in case of failure (e.g. "30s"). | | hubble.relay.rollOutPods | bool | `false` | Roll out Hubble Relay pods automatically when configmap is updated. | -| hubble.relay.securityContext | object | `{"capabilities":{"drop":["ALL"]},"runAsGroup":65532,"runAsNonRoot":true,"runAsUser":65532}` | hubble-relay container security context | +| hubble.relay.securityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"runAsGroup":65532,"runAsNonRoot":true,"runAsUser":65532,"seccompProfile":{"type":"RuntimeDefault"}}` | hubble-relay container security context | | hubble.relay.service | object | `{"nodePort":31234,"type":"ClusterIP"}` | hubble-relay service configuration. | | hubble.relay.service.nodePort | int | `31234` | - The port to use when the service type is set to NodePort. | | hubble.relay.service.type | string | `"ClusterIP"` | - The type of service used for Hubble Relay access, either ClusterIP, NodePort or LoadBalancer. | @@ -589,7 +608,7 @@ contributors across the globe, there is almost always someone available to help. | hubble.ui.backend.livenessProbe.enabled | bool | `false` | Enable liveness probe for Hubble-ui backend (requires Hubble-ui 0.12+) | | hubble.ui.backend.readinessProbe.enabled | bool | `false` | Enable readiness probe for Hubble-ui backend (requires Hubble-ui 0.12+) | | hubble.ui.backend.resources | object | `{}` | Resource requests and limits for the 'backend' container of the 'hubble-ui' deployment. | -| hubble.ui.backend.securityContext | object | `{}` | Hubble-ui backend security context. | +| hubble.ui.backend.securityContext | object | `{"allowPrivilegeEscalation":false}` | Hubble-ui backend security context. | | hubble.ui.baseUrl | string | `"/"` | Defines base url prefix for all hubble-ui http requests. It needs to be changed in case if ingress for hubble-ui is configured under some sub-path. Trailing `/` is required for custom path, ex. `/service-map/` | | hubble.ui.enabled | bool | `false` | Whether to enable the Hubble UI. | | hubble.ui.frontend.extraEnv | list | `[]` | Additional hubble-ui frontend environment variables. | @@ -597,7 +616,7 @@ contributors across the globe, there is almost always someone available to help. | hubble.ui.frontend.extraVolumes | list | `[]` | Additional hubble-ui frontend volumes. | | hubble.ui.frontend.image | object | `{"digest":"sha256:661d5de7050182d495c6497ff0b007a7a1e379648e60830dd68c4d78ae21761d","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/hubble-ui","tag":"v0.13.3","useDigest":true}` | Hubble-ui frontend image. | | hubble.ui.frontend.resources | object | `{}` | Resource requests and limits for the 'frontend' container of the 'hubble-ui' deployment. | -| hubble.ui.frontend.securityContext | object | `{}` | Hubble-ui frontend security context. | +| hubble.ui.frontend.securityContext | object | `{"allowPrivilegeEscalation":false}` | Hubble-ui frontend security context. | | hubble.ui.frontend.server.ipv6 | object | `{"enabled":true}` | Controls server listener for ipv6 | | hubble.ui.ingress | object | `{"annotations":{},"className":"","enabled":false,"hosts":["chart-example.local"],"labels":{},"tls":[]}` | hubble-ui ingress configuration. | | hubble.ui.labels | object | `{}` | Additional labels to be added to 'hubble-ui' deployment object | @@ -606,13 +625,15 @@ contributors across the globe, there is almost always someone available to help. | hubble.ui.podDisruptionBudget.enabled | bool | `false` | enable PodDisruptionBudget ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ | | hubble.ui.podDisruptionBudget.maxUnavailable | int | `1` | Maximum number/percentage of pods that may be made unavailable | | hubble.ui.podDisruptionBudget.minAvailable | string | `nil` | Minimum number/percentage of pods that should remain scheduled. When it's set, maxUnavailable must be disabled by `maxUnavailable: null` | +| hubble.ui.podDisruptionBudget.unhealthyPodEvictionPolicy | string | `nil` | How are unhealthy, but running, pods counted for eviction | | hubble.ui.podLabels | object | `{}` | Labels to be added to hubble-ui pods | | hubble.ui.priorityClassName | string | `""` | The priority class to use for hubble-ui | | hubble.ui.replicas | int | `1` | The number of replicas of Hubble UI to deploy. | | hubble.ui.rollOutPods | bool | `false` | Roll out Hubble-ui pods automatically when configmap is updated. | | hubble.ui.securityContext | object | `{"fsGroup":1001,"runAsGroup":1001,"runAsUser":1001}` | Security context to be added to Hubble UI pods | -| hubble.ui.service | object | `{"annotations":{},"nodePort":31235,"type":"ClusterIP"}` | hubble-ui service configuration. | +| hubble.ui.service | object | `{"annotations":{},"labels":{},"nodePort":31235,"type":"ClusterIP"}` | hubble-ui service configuration. | | hubble.ui.service.annotations | object | `{}` | Annotations to be added for the Hubble UI service | +| hubble.ui.service.labels | object | `{}` | Labels to be added for the Hubble UI service | | hubble.ui.service.nodePort | int | `31235` | - The port to use when the service type is set to NodePort. | | hubble.ui.service.type | string | `"ClusterIP"` | - The type of service used for Hubble UI access, either ClusterIP or NodePort. | | hubble.ui.standalone.enabled | bool | `false` | When true, it will allow installing the Hubble UI only, without checking dependencies. It is useful if a cluster already has cilium and Hubble relay installed and you just want Hubble UI to be deployed. When installed via helm, installing UI should be done via `helm upgrade` and when installed via the cilium cli, then `cilium hubble enable --ui` | @@ -625,7 +646,8 @@ contributors across the globe, there is almost always someone available to help. | hubble.ui.updateStrategy | object | `{"rollingUpdate":{"maxUnavailable":1},"type":"RollingUpdate"}` | hubble-ui update strategy. | | identityAllocationMode | string | `"crd"` | Method to use for identity allocation (`crd`, `kvstore` or `doublewrite-readkvstore` / `doublewrite-readcrd` for migrating between identity backends). | | identityChangeGracePeriod | string | `"5s"` | Time to wait before using new identity on endpoint identity change. | -| image | object | `{"digest":"sha256:6d7ea72ed311eeca4c75a1f17617a3d596fb6038d30d00799090679f82a01636","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium","tag":"v1.17.8","useDigest":true}` | Agent container image. | +| identityManagementMode | string | `"agent"` | Control whether CiliumIdentities are created by the agent ("agent"), the operator ("operator") or both ("both"). "Both" should be used only to migrate between "agent" and "operator". Operator-managed identities is a beta feature. | +| image | object | `{"digest":"sha256: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. | @@ -675,6 +697,10 @@ contributors across the globe, there is almost always someone available to help. | k8s | object | `{"requireIPv4PodCIDR":false,"requireIPv6PodCIDR":false}` | Configure Kubernetes specific configuration | | k8s.requireIPv4PodCIDR | bool | `false` | requireIPv4PodCIDR enables waiting for Kubernetes to provide the PodCIDR range via the Kubernetes node resource | | k8s.requireIPv6PodCIDR | bool | `false` | requireIPv6PodCIDR enables waiting for Kubernetes to provide the PodCIDR range via the Kubernetes node resource | +| k8sClientExponentialBackoff | object | `{"backoffBaseSeconds":1,"backoffMaxDurationSeconds":120,"enabled":true}` | Configure exponential backoff for client-go in Cilium agent. | +| k8sClientExponentialBackoff.backoffBaseSeconds | int | `1` | Configure base (in seconds) for exponential backoff. | +| k8sClientExponentialBackoff.backoffMaxDurationSeconds | int | `120` | Configure maximum duration (in seconds) for exponential backoff. | +| k8sClientExponentialBackoff.enabled | bool | `true` | Enable exponential backoff for client-go in Cilium agent. | | k8sClientRateLimit | object | `{"burst":null,"operator":{"burst":null,"qps":null},"qps":null}` | Configure the client side rate limit for the agent If the amount of requests to the Kubernetes API server exceeds the configured rate limit, the agent will start to throttle requests by delaying them until there is budget or the request times out. | | k8sClientRateLimit.burst | int | 20 | The burst request rate in requests per second. The rate limiter will allow short bursts with a higher rate. | | k8sClientRateLimit.operator | object | `{"burst":null,"qps":null}` | Configure the client side rate limit for the Cilium Operator | @@ -683,15 +709,18 @@ contributors across the globe, there is almost always someone available to help. | k8sClientRateLimit.qps | int | 10 | The sustained request rate in requests per second. | | k8sNetworkPolicy.enabled | bool | `true` | Enable support for K8s NetworkPolicy | | k8sServiceHost | string | `""` | Kubernetes service host - use "auto" for automatic lookup from the cluster-info ConfigMap | +| k8sServiceHostRef | object | `{"key":null,"name":null}` | Configure the Kubernetes service endpoint dynamically using a ConfigMap. Mutually exclusive with `k8sServiceHost`. | +| k8sServiceHostRef.key | string | `nil` | Key in the ConfigMap containing the Kubernetes service endpoint | +| k8sServiceHostRef.name | string | `nil` | name of the ConfigMap containing the Kubernetes service endpoint | | k8sServiceLookupConfigMapName | string | `""` | When `k8sServiceHost=auto`, allows to customize the configMap name. It defaults to `cluster-info`. | | k8sServiceLookupNamespace | string | `""` | When `k8sServiceHost=auto`, allows to customize the namespace that contains `k8sServiceLookupConfigMapName`. It defaults to `kube-public`. | | k8sServicePort | string | `""` | Kubernetes service port | | keepDeprecatedLabels | bool | `false` | Keep the deprecated selector labels when deploying Cilium DaemonSet. | | keepDeprecatedProbes | bool | `false` | Keep the deprecated probes when deploying Cilium DaemonSet | | kubeConfigPath | string | `"~/.kube/config"` | Kubernetes config path | +| kubeProxyReplacement | string | `"false"` | Configure the kube-proxy replacement in Cilium BPF datapath Valid options are "true" or "false". ref: https://docs.cilium.io/en/stable/network/kubernetes/kubeproxy-free/ @schema@ type: [string, boolean] @schema@ | | kubeProxyReplacementHealthzBindAddr | string | `""` | healthz server bind address for the kube-proxy replacement. To enable set the value to '0.0.0.0:10256' for all ipv4 addresses and this '[::]:10256' for all ipv6 addresses. By default it is disabled. | -| l2NeighDiscovery.enabled | bool | `true` | Enable L2 neighbor discovery in the agent | -| l2NeighDiscovery.refreshPeriod | string | `"30s"` | Override the agent's default neighbor resolution refresh period. | +| l2NeighDiscovery.enabled | bool | `false` | Enable L2 neighbor discovery in the agent | | l2announcements | object | `{"enabled":false}` | Configure L2 announcements | | l2announcements.enabled | bool | `false` | Enable L2 announcements | | l2podAnnouncements | object | `{"enabled":false,"interface":"eth0"}` | Configure L2 pod announcements | @@ -701,24 +730,25 @@ contributors across the globe, there is almost always someone available to help. | livenessProbe.failureThreshold | int | `10` | failure threshold of liveness probe | | livenessProbe.periodSeconds | int | `30` | interval between checks of the liveness probe | | livenessProbe.requireK8sConnectivity | bool | `false` | whether to require k8s connectivity as part of the check. | -| loadBalancer | object | `{"acceleration":"disabled","experimental":false,"l7":{"algorithm":"round_robin","backend":"disabled","ports":[]}}` | Configure service load balancing | +| loadBalancer | object | `{"acceleration":"disabled","l7":{"algorithm":"round_robin","backend":"disabled","ports":[]}}` | Configure service load balancing | | loadBalancer.acceleration | string | `"disabled"` | acceleration is the option to accelerate service handling via XDP Applicable values can be: disabled (do not use XDP), native (XDP BPF program is run directly out of the networking driver's early receive path), or best-effort (use native mode XDP acceleration on devices that support it). | -| loadBalancer.experimental | bool | `false` | experimental enables support for the experimental load-balancing control-plane. | | loadBalancer.l7 | object | `{"algorithm":"round_robin","backend":"disabled","ports":[]}` | L7 LoadBalancer | | loadBalancer.l7.algorithm | string | `"round_robin"` | Default LB algorithm The default LB algorithm to be used for services, which can be overridden by the service annotation (e.g. service.cilium.io/lb-l7-algorithm) Applicable values: round_robin, least_request, random | | loadBalancer.l7.backend | string | `"disabled"` | Enable L7 service load balancing via envoy proxy. The request to a k8s service, which has specific annotation e.g. service.cilium.io/lb-l7, will be forwarded to the local backend proxy to be load balanced to the service endpoints. Please refer to docs for supported annotations for more configuration. Applicable values: - envoy: Enable L7 load balancing via envoy proxy. This will automatically set enable-envoy-config as well. - disabled: Disable L7 load balancing by way of service annotation. | | loadBalancer.l7.ports | list | `[]` | List of ports from service to be automatically redirected to above backend. Any service exposing one of these ports will be automatically redirected. Fine-grained control can be achieved by using the service annotation. | -| localRedirectPolicy | bool | `false` | Enable Local Redirect Policy. | +| localRedirectPolicies.addressMatcherCIDRs | string | `nil` | Limit the allowed addresses in Address Matcher rule of Local Redirect Policies to the given CIDRs. @schema@ type: [null, array] @schema@ | +| localRedirectPolicies.enabled | bool | `false` | Enable local redirect policies. | +| localRedirectPolicy | bool | `false` | Enable Local Redirect Policy (deprecated, please use 'localRedirectPolicies.enabled' instead) | | logSystemLoad | bool | `false` | Enables periodic logging of system load | | maglev | object | `{}` | Configure maglev consistent hashing | | monitor | object | `{"enabled":false}` | cilium-monitor sidecar. | | monitor.enabled | bool | `false` | Enable the cilium-monitor sidecar. | -| name | string | `"cilium"` | Agent container name. | +| name | string | `"cilium"` | Agent daemonset name. | | namespaceOverride | string | `""` | namespaceOverride allows to override the destination namespace for Cilium resources. This property allows to use Cilium as part of an Umbrella Chart with different targets. | | nat.mapStatsEntries | int | `32` | Number of the top-k SNAT map connections to track in Cilium statedb. | | nat.mapStatsInterval | string | `"30s"` | Interval between how often SNAT map is counted for stats. | | nat46x64Gateway | object | `{"enabled":false}` | Configure standalone NAT46/NAT64 gateway | -| nat46x64Gateway.enabled | bool | `false` | Enable RFC8215-prefixed translation | +| nat46x64Gateway.enabled | bool | `false` | Enable RFC6052-prefixed translation | | nodeIPAM.enabled | bool | `false` | Configure Node IPAM ref: https://docs.cilium.io/en/stable/network/node-ipam/ | | nodePort | object | `{"addresses":null,"autoProtectPortRange":true,"bindProtection":true,"enableHealthCheck":true,"enableHealthCheckLoadBalancerIP":false,"enabled":false}` | Configure N-S k8s service loadbalancing | | nodePort.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"] | @@ -745,7 +775,7 @@ contributors across the globe, there is almost always someone available to help. | nodeinit.prestop | object | `{"postScript":"","preScript":""}` | prestop offers way to customize prestop nodeinit script (pre and post position) | | nodeinit.priorityClassName | string | `""` | The priority class to use for the nodeinit pod. | | nodeinit.resources | object | `{"requests":{"cpu":"100m","memory":"100Mi"}}` | nodeinit resource limits & requests ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | -| nodeinit.securityContext | object | `{"capabilities":{"add":["SYS_MODULE","NET_ADMIN","SYS_ADMIN","SYS_CHROOT","SYS_PTRACE"]},"privileged":false,"seLinuxOptions":{"level":"s0","type":"spc_t"}}` | Security context to be added to nodeinit pods. | +| nodeinit.securityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"add":["SYS_MODULE","NET_ADMIN","SYS_ADMIN","SYS_CHROOT","SYS_PTRACE"]},"privileged":false,"seLinuxOptions":{"level":"s0","type":"spc_t"}}` | Security context to be added to nodeinit pods. | | nodeinit.startup | object | `{"postScript":"","preScript":""}` | startup offers way to customize startup nodeinit script (pre and post position) | | nodeinit.tolerations | list | `[{"operator":"Exists"}]` | Node tolerations for nodeinit scheduling to nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ | | nodeinit.updateStrategy | object | `{"type":"RollingUpdate"}` | node-init update strategy | @@ -763,20 +793,21 @@ 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:72c25a405ad8e58d2cf03f7ea2b6696ed1edcfb51716b5f85e45c6c4fcaa6056","awsDigest":"sha256:28012f7d0f4f23e9f6c7d6a5dd931afa326bbac3e8103f3f6f22b9670847dffa","azureDigest":"sha256:619f9febf3efef2724a26522b253e4595cd33c274f5f49925e29a795fdc2d2d7","genericDigest":"sha256:5468807b9c31997f3a1a14558ec7c20c5b962a2df6db633b7afbe2f45a15da1c","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/operator","suffix":"","tag":"v1.17.8","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 | | operator.podDisruptionBudget.enabled | bool | `false` | enable PodDisruptionBudget ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ | | operator.podDisruptionBudget.maxUnavailable | int | `1` | Maximum number/percentage of pods that may be made unavailable | | operator.podDisruptionBudget.minAvailable | string | `nil` | Minimum number/percentage of pods that should remain scheduled. When it's set, maxUnavailable must be disabled by `maxUnavailable: null` | +| operator.podDisruptionBudget.unhealthyPodEvictionPolicy | string | `nil` | How are unhealthy, but running, pods counted for eviction | | operator.podLabels | object | `{}` | Labels to be added to cilium-operator pods | -| operator.podSecurityContext | object | `{}` | Security context to be added to cilium-operator pods | +| operator.podSecurityContext | object | `{"seccompProfile":{"type":"RuntimeDefault"}}` | Security context to be added to cilium-operator pods | | operator.pprof.address | string | `"localhost"` | Configure pprof listen address for cilium-operator | | operator.pprof.enabled | bool | `false` | Enable pprof for cilium-operator | | operator.pprof.port | int | `6061` | Configure pprof listen port for cilium-operator | | operator.priorityClassName | string | `""` | The priority class to use for cilium-operator | -| operator.prometheus | object | `{"enabled":true,"metricsService":false,"port":9963,"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","jobLabel":"","labels":{},"metricRelabelings":null,"relabelings":null}}` | Enable prometheus metrics for cilium-operator on the configured port at /metrics | +| operator.prometheus | object | `{"enabled":true,"metricsService":false,"port":9963,"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","jobLabel":"","labels":{},"metricRelabelings":null,"relabelings":null,"scrapeTimeout":null}}` | Enable prometheus metrics for cilium-operator on the configured port at /metrics | | operator.prometheus.serviceMonitor.annotations | object | `{}` | Annotations to add to ServiceMonitor cilium-operator | | operator.prometheus.serviceMonitor.enabled | bool | `false` | Enable service monitors. This requires the prometheus CRDs to be available (see https://github.com/prometheus-operator/prometheus-operator/blob/main/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml) | | operator.prometheus.serviceMonitor.interval | string | `"10s"` | Interval for scrape metrics. | @@ -784,15 +815,16 @@ contributors across the globe, there is almost always someone available to help. | operator.prometheus.serviceMonitor.labels | object | `{}` | Labels to add to ServiceMonitor cilium-operator | | operator.prometheus.serviceMonitor.metricRelabelings | string | `nil` | Metrics relabeling configs for the ServiceMonitor cilium-operator | | operator.prometheus.serviceMonitor.relabelings | string | `nil` | Relabeling configs for the ServiceMonitor cilium-operator | +| operator.prometheus.serviceMonitor.scrapeTimeout | string | `nil` | Timeout after which scrape is considered to be failed. | | operator.removeNodeTaints | bool | `true` | Remove Cilium node taint from Kubernetes nodes that have a healthy Cilium pod running. | | operator.replicas | int | `2` | Number of replicas to run for the cilium-operator deployment | | operator.resources | object | `{}` | cilium-operator resource limits & requests ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | | operator.rollOutPods | bool | `false` | Roll out cilium-operator pods automatically when configmap is updated. | -| operator.securityContext | object | `{}` | Security context to be added to cilium-operator pods | +| operator.securityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]}}` | Security context to be added to cilium-operator pods | | operator.setNodeNetworkStatus | bool | `true` | Set Node condition NetworkUnavailable to 'false' with the reason 'CiliumIsUp' for nodes that have a healthy Cilium pod. | | operator.setNodeTaints | string | same as removeNodeTaints | Taint nodes where Cilium is scheduled but not running. This prevents pods from being scheduled to nodes where Cilium is not the default CNI provider. | | operator.skipCRDCreation | bool | `false` | Skip CRDs creation for cilium-operator | -| operator.tolerations | list | `[{"operator":"Exists"}]` | Node tolerations for cilium-operator scheduling to nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ | +| operator.tolerations | list | `[{"key":"node-role.kubernetes.io/control-plane","operator":"Exists"},{"key":"node-role.kubernetes.io/master","operator":"Exists"},{"key":"node.kubernetes.io/not-ready","operator":"Exists"},{"key":"node.cloudprovider.kubernetes.io/uninitialized","operator":"Exists"}]` | Node tolerations for cilium-operator scheduling to nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ Toleration for agentNotReadyTaintKey taint is always added to cilium-operator pods. @schema type: [null, array] @schema | | operator.topologySpreadConstraints | list | `[]` | Pod topology spread constraints for cilium-operator | | operator.unmanagedPodWatcher.intervalSeconds | int | `15` | Interval, in seconds, to check if there are any pods that are not managed by Cilium. | | operator.unmanagedPodWatcher.restart | bool | `true` | Restart any pod that are not managed by Cilium. | @@ -810,29 +842,31 @@ contributors across the globe, there is almost always someone available to help. | 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: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:6d7ea72ed311eeca4c75a1f17617a3d596fb6038d30d00799090679f82a01636","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium","tag":"v1.17.8","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/ | | preflight.podDisruptionBudget.maxUnavailable | int | `1` | Maximum number/percentage of pods that may be made unavailable | | preflight.podDisruptionBudget.minAvailable | string | `nil` | Minimum number/percentage of pods that should remain scheduled. When it's set, maxUnavailable must be disabled by `maxUnavailable: null` | +| preflight.podDisruptionBudget.unhealthyPodEvictionPolicy | string | `nil` | How are unhealthy, but running, pods counted for eviction | | preflight.podLabels | object | `{}` | Labels to be added to the preflight pod. | | preflight.podSecurityContext | object | `{}` | Security context to be added to preflight pods. | | preflight.priorityClassName | string | `""` | The priority class to use for the preflight pod. | | preflight.readinessProbe.initialDelaySeconds | int | `5` | For how long kubelet should wait before performing the first probe | | preflight.readinessProbe.periodSeconds | int | `5` | interval between checks of the readiness probe | | preflight.resources | object | `{}` | preflight resource limits & requests ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | -| preflight.securityContext | object | `{}` | Security context to be added to preflight pods | +| preflight.securityContext | object | `{"allowPrivilegeEscalation":false}` | Security context to be added to preflight pods | | preflight.terminationGracePeriodSeconds | int | `1` | Configure termination grace period for preflight Deployment and DaemonSet. | | preflight.tofqdnsPreCache | string | `""` | Path to write the `--tofqdns-pre-cache` file to. | | preflight.tolerations | list | `[{"operator":"Exists"}]` | Node tolerations for preflight scheduling to nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ | | preflight.updateStrategy | object | `{"type":"RollingUpdate"}` | preflight update strategy | | preflight.validateCNPs | bool | `true` | By default we should always validate the installed CNPs before upgrading Cilium. This will make sure the user will have the policies deployed in the cluster with the right schema. | | priorityClassName | string | `""` | The priority class to use for cilium-agent. | -| prometheus | object | `{"controllerGroupMetrics":["write-cni-file","sync-host-ips","sync-lb-maps-with-k8s-services"],"enabled":false,"metrics":null,"metricsService":false,"port":9962,"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","jobLabel":"","labels":{},"metricRelabelings":null,"relabelings":[{"replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}],"trustCRDsExist":false}}` | Configure prometheus metrics on the configured port at /metrics | +| prometheus | object | `{"controllerGroupMetrics":["write-cni-file","sync-host-ips","sync-lb-maps-with-k8s-services"],"enabled":false,"metrics":null,"metricsService":false,"port":9962,"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","jobLabel":"","labels":{},"metricRelabelings":null,"relabelings":[{"action":"replace","replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}],"scrapeTimeout":null,"trustCRDsExist":false}}` | Configure prometheus metrics on the configured port at /metrics | | prometheus.controllerGroupMetrics | list | `["write-cni-file","sync-host-ips","sync-lb-maps-with-k8s-services"]` | - Enable controller group metrics for monitoring specific Cilium subsystems. The list is a list of controller group names. The special values of "all" and "none" are supported. The set of controller group names is not guaranteed to be stable between Cilium versions. | | prometheus.metrics | string | `nil` | Metrics that should be enabled or disabled from the default metric list. The list is expected to be separated by a space. (+metric_foo to enable metric_foo , -metric_bar to disable metric_bar). ref: https://docs.cilium.io/en/stable/observability/metrics/ | | prometheus.serviceMonitor.annotations | object | `{}` | Annotations to add to ServiceMonitor cilium-agent | @@ -841,7 +875,8 @@ contributors across the globe, there is almost always someone available to help. | prometheus.serviceMonitor.jobLabel | string | `""` | jobLabel to add for ServiceMonitor cilium-agent | | prometheus.serviceMonitor.labels | object | `{}` | Labels to add to ServiceMonitor cilium-agent | | prometheus.serviceMonitor.metricRelabelings | string | `nil` | Metrics relabeling configs for the ServiceMonitor cilium-agent | -| prometheus.serviceMonitor.relabelings | list | `[{"replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}]` | Relabeling configs for the ServiceMonitor cilium-agent | +| prometheus.serviceMonitor.relabelings | list | `[{"action":"replace","replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}]` | Relabeling configs for the ServiceMonitor cilium-agent | +| prometheus.serviceMonitor.scrapeTimeout | string | `nil` | Timeout after which scrape is considered to be failed. | | prometheus.serviceMonitor.trustCRDsExist | bool | `false` | Set to `true` and helm will not check for monitoring.coreos.com/v1 CRDs before deploying | | rbac.create | bool | `true` | Enable creation of Resource-Based Access Control configuration. | | readinessProbe.failureThreshold | int | `3` | failure threshold of readiness probe | @@ -854,6 +889,8 @@ contributors across the globe, there is almost always someone available to help. | scheduling.mode | string | Defaults to apply a pod anti-affinity rule to the agent pod - `anti-affinity` | Mode specifies how Cilium daemonset pods should be scheduled to Nodes. `anti-affinity` mode applies a pod anti-affinity rule to the cilium daemonset. Pod anti-affinity may significantly impact scheduling throughput for large clusters. See: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity `kube-scheduler` mode forgoes the anti-affinity rule for full scheduling throughput. Kube-scheduler avoids host port conflict when scheduling pods. | | sctp | object | `{"enabled":false}` | SCTP Configuration Values | | sctp.enabled | bool | `false` | Enable SCTP support. NOTE: Currently, SCTP support does not support rewriting ports or multihoming. | +| secretsNamespaceAnnotations | object | `{}` | Annotations to be added to all cilium-secret namespaces (resources under templates/cilium-secrets-namespace) | +| securityContext.allowPrivilegeEscalation | bool | `false` | disable privilege escalation | | securityContext.capabilities.applySysctlOverwrites | list | `["SYS_ADMIN","SYS_CHROOT","SYS_PTRACE"]` | capabilities for the `apply-sysctl-overwrites` init container | | securityContext.capabilities.ciliumAgent | list | `["CHOWN","KILL","NET_ADMIN","NET_RAW","IPC_LOCK","SYS_MODULE","SYS_ADMIN","SYS_RESOURCE","DAC_OVERRIDE","FOWNER","SETGID","SETUID"]` | Capabilities for the `cilium-agent` container | | securityContext.capabilities.cleanCiliumState | list | `["NET_ADMIN","SYS_MODULE","SYS_ADMIN","SYS_RESOURCE"]` | Capabilities for the `clean-cilium-state` init container | @@ -868,7 +905,7 @@ contributors across the globe, there is almost always someone available to help. | sleepAfterInit | bool | `false` | Do not run Cilium agent when running with clean mode. Useful to completely uninstall Cilium as it will stop Cilium from starting and create artifacts in the node. | | socketLB | object | `{"enabled":false}` | Configure socket LB | | socketLB.enabled | bool | `false` | Enable socket LB | -| startupProbe.failureThreshold | int | `105` | failure threshold of startup probe. 105 x 2s translates to the old behaviour of the readiness probe (120s delay + 30 x 3s) | +| 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. | @@ -896,6 +933,7 @@ contributors across the globe, there is almost always someone available to help. | 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. | | updateStrategy | object | `{"rollingUpdate":{"maxUnavailable":2},"type":"RollingUpdate"}` | Cilium agent update strategy | | upgradeCompatibility | string | `nil` | upgradeCompatibility helps users upgrading to ensure that the configMap for Cilium will not change critical values to ensure continued operation This flag is not required for new installations. For example: '1.7', '1.8', '1.9' | | vtep.cidr | string | `""` | A space separated list of VTEP device CIDRs, for example "1.1.1.0/24 1.1.2.0/24" | diff --git a/packages/system/cilium/charts/cilium/files/cilium-agent/dashboards/cilium-dashboard.json b/packages/system/cilium/charts/cilium/files/cilium-agent/dashboards/cilium-dashboard.json index e6cf5c26..1f0a1080 100644 --- a/packages/system/cilium/charts/cilium/files/cilium-agent/dashboards/cilium-dashboard.json +++ b/packages/system/cilium/charts/cilium/files/cilium-agent/dashboards/cilium-dashboard.json @@ -39,6 +39,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -133,7 +134,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -169,6 +170,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -276,7 +278,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -317,7 +319,6 @@ }, { "collapsed": false, - "datasource": null, "gridPos": { "h": 1, "w": 24, @@ -346,6 +347,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -498,7 +500,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -554,6 +556,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -633,7 +636,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -691,6 +694,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -770,7 +774,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -838,6 +842,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -917,7 +922,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -981,6 +986,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -1045,7 +1051,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -1063,7 +1069,6 @@ }, { "collapsed": false, - "datasource": null, "gridPos": { "h": 1, "w": 24, @@ -1092,6 +1097,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -1198,7 +1204,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -1232,6 +1238,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -1338,7 +1345,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -1372,6 +1379,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -1478,7 +1486,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -1512,6 +1520,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -1618,7 +1627,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -1652,6 +1661,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -1758,7 +1768,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -1792,6 +1802,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -1898,7 +1909,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -1917,7 +1928,6 @@ }, { "collapsed": false, - "datasource": null, "gridPos": { "h": 1, "w": 24, @@ -1930,7 +1940,10 @@ "type": "row" }, { - "datasource": null, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, "gridPos": { "h": 1, "w": 24, @@ -1947,13 +1960,7 @@ "content": "", "mode": "markdown" }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": null, - "refId": "A" - } - ], + "pluginVersion": "11.3.1", "title": "BPF", "type": "text" }, @@ -1974,6 +1981,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -2081,7 +2089,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -2117,6 +2125,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -2225,7 +2234,7 @@ "sort": "desc" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -2259,6 +2268,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -2366,7 +2376,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -2400,6 +2410,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -2466,7 +2477,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -2500,6 +2511,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -2584,7 +2596,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -2618,6 +2630,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -2702,7 +2715,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -2736,6 +2749,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -2840,7 +2854,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -2858,7 +2872,10 @@ "type": "timeseries" }, { - "datasource": null, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, "gridPos": { "h": 1, "w": 24, @@ -2875,13 +2892,7 @@ "content": "", "mode": "markdown" }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": null, - "refId": "A" - } - ], + "pluginVersion": "11.3.1", "title": "kvstore", "type": "text" }, @@ -2902,6 +2913,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -3010,7 +3022,7 @@ "sort": "desc" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -3044,6 +3056,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -3152,7 +3165,7 @@ "sort": "desc" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -3186,6 +3199,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -3293,7 +3307,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -3327,6 +3341,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -3434,7 +3449,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -3468,6 +3483,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -3572,7 +3588,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -3590,7 +3606,10 @@ "type": "timeseries" }, { - "datasource": null, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, "gridPos": { "h": 1, "w": 24, @@ -3607,13 +3626,7 @@ "content": "", "mode": "markdown" }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": null, - "refId": "A" - } - ], + "pluginVersion": "11.3.1", "title": "Cilium network information", "type": "text" }, @@ -3634,6 +3647,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -3697,7 +3711,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -3731,6 +3745,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -3794,7 +3809,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -3828,6 +3843,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -4175,7 +4191,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -4254,6 +4270,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -4601,7 +4618,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -4680,6 +4697,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -5027,7 +5045,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -5106,6 +5124,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -5453,7 +5472,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -5532,6 +5551,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 0, "gradientMode": "none", @@ -5631,7 +5651,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -5665,6 +5685,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -5759,7 +5780,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -5793,6 +5814,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -5856,7 +5878,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -5890,6 +5912,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -5953,7 +5976,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -5998,6 +6021,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -6061,7 +6085,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -6095,6 +6119,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -6265,7 +6290,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -6299,6 +6324,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -6362,7 +6388,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -6396,6 +6422,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -6518,7 +6545,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -6558,7 +6585,10 @@ "type": "timeseries" }, { - "datasource": null, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, "gridPos": { "h": 1, "w": 24, @@ -6575,13 +6605,7 @@ "content": "", "mode": "markdown" }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": null, - "refId": "A" - } - ], + "pluginVersion": "11.3.1", "title": "Policy", "type": "text" }, @@ -6602,6 +6626,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -6711,40 +6736,20 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "sum(rate(cilium_policy_l7_total{k8s_app=\"cilium\", pod=~\"$pod\", rule=\"denied\"}[1m]))", + "editorMode": "code", + "expr": "sum by(rule, proxy_type) (rate(cilium_policy_l7_total{k8s_app=\"cilium\", pod=~\"$pod\"}[1m]))", "format": "time_series", "intervalFactor": 1, - "legendFormat": "denied", + "legendFormat": "{{proxy_type}} - {{rule}}", + "range": true, "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "sum(rate(cilium_policy_l7_total{k8s_app=\"cilium\", pod=~\"$pod\", rule=\"forwarded\"}[1m]))", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "forwarded", - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "sum(rate(cilium_policy_l7_total{k8s_app=\"cilium\", pod=~\"$pod\", rule=\"received\"}[1m]))", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "received", - "refId": "C" } ], "title": "L7 forwarded request", @@ -6755,6 +6760,7 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "description": "99th percentile of DNS proxy request processing latency, by span", "fieldConfig": { "defaults": { "color": { @@ -6767,8 +6773,9 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", - "fillOpacity": 10, + "fillOpacity": 34, "gradientMode": "none", "hideFrom": { "legend": false, @@ -6777,12 +6784,15 @@ }, "insertNulls": false, "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, - "showPoints": "never", + "showPoints": "auto", "spanNulls": false, "stacking": { "group": "A", @@ -6800,14 +6810,10 @@ { "color": "green", "value": null - }, - { - "color": "red", - "value": 80 } ] }, - "unit": "ops" + "unit": "s" }, "overrides": [] }, @@ -6817,213 +6823,7 @@ "x": 12, "y": 115 }, - "id": 37, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "sum(rate(cilium_drop_count_total{direction=\"INGRESS\", k8s_app=\"cilium\", pod=~\"$pod\"}[5m])) by (reason)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "{{reason}}", - "refId": "A" - } - ], - "title": "Cilium drops Ingress", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "bars", - "fillOpacity": 100, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "normal" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Max per node processingTime" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#e24d42", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Max per node upstreamTime" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#58140c", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "avg(cilium_policy_l7_total{pod=~\"cilium.*\", rule=\"parse_errors\"})" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#bf1b00", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "parse errors" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#bf1b00", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Max per node processingTime" - }, - "properties": [ - { - "id": "unit", - "value": "short" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Max per node upstreamTime" - }, - "properties": [ - { - "id": "unit", - "value": "short" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "avg(cilium_policy_l7_total{pod=~\"cilium.*\", rule=\"parse_errors\"})" - }, - "properties": [ - { - "id": "unit", - "value": "short" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "parse errors" - }, - "properties": [ - { - "id": "unit", - "value": "short" - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 12, - "x": 0, - "y": 120 - }, - "id": 94, + "id": 123, "options": { "legend": { "calcs": [ @@ -7038,33 +6838,23 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "avg(rate(cilium_proxy_upstream_reply_seconds_sum{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope) / sum(rate(cilium_proxy_upstream_reply_seconds_count{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope)", + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by(scope, le) (rate(cilium_proxy_upstream_reply_seconds_bucket{protocol_l7=\"dns\", k8s_app=\"cilium\", pod=~\"$pod\", scope!=\"totalTime\"}[5m]))) \n", "format": "time_series", - "interval": "", "intervalFactor": 1, "legendFormat": "{{scope}}", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "avg(cilium_policy_l7_total{k8s_app=\"cilium\", pod=~\"$pod\", rule=\"parse_errors\"}) by (pod)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "parse errors", + "range": true, "refId": "B" } ], - "title": "Proxy response time (Avg)", + "title": "DNS proxy request latency", "type": "timeseries" }, { @@ -7084,6 +6874,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -7117,21 +6908,17 @@ { "color": "green", "value": null - }, - { - "color": "red", - "value": 80 } ] }, - "unit": "bps" + "unit": "pps" }, "overrides": [] }, "gridPos": { "h": 5, "w": 12, - "x": 12, + "x": 0, "y": 120 }, "id": 114, @@ -7147,21 +6934,22 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "sum(rate(cilium_drop_bytes_total{direction=\"INGRESS\", k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (reason) * 8", + "expr": "sum(rate(cilium_drop_count_total{k8s_app=\"cilium\", pod=~\"$pod\", reason=\"Policy denied\"}[1m])) by (direction)", "format": "time_series", "intervalFactor": 1, - "legendFormat": "{{reason}}", + "legendFormat": "{{direction}}", + "range": true, "refId": "A" } ], - "title": "Dropped Ingress Traffic", + "title": "Policy Denies: L3/L4", "type": "timeseries" }, { @@ -7181,6 +6969,103 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 120 + }, + "id": 37, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(cilium_policy_l7_total{rule=\"denied\", k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (proxy_type)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{reason}}", + "range": true, + "refId": "A" + } + ], + "title": "Policy Denies: L7", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "End-to-end duration to apply incremental identity updates to the policy control and data planes.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -7357,17 +7242,19 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "min(rate(cilium_triggers_policy_update_call_duration_seconds_sum{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope) / sum(rate(cilium_triggers_policy_update_call_duration_seconds_count{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope)", + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by(le) (rate(cilium_policy_incremental_update_duration_bucket{k8s_app=\"cilium\", pod=~\"$pod\"}[5m])))", "format": "time_series", "intervalFactor": 1, - "legendFormat": "min", + "legendFormat": "99%", + "range": true, "refId": "A" }, { @@ -7375,25 +7262,16 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "avg(rate(cilium_triggers_policy_update_call_duration_seconds_sum{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope) / sum(rate(cilium_triggers_policy_update_call_duration_seconds_count{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope)", + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum by(le) (rate(cilium_policy_incremental_update_duration_bucket{k8s_app=\"cilium\", pod=~\"$pod\"}[5m])))", "format": "time_series", "intervalFactor": 1, - "legendFormat": "avg", + "legendFormat": "50%", + "range": true, "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "max(rate(cilium_triggers_policy_update_call_duration_seconds_sum{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope) / sum(rate(cilium_triggers_policy_update_call_duration_seconds_count{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "max", - "refId": "C" } ], - "title": "Policy Trigger Duration", + "title": "Policy Identity Update Latency", "type": "timeseries" }, { @@ -7401,6 +7279,7 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "description": "The time taken for new or updated network policy to be applied to all affected endpoints", "fieldConfig": { "defaults": { "color": { @@ -7413,8 +7292,9 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, - "drawStyle": "bars", - "fillOpacity": 100, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 35, "gradientMode": "none", "hideFrom": { "legend": false, @@ -7432,7 +7312,7 @@ "spanNulls": false, "stacking": { "group": "A", - "mode": "normal" + "mode": "none" }, "thresholdsStyle": { "mode": "off" @@ -7455,530 +7335,6 @@ }, "unit": "s" }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Max per node processingTime" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#e24d42", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Max per node upstreamTime" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#58140c", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "parse errors" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#bf1b00", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "parse errors" - }, - "properties": [ - { - "id": "unit", - "value": "short" - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 12, - "x": 12, - "y": 125 - }, - "id": 66, - "options": { - "legend": { - "calcs": [ - "mean" - ], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "max(rate(cilium_proxy_upstream_reply_seconds_sum{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope) / sum(rate(cilium_proxy_upstream_reply_seconds_count{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Max {{scope}}", - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "max(rate(cilium_policy_l7_total{k8s_app=\"cilium\", pod=~\"$pod\", rule=\"parse_errors\"}[1m])) by (pod)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "parse errors", - "refId": "A" - } - ], - "title": "Proxy response time (Max)", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "bars", - "fillOpacity": 100, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "both" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#7eb26d", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "egress" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#e5ac0e", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "ingress" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#e0752d", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "none" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#bf1b00", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 0, - "y": 130 - }, - "id": 33, - "options": { - "legend": { - "calcs": [ - "lastNotNull" - ], - "displayMode": "list", - "placement": "right", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "sum(cilium_policy_endpoint_enforcement_status{k8s_app=\"cilium\", pod=~\"$pod\"}) by (enforcement)", - "format": "time_series", - "hide": false, - "instant": true, - "interval": "1s", - "intervalFactor": 1, - "legendFormat": "{{enforcement}}", - "refId": "B" - } - ], - "title": "Endpoints policy enforcement status", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 35, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "avg" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#b7dbab", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "max" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "rgba(89, 132, 76, 0.54)", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "min" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#2f575e", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "max" - }, - "properties": [ - { - "id": "custom.fillBelowTo", - "value": "min" - }, - { - "id": "custom.lineWidth", - "value": 0 - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "min" - }, - "properties": [ - { - "id": "custom.lineWidth", - "value": 0 - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 6, - "y": 130 - }, - "id": 100, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "min(cilium_proxy_redirects{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "min", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "avg(cilium_proxy_redirects{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "avg", - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "max(cilium_proxy_redirects{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "max", - "refId": "C" - } - ], - "title": "Proxy Redirects", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 35, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "opm" - }, "overrides": [ { "matcher": { @@ -8116,7 +7472,7 @@ "h": 5, "w": 12, "x": 12, - "y": 130 + "y": 125 }, "id": 102, "options": { @@ -8131,17 +7487,19 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "min(rate(cilium_triggers_policy_update_total{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod) * 60", + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by(le) (rate(cilium_policy_implementation_delay_bucket{k8s_app=\"cilium\", pod=~\"$pod\"}[5m])))", "format": "time_series", "intervalFactor": 1, - "legendFormat": "min trigger", + "legendFormat": "99%", + "range": true, "refId": "A" }, { @@ -8149,36 +7507,16 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "avg(rate(cilium_triggers_policy_update_total{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod) * 60", + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum by(le) (rate(cilium_policy_implementation_delay_bucket{k8s_app=\"cilium\", pod=~\"$pod\"}[5m]))) ", "format": "time_series", "intervalFactor": 1, - "legendFormat": "average trigger", + "legendFormat": "50%", + "range": true, "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "max(rate(cilium_triggers_policy_update_total{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod) * 60", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "max trigger", - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "max(rate(cilium_triggers_policy_update_folds{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod) * 60", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "folds", - "refId": "D" } ], - "title": "Policy Trigger Runs", + "title": "Policy Apply Latency", "type": "timeseries" }, { @@ -8198,6 +7536,540 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "bars", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "both" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7eb26d", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "egress" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#e5ac0e", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ingress" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#e0752d", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "none" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 130 + }, + "id": 33, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(cilium_policy_endpoint_enforcement_status{k8s_app=\"cilium\", pod=~\"$pod\"}) by (enforcement)", + "format": "time_series", + "hide": false, + "instant": true, + "interval": "1s", + "intervalFactor": 1, + "legendFormat": "{{enforcement}}", + "refId": "B" + } + ], + "title": "Endpoints policy enforcement status", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 35, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "avg" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#b7dbab", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "max" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "rgba(89, 132, 76, 0.54)", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "min" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2f575e", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "max" + }, + "properties": [ + { + "id": "custom.fillBelowTo", + "value": "min" + }, + { + "id": "custom.lineWidth", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "min" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 130 + }, + "id": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "min(cilium_proxy_redirects{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "min", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "avg(cilium_proxy_redirects{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "avg", + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "max(cilium_proxy_redirects{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "max", + "refId": "C" + } + ], + "title": "Proxy Redirects", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Endpoint policy calculation time by stage. Shows the 99th-percentile.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 35, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "avg" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#f9d9f9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "max" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806eb7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "min" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806eb7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "max" + }, + "properties": [ + { + "id": "custom.fillBelowTo", + "value": "min" + }, + { + "id": "custom.lineWidth", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "min" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 130 + }, + "id": 117, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by(scope, le) (rate(cilium_endpoint_regeneration_time_stats_seconds_bucket{scope=~\"proxyConfiguration|endpointPolicyCalculation|selectorPolicyCalculation|proxyPolicyCalculation\",k8s_app=\"cilium\",status=\"success\",pod=~\"$pod\"}[5m])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Policy Calculation Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -8337,7 +8209,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -8388,366 +8260,15 @@ "type": "timeseries" }, { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "bars", - "fillOpacity": 100, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "normal" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "ops" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Max per node processingTime" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#e24d42", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Max per node upstreamTime" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#58140c", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "parse errors" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#bf1b00", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "parse errors" - }, - "properties": [ - { - "id": "unit", - "value": "s" - }, - { - "id": "custom.axisPlacement", - "value": "hidden" - } - ] - } - ] + "defaults": {}, + "overrides": [] }, - "gridPos": { - "h": 5, - "w": 12, - "x": 12, - "y": 135 - }, - "id": 123, - "options": { - "legend": { - "calcs": [ - "mean" - ], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "avg(rate(cilium_proxy_upstream_reply_seconds_count{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "{{scope}}", - "refId": "B" - } - ], - "title": "DNS proxy requests", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 35, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "avg" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#f9d9f9", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "max" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#806eb7", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "min" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#806eb7", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "max" - }, - "properties": [ - { - "id": "custom.fillBelowTo", - "value": "min" - }, - { - "id": "custom.lineWidth", - "value": 0 - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "min" - }, - "properties": [ - { - "id": "custom.lineWidth", - "value": 0 - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 12, - "x": 12, - "y": 140 - }, - "id": 117, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "min(cilium_policy_max_revision{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "min", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "avg(cilium_policy_max_revision{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "avg", - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "max(cilium_policy_max_revision{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "max", - "refId": "C" - } - ], - "title": "Policy Revision", - "type": "timeseries" - }, - { - "datasource": null, "gridPos": { "h": 1, "w": 24, "x": 0, - "y": 145 + "y": 140 }, "id": 73, "options": { @@ -8759,13 +8280,7 @@ "content": "", "mode": "markdown" }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": null, - "refId": "A" - } - ], + "pluginVersion": "11.3.1", "title": "Endpoints", "type": "text" }, @@ -8786,6 +8301,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -8834,7 +8350,7 @@ "h": 9, "w": 12, "x": 0, - "y": 146 + "y": 141 }, "id": 55, "options": { @@ -8851,7 +8367,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -8885,6 +8401,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -8933,7 +8450,7 @@ "h": 9, "w": 12, "x": 12, - "y": 146 + "y": 141 }, "id": 115, "options": { @@ -8950,7 +8467,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -8984,6 +8501,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -9093,7 +8611,7 @@ "h": 5, "w": 12, "x": 0, - "y": 155 + "y": 150 }, "id": 49, "options": { @@ -9111,7 +8629,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -9146,6 +8664,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -9240,7 +8759,7 @@ "h": 5, "w": 12, "x": 12, - "y": 155 + "y": 150 }, "id": 51, "options": { @@ -9257,7 +8776,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -9275,12 +8794,15 @@ "type": "timeseries" }, { - "datasource": null, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, "gridPos": { "h": 1, "w": 24, "x": 0, - "y": 160 + "y": 155 }, "id": 74, "options": { @@ -9292,13 +8814,7 @@ "content": "", "mode": "markdown" }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": null, - "refId": "A" - } - ], + "pluginVersion": "11.3.1", "title": "Controllers", "type": "text" }, @@ -9319,6 +8835,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 30, "gradientMode": "none", @@ -9413,7 +8930,7 @@ "h": 5, "w": 12, "x": 0, - "y": 161 + "y": 156 }, "id": 70, "options": { @@ -9431,7 +8948,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -9476,6 +8993,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -9615,7 +9133,7 @@ "h": 5, "w": 12, "x": 12, - "y": 161 + "y": 156 }, "id": 68, "options": { @@ -9634,8 +9152,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", - "repeatDirection": "h", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -9653,12 +9170,15 @@ "type": "timeseries" }, { - "datasource": null, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, "gridPos": { "h": 1, "w": 24, "x": 0, - "y": 166 + "y": 161 }, "id": 60, "options": { @@ -9670,13 +9190,7 @@ "content": "", "mode": "markdown" }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": null, - "refId": "A" - } - ], + "pluginVersion": "11.3.1", "title": "Kubernetes integration", "type": "text" }, @@ -9697,6 +9211,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -9786,7 +9301,7 @@ "h": 7, "w": 12, "x": 0, - "y": 167 + "y": 162 }, "id": 163, "options": { @@ -9801,7 +9316,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -9835,6 +9350,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -9924,7 +9440,7 @@ "h": 7, "w": 12, "x": 12, - "y": 167 + "y": 162 }, "id": 165, "options": { @@ -9939,7 +9455,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -9973,6 +9489,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -10062,7 +9579,7 @@ "h": 8, "w": 12, "x": 0, - "y": 174 + "y": 169 }, "id": 168, "options": { @@ -10080,7 +9597,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -10114,6 +9631,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -10203,7 +9721,7 @@ "h": 8, "w": 12, "x": 12, - "y": 174 + "y": 169 }, "id": 166, "options": { @@ -10220,7 +9738,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -10254,6 +9772,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -10343,7 +9862,7 @@ "h": 6, "w": 12, "x": 0, - "y": 182 + "y": 177 }, "id": 172, "options": { @@ -10360,7 +9879,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -10394,6 +9913,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -10483,7 +10003,7 @@ "h": 6, "w": 12, "x": 12, - "y": 182 + "y": 177 }, "id": 174, "options": { @@ -10500,7 +10020,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -10534,6 +10054,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -10623,7 +10144,7 @@ "h": 8, "w": 12, "x": 0, - "y": 188 + "y": 183 }, "id": 175, "options": { @@ -10640,7 +10161,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -10674,6 +10195,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -10763,7 +10285,7 @@ "h": 8, "w": 12, "x": 12, - "y": 188 + "y": 183 }, "id": 173, "options": { @@ -10780,7 +10302,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -10814,6 +10336,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -10862,7 +10385,7 @@ "h": 7, "w": 12, "x": 0, - "y": 196 + "y": 191 }, "id": 108, "options": { @@ -10877,7 +10400,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -10911,6 +10434,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -11005,7 +10529,7 @@ "h": 7, "w": 12, "x": 12, - "y": 196 + "y": 191 }, "id": 119, "options": { @@ -11020,7 +10544,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -11054,6 +10578,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -11148,7 +10673,7 @@ "h": 7, "w": 12, "x": 0, - "y": 203 + "y": 198 }, "id": 109, "options": { @@ -11163,7 +10688,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -11197,6 +10722,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -11291,7 +10817,7 @@ "h": 7, "w": 12, "x": 12, - "y": 203 + "y": 198 }, "id": 122, "options": { @@ -11306,7 +10832,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -11340,6 +10866,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -11388,7 +10915,7 @@ "h": 7, "w": 12, "x": 0, - "y": 210 + "y": 205 }, "id": 118, "options": { @@ -11403,7 +10930,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -11437,6 +10964,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -11485,7 +11013,7 @@ "h": 7, "w": 12, "x": 12, - "y": 210 + "y": 205 }, "id": 120, "options": { @@ -11500,7 +11028,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -11534,6 +11062,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -11582,7 +11111,7 @@ "h": 7, "w": 12, "x": 0, - "y": 217 + "y": 212 }, "id": 121, "options": { @@ -11597,7 +11126,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -11615,30 +11144,26 @@ "type": "timeseries" } ], - "refresh": false, - "schemaVersion": 39, + "preload": false, + "refresh": "", + "schemaVersion": 40, "tags": [], "templating": { "list": [ { "current": {}, - "hide": 0, "includeAll": false, "label": "Prometheus", - "multi": false, "name": "DS_PROMETHEUS", "options": [], "query": "prometheus", - "queryValue": "", "refresh": 1, "regex": "", - "skipUrlSync": false, "type": "datasource" }, { "allValue": "cilium.*", "current": { - "selected": false, "text": "All", "value": "$__all" }, @@ -11647,20 +11172,14 @@ "uid": "${DS_PROMETHEUS}" }, "definition": "label_values(cilium_version, pod)", - "hide": 0, "includeAll": true, - "multi": false, "name": "pod", "options": [], "query": "label_values(cilium_version, pod)", "refresh": 2, "regex": "", - "skipUrlSync": false, "sort": 1, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false + "type": "query" } ] }, @@ -11679,17 +11198,6 @@ "1h", "2h", "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" ] }, "timezone": "utc", @@ -11697,4 +11205,4 @@ "uid": "vtuWtdumz", "version": 1, "weekStart": "" -} +} \ No newline at end of file diff --git a/packages/system/cilium/charts/cilium/files/cilium-envoy/configmap/bootstrap-config.yaml b/packages/system/cilium/charts/cilium/files/cilium-envoy/configmap/bootstrap-config.yaml index 3a26b3c2..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 @@ -54,7 +54,7 @@ staticResources: - addressPrefix: "::1" prefixLen: 128 {{- end }} - streamIdleTimeout: "0s" + streamIdleTimeout: "{{ .Values.envoy.streamIdleTimeoutDurationSeconds }}s" {{- end }} {{- if and .Values.envoy.debug.admin.enabled }} - name: "envoy-admin-listener" @@ -107,7 +107,7 @@ staticResources: - addressPrefix: "::1" prefixLen: 128 {{- end }} - streamIdleTimeout: "0s" + streamIdleTimeout: "{{ .Values.envoy.streamIdleTimeoutDurationSeconds }}s" {{- end }} - name: "envoy-health-listener" address: @@ -159,7 +159,7 @@ staticResources: - addressPrefix: "::1" prefixLen: 128 {{- end }} - streamIdleTimeout: "0s" + streamIdleTimeout: "{{ .Values.envoy.streamIdleTimeoutDurationSeconds }}s" clusters: - name: "ingress-cluster" type: "ORIGINAL_DST" diff --git a/packages/system/cilium/charts/cilium/templates/NOTES.txt b/packages/system/cilium/charts/cilium/templates/NOTES.txt index f5405074..5d82f4d2 100644 --- a/packages/system/cilium/charts/cilium/templates/NOTES.txt +++ b/packages/system/cilium/charts/cilium/templates/NOTES.txt @@ -17,6 +17,13 @@ You have successfully installed {{ title .Chart.Name }}. {{- end }} +{{- $warnings := include "cilium.warnings" . }} +{{- if $warnings }} + +WARNINGS: +{{ $warnings }} +{{- end }} + Your release version is {{ .Chart.Version }}. For any further help, visit https://docs.cilium.io/en/v{{ (semver .Chart.Version).Major }}.{{ (semver .Chart.Version).Minor }}/gettinghelp diff --git a/packages/system/cilium/charts/cilium/templates/_helpers.tpl b/packages/system/cilium/charts/cilium/templates/_helpers.tpl index dc113ba0..ba91c353 100644 --- a/packages/system/cilium/charts/cilium/templates/_helpers.tpl +++ b/packages/system/cilium/charts/cilium/templates/_helpers.tpl @@ -209,4 +209,11 @@ Return user specify tls.secretSync.enabled or default value based on the upgrade {{- false }} {{- end }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} + +{{/* +Determine if CRDs are used for identity allocation +*/}} +{{- define "identityAllocationCRD" }} + {{- list "crd" "doublewrite-readkvstore" "doublewrite-readcrd" | has .Values.identityAllocationMode }} +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-agent/clusterrole.yaml b/packages/system/cilium/charts/cilium/templates/cilium-agent/clusterrole.yaml index 6aef1b21..eaca204e 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-agent/clusterrole.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-agent/clusterrole.yaml @@ -42,6 +42,9 @@ rules: - pods - endpoints - nodes +{{- if not $readSecretsOnlyFromSecretsNamespace }} + - secrets +{{- end }} verbs: - get - list @@ -87,14 +90,6 @@ rules: # until we figure out how to avoid "get" inside the preflight, and then # should be removed ideally. - get -{{- if not $readSecretsOnlyFromSecretsNamespace }} -- apiGroups: - - "" - resources: - - secrets - verbs: - - get -{{- end }} - apiGroups: - cilium.io resources: 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 5d73cb7e..c706da51 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-agent/daemonset.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-agent/daemonset.yaml @@ -15,7 +15,7 @@ apiVersion: apps/v1 kind: DaemonSet metadata: - name: cilium + name: {{ .Values.name }} namespace: {{ include "cilium.namespace" . }} {{- with .Values.annotations }} annotations: @@ -72,6 +72,7 @@ spec: {{- with .Values.podAnnotations }} {{- toYaml . | nindent 8 }} {{- end }} + kubectl.kubernetes.io/default-container: cilium-agent labels: k8s-app: cilium app.kubernetes.io/name: cilium-agent @@ -205,18 +206,33 @@ spec: resourceFieldRef: resource: limits.memory divisor: '1' + {{- if and .Values.k8sServiceHostRef.name .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_HOST + valueFrom: + configMapKeyRef: + name: {{ .Values.k8sServiceHostRef.name }} + key: {{ .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_PORT + value: {{ include "k8sServicePort" . }} + {{- end }} {{- if .Values.k8sServiceHost }} - name: KUBERNETES_SERVICE_HOST value: {{ include "k8sServiceHost" . }} - name: KUBERNETES_SERVICE_PORT value: {{ include "k8sServicePort" . }} {{- end }} + {{- if .Values.k8sClientExponentialBackoff.enabled }} + - name: KUBE_CLIENT_BACKOFF_BASE + value: {{ .Values.k8sClientExponentialBackoff.backoffBaseSeconds | quote }} + - name: KUBE_CLIENT_BACKOFF_DURATION + value: {{ .Values.k8sClientExponentialBackoff.backoffMaxDurationSeconds | quote }} + {{- end }} {{- with .Values.extraEnv }} {{- toYaml . | trim | nindent 8 }} {{- end }} {{- if .Values.cni.install }} lifecycle: - {{- if ne .Values.cni.chainingMode "aws-cni" }} + {{- if and .Values.cni.iptablesRemoveAWSRules (ne .Values.cni.chainingMode "aws-cni") }} postStart: exec: command: @@ -251,7 +267,7 @@ spec: hostPort: {{ .Values.envoy.prometheus.port }} protocol: TCP {{- end }} - {{- if and .Values.envoy.debug.admin.port (not $envoyDS) }} + {{- if and .Values.envoy.debug.admin.enabled .Values.envoy.debug.admin.port (not $envoyDS) }} - name: envoy-admin containerPort: {{ .Values.envoy.debug.admin.port }} hostPort: {{ .Values.envoy.debug.admin.port }} @@ -303,7 +319,6 @@ spec: - mountPath: /host/proc/sys/kernel name: host-proc-sys-kernel {{- end}} - {{- if .Values.bpf.autoMount.enabled }} - name: bpf-maps mountPath: /sys/fs/bpf {{- if .Values.securityContext.privileged }} @@ -315,7 +330,6 @@ spec: # in Cilium. mountPropagation: HostToContainer {{- end}} - {{- end }} {{- if not (contains "/run/cilium/cgroupv2" .Values.cgroup.hostRoot) }} # Check for duplicate mounts before mounting - name: cilium-cgroup @@ -436,6 +450,10 @@ spec: - name: config image: {{ include "cilium.image" .Values.image | quote }} imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- with .Values.initResources }} + resources: + {{- toYaml . | trim | nindent 10 }} + {{- end }} command: - cilium-dbg - build-config @@ -451,6 +469,9 @@ spec: {{- if .Values.kubeConfigPath }} - "--k8s-kubeconfig-path={{ .Values.kubeConfigPath }}" {{- end }} + {{- if hasKey .Values.k8s "apiServerURLs" }} + - "--k8s-api-server-urls={{ .Values.k8s.apiServerURLs }}" + {{- end }} env: - name: K8S_NODE_NAME valueFrom: @@ -462,6 +483,15 @@ spec: fieldRef: apiVersion: v1 fieldPath: metadata.namespace + {{- if and .Values.k8sServiceHostRef.name .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_HOST + valueFrom: + configMapKeyRef: + name: {{ .Values.k8sServiceHostRef.name }} + key: {{ .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_PORT + value: {{ include "k8sServicePort" . }} + {{- end }} {{- if .Values.k8sServiceHost }} - name: KUBERNETES_SERVICE_HOST value: {{ include "k8sServiceHost" . }} @@ -599,12 +629,10 @@ spec: terminationMessagePolicy: FallbackToLogsOnError securityContext: privileged: true - {{- if and .Values.bpf.autoMount.enabled }} volumeMounts: - name: bpf-maps mountPath: /sys/fs/bpf mountPropagation: Bidirectional - {{- end }} {{- end }} {{- if and .Values.nodeinit.enabled .Values.nodeinit.bootstrapFile }} - name: wait-for-node-init @@ -651,6 +679,15 @@ spec: name: cilium-config key: write-cni-conf-when-ready optional: true + {{- if and .Values.k8sServiceHostRef.name .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_HOST + valueFrom: + configMapKeyRef: + name: {{ .Values.k8sServiceHostRef.name }} + key: {{ .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_PORT + value: {{ include "k8sServicePort" . }} + {{- end }} {{- if .Values.k8sServiceHost }} - name: KUBERNETES_SERVICE_HOST value: {{ include "k8sServiceHost" . }} @@ -678,10 +715,8 @@ spec: - ALL {{- end}} volumeMounts: - {{- if .Values.bpf.autoMount.enabled}} - name: bpf-maps mountPath: /sys/fs/bpf - {{- end }} # Required to mount cgroup filesystem from the host to cilium agent pod - name: cilium-cgroup mountPath: {{ .Values.cgroup.hostRoot }} @@ -807,13 +842,11 @@ spec: hostPath: path: /var/run/netns type: DirectoryOrCreate - {{- if .Values.bpf.autoMount.enabled }} # To keep state between restarts / upgrades for bpf maps - name: bpf-maps hostPath: path: /sys/fs/bpf type: DirectoryOrCreate - {{- end }} {{- if or .Values.cgroup.autoMount.enabled .Values.sysctlfix.enabled }} # To mount cgroup2 filesystem on the host or apply sysctlfix - name: hostproc diff --git a/packages/system/cilium/charts/cilium/templates/cilium-agent/role.yaml b/packages/system/cilium/charts/cilium/templates/cilium-agent/role.yaml index 0a2b43d1..89266e0d 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-agent/role.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-agent/role.yaml @@ -130,7 +130,7 @@ metadata: {{- with .Values.annotations }} annotations: {{- toYaml . | nindent 4 }} - {{- end }} + {{- end }} labels: app.kubernetes.io/part-of: cilium rules: diff --git a/packages/system/cilium/charts/cilium/templates/cilium-agent/rolebinding.yaml b/packages/system/cilium/charts/cilium/templates/cilium-agent/rolebinding.yaml index fc4f35ec..c76350b3 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-agent/rolebinding.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-agent/rolebinding.yaml @@ -27,7 +27,7 @@ subjects: {{- end}} {{- if and .Values.agent (not .Values.preflight.enabled) .Values.serviceAccounts.cilium.create .Values.ingressController.enabled .Values.ingressController.secretsNamespace.name}} ---- +--- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: @@ -145,5 +145,5 @@ roleRef: subjects: - kind: ServiceAccount name: {{ .Values.serviceAccounts.cilium.name | quote }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "cilium.namespace" . }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-agent/servicemonitor.yaml b/packages/system/cilium/charts/cilium/templates/cilium-agent/servicemonitor.yaml index 09d11a5d..10be4cce 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-agent/servicemonitor.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-agent/servicemonitor.yaml @@ -7,6 +7,7 @@ metadata: namespace: {{ .Values.prometheus.serviceMonitor.namespace | default (include "cilium.namespace" .) }} labels: app.kubernetes.io/part-of: cilium + app.kubernetes.io/name: cilium-agent {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} @@ -49,6 +50,9 @@ spec: {{- if and .Values.envoy.enabled .Values.envoy.prometheus.serviceMonitor.enabled }} - port: envoy-metrics interval: {{ .Values.envoy.prometheus.serviceMonitor.interval | quote }} + {{- if .Values.envoy.prometheus.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.envoy.prometheus.serviceMonitor.scrapeTimeout | quote }} + {{- end }} honorLabels: true path: /metrics {{- with .Values.envoy.prometheus.serviceMonitor.relabelings }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-ca-secret.yaml b/packages/system/cilium/charts/cilium/templates/cilium-ca-secret.yaml index f5a6674d..7dd15d02 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-ca-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-ca-secret.yaml @@ -1,5 +1,5 @@ {{- if or - (and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm")) + (and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm")) (and (or .Values.agent .Values.hubble.relay.enabled .Values.hubble.ui.enabled) .Values.hubble.enabled .Values.hubble.tls.enabled .Values.hubble.tls.auto.enabled (eq .Values.hubble.tls.auto.method "helm")) (and .Values.tls.ca.key .Values.tls.ca.cert) -}} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-configmap.yaml b/packages/system/cilium/charts/cilium/templates/cilium-configmap.yaml index 72c391da..a9bb1cd9 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-configmap.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-configmap.yaml @@ -1,4 +1,4 @@ -{{- if and ( or (.Values.agent) (.Values.operator.enabled) .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) (not .Values.preflight.enabled) }} +{{- if and ( or (.Values.agent) (.Values.operator.enabled) .Values.clustermesh.useAPIServer) (not .Values.preflight.enabled) }} {{- /* Default values with backwards compatibility */ -}} {{- $defaultBpfMapDynamicSizeRatio := 0.0 -}} {{- $defaultBpfMasquerade := "false" -}} @@ -15,6 +15,7 @@ {{- $defaultK8sClientQPS := 5 -}} {{- $defaultK8sClientBurst := 10 -}} {{- $defaultDNSProxyEnableTransparentMode := "false" -}} +{{- $defaultEnableIPv4Masquerade := "true" -}} {{- $envoyDS := eq (include "envoyDaemonSetEnabled" .) "true" -}} {{- $readSecretsOnlyFromSecretsNamespace := eq (include "readSecretsOnlyFromSecretsNamespace" .) "true" -}} {{- $secretSyncEnabled := eq (include "secretSyncEnabled" .) "true" -}} @@ -61,6 +62,14 @@ {{- $defaultKubeProxyReplacement = "false" -}} {{- end -}} +{{- /* Default values when 1.18 was initially deployed */ -}} +{{- if semverCompare ">=1.18" (default "1.18" .Values.upgradeCompatibility) -}} + {{- /* defaultIPv4Masquerad in ENI mode for 1.18 needed to override earlier version defaults set above when upgradeCompatibility is not specified */ -}} + {{- if .Values.eni.enabled }} + {{- $defaultEnableIPv4Masquerade = "false" -}} + # Will also do this for ipv6 when ENI mode works with ipv6. + {{- end }} +{{- end -}} {{- $ipam := (coalesce .Values.ipam.mode $defaultIPAM) -}} {{- $bpfCtTcpMax := (coalesce .Values.bpf.ctTcpMax $defaultBpfCtTcpMax) -}} {{- $bpfCtAnyMax := (coalesce .Values.bpf.ctAnyMax $defaultBpfCtAnyMax) -}} @@ -177,6 +186,10 @@ data: debug-verbose: "{{ .Values.debug.verbose }}" {{- end }} +{{- if hasKey .Values.debug "metricsSamplingInterval" }} + metrics-sampling-interval: "{{ .Values.debug.metricsSamplingInterval }}" +{{- end }} + {{- if ne (int .Values.healthPort) 9879 }} # Set the TCP port for the agent health status API. This is not the port used # for cilium-health. @@ -443,6 +456,11 @@ data: # policy map (per endpoint) bpf-policy-map-max: "{{ .Values.bpf.policyMapMax | int }}" {{- end }} +{{- if hasKey .Values.bpf "policyStatsMapMax" }} + # bpf-policy-stats-map-max specifies the maximum number of entries in global + # policy stats map + bpf-policy-stats-map-max: "{{ .Values.bpf.policyStatsMapMax | int }}" +{{- end }} {{- if hasKey .Values.bpf "lbMapMax" }} # bpf-lb-map-max specifies the maximum number of entries in bpf lb service, # backend and affinity maps. @@ -484,7 +502,7 @@ data: preallocate-bpf-maps: "{{ .Values.bpf.preallocateMaps }}" # Name of the cluster. Only relevant when building a mesh of clusters. - cluster-name: {{ .Values.cluster.name }} + cluster-name: {{ .Values.cluster.name | quote }} {{- if hasKey .Values.cluster "id" }} # Unique ID of the cluster. Must be unique across all conneted clusters and @@ -511,12 +529,30 @@ data: routing-mode: {{ .Values.routingMode | default (ternary "native" "tunnel" .Values.gke.enabled) | quote }} tunnel-protocol: {{ .Values.tunnelProtocol | default "vxlan" | quote }} +{{- if eq .Values.routingMode "native" }} + {{- if and .Values.ipv4.enabled .Values.enableIPv4Masquerade (not .Values.ipMasqAgent.enabled) }} + {{- if and (ne $ipam "eni") (ne $ipam "alibabacloud") }} + {{- if not .Values.ipv4NativeRoutingCIDR }} + {{- fail " ipv4NativeRoutingCIDR must be set when routingMode is native"}} + {{- end }} + {{- end }} + {{- end }} + {{- if and .Values.ipv6.enabled .Values.enableIPv6Masquerade (not .Values.ipMasqAgent.enabled) }} + {{- if not .Values.ipv6NativeRoutingCIDR }} + {{- fail "ipv6NativeRoutingCIDR must be set when routingMode is native" }} + {{- end }} + {{- end }} +{{- end }} + {{- if .Values.tunnelPort }} tunnel-port: {{ .Values.tunnelPort | quote }} {{- end }} {{- if .Values.tunnelSourcePortRange }} tunnel-source-port-range: {{ .Values.tunnelSourcePortRange | quote }} {{- end }} +{{- if .Values.underlayProtocol }} + underlay-protocol: {{ .Values.underlayProtocol | quote }} +{{- end }} {{- if .Values.serviceNoBackendResponse }} service-no-backend-response: "{{ .Values.serviceNoBackendResponse }}" @@ -531,9 +567,6 @@ data: enable-endpoint-routes: "true" {{- end }} auto-create-cilium-node-resource: "true" -{{- if .Values.eni.updateEC2AdapterLimitViaAPI }} - update-ec2-adapter-limit-via-api: "true" -{{- end }} {{- if .Values.eni.awsReleaseExcessIPs }} aws-release-excess-ips: "true" {{- end }} @@ -602,7 +635,11 @@ data: {{- end }} {{- end }} - enable-ipv4-masquerade: {{ .Values.enableIPv4Masquerade | quote }} +{{- if (not (kindIs "invalid" .Values.enableIPv4Masquerade)) }} + enable-ipv4-masquerade: {{.Values.enableIPv4Masquerade | quote }} +{{- else }} + enable-ipv4-masquerade: {{ $defaultEnableIPv4Masquerade | quote }} +{{- end }} enable-ipv4-big-tcp: {{ .Values.enableIPv4BIGTCP | quote }} enable-ipv6-big-tcp: {{ .Values.enableIPv6BIGTCP | quote }} enable-ipv6-masquerade: {{ .Values.enableIPv6Masquerade | quote }} @@ -686,15 +723,16 @@ data: {{- if .Values.bandwidthManager.enabled }} enable-bandwidth-manager: {{ .Values.bandwidthManager.enabled | quote }} enable-bbr: {{ .Values.bandwidthManager.bbr | quote }} + enable-bbr-hostns-only: {{ .Values.bandwidthManager.bbrHostNamespaceOnly | quote }} {{- end }} {{- end }} -{{- if .Values.highScaleIPcache.enabled }} - enable-high-scale-ipcache: {{ .Values.highScaleIPcache.enabled | quote }} +{{ if or .Values.localRedirectPolicies.enabled .Values.localRedirectPolicy }} + enable-local-redirect-policy: "true" {{- end }} -{{- if hasKey .Values "localRedirectPolicy" }} - enable-local-redirect-policy: {{ .Values.localRedirectPolicy | quote }} +{{- if .Values.localRedirectPolicies.addressMatcherCIDRs }} + lrp-address-matcher-cidrs: {{ .Values.localRedirectPolicies.addressMatcherCIDRs | join "," | quote }} {{- end }} {{- if .Values.ipv4NativeRoutingCIDR }} @@ -725,10 +763,6 @@ data: devices: {{ join " " .Values.devices | quote }} {{- end }} -{{- if .Values.enableRuntimeDeviceDetection }} - enable-runtime-device-detection: "true" -{{- end }} - {{- if .Values.forceDeviceDetection }} force-device-detection: "true" {{- end }} @@ -754,12 +788,6 @@ data: {{- end }} {{- end }} -{{- if hasKey .Values "hostPort" }} -{{- if eq $kubeProxyReplacement "false" }} - enable-host-port: {{ .Values.hostPort.enabled | quote }} -{{- end }} -{{- end }} - {{- if hasKey .Values "nodePort" }} {{- if eq $kubeProxyReplacement "false" }} enable-node-port: {{ .Values.nodePort.enabled | quote }} @@ -786,7 +814,7 @@ data: {{- end }} {{- if hasKey .Values "loadBalancer" }} {{- if .Values.loadBalancer.standalone }} - datapath-mode: lb-only + bpf-lb-only: {{ .Values.loadBalancer.standalone | quote }} {{- end }} {{- if hasKey .Values.loadBalancer "mode" }} bpf-lb-mode: {{ .Values.loadBalancer.mode | quote }} @@ -804,9 +832,6 @@ data: enable-service-topology: {{ .Values.loadBalancer.serviceTopology | quote }} # {{- end }} -{{- if hasKey .Values.loadBalancer "experimental" }} - enable-experimental-lb: {{ .Values.loadBalancer.experimental | quote }} -{{- end }} {{- if hasKey .Values.loadBalancer "protocolDifferentiation" }} bpf-lb-proto-diff: {{ .Values.loadBalancer.protocolDifferentiation.enabled | quote }} {{- end }} @@ -829,7 +854,6 @@ data: {{- if hasKey .Values.l2NeighDiscovery "enabled" }} enable-l2-neigh-discovery: {{ .Values.l2NeighDiscovery.enabled | quote }} {{- end }} - arping-refresh-period: {{ include "validateDuration" .Values.l2NeighDiscovery.refreshPeriod | quote }} {{- end }} {{- if .Values.pprof.enabled }} @@ -856,6 +880,9 @@ data: {{- if hasKey .Values.k8s "requireIPv6PodCIDR" }} k8s-require-ipv6-pod-cidr: {{ .Values.k8s.requireIPv6PodCIDR | quote }} {{- end }} +{{- if hasKey .Values.k8s "apiServerURLs" }} + k8s-api-server-urls: {{ .Values.k8s.apiServerURLs | quote }} +{{- end }} {{- if and .Values.endpointRoutes .Values.endpointRoutes.enabled }} enable-endpoint-routes: {{ .Values.endpointRoutes.enabled | quote }} {{- end }} @@ -915,6 +942,12 @@ data: {{- end }} enable-node-selector-labels: {{ .Values.nodeSelectorLabels | quote }} +{{- if hasKey .Values "nodeLabels" }} + # To include or exclude matched resources from cilium node identity evaluation + # List of labels just like --labels flag (.Values.labels) + node-labels: {{ .Values.nodeLabels | quote }} +{{- end }} + {{- if hasKey .Values "synchronizeK8sNodes" }} synchronize-k8s-nodes: {{ .Values.synchronizeK8sNodes | quote }} {{- end }} @@ -967,6 +1000,9 @@ data: hubble-dynamic-metrics-config-path: /dynamic-metrics-config/dynamic-metrics.yaml {{- end }} +{{- if hasKey .Values.hubble.networkPolicyCorrelation "enabled" }} + hubble-network-policy-correlation-enabled: {{ .Values.hubble.networkPolicyCorrelation.enabled | quote }} +{{- end }} {{- if .Values.hubble.redact }} {{- if eq .Values.hubble.redact.enabled true }} # Enables hubble redact capabilities @@ -998,9 +1034,12 @@ data: {{- end }} {{- end }} {{- if .Values.hubble.export }} - hubble-export-file-max-size-mb: {{ .Values.hubble.export.fileMaxSizeMb | quote }} - hubble-export-file-max-backups: {{ .Values.hubble.export.fileMaxBackups | quote }} +{{- /* hubble export configurations moved, use default to make upgrades seemless */ -}} +{{- /* TODO: remove default once v1.18 is released, remove warning in warnings.txt and add failure validation in validate.yaml */ -}} {{- if .Values.hubble.export.static.enabled }} + hubble-export-file-max-size-mb: {{ .Values.hubble.export.fileMaxSizeMb | default .Values.hubble.export.static.fileMaxSizeMb | quote }} + hubble-export-file-max-backups: {{ .Values.hubble.export.fileMaxBackups | default .Values.hubble.export.static.fileMaxBackups | quote }} + hubble-export-file-compress: {{ .Values.hubble.export.fileCompress | default .Values.hubble.export.static.fileCompress | quote }} hubble-export-file-path: {{ .Values.hubble.export.static.filePath | quote }} hubble-export-fieldmask: {{ .Values.hubble.export.static.fieldMask | join " " | quote }} hubble-export-allowlist: {{ .Values.hubble.export.static.allowList | join " " | quote }} @@ -1104,7 +1143,7 @@ data: {{- end }} {{- if .Values.egressGateway.enabled }} - enable-ipv4-egress-gateway: "true" + enable-egress-gateway: "true" {{- end }} {{- if hasKey .Values.egressGateway "reconciliationTriggerInterval" }} egress-gateway-reconciliation-trigger-interval: {{ .Values.egressGateway.reconciliationTriggerInterval | quote }} @@ -1163,13 +1202,20 @@ data: {{- if .Values.l2podAnnouncements.enabled }} enable-l2-pod-announcements: {{ .Values.l2podAnnouncements.enabled | quote }} + {{- if .Values.l2podAnnouncements.interfacePattern }} + l2-pod-announcements-interface-pattern: {{ .Values.l2podAnnouncements.interfacePattern | quote }} + {{- else }} l2-pod-announcements-interface: {{ .Values.l2podAnnouncements.interface | quote }} + {{- end }} {{- end }} {{- if .Values.bgpControlPlane.enabled }} enable-bgp-control-plane: "true" bgp-secrets-namespace: {{ .Values.bgpControlPlane.secretsNamespace.name | quote }} enable-bgp-control-plane-status-report: {{ .Values.bgpControlPlane.statusReport.enabled | quote }} + bgp-router-id-allocation-mode: {{ .Values.bgpControlPlane.routerIDAllocation.mode | quote }} + bgp-router-id-allocation-ip-pool: {{ .Values.bgpControlPlane.routerIDAllocation.ipPool | quote }} + enable-bgp-legacy-origin-attribute: {{ .Values.bgpControlPlane.legacyOriginAttribute.enabled | quote }} {{- end }} {{- if .Values.pmtuDiscovery.enabled }} @@ -1197,19 +1243,14 @@ data: disable-external-ip-mitigation: {{ .Values.bpf.disableExternalIPMitigation | quote }} {{- end }} -{{- if or .Values.ciliumEndpointSlice.enabled .Values.enableCiliumEndpointSlice }} +{{- if .Values.ciliumEndpointSlice.enabled }} enable-cilium-endpoint-slice: "true" {{- if .Values.ciliumEndpointSlice.rateLimits }} ces-rate-limits: {{ .Values.ciliumEndpointSlice.rateLimits | toJson | quote }} {{- end }} - {{- if .Values.ciliumEndpointSlice.sliceMode }} - ces-slice-mode: {{ .Values.ciliumEndpointSlice.sliceMode | quote }} - {{- end }} {{- end }} -{{- if hasKey .Values "enableK8sTerminatingEndpoint" }} - enable-k8s-terminating-endpoint: {{ .Values.enableK8sTerminatingEndpoint | quote }} -{{- end }} + identity-management-mode: {{ .Values.identityManagementMode | quote }} {{- if hasKey .Values.sctp "enabled" }} enable-sctp: {{ .Values.sctp.enabled | quote }} @@ -1298,6 +1339,7 @@ data: {{- if .Values.dnsProxy.proxyResponseMaxDelay }} tofqdns-proxy-response-max-delay: {{ .Values.dnsProxy.proxyResponseMaxDelay | quote }} {{- end }} + tofqdns-preallocate-identities: {{ .Values.dnsProxy.preAllocateIdentities | quote }} {{- end }} {{- if hasKey .Values "agentNotReadyTaintKey" }} @@ -1333,10 +1375,15 @@ data: proxy-idle-timeout-seconds: {{ .Values.envoy.idleTimeoutDurationSeconds | quote }} proxy-max-concurrent-retries: {{ .Values.envoy.maxConcurrentRetries | quote }} http-retry-count: {{ .Values.envoy.httpRetryCount | quote }} + http-stream-idle-timeout: {{ .Values.envoy.streamIdleTimeoutDurationSeconds | quote }} external-envoy-proxy: {{ include "envoyDaemonSetEnabled" . | quote }} envoy-base-id: {{ .Values.envoy.baseID | quote }} +{{- if .Values.envoy.httpUpstreamLingerTimeout }} + envoy-http-upstream-linger-timeout: {{ .Values.envoy.httpUpstreamLingerTimeout | quote }} +{{- end }} + {{- if .Values.envoy.policyRestoreTimeoutDuration }} envoy-policy-restore-timeout: {{ .Values.envoy.policyRestoreTimeoutDuration | quote }} {{- end }} @@ -1357,6 +1404,7 @@ data: {{- end }} clustermesh-enable-endpoint-sync: {{ .Values.clustermesh.enableEndpointSliceSynchronization | 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 }} @@ -1368,6 +1416,10 @@ data: enable-source-ip-verification: {{ .Values.daemon.enableSourceIPVerification | quote }} {{- end }} +{{- if has (kindOf .Values.connectivityProbeFrequencyRatio) (list "int64" "float64") }} + connectivity-probe-frequency-ratio: {{ .Values.connectivityProbeFrequencyRatio | quote }} +{{- end }} + # Extra config allows adding arbitrary properties to the cilium config. # By putting it at the end of the ConfigMap, it's also possible to override existing properties. {{- if .Values.extraConfig }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-envoy/configmap.yaml b/packages/system/cilium/charts/cilium/templates/cilium-envoy/configmap.yaml index b2639892..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 5649796a..a5decd02 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-envoy/daemonset.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-envoy/daemonset.yaml @@ -97,6 +97,7 @@ spec: {{- with .Values.envoy.extraArgs }} {{- toYaml . | trim | nindent 8 }} {{- end }} + {{- if .Values.envoy.startupProbe.enabled }} startupProbe: httpGet: host: {{ .Values.ipv4.enabled | ternary "127.0.0.1" "::1" | quote }} @@ -107,6 +108,8 @@ spec: periodSeconds: {{ .Values.envoy.startupProbe.periodSeconds }} successThreshold: 1 initialDelaySeconds: 5 + {{- end }} + {{- if .Values.envoy.livenessProbe.enabled }} livenessProbe: httpGet: host: {{ .Values.ipv4.enabled | ternary "127.0.0.1" "::1" | quote }} @@ -117,6 +120,7 @@ spec: successThreshold: 1 failureThreshold: {{ .Values.envoy.livenessProbe.failureThreshold }} timeoutSeconds: 5 + {{- end }} readinessProbe: httpGet: host: {{ .Values.ipv4.enabled | ternary "127.0.0.1" "::1" | quote }} @@ -138,6 +142,15 @@ spec: fieldRef: apiVersion: v1 fieldPath: metadata.namespace + {{- if and .Values.k8sServiceHostRef.name .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_HOST + valueFrom: + configMapKeyRef: + name: {{ .Values.k8sServiceHostRef.name }} + key: {{ .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_PORT + value: {{ include "k8sServicePort" . }} + {{- end }} {{- if .Values.k8sServiceHost }} - name: KUBERNETES_SERVICE_HOST value: {{ include "k8sServiceHost" . }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-envoy/servicemonitor.yaml b/packages/system/cilium/charts/cilium/templates/cilium-envoy/servicemonitor.yaml index a46aeeb8..6c2bce3c 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-envoy/servicemonitor.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-envoy/servicemonitor.yaml @@ -34,6 +34,9 @@ spec: endpoints: - port: envoy-metrics interval: {{ .Values.envoy.prometheus.serviceMonitor.interval | quote }} + {{- if .Values.envoy.prometheus.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.envoy.prometheus.serviceMonitor.scrapeTimeout | quote }} + {{- end }} honorLabels: true path: /metrics {{- with .Values.envoy.prometheus.serviceMonitor.relabelings }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-flowlog-configmap.yaml b/packages/system/cilium/charts/cilium/templates/cilium-flowlog-configmap.yaml index 7d86eb7f..84e12eae 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-flowlog-configmap.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-flowlog-configmap.yaml @@ -12,5 +12,18 @@ metadata: data: flowlogs.yaml: | flowLogs: -{{ .Values.hubble.export.dynamic.config.content | toYaml | indent 4 }} + {{- /* hubble export configurations moved, use default to make upgrades seemless */ -}} + {{- /* TODO: remove default once v1.18 is released, remove warning in warnings.txt and add failure validation in validate.yaml */ -}} + {{- range .Values.hubble.export.dynamic.config.content }} + {{- if hasKey $.Values.hubble.export "fileMaxSizeMb" }} + {{- $_ := set . "fileMaxSizeMb" (get $.Values.hubble.export "fileMaxSizeMb") -}} + {{- end }} + {{- if hasKey $.Values.hubble.export "fileMaxBackups" }} + {{- $_ := set . "fileMaxBackups" (get $.Values.hubble.export "fileMaxBackups") -}} + {{- end }} + {{- if hasKey $.Values.hubble.export "fileCompress" }} + {{- $_ := set . "fileCompress" (get $.Values.hubble.export "fileCompress") -}} + {{- end }} + {{- list . | toYaml | nindent 6 }} + {{- end }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-ingress-service.yaml b/packages/system/cilium/charts/cilium/templates/cilium-ingress-service.yaml index 8d806f21..5d16d7ca 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-ingress-service.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-ingress-service.yaml @@ -22,11 +22,15 @@ spec: - name: http port: 80 protocol: TCP + {{- if .Values.ingressController.service.insecureNodePort }} nodePort: {{ .Values.ingressController.service.insecureNodePort }} + {{- end }} - name: https port: 443 protocol: TCP + {{- if .Values.ingressController.service.secureNodePort }} nodePort: {{ .Values.ingressController.service.secureNodePort }} + {{- end }} {{- if .Values.ingressController.hostNetwork.enabled }} type: ClusterIP {{- else }} @@ -41,7 +45,7 @@ spec: {{- if .Values.ingressController.service.loadBalancerIP }} loadBalancerIP: {{ .Values.ingressController.service.loadBalancerIP }} {{- end }} - {{- if .Values.ingressController.service.externalTrafficPolicy }} + {{- if and .Values.ingressController.service.externalTrafficPolicy (not .Values.ingressController.hostNetwork.enabled) }} externalTrafficPolicy: {{ .Values.ingressController.service.externalTrafficPolicy }} {{- end }} --- diff --git a/packages/system/cilium/charts/cilium/templates/cilium-operator/clusterrole.yaml b/packages/system/cilium/charts/cilium/templates/cilium-operator/clusterrole.yaml index dba1ca8b..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 .Values.clustermesh.enableEndpointSliceSynchronization }} +{{- if or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.enableMCSAPISupport }} - create - update - delete @@ -164,6 +164,9 @@ rules: verbs: # To synchronize garbage collection of such resources - update + {{- if (or (eq .Values.identityManagementMode "operator") (eq .Values.identityManagementMode "both")) }} + - create + {{- end }} - apiGroups: - cilium.io resources: @@ -236,7 +239,6 @@ rules: - ciliumendpoints.cilium.io - ciliumendpointslices.cilium.io - ciliumenvoyconfigs.cilium.io - - ciliumexternalworkloads.cilium.io - ciliumidentities.cilium.io - ciliumlocalredirectpolicies.cilium.io - ciliumnetworkpolicies.cilium.io @@ -245,6 +247,7 @@ rules: - ciliumcidrgroups.cilium.io - ciliuml2announcementpolicies.cilium.io - ciliumpodippools.cilium.io + - ciliumgatewayclassconfigs.cilium.io - apiGroups: - cilium.io resources: @@ -316,6 +319,12 @@ rules: - get - list - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - gatewayclasses + verbs: + - patch - apiGroups: - gateway.networking.k8s.io resources: @@ -327,6 +336,21 @@ rules: verbs: - update - patch +- apiGroups: + - cilium.io + resources: + - ciliumgatewayclassconfigs + verbs: + - get + - list + - watch +- apiGroups: + - cilium.io + resources: + - ciliumgatewayclassconfigs/status + verbs: + - update + - patch {{- end }} {{- if or .Values.gatewayAPI.enabled .Values.clustermesh.enableMCSAPISupport }} - apiGroups: diff --git a/packages/system/cilium/charts/cilium/templates/cilium-operator/deployment.yaml b/packages/system/cilium/charts/cilium/templates/cilium-operator/deployment.yaml index e0fe3115..606807f3 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-operator/deployment.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-operator/deployment.yaml @@ -142,6 +142,15 @@ spec: key: ALIBABA_CLOUD_ACCESS_KEY_SECRET optional: true {{- end }} + {{- if and .Values.k8sServiceHostRef.name .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_HOST + valueFrom: + configMapKeyRef: + name: {{ .Values.k8sServiceHostRef.name }} + key: {{ .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_PORT + value: {{ include "k8sServicePort" . }} + {{- end }} {{- if .Values.k8sServiceHost }} - name: KUBERNETES_SERVICE_HOST value: {{ include "k8sServiceHost" . }} @@ -299,6 +308,10 @@ spec: tolerations: {{- toYaml . | trim | nindent 8 }} {{- end }} + {{- if hasKey .Values "agentNotReadyTaintKey" }} + - key: {{ .Values.agentNotReadyTaintKey }} + operator: Exists + {{ end}} volumes: # To read the configuration from the config map - name: cilium-config-path diff --git a/packages/system/cilium/charts/cilium/templates/cilium-operator/poddisruptionbudget.yaml b/packages/system/cilium/charts/cilium/templates/cilium-operator/poddisruptionbudget.yaml index 74d29b43..ee543e93 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-operator/poddisruptionbudget.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-operator/poddisruptionbudget.yaml @@ -24,6 +24,13 @@ spec: {{- with $component.minAvailable }} minAvailable: {{ . }} {{- end }} + {{- if (semverCompare ">= 1.27-0" .Capabilities.KubeVersion.Version) }} + {{- if hasKey $component "unhealthyPodEvictionPolicy" }} + {{- with $component.unhealthyPodEvictionPolicy }} + unhealthyPodEvictionPolicy: {{ . }} + {{- end }} + {{- end }} + {{- end }} selector: matchLabels: io.cilium/app: operator diff --git a/packages/system/cilium/charts/cilium/templates/cilium-operator/rolebinding.yaml b/packages/system/cilium/charts/cilium/templates/cilium-operator/rolebinding.yaml index c77e39e9..56b89209 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-operator/rolebinding.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-operator/rolebinding.yaml @@ -75,5 +75,5 @@ roleRef: subjects: - kind: ServiceAccount name: {{ .Values.serviceAccounts.operator.name | quote }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "cilium.namespace" . }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-operator/servicemonitor.yaml b/packages/system/cilium/charts/cilium/templates/cilium-operator/servicemonitor.yaml index c73b49da..b0a91f43 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-operator/servicemonitor.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-operator/servicemonitor.yaml @@ -33,6 +33,9 @@ spec: endpoints: - port: metrics interval: {{ .Values.operator.prometheus.serviceMonitor.interval | quote }} + {{- if .Values.operator.prometheus.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.operator.prometheus.serviceMonitor.scrapeTimeout | quote }} + {{- end }} honorLabels: true path: /metrics {{- with .Values.operator.prometheus.serviceMonitor.relabelings }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrole.yaml b/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrole.yaml index 9a2c0615..bf0f07da 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrole.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrole.yaml @@ -42,6 +42,9 @@ rules: - pods - endpoints - nodes +{{- if $readSecretsOnlyFromSecretsNamespace }} + - secrets +{{- end }} verbs: - get - list @@ -87,14 +90,6 @@ rules: # until we figure out how to avoid "get" inside the preflight, and then # should be removed ideally. - get -{{- if $readSecretsOnlyFromSecretsNamespace }} -- apiGroups: - - "" - resources: - - secrets - verbs: - - get -{{- end }} - apiGroups: - cilium.io resources: diff --git a/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrolebinding.yaml b/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrolebinding.yaml index 93827895..ec667ea0 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrolebinding.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrolebinding.yaml @@ -18,6 +18,6 @@ roleRef: name: cilium-pre-flight subjects: - kind: ServiceAccount - name: {{ .Values.serviceAccounts.preflight.name | quote }} + name: {{ .Values.serviceAccounts.preflight.name | quote }} namespace: {{ include "cilium.namespace" . }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-preflight/daemonset.yaml b/packages/system/cilium/charts/cilium/templates/cilium-preflight/daemonset.yaml index 0e793cfa..17c39a41 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-preflight/daemonset.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-preflight/daemonset.yaml @@ -1,14 +1,16 @@ +{{- $envoyDS := eq (include "envoyDaemonSetEnabled" .) "true" -}} + {{- if .Values.preflight.enabled }} apiVersion: apps/v1 kind: DaemonSet metadata: name: cilium-pre-flight-check namespace: {{ include "cilium.namespace" . }} - {{- with .Values.preflight.annotations }} {{- with .Values.commonLabels }} labels: {{- toYaml . | nindent 4 }} {{- end }} + {{- with .Values.preflight.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} @@ -19,10 +21,11 @@ spec: kubernetes.io/cluster-service: "true" template: metadata: - {{- with .Values.preflight.podAnnotations }} annotations: + kubectl.kubernetes.io/default-container: cilium-pre-flight-check + {{- with .Values.preflight.podAnnotations }} {{- toYaml . | nindent 8 }} - {{- end }} + {{- end }} labels: app.kubernetes.io/part-of: cilium k8s-app: cilium-pre-flight-check @@ -84,7 +87,7 @@ spec: apiVersion: v1 fieldPath: spec.nodeName {{- with .Values.preflight.extraEnv }} - {{- toYaml . | trim | nindent 12 }} + {{- toYaml . | trim | nindent 10 }} {{- end }} volumeMounts: - name: cilium-run @@ -137,6 +140,15 @@ spec: initialDelaySeconds: 5 periodSeconds: 5 env: + {{- if and .Values.k8sServiceHostRef.name .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_HOST + valueFrom: + configMapKeyRef: + name: {{ .Values.k8sServiceHostRef.name }} + key: {{ .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_PORT + value: {{ include "k8sServicePort" . }} + {{- end }} {{- if .Values.k8sServiceHost }} - name: KUBERNETES_SERVICE_HOST value: {{ include "k8sServiceHost" . }} @@ -172,6 +184,48 @@ spec: {{- end }} terminationMessagePolicy: FallbackToLogsOnError {{- end }} + {{- if $envoyDS }} + - name: cilium-pre-flight-envoy + image: {{ include "cilium.image" .Values.preflight.envoy.image | quote }} + imagePullPolicy: {{ .Values.preflight.image.pullPolicy }} + command: ["/bin/sh"] + args: + - -c + - "touch /tmp/ready; sleep 1h" + livenessProbe: + exec: + command: + - cat + - /tmp/ready + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + exec: + command: + - cat + - /tmp/ready + initialDelaySeconds: 5 + periodSeconds: 5 + volumeMounts: + - name: envoy-sockets + mountPath: /var/run/cilium/envoy/sockets + readOnly: false + - name: envoy-artifacts + mountPath: /var/run/cilium/envoy/artifacts + readOnly: true + - name: envoy-config + mountPath: /var/run/cilium/envoy/ + readOnly: true + {{- with .Values.preflight.resources }} + resources: + {{- toYaml . | trim | nindent 12 }} + {{- end }} + {{- with .Values.preflight.securityContext }} + securityContext: + {{- toYaml . | trim | nindent 14 }} + {{- end }} + terminationMessagePolicy: FallbackToLogsOnError + {{- end }} hostNetwork: true dnsPolicy: ClusterFirstWithHostNet restartPolicy: Always @@ -217,6 +271,24 @@ spec: optional: true {{- end }} {{- end }} + {{- if $envoyDS }} + - name: envoy-sockets + hostPath: + path: "{{ .Values.daemon.runPath }}/envoy/sockets" + type: DirectoryOrCreate + - name: envoy-artifacts + hostPath: + path: "{{ .Values.daemon.runPath }}/envoy/artifacts" + type: DirectoryOrCreate + - 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 }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-preflight/deployment.yaml b/packages/system/cilium/charts/cilium/templates/cilium-preflight/deployment.yaml index 26c7f063..6218b460 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-preflight/deployment.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-preflight/deployment.yaml @@ -13,7 +13,7 @@ metadata: app.kubernetes.io/name: cilium-pre-flight-check {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} - {{- end }} + {{- end }} spec: selector: matchLabels: @@ -64,7 +64,16 @@ spec: {{- toYaml . | nindent 10 }} {{- end }} env: - {{- if .Values.k8sServiceHost }} + {{- if and .Values.k8sServiceHostRef.name .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_HOST + valueFrom: + configMapKeyRef: + name: {{ .Values.k8sServiceHostRef.name }} + key: {{ .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_PORT + value: {{ include "k8sServicePort" . }} + {{- end }} + {{- if .Values.k8sServiceHost }} - name: KUBERNETES_SERVICE_HOST value: {{ include "k8sServiceHost" . }} - name: KUBERNETES_SERVICE_PORT diff --git a/packages/system/cilium/charts/cilium/templates/cilium-preflight/poddisruptionbudget.yaml b/packages/system/cilium/charts/cilium/templates/cilium-preflight/poddisruptionbudget.yaml index be41a74c..576d9d35 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-preflight/poddisruptionbudget.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-preflight/poddisruptionbudget.yaml @@ -24,6 +24,13 @@ spec: {{- with $component.minAvailable }} minAvailable: {{ . }} {{- end }} + {{- if (semverCompare ">= 1.27-0" .Capabilities.KubeVersion.Version) }} + {{- if hasKey $component "unhealthyPodEvictionPolicy" }} + {{- with $component.unhealthyPodEvictionPolicy }} + unhealthyPodEvictionPolicy: {{ . }} + {{- end }} + {{- end }} + {{- end }} selector: matchLabels: k8s-app: cilium-pre-flight-check-deployment diff --git a/packages/system/cilium/charts/cilium/templates/cilium-secrets-namespace.yaml b/packages/system/cilium/charts/cilium/templates/cilium-secrets-namespace.yaml index 2a7726d8..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,4 +20,8 @@ metadata: {{- with $.Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} + annotations: + {{- with $.Values.secretsNamespaceAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} {{- end}} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrole.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrole.yaml index e7ebda95..8565f585 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrole.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrole.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.serviceAccounts.clustermeshApiserver.create .Values.rbac.create }} +{{- if and .Values.clustermesh.useAPIServer .Values.serviceAccounts.clustermeshApiserver.create .Values.rbac.create (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") (eq "true" (include "identityAllocationCRD" .)) }} apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: @@ -13,40 +13,13 @@ metadata: {{- toYaml . | nindent 4 }} {{- end }} rules: -{{- if .Values.externalWorkloads.enabled }} -- apiGroups: - - cilium.io - resources: - - ciliumnodes - - ciliumendpoints - - ciliumidentities - verbs: - - create -- apiGroups: - - cilium.io - resources: - - ciliumexternalworkloads/status - - ciliumnodes - - ciliumidentities - verbs: - - update -- apiGroups: - - cilium.io - resources: - - ciliumendpoints - - ciliumendpoints/status - verbs: - - patch -{{- end }} - apiGroups: - cilium.io resources: - ciliumidentities -{{- if .Values.externalWorkloads.enabled }} - - ciliumexternalworkloads -{{- end }} - ciliumendpoints - ciliumnodes + - ciliumendpointslices verbs: - get - list diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrolebinding.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrolebinding.yaml index ecd5fe31..efbcf138 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrolebinding.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrolebinding.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.serviceAccounts.clustermeshApiserver.create .Values.rbac.create }} +{{- if and .Values.clustermesh.useAPIServer .Values.serviceAccounts.clustermeshApiserver.create .Values.rbac.create (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") (eq "true" (include "identityAllocationCRD" .)) }} apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/deployment.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/deployment.yaml index 72b41679..b0366e3b 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/deployment.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/deployment.yaml @@ -1,4 +1,4 @@ -{{- if (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) }} +{{- if .Values.clustermesh.useAPIServer }} {{- if not (list "legacy" "migration" "cluster" | has .Values.clustermesh.apiserver.tls.authMode) -}} {{- fail ".Values.clustermesh.apiserver.tls.authMode must be one of legacy, migration, cluster" -}} {{- end -}} @@ -23,9 +23,16 @@ spec: selector: matchLabels: k8s-app: clustermesh-apiserver - {{- with .Values.clustermesh.apiserver.updateStrategy }} + {{- if eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "external" }} + {{/* without proper locking in kvstoremesh we can't run multiple pods at once */}} strategy: + type: Recreate + {{- else }} + {{- with .Values.clustermesh.apiserver.updateStrategy }} + strategy: + # -- The priority class to use for clustermesh-apiserver {{- toYaml . | nindent 4 }} + {{- end }} {{- end }} template: metadata: @@ -33,6 +40,7 @@ spec: {{- with .Values.clustermesh.apiserver.podAnnotations }} {{- toYaml . | nindent 8 }} {{- end }} + kubectl.kubernetes.io/default-container: apiserver labels: app.kubernetes.io/part-of: cilium app.kubernetes.io/name: clustermesh-apiserver @@ -52,6 +60,7 @@ spec: securityContext: {{- toYaml . | nindent 8 }} {{- end }} + {{- if eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal" }} initContainers: - name: etcd-init image: {{ include "cilium.image" .Values.clustermesh.apiserver.image | quote }} @@ -104,7 +113,9 @@ spec: resources: {{- toYaml . | nindent 10 }} {{- end }} + {{- end }} containers: + {{- if eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal" }} - name: etcd # The clustermesh-apiserver container image includes an etcd binary. image: {{ include "cilium.image" .Values.clustermesh.apiserver.image | quote }} @@ -118,23 +129,21 @@ spec: - --trusted-ca-file=/var/lib/etcd-secrets/ca.crt - --cert-file=/var/lib/etcd-secrets/tls.crt - --key-file=/var/lib/etcd-secrets/tls.key - # Surrounding the IPv4 address with brackets works in this case, since etcd - # uses net.SplitHostPort() internally and it accepts the that format. - - --listen-client-urls=https://127.0.0.1:2379,https://[$(HOSTNAME_IP)]:2379 - - --advertise-client-urls=https://[$(HOSTNAME_IP)]:2379 + - --listen-client-urls=https://0.0.0.0:2379 + # We advertise localhost as client URLs for convenience, even though + # technically not correct. However, it doesn't matter, as this is a + # single replica cluster, and clients directly connect to it via the + # address provided as part of their configuration. + - --advertise-client-urls=https://localhost:2379 - --initial-cluster-token=$(INITIAL_CLUSTER_TOKEN) - --auto-compaction-retention=1 {{- if .Values.clustermesh.apiserver.metrics.etcd.enabled }} - - --listen-metrics-urls=http://[$(HOSTNAME_IP)]:{{ .Values.clustermesh.apiserver.metrics.etcd.port }} + - --listen-metrics-urls=http://0.0.0.0:{{ .Values.clustermesh.apiserver.metrics.etcd.port }} - --metrics={{ .Values.clustermesh.apiserver.metrics.etcd.mode }} {{- end }} env: - name: ETCDCTL_API value: "3" - - name: HOSTNAME_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - name: INITIAL_CLUSTER_TOKEN valueFrom: fieldRef: @@ -170,6 +179,8 @@ spec: lifecycle: {{- toYaml . | nindent 10 }} {{- end }} + {{- end }} + {{- if eq "true" (include "identityAllocationCRD" .) }} - name: apiserver image: {{ include "cilium.image" .Values.clustermesh.apiserver.image | quote }} imagePullPolicy: {{ .Values.clustermesh.apiserver.image.pullPolicy }} @@ -193,7 +204,6 @@ spec: - --cluster-users-enabled - --cluster-users-config-path=/var/lib/cilium/etcd-config/users.yaml {{- end }} - - --enable-external-workloads={{ .Values.externalWorkloads.enabled }} {{- if .Values.clustermesh.apiserver.metrics.enabled }} - --prometheus-serve-addr=:{{ .Values.clustermesh.apiserver.metrics.port }} - --controller-group-metrics=all @@ -201,6 +211,9 @@ spec: {{- if .Values.clustermesh.enableMCSAPISupport }} - --clustermesh-enable-mcs-api {{- end }} + {{- if .Values.ciliumEndpointSlice.enabled }} + - --enable-cilium-endpoint-slice + {{- end }} {{- with .Values.clustermesh.apiserver.extraArgs }} {{- toYaml . | trim | nindent 8 }} {{- end }} @@ -266,6 +279,7 @@ spec: lifecycle: {{- toYaml . | nindent 10 }} {{- end }} + {{- end }} {{- if .Values.clustermesh.apiserver.kvstoremesh.enabled }} - name: kvstoremesh image: {{ include "cilium.image" .Values.clustermesh.apiserver.image | quote }} @@ -281,7 +295,9 @@ spec: - --cluster-id=$(CLUSTER_ID) - --kvstore-opt=etcd.config=/var/lib/cilium/etcd-config.yaml - --kvstore-opt=etcd.qps=100 + {{- if ne .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "external" }} - --kvstore-opt=etcd.bootstrapQps=10000 + {{- end }} - --kvstore-opt=etcd.maxInflight=10 - --clustermesh-config=/var/lib/cilium/clustermesh {{- if hasKey .Values.clustermesh "maxConnectedClusters" }} @@ -292,6 +308,7 @@ spec: - --prometheus-serve-addr=:{{ .Values.clustermesh.apiserver.metrics.kvstoremesh.port }} - --controller-group-metrics=all {{- end }} + - --enable-heartbeat={{ eq "true" (include "identityAllocationCRD" .) | ternary "false" "true" }} {{- with .Values.clustermesh.apiserver.kvstoremesh.extraArgs }} {{- toYaml . | trim | nindent 8 }} {{- end }} @@ -330,12 +347,19 @@ spec: {{- toYaml . | nindent 10 }} {{- end }} volumeMounts: + {{- if (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") }} - name: etcd-admin-client mountPath: /var/lib/cilium/etcd-secrets readOnly: true + {{- end }} - name: kvstoremesh-secrets mountPath: /var/lib/cilium/clustermesh readOnly: true + {{- if eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "external"}} + - name: etcd-config + mountPath: /var/lib/cilium + readOnly: true + {{- end }} {{- with .Values.clustermesh.apiserver.kvstoremesh.extraVolumeMounts }} {{- toYaml . | nindent 8 }} {{- end }} @@ -350,6 +374,7 @@ spec: {{- end }} {{- end }} volumes: + {{- if (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") }} - name: etcd-server-secrets projected: # note: the leading zero means this number is in octal representation: do not remove it @@ -404,6 +429,7 @@ spec: - name: etcd-data-dir emptyDir: medium: {{ ternary "Memory" "" (eq .Values.clustermesh.apiserver.etcd.storageMedium "Memory") | quote }} + {{- end }} {{- if .Values.clustermesh.apiserver.kvstoremesh.enabled }} - name: kvstoremesh-secrets projected: @@ -425,8 +451,26 @@ spec: path: common-etcd-client.key - key: tls.crt path: common-etcd-client.crt + {{- if not .Values.tls.caBundle.enabled }} - key: ca.crt path: common-etcd-client-ca.crt + {{- else }} + - {{ .Values.tls.caBundle.useSecret | ternary "secret" "configMap" }}: + name: {{ .Values.tls.caBundle.name }} + optional: true + items: + - key: {{ .Values.tls.caBundle.key }} + path: common-etcd-client-ca.crt + {{- end }} + {{- if eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "external"}} + - configMap: + defaultMode: 0400 + items: + - key: etcd-config + path: etcd-config.yaml + name: cilium-config + name: etcd-config + {{- end }} {{- end }} {{- with .Values.clustermesh.apiserver.extraVolumes }} {{- toYaml . | nindent 6 }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/metrics-service.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/metrics-service.yaml index 915b3165..587c9b13 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/metrics-service.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/metrics-service.yaml @@ -1,6 +1,6 @@ {{- $kvstoreMetricsEnabled := and .Values.clustermesh.apiserver.kvstoremesh.enabled .Values.clustermesh.apiserver.metrics.kvstoremesh.enabled -}} {{- if and - (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) + .Values.clustermesh.useAPIServer (or .Values.clustermesh.apiserver.metrics.enabled $kvstoreMetricsEnabled .Values.clustermesh.apiserver.metrics.etcd.enabled) }} apiVersion: v1 kind: Service @@ -24,11 +24,13 @@ spec: clusterIP: None type: ClusterIP ports: - {{- if .Values.clustermesh.apiserver.metrics.enabled }} + {{- if and (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") (eq "true" (include "identityAllocationCRD" .)) }} + {{- if .Values.clustermesh.apiserver.metrics.enabled }} - name: apiserv-metrics port: {{ .Values.clustermesh.apiserver.metrics.port }} protocol: TCP targetPort: apiserv-metrics + {{- end }} {{- end }} {{- if $kvstoreMetricsEnabled }} - name: kvmesh-metrics @@ -36,11 +38,13 @@ spec: protocol: TCP targetPort: kvmesh-metrics {{- end }} - {{- if .Values.clustermesh.apiserver.metrics.etcd.enabled }} + {{- if eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal" }} + {{- if .Values.clustermesh.apiserver.metrics.etcd.enabled }} - name: etcd-metrics port: {{ .Values.clustermesh.apiserver.metrics.etcd.port }} protocol: TCP targetPort: etcd-metrics + {{- end }} {{- end }} selector: k8s-app: clustermesh-apiserver diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/poddisruptionbudget.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/poddisruptionbudget.yaml index 491b075d..2ead8f29 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/poddisruptionbudget.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/poddisruptionbudget.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.podDisruptionBudget.enabled }} +{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.podDisruptionBudget.enabled }} {{- $component := .Values.clustermesh.apiserver.podDisruptionBudget }} apiVersion: policy/v1 kind: PodDisruptionBudget @@ -24,6 +24,13 @@ spec: {{- with $component.minAvailable }} minAvailable: {{ . }} {{- end }} + {{- if (semverCompare ">= 1.27-0" .Capabilities.KubeVersion.Version) }} + {{- if hasKey $component "unhealthyPodEvictionPolicy" }} + {{- with $component.unhealthyPodEvictionPolicy }} + unhealthyPodEvictionPolicy: {{ . }} + {{- end }} + {{- end }} + {{- end }} selector: matchLabels: k8s-app: clustermesh-apiserver diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/service.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/service.yaml index cdfc55c8..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 (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) }} +{{- 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/serviceaccount.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/serviceaccount.yaml index 2df6aa87..a24369ef 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/serviceaccount.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/serviceaccount.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.serviceAccounts.clustermeshApiserver.create -}} +{{- if and .Values.clustermesh.useAPIServer .Values.serviceAccounts.clustermeshApiserver.create -}} apiVersion: v1 kind: ServiceAccount metadata: diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/servicemonitor.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/servicemonitor.yaml index 800d79f7..a9d4d5bc 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/servicemonitor.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/servicemonitor.yaml @@ -1,6 +1,6 @@ {{- $kvstoreMetricsEnabled := and .Values.clustermesh.apiserver.kvstoremesh.enabled .Values.clustermesh.apiserver.metrics.kvstoremesh.enabled -}} {{- if and - (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) + .Values.clustermesh.useAPIServer (or .Values.clustermesh.apiserver.metrics.enabled $kvstoreMetricsEnabled .Values.clustermesh.apiserver.metrics.etcd.enabled) .Values.clustermesh.apiserver.metrics.serviceMonitor.enabled }} --- @@ -11,6 +11,7 @@ metadata: namespace: {{ .Values.clustermesh.apiserver.metrics.serviceMonitor.namespace | default (include "cilium.namespace" .) }} labels: app.kubernetes.io/part-of: cilium + app.kubernetes.io/name: clustermesh-apiserver {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} @@ -35,9 +36,12 @@ spec: matchNames: - {{ include "cilium.namespace" . }} endpoints: - {{- if .Values.clustermesh.apiserver.metrics.enabled }} + {{- if and .Values.clustermesh.apiserver.metrics.enabled (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") (eq "true" (include "identityAllocationCRD" .)) }} - port: apiserv-metrics interval: {{ .Values.clustermesh.apiserver.metrics.serviceMonitor.interval | quote }} + {{- if .Values.clustermesh.apiserver.metrics.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.clustermesh.apiserver.metrics.serviceMonitor.scrapeTimeout | quote }} + {{- end }} honorLabels: true path: /metrics {{- with .Values.clustermesh.apiserver.metrics.serviceMonitor.relabelings }} @@ -52,6 +56,9 @@ spec: {{- if $kvstoreMetricsEnabled }} - port: kvmesh-metrics interval: {{ .Values.clustermesh.apiserver.metrics.serviceMonitor.kvstoremesh.interval | quote }} + {{- if .Values.clustermesh.apiserver.metrics.serviceMonitor.kvstoremesh.scrapeTimeout }} + scrapeTimeout: {{ .Values.clustermesh.apiserver.metrics.serviceMonitor.kvstoremesh.scrapeTimeout | quote }} + {{- end }} honorLabels: true path: /metrics {{- with .Values.clustermesh.apiserver.metrics.serviceMonitor.kvstoremesh.relabelings }} @@ -63,9 +70,12 @@ spec: {{- toYaml . | nindent 4 }} {{- end }} {{- end }} - {{- if .Values.clustermesh.apiserver.metrics.etcd.enabled }} + {{- if and .Values.clustermesh.apiserver.metrics.etcd.enabled (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") }} - port: etcd-metrics interval: {{ .Values.clustermesh.apiserver.metrics.serviceMonitor.etcd.interval | quote }} + {{- if .Values.clustermesh.apiserver.metrics.serviceMonitor.etcd.scrapeTimeout }} + scrapeTimeout: {{ .Values.clustermesh.apiserver.metrics.serviceMonitor.etcd.scrapeTimeout | quote }} + {{- end }} honorLabels: true path: /metrics {{- with .Values.clustermesh.apiserver.metrics.serviceMonitor.etcd.relabelings }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/admin-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/admin-secret.yaml index 974ebfa8..7a2713b6 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/admin-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/admin-secret.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} +{{- if and (and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal")) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} --- apiVersion: cert-manager.io/v1 kind: Certificate diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/client-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/client-secret.yaml deleted file mode 100644 index 0b33c852..00000000 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/client-secret.yaml +++ /dev/null @@ -1,22 +0,0 @@ -{{- if and .Values.externalWorkloads.enabled .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} ---- -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - name: clustermesh-apiserver-client-cert - namespace: {{ include "cilium.namespace" . }} - {{- with .Values.commonLabels }} - labels: - {{- toYaml . | nindent 4 }} - {{- end }} - {{- with .Values.clustermesh.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - issuerRef: - {{- toYaml .Values.clustermesh.apiserver.tls.auto.certManagerIssuerRef | nindent 4 }} - secretName: clustermesh-apiserver-client-cert - commonName: externalworkload - duration: {{ printf "%dh0m0s" (mul .Values.clustermesh.apiserver.tls.auto.certValidityDuration 24) }} -{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/local-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/local-secret.yaml index d38e8195..376fd61b 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/local-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/local-secret.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.kvstoremesh.enabled .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} +{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.kvstoremesh.enabled (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} --- apiVersion: cert-manager.io/v1 kind: Certificate diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/remote-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/remote-secret.yaml index 47cb29ff..94ab4119 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/remote-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/remote-secret.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} +{{- if and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} --- apiVersion: cert-manager.io/v1 kind: Certificate diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/server-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/server-secret.yaml index 8e94d1fe..a8772ae2 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/server-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/server-secret.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} +{{- if and (and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal")) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} --- apiVersion: cert-manager.io/v1 kind: Certificate diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/_job-spec.tpl b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/_job-spec.tpl index a12d3256..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 @@ -13,6 +13,10 @@ spec: - name: certgen image: {{ include "cilium.image" .Values.certgen.image | quote }} imagePullPolicy: {{ .Values.certgen.image.pullPolicy }} + {{- with .Values.certgen.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} command: - "/usr/bin/cilium-certgen" args: @@ -76,16 +80,6 @@ spec: - client auth validity: {{ $certValidityStr }} {{- end }} - {{- if .Values.externalWorkloads.enabled }} - - name: clustermesh-apiserver-client-cert - namespace: {{ include "cilium.namespace" . }} - commonName: "externalworkload" - usage: - - signing - - key encipherment - - client auth - validity: {{ $certValidityStr }} - {{- end }} {{- with .Values.certgen.extraVolumeMounts }} volumeMounts: {{- toYaml . | nindent 10 }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/cronjob.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/cronjob.yaml index 4dfc8076..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 @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") .Values.clustermesh.apiserver.tls.auto.schedule }} +{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") .Values.clustermesh.apiserver.tls.auto.schedule }} apiVersion: batch/v1 kind: CronJob metadata: diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/job.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/job.yaml index d27a3150..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,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") }} +{{- 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") }} --- apiVersion: batch/v1 kind: Job diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/role.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/role.yaml index e8e8b0ae..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 @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") .Values.serviceAccounts.clustermeshcertgen.create }} +{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") .Values.serviceAccounts.clustermeshcertgen.create }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/rolebinding.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/rolebinding.yaml index 28f36797..6e5dd695 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/rolebinding.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/rolebinding.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") .Values.serviceAccounts.clustermeshcertgen.create }} +{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") .Values.serviceAccounts.clustermeshcertgen.create }} apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/serviceaccount.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/serviceaccount.yaml index 1a8c3ea1..42066dd1 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/serviceaccount.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/serviceaccount.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") .Values.serviceAccounts.clustermeshcertgen.create }} +{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") .Values.serviceAccounts.clustermeshcertgen.create }} apiVersion: v1 kind: ServiceAccount metadata: diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/admin-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/admin-secret.yaml index a35f7cdc..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 @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} +{{- if and ( and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal")) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} {{- $_ := include "cilium.ca.setup" . -}} {{- $cn := include "clustermesh-apiserver-generate-certs.admin-common-name" . -}} {{- $cert := genSignedCert $cn nil nil (.Values.clustermesh.apiserver.tls.auto.certValidityDuration | int) .commonCA -}} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/client-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/client-secret.yaml deleted file mode 100644 index 220e9d3d..00000000 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/client-secret.yaml +++ /dev/null @@ -1,24 +0,0 @@ -{{- if and .Values.externalWorkloads.enabled .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} -{{- $_ := include "cilium.ca.setup" . -}} -{{- $cn := "externalworkload" }} -{{- $cert := genSignedCert $cn nil nil (.Values.clustermesh.apiserver.tls.auto.certValidityDuration | int) .commonCA -}} ---- -apiVersion: v1 -kind: Secret -metadata: - name: clustermesh-apiserver-client-cert - namespace: {{ include "cilium.namespace" . }} - {{- with .Values.commonLabels }} - labels: - {{- toYaml . | nindent 4 }} - {{- end }} - {{- with .Values.clustermesh.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -type: kubernetes.io/tls -data: - ca.crt: {{ .commonCA.Cert | b64enc }} - tls.crt: {{ $cert.Cert | b64enc }} - tls.key: {{ $cert.Key | b64enc }} -{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/local-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/local-secret.yaml index 4efc252d..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 @@ -1,4 +1,4 @@ -{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.kvstoremesh.enabled .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} +{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.kvstoremesh.enabled (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} {{- $_ := include "cilium.ca.setup" . -}} {{- $cn := include "clustermesh-apiserver-generate-certs.local-common-name" . -}} {{- $cert := genSignedCert $cn nil nil (.Values.clustermesh.apiserver.tls.auto.certValidityDuration | int) .commonCA -}} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/remote-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/remote-secret.yaml index 04175f7a..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 @@ -1,4 +1,4 @@ -{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} +{{- if and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} {{- $_ := include "cilium.ca.setup" . -}} {{- $cn := include "clustermesh-apiserver-generate-certs.remote-common-name" . -}} {{- $cert := genSignedCert $cn nil nil (.Values.clustermesh.apiserver.tls.auto.certValidityDuration | int) .commonCA -}} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/server-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/server-secret.yaml index 53c895fa..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 @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} +{{- if and (and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal")) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} {{- $_ := include "cilium.ca.setup" . -}} {{- $cn := "clustermesh-apiserver.cilium.io" }} {{- $ip := concat (list "127.0.0.1" "::1") .Values.clustermesh.apiserver.tls.server.extraIpAddresses }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/admin-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/admin-secret.yaml index 91955979..24a8f1c9 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/admin-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/admin-secret.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) (not .Values.clustermesh.apiserver.tls.auto.enabled) }} +{{- if and (and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal")) (not .Values.clustermesh.apiserver.tls.auto.enabled) }} {{- if .Values.clustermesh.apiserver.tls.enableSecrets }} apiVersion: v1 kind: Secret diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/client-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/client-secret.yaml deleted file mode 100644 index 92c977cc..00000000 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/client-secret.yaml +++ /dev/null @@ -1,22 +0,0 @@ -{{- if and .Values.externalWorkloads.enabled (not .Values.clustermesh.apiserver.tls.auto.enabled) }} -{{- if .Values.clustermesh.apiserver.tls.enableSecrets }} -apiVersion: v1 -kind: Secret -metadata: - name: clustermesh-apiserver-client-cert - namespace: {{ include "cilium.namespace" . }} - {{- with .Values.clustermesh.annotations }} - {{- with .Values.commonLabels }} - labels: - {{- toYaml . | nindent 4 }} - {{- end }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -type: kubernetes.io/tls -data: - ca.crt: {{ .Values.tls.ca.cert }} - tls.crt: {{ .Values.clustermesh.apiserver.tls.client.cert | required "missing clustermesh.apiserver.tls.client.cert" }} - tls.key: {{ .Values.clustermesh.apiserver.tls.client.key | required "missing clustermesh.apiserver.tls.client.key" }} -{{- end }} -{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/remote-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/remote-secret.yaml index 62173a1f..46a1b6c4 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/remote-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/remote-secret.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.clustermesh.useAPIServer (not .Values.clustermesh.apiserver.tls.auto.enabled) }} +{{- if and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") (not .Values.clustermesh.apiserver.tls.auto.enabled) }} {{- if .Values.clustermesh.apiserver.tls.enableSecrets }} apiVersion: v1 kind: Secret diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/server-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/server-secret.yaml index 231178ca..02b23986 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/server-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/server-secret.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) (not .Values.clustermesh.apiserver.tls.auto.enabled) }} +{{- if and (and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal")) (not .Values.clustermesh.apiserver.tls.auto.enabled) }} {{- if .Values.clustermesh.apiserver.tls.enableSecrets }} apiVersion: v1 kind: Secret diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/users-configmap.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/users-configmap.yaml index 56572bb2..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 - (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) + (and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") (eq "true" (include "identityAllocationCRD" .))) (ne .Values.clustermesh.apiserver.tls.authMode "legacy") }} --- diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-config/_helpers.tpl b/packages/system/cilium/charts/cilium/templates/clustermesh-config/_helpers.tpl index 3529f066..47c3393c 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-config/_helpers.tpl +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-config/_helpers.tpl @@ -2,6 +2,8 @@ {{- $cluster := index . 0 -}} {{- $domain := index . 1 -}} {{- $override := index . 2 -}} +{{- $local_etcd := index . 3 -}} +{{- $etcd_config := index . 4 -}} {{- /* The parenthesis around $cluster.tls are required, since it can be null: https://stackoverflow.com/a/68807258 */}} {{- $prefix := ternary "common-" (printf "%s." $cluster.name) (or (empty ($cluster.tls).cert) (empty ($cluster.tls).key)) -}} {{- /* KVStoreMesh is enabled, and we are generating the secret used by Cilium agents. */}} @@ -12,15 +14,24 @@ {{- end -}} endpoints: -{{- if ne $override "" }} +{{- if $local_etcd }} +{{ $etcd_config.endpoints | toYaml }} +{{- else if ne $override "" }} - {{ $override }} {{- else if $cluster.ips }} - https://{{ $cluster.name }}.{{ $domain }}:{{ $cluster.port }} {{- else }} - https://{{ $cluster.address | required "missing clustermesh.apiserver.config.clusters.address" }}:{{ $cluster.port }} {{- end }} +{{- if $local_etcd }} + {{- if $etcd_config.ssl }} +trusted-ca-file: '/var/lib/etcd-secrets/etcd-client-ca.crt' +key-file: '/var/lib/etcd-secrets/etcd-client.key' +cert-file: '/var/lib/etcd-secrets/etcd-client.crt' + {{- end }} +{{- else }} {{- if or (ne $override "") (not (empty ($cluster.tls).caCert)) }} -{{- /* The custom CA configuration takes effect only if a custom certificate and key are also set, */}} +{{- /* The custom CA configuration takes effect only if a custom certificate and key are also set */}} {{- /* otherwise we may enter this branch, but the prefix is still set to common-. */}} {{- /* Additionally, when KVStoreMesh is enabled, and we are generating the secret for the agents, */}} {{- /* we want to always use the corresponding CA certificate, that is the one with local- prefix. */}} @@ -31,3 +42,4 @@ trusted-ca-file: /var/lib/cilium/clustermesh/common-etcd-client-ca.crt key-file: /var/lib/cilium/clustermesh/{{ $prefix }}etcd-client.key cert-file: /var/lib/cilium/clustermesh/{{ $prefix }}etcd-client.crt {{- end }} +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-config/clustermesh-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-config/clustermesh-secret.yaml index 7f4f14b2..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 @@ -17,8 +17,9 @@ metadata: data: {{- $kvstoremesh := and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.kvstoremesh.enabled }} {{- $override := ternary (printf "https://clustermesh-apiserver.%s.svc:2379" (include "cilium.namespace" .)) "" $kvstoremesh }} + {{- $local_etcd := and $kvstoremesh (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "external") }} {{- range .Values.clustermesh.config.clusters }} - {{ .name }}: {{ include "clustermesh-config-generate-etcd-cfg" (list . $.Values.clustermesh.config.domain $override) | b64enc }} + {{ .name }}: {{ include "clustermesh-config-generate-etcd-cfg" (list . $.Values.clustermesh.config.domain $override $local_etcd $.Values.etcd ) | b64enc }} {{- /* The parenthesis around .tls are required, since it can be null: https://stackoverflow.com/a/68807258 */}} {{- if and (eq $override "") (.tls).cert (.tls).key }} {{- if .tls.caCert }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-config/kvstoremesh-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-config/kvstoremesh-secret.yaml index e9b554ac..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 @@ -16,7 +16,7 @@ metadata: {{- end }} data: {{- range .Values.clustermesh.config.clusters }} - {{ .name }}: {{ include "clustermesh-config-generate-etcd-cfg" (list . $.Values.clustermesh.config.domain "") | b64enc }} + {{ .name }}: {{ include "clustermesh-config-generate-etcd-cfg" (list . $.Values.clustermesh.config.domain "" false $.Values.etcd ) | b64enc }} {{- /* The parenthesis around .tls are required, since it can be null: https://stackoverflow.com/a/68807258 */}} {{- if and (.tls).cert (.tls).key }} {{- if .tls.caCert }} diff --git a/packages/system/cilium/charts/cilium/templates/hubble-relay/poddisruptionbudget.yaml b/packages/system/cilium/charts/cilium/templates/hubble-relay/poddisruptionbudget.yaml index b44cecfa..5f28b83f 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble-relay/poddisruptionbudget.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble-relay/poddisruptionbudget.yaml @@ -24,6 +24,13 @@ spec: {{- with $component.minAvailable }} minAvailable: {{ . }} {{- end }} + {{- if (semverCompare ">= 1.27-0" .Capabilities.KubeVersion.Version) }} + {{- if hasKey $component "unhealthyPodEvictionPolicy" }} + {{- with $component.unhealthyPodEvictionPolicy }} + unhealthyPodEvictionPolicy: {{ . }} + {{- end }} + {{- end }} + {{- end }} selector: matchLabels: k8s-app: hubble-relay diff --git a/packages/system/cilium/charts/cilium/templates/hubble-relay/servicemonitor.yaml b/packages/system/cilium/charts/cilium/templates/hubble-relay/servicemonitor.yaml index b6b1733c..e4b62ce0 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble-relay/servicemonitor.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble-relay/servicemonitor.yaml @@ -5,6 +5,8 @@ metadata: name: hubble-relay namespace: {{ .Values.hubble.relay.prometheus.serviceMonitor.namespace | default (include "cilium.namespace" .) }} labels: + app.kubernetes.io/part-of: cilium + app.kubernetes.io/name: hubble-relay {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} @@ -31,6 +33,9 @@ spec: endpoints: - port: metrics interval: {{ .Values.hubble.relay.prometheus.serviceMonitor.interval | quote }} + {{- if .Values.hubble.relay.prometheus.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.hubble.relay.prometheus.serviceMonitor.scrapeTimeout | quote }} + {{- end }} path: /metrics {{- with .Values.hubble.relay.prometheus.serviceMonitor.relabelings }} relabelings: diff --git a/packages/system/cilium/charts/cilium/templates/hubble-ui/_nginx.tpl b/packages/system/cilium/charts/cilium/templates/hubble-ui/_nginx.tpl index 5d3d0a80..4d8f7b90 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble-ui/_nginx.tpl +++ b/packages/system/cilium/charts/cilium/templates/hubble-ui/_nginx.tpl @@ -31,10 +31,11 @@ server { sub_filter '' ''; {{- end }} location {{ .Values.hubble.ui.baseUrl }} { + if ($http_user_agent ~* "kube-probe") { access_log off; } {{- if not (eq .Values.hubble.ui.baseUrl "/") }} rewrite ^{{ (trimSuffix "/" .Values.hubble.ui.baseUrl) }}(/.*)$ $1 break; {{- end }} - # double `/index.html` is required here + # double `/index.html` is required here try_files $uri $uri/ /index.html /index.html; } diff --git a/packages/system/cilium/charts/cilium/templates/hubble-ui/poddisruptionbudget.yaml b/packages/system/cilium/charts/cilium/templates/hubble-ui/poddisruptionbudget.yaml index 35402984..93e909fb 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble-ui/poddisruptionbudget.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble-ui/poddisruptionbudget.yaml @@ -24,6 +24,13 @@ spec: {{- with $component.minAvailable }} minAvailable: {{ . }} {{- end }} + {{- if (semverCompare ">= 1.27-0" .Capabilities.KubeVersion.Version) }} + {{- if hasKey $component "unhealthyPodEvictionPolicy" }} + {{- with $component.unhealthyPodEvictionPolicy }} + unhealthyPodEvictionPolicy: {{ . }} + {{- end }} + {{- end }} + {{- end }} selector: matchLabels: k8s-app: hubble-ui diff --git a/packages/system/cilium/charts/cilium/templates/hubble-ui/service.yaml b/packages/system/cilium/charts/cilium/templates/hubble-ui/service.yaml index 90b3b1b7..ade023fe 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble-ui/service.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble-ui/service.yaml @@ -21,6 +21,9 @@ metadata: {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} + {{- with .Values.hubble.ui.service.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} spec: type: {{ .Values.hubble.ui.service.type | quote }} diff --git a/packages/system/cilium/charts/cilium/templates/hubble/servicemonitor.yaml b/packages/system/cilium/charts/cilium/templates/hubble/servicemonitor.yaml index 1f3717fa..909f05ed 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble/servicemonitor.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble/servicemonitor.yaml @@ -6,7 +6,7 @@ metadata: namespace: {{ .Values.prometheus.serviceMonitor.namespace | default (include "cilium.namespace" .) }} labels: app.kubernetes.io/part-of: cilium - + app.kubernetes.io/name: hubble {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} @@ -33,6 +33,9 @@ spec: endpoints: - port: hubble-metrics interval: {{ .Values.hubble.metrics.serviceMonitor.interval | quote }} + {{- if .Values.hubble.metrics.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.hubble.metrics.serviceMonitor.scrapeTimeout | quote }} + {{- end }} honorLabels: true path: /metrics {{- if .Values.hubble.metrics.tls.enabled }} diff --git a/packages/system/cilium/charts/cilium/templates/hubble/tls-cronjob/_job-spec.tpl b/packages/system/cilium/charts/cilium/templates/hubble/tls-cronjob/_job-spec.tpl index 2b37bdc0..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 @@ -21,6 +21,10 @@ spec: drop: - ALL allowPrivilegeEscalation: false + {{- with .Values.certgen.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} command: - "/usr/bin/cilium-certgen" # Because this is executed as a job, we pass the values as command diff --git a/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/relay-client-secret.yaml b/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/relay-client-secret.yaml index f6ba3279..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 @@ -3,6 +3,14 @@ {{- $cn := "*.hubble-relay.cilium.io" }} {{- $dns := list $cn }} {{- $cert := genSignedCert $cn nil $dns (.Values.hubble.tls.auto.certValidityDuration | int) .commonCA -}} +{{- $tls_crt := ($cert.Cert | b64enc) }} +{{- $tls_key := ($cert.Key | b64enc) }} +{{- with lookup "v1" "Secret" (include "cilium.namespace" .) "hubble-relay-client-certs" }} + {{- if and (index .data "tls.crt") (index .data "tls.key") }} + {{- $tls_key = (index .data "tls.key") }} + {{- $tls_crt = (index .data "tls.crt") }} + {{- end }} +{{- end }} --- apiVersion: v1 kind: Secret @@ -21,6 +29,6 @@ metadata: type: kubernetes.io/tls data: ca.crt: {{ .commonCA.Cert | b64enc }} - tls.crt: {{ $cert.Cert | b64enc }} - tls.key: {{ $cert.Key | b64enc }} + tls.crt: {{ $tls_crt }} + tls.key: {{ $tls_key }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/server-secret.yaml b/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/server-secret.yaml index a159240d..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 @@ -4,6 +4,14 @@ {{- $ip := .Values.hubble.tls.server.extraIpAddresses }} {{- $dns := prepend .Values.hubble.tls.server.extraDnsNames $cn }} {{- $cert := genSignedCert $cn $ip $dns (.Values.hubble.tls.auto.certValidityDuration | int) .commonCA -}} +{{- $tls_crt := ($cert.Cert | b64enc) }} +{{- $tls_key := ($cert.Key | b64enc) }} +{{- with lookup "v1" "Secret" (include "cilium.namespace" .) "hubble-server-certs" }} + {{- if and (index .data "tls.crt") (index .data "tls.key") }} + {{- $tls_key = (index .data "tls.key") }} + {{- $tls_crt = (index .data "tls.crt") }} + {{- end }} +{{- end }} --- apiVersion: v1 kind: Secret @@ -22,6 +30,6 @@ metadata: type: kubernetes.io/tls data: ca.crt: {{ .commonCA.Cert | b64enc }} - tls.crt: {{ $cert.Cert | b64enc }} - tls.key: {{ $cert.Key | b64enc }} + tls.crt: {{ $tls_crt }} + tls.key: {{ $tls_key }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/hubble/tls-provided/metrics-server-secret.yaml b/packages/system/cilium/charts/cilium/templates/hubble/tls-provided/metrics-server-secret.yaml index 8137aef3..64183918 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble/tls-provided/metrics-server-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble/tls-provided/metrics-server-secret.yaml @@ -4,7 +4,7 @@ kind: Secret metadata: name: hubble-metrics-server-certs namespace: {{ include "cilium.namespace" . }} - + {{- with .Values.commonLabels }} labels: {{- toYaml . | nindent 4 }} diff --git a/packages/system/cilium/charts/cilium/templates/spire/agent/daemonset.yaml b/packages/system/cilium/charts/cilium/templates/spire/agent/daemonset.yaml index cac60877..00bfee91 100644 --- a/packages/system/cilium/charts/cilium/templates/spire/agent/daemonset.yaml +++ b/packages/system/cilium/charts/cilium/templates/spire/agent/daemonset.yaml @@ -91,7 +91,7 @@ spec: {{- with .Values.authentication.mutual.spire.install.agent.resources }} resources: {{- toYaml . | trim | nindent 12 }} - {{- end }} + {{- end }} livenessProbe: httpGet: path: /live diff --git a/packages/system/cilium/charts/cilium/templates/spire/server/statefulset.yaml b/packages/system/cilium/charts/cilium/templates/spire/server/statefulset.yaml index 3b243fc8..23dda2c0 100644 --- a/packages/system/cilium/charts/cilium/templates/spire/server/statefulset.yaml +++ b/packages/system/cilium/charts/cilium/templates/spire/server/statefulset.yaml @@ -29,6 +29,8 @@ spec: serviceName: spire-server template: metadata: + annotations: + kubectl.kubernetes.io/default-container: spire-server labels: app: spire-server {{- with .Values.commonLabels }} @@ -75,7 +77,7 @@ spec: {{- with .Values.authentication.mutual.spire.install.server.resources }} resources: {{- toYaml . | trim | nindent 10 }} - {{- end }} + {{- end }} ports: - name: grpc containerPort: 8081 diff --git a/packages/system/cilium/charts/cilium/templates/validate.yaml b/packages/system/cilium/charts/cilium/templates/validate.yaml index 37da6cd6..4fff21a3 100644 --- a/packages/system/cilium/charts/cilium/templates/validate.yaml +++ b/packages/system/cilium/charts/cilium/templates/validate.yaml @@ -1,5 +1,13 @@ {{/* validate deprecated options are not being used */}} +{{/* Options removed in v1.18 */}} +{{- if (dig "enableCiliumEndpointSlice" "" .Values.AsMap) }} + {{ fail "enableCiliumEndpointSlice was deprecated in v1.16 and has been removed in v1.18. For details please refer to https://docs.cilium.io/en/v1.18/operations/upgrade/#helm-options" }} +{{- end }} +{{- if (dig "ciliumEndpointSlice" "sliceMode" "" .Values.AsMap) }} + {{ fail "ciliumEndpointSlice.sliceMode has been removed in v1.18. For details please refer to https://docs.cilium.io/en/v1.18/operations/upgrade/#helm-options" }} +{{- end }} + {{/* Options deprecated in v1.15 and removed in v1.16 */}} {{- if or (dig "encryption" "keyFile" "" .Values.AsMap) @@ -42,6 +50,11 @@ {{ fail "enableCnpStatusUpdates was deprecated in v1.14 and has been removed in v1.15. For details please refer to https://docs.cilium.io/en/v1.15/operations/upgrade/#helm-options" }} {{- end }} +{{/* validate single k8sServiceHost strategy */}} +{{- if and (and .Values.k8sServiceHostRef.name .Values.k8sServiceHostRef.key) .Values.k8sServiceHost }} + {{- fail "Both k8sServiceHostRef and k8sServiceHost are set. Please set only one of them." }} +{{- end }} + {{/* validate hubble config */}} {{- if and .Values.hubble.ui.enabled (not .Values.hubble.ui.standalone.enabled) }} {{- if not .Values.hubble.relay.enabled }} @@ -78,7 +91,7 @@ {{ fail "Only one of .Values.hubble.redact.http.headers.allow, .Values.hubble.redact.http.headers.deny can be specified"}} {{- end }} -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} +{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} {{- if not .Values.clustermesh.apiserver.tls.auto.certManagerIssuerRef }} {{ fail "ClusterMesh TLS certgen method=certmanager requires that user specifies .Values.clustermesh.apiserver.tls.auto.certManagerIssuerRef" }} {{- end }} @@ -129,7 +142,7 @@ {{- end }} {{/* validate Cilium operator */}} -{{- if or .Values.ciliumEndpointSlice.enabled .Values.enableCiliumEndpointSlice }} +{{- if .Values.ciliumEndpointSlice.enabled }} {{- if eq .Values.disableEndpointCRD true }} {{ fail "if Cilium Endpoint Slice is enabled (.Values.ciliumEndpointSlice.enabled=true), it requires .Values.disableEndpointCRD=false" }} {{- end }} @@ -156,29 +169,54 @@ {{- end }} {{/* validate clustermesh-apiserver */}} + +{{- if not (list "internal" "external" | has .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode) -}} +{{- fail ".Values.clustermesh.apiserver.kvstoremesh.kvstoreMode must have the value of external or internal" -}} +{{- end -}} + {{- if .Values.clustermesh.useAPIServer }} - {{- if and (ne .Values.identityAllocationMode "crd") (ne .Values.identityAllocationMode "doublewrite-readkvstore") (ne .Values.identityAllocationMode "doublewrite-readcrd") }} - {{ fail (printf "The clustermesh-apiserver cannot be enabled in combination with .Values.identityAllocationMode=%s. To establish a Cluster Mesh, directly configure the parameters to access the remote kvstore through .Values.clustermesh.config" .Values.identityAllocationMode ) }} - {{- end }} - {{- if .Values.disableEndpointCRD }} - {{ fail "The clustermesh-apiserver cannot be enabled in combination with .Values.disableEndpointCRD=true" }} + {{- if eq "true" (include "identityAllocationCRD" .) }} + {{/* CRDs are used */}} + {{- if and .Values.disableEndpointCRD }} + {{ fail "The clustermesh-apiserver cannot be enabled in combination with .Values.disableEndpointCRD=true" }} + {{- end }} + {{- else }} + {{/* kvstore is used */}} + {{- if not .Values.clustermesh.apiserver.kvstoremesh.enabled }} + {{ fail (printf "The kvstoremesh container cannot be disabled in combination with .Values.identityAllocationMode=%s. To establish a Cluster Mesh, directly configure the parameters to access the remote kvstores through .Values.clustermesh.config" .Values.identityAllocationMode ) }} + {{- end}} {{- end }} {{- end }} -{{- if .Values.externalWorkloads.enabled }} - {{- if and (ne .Values.identityAllocationMode "crd") (ne .Values.identityAllocationMode "doublewrite-readkvstore") (ne .Values.identityAllocationMode "doublewrite-readcrd") }} - {{ fail (printf "External workloads support cannot be enabled in combination with .Values.identityAllocationMode=%s" .Values.identityAllocationMode ) }} +{{- if eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "external"}} + {{- if not .Values.clustermesh.useAPIServer }} + {{- fail "kvstoremesh.kvstoreMode=external can only be used with clustermesh.useAPIServer=true" }} {{- end }} - {{- if .Values.disableEndpointCRD }} - {{ fail "External workloads support cannot be enabled in combination with .Values.disableEndpointCRD=true" }} + {{- if not .Values.clustermesh.apiserver.kvstoremesh.enabled }} + {{- fail "kvstoremesh.kvstoreMode=external can only be used with kvstoremesh.enabled=true" }} + {{- end }} + {{- if ne (toString .Values.clustermesh.apiserver.replicas) "1" }} + {{- fail "Only single clustermesh-apiserver replica is allowed when kvstoreMode=external" }} + {{- end }} + {{- if and (ne .Values.identityAllocationMode "kvstore") (ne .Values.identityAllocationMode "doublewrite-readkvstore") (ne .Values.identityAllocationMode "doublewrite-readcrd") }} + {{- fail (printf "KVStoreMesh with %s etcd cannot be enabled in combination with .Values.identityAllocationMode=%s" .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode .Values.identityAllocationMode) }} {{- end }} {{- end }} -{{/*validate ClusterMesh */}} +{{/* validate ClusterMesh */}} {{- if and (ne (int .Values.clustermesh.maxConnectedClusters) 255) (ne (int .Values.clustermesh.maxConnectedClusters) 511) }} {{- fail "max-connected-clusters must be set to 255 or 511" }} {{- end }} -{{/*validate Envoy baseID */}} +{{/* validate Envoy baseID */}} {{- if not (and (ge (int .Values.envoy.baseID) 0) (le (int .Values.envoy.baseID) 4294967295)) }} {{- fail "envoy.baseID must be an int. Supported values 0 - 4294967295" }} {{- end }} + +{{/* validate enableK8sClientExponentialBackoff and extraEnv to avoid duplicate env var keys */}} +{{- if .Values.k8sClientExponentialBackoff.enabled }} + {{- range .Values.extraEnv }} + {{- if or (eq .name "KUBE_CLIENT_BACKOFF_BASE") (eq .name "KUBE_CLIENT_BACKOFF_DURATION") }} + {{ fail "k8sClientExponentialBackoff cannot be enabled when extraEnv contains KUBE_CLIENT_BACKOFF_BASE or KUBE_CLIENT_BACKOFF_DURATION" }} + {{- end }} + {{- end }} +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/warnings.txt b/packages/system/cilium/charts/cilium/templates/warnings.txt new file mode 100644 index 00000000..8cc823b3 --- /dev/null +++ b/packages/system/cilium/charts/cilium/templates/warnings.txt @@ -0,0 +1,13 @@ +{{- define "cilium.warnings" }} +{{- /* TODO: move this warning to a validation failure once v1.18 is released */ -}} +{{- if or + (hasKey .Values.hubble.export "fileMaxSizeMb") + (hasKey .Values.hubble.export "fileMaxBackups") + (hasKey .Values.hubble.export "fileCompress") +-}} +- We detected that one or more Hubble export options under 'hubble.export' are currently set + ('fileMaxSizeMb', 'fileMaxBackups', 'fileCompress'). Please note that these have moved to + their corresponding exporter type ('hubble.export.static', 'hubble.export.dynamic.config.content') + and will be removed in v1.19. +{{- end -}} +{{- end -}} diff --git a/packages/system/cilium/charts/cilium/values.schema.json b/packages/system/cilium/charts/cilium/values.schema.json index 762efbf9..fb1ea4c3 100644 --- a/packages/system/cilium/charts/cilium/values.schema.json +++ b/packages/system/cilium/charts/cilium/values.schema.json @@ -449,6 +449,9 @@ "bbr": { "type": "boolean" }, + "bbrHostNamespaceOnly": { + "type": "boolean" + }, "enabled": { "type": "boolean" } @@ -460,6 +463,25 @@ "enabled": { "type": "boolean" }, + "legacyOriginAttribute": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "routerIDAllocation": { + "properties": { + "ipPool": { + "type": "string" + }, + "mode": { + "type": "string" + } + }, + "type": "object" + }, "secretsNamespace": { "properties": { "create": { @@ -646,6 +668,12 @@ "integer" ] }, + "policyStatsMapMax": { + "type": [ + "null", + "integer" + ] + }, "preallocateMaps": { "type": "boolean" }, @@ -732,6 +760,9 @@ "priorityClassName": { "type": "string" }, + "resources": { + "type": "object" + }, "tolerations": { "items": {}, "type": "array" @@ -798,12 +829,6 @@ ] }, "type": "array" - }, - "sliceMode": { - "enum": [ - "identity", - "fcfs" - ] } }, "type": "object" @@ -998,6 +1023,9 @@ "healthPort": { "type": "integer" }, + "kvstoreMode": { + "type": "string" + }, "lifecycle": { "type": "object" }, @@ -1093,6 +1121,12 @@ "null", "array" ] + }, + "scrapeTimeout": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -1116,6 +1150,12 @@ "null", "array" ] + }, + "scrapeTimeout": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -1134,6 +1174,12 @@ "null", "array" ] + }, + "scrapeTimeout": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -1170,6 +1216,12 @@ "integer", "string" ] + }, + "unhealthyPodEvictionPolicy": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -1424,6 +1476,9 @@ "maxConnectedClusters": { "type": "integer" }, + "policyDefaultLocalCluster": { + "type": "boolean" + }, "useAPIServer": { "type": "boolean" } @@ -1453,6 +1508,9 @@ "confPath": { "type": "string" }, + "configMap": { + "type": "string" + }, "configMapKey": { "type": "string" }, @@ -1471,6 +1529,9 @@ "install": { "type": "boolean" }, + "iptablesRemoveAWSRules": { + "type": "boolean" + }, "logFile": { "type": "string" }, @@ -1502,6 +1563,12 @@ "object" ] }, + "connectivityProbeFrequencyRatio": { + "type": [ + "null", + "number" + ] + }, "conntrackGCInterval": { "type": "string" }, @@ -1579,6 +1646,12 @@ "enabled": { "type": "boolean" }, + "metricsSamplingInterval": { + "type": [ + "null", + "string" + ] + }, "verbose": { "type": [ "null", @@ -1620,6 +1693,9 @@ "minTtl": { "type": "integer" }, + "preAllocateIdentities": { + "type": "boolean" + }, "preCache": { "type": "string" }, @@ -1646,9 +1722,6 @@ }, "type": "object" }, - "enableCiliumEndpointSlice": { - "type": "boolean" - }, "enableCriticalPriorityClass": { "type": "boolean" }, @@ -1656,7 +1729,10 @@ "type": "boolean" }, "enableIPv4Masquerade": { - "type": "boolean" + "type": [ + "null", + "boolean" + ] }, "enableIPv6BIGTCP": { "type": "boolean" @@ -1667,9 +1743,6 @@ "enableInternalTrafficPolicy": { "type": "boolean" }, - "enableK8sTerminatingEndpoint": { - "type": "boolean" - }, "enableLBIPAM": { "type": "boolean" }, @@ -1679,9 +1752,6 @@ "enableNonDefaultDenyPolicies": { "type": "boolean" }, - "enableRuntimeDeviceDetection": { - "type": "boolean" - }, "enableXTSocketFallback": { "type": "boolean" }, @@ -1806,9 +1876,6 @@ "subnetTagsFilter": { "items": {}, "type": "array" - }, - "updateEC2AdapterLimitViaAPI": { - "type": "boolean" } }, "type": "object" @@ -2005,6 +2072,9 @@ "httpRetryCount": { "type": "integer" }, + "httpUpstreamLingerTimeout": { + "type": "null" + }, "idleTimeoutDurationSeconds": { "type": "integer" }, @@ -2039,6 +2109,9 @@ }, "livenessProbe": { "properties": { + "enabled": { + "type": "boolean" + }, "failureThreshold": { "type": "integer" }, @@ -2173,6 +2246,9 @@ "anyOf": [ { "properties": { + "action": { + "type": "string" + }, "replacement": { "type": "string" }, @@ -2194,6 +2270,12 @@ ] }, "type": "array" + }, + "scrapeTimeout": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -2260,6 +2342,9 @@ }, "startupProbe": { "properties": { + "enabled": { + "type": "boolean" + }, "failureThreshold": { "type": "integer" }, @@ -2269,6 +2354,9 @@ }, "type": "object" }, + "streamIdleTimeoutDurationSeconds": { + "type": "integer" + }, "terminationGracePeriodSeconds": { "type": "integer" }, @@ -2357,14 +2445,6 @@ }, "type": "object" }, - "externalWorkloads": { - "properties": { - "enabled": { - "type": "boolean" - } - }, - "type": "object" - }, "extraArgs": { "items": {}, "type": "array" @@ -2480,14 +2560,6 @@ "healthPort": { "type": "integer" }, - "highScaleIPcache": { - "properties": { - "enabled": { - "type": "boolean" - } - }, - "type": "object" - }, "hostFirewall": { "properties": { "enabled": { @@ -2496,14 +2568,6 @@ }, "type": "object" }, - "hostPort": { - "properties": { - "enabled": { - "type": "boolean" - } - }, - "type": "object" - }, "hubble": { "properties": { "annotations": { @@ -2558,6 +2622,15 @@ "items": {}, "type": "array" }, + "fileCompress": { + "type": "boolean" + }, + "fileMaxBackups": { + "type": "integer" + }, + "fileMaxSizeMb": { + "type": "integer" + }, "filePath": { "type": "string" }, @@ -2586,12 +2659,6 @@ }, "type": "object" }, - "fileMaxBackups": { - "type": "integer" - }, - "fileMaxSizeMb": { - "type": "integer" - }, "static": { "properties": { "allowList": { @@ -2609,6 +2676,15 @@ "items": {}, "type": "array" }, + "fileCompress": { + "type": "boolean" + }, + "fileMaxBackups": { + "type": "integer" + }, + "fileMaxSizeMb": { + "type": "integer" + }, "filePath": { "type": "string" } @@ -2712,6 +2788,9 @@ "anyOf": [ { "properties": { + "action": { + "type": "string" + }, "replacement": { "type": "string" }, @@ -2734,6 +2813,12 @@ }, "type": "array" }, + "scrapeTimeout": { + "type": [ + "null", + "string" + ] + }, "tlsConfig": { "type": "object" } @@ -2790,6 +2875,14 @@ }, "type": "object" }, + "networkPolicyCorrelation": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, "peerService": { "properties": { "clusterDomain": { @@ -2886,12 +2979,6 @@ "annotations": { "type": "object" }, - "dialTimeout": { - "type": [ - "null", - "string" - ] - }, "enabled": { "type": "boolean" }, @@ -2979,6 +3066,12 @@ "integer", "string" ] + }, + "unhealthyPodEvictionPolicy": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -2990,6 +3083,14 @@ "properties": { "fsGroup": { "type": "integer" + }, + "seccompProfile": { + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" } }, "type": "object" @@ -3044,6 +3145,12 @@ "null", "array" ] + }, + "scrapeTimeout": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -3068,6 +3175,9 @@ }, "securityContext": { "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, "capabilities": { "properties": { "drop": { @@ -3091,6 +3201,14 @@ }, "runAsUser": { "type": "integer" + }, + "seccompProfile": { + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" } }, "type": "object" @@ -3328,6 +3446,11 @@ "type": "object" }, "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + } + }, "type": "object" } }, @@ -3383,6 +3506,11 @@ "type": "object" }, "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + } + }, "type": "object" }, "server": { @@ -3464,6 +3592,12 @@ "integer", "string" ] + }, + "unhealthyPodEvictionPolicy": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -3499,6 +3633,9 @@ "annotations": { "type": "object" }, + "labels": { + "type": "object" + }, "nodePort": { "type": "integer" }, @@ -3582,6 +3719,13 @@ "identityChangeGracePeriod": { "type": "string" }, + "identityManagementMode": { + "enum": [ + "agent", + "operator", + "both" + ] + }, "image": { "properties": { "digest": { @@ -3868,6 +4012,20 @@ }, "type": "object" }, + "k8sClientExponentialBackoff": { + "properties": { + "backoffBaseSeconds": { + "type": "integer" + }, + "backoffMaxDurationSeconds": { + "type": "integer" + }, + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, "k8sClientRateLimit": { "properties": { "burst": { @@ -3913,6 +4071,23 @@ "k8sServiceHost": { "type": "string" }, + "k8sServiceHostRef": { + "properties": { + "key": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, "k8sServiceLookupConfigMapName": { "type": [ "null", @@ -3940,6 +4115,12 @@ "kubeConfigPath": { "type": "string" }, + "kubeProxyReplacement": { + "type": [ + "string", + "boolean" + ] + }, "kubeProxyReplacementHealthzBindAddr": { "type": "string" }, @@ -3947,9 +4128,6 @@ "properties": { "enabled": { "type": "boolean" - }, - "refreshPeriod": { - "type": "string" } }, "type": "object" @@ -3995,9 +4173,6 @@ "acceleration": { "type": "string" }, - "experimental": { - "type": "boolean" - }, "l7": { "properties": { "algorithm": { @@ -4016,6 +4191,20 @@ }, "type": "object" }, + "localRedirectPolicies": { + "properties": { + "addressMatcherCIDRs": { + "type": [ + "null", + "array" + ] + }, + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, "localRedirectPolicy": { "type": "boolean" }, @@ -4218,6 +4407,9 @@ }, "securityContext": { "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, "capabilities": { "properties": { "add": { @@ -4471,6 +4663,12 @@ "integer", "string" ] + }, + "unhealthyPodEvictionPolicy": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -4479,6 +4677,16 @@ "type": "object" }, "podSecurityContext": { + "properties": { + "seccompProfile": { + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" + } + }, "type": "object" }, "pprof": { @@ -4537,6 +4745,12 @@ "null", "array" ] + }, + "scrapeTimeout": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -4557,6 +4771,26 @@ "type": "boolean" }, "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "properties": { + "drop": { + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "type": "array" + } + }, + "type": "object" + } + }, "type": "object" }, "setNodeNetworkStatus": { @@ -4576,6 +4810,39 @@ "anyOf": [ { "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + } + } + }, + { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + } + } + }, + { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + } + } + }, + { + "properties": { + "key": { + "type": "string" + }, "operator": { "type": "string" } @@ -4583,7 +4850,10 @@ } ] }, - "type": "array" + "type": [ + "null", + "array" + ] }, "topologySpreadConstraints": { "items": {}, @@ -4732,6 +5002,37 @@ "enabled": { "type": "boolean" }, + "envoy": { + "properties": { + "image": { + "properties": { + "digest": { + "type": "string" + }, + "override": { + "type": [ + "null", + "string" + ] + }, + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + }, + "useDigest": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, "extraEnv": { "items": {}, "type": "array" @@ -4799,6 +5100,12 @@ "integer", "string" ] + }, + "unhealthyPodEvictionPolicy": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -4827,6 +5134,11 @@ "type": "object" }, "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + } + }, "type": "object" }, "terminationGracePeriodSeconds": { @@ -4927,6 +5239,9 @@ "anyOf": [ { "properties": { + "action": { + "type": "string" + }, "replacement": { "type": "string" }, @@ -4949,6 +5264,12 @@ }, "type": "array" }, + "scrapeTimeout": { + "type": [ + "null", + "string" + ] + }, "trustCRDsExist": { "type": "boolean" } @@ -5039,8 +5360,14 @@ }, "type": "object" }, + "secretsNamespaceAnnotations": { + "type": "object" + }, "securityContext": { "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, "capabilities": { "properties": { "applySysctlOverwrites": { @@ -5470,6 +5797,9 @@ "tunnelSourcePortRange": { "type": "string" }, + "underlayProtocol": { + "type": "string" + }, "updateStrategy": { "properties": { "rollingUpdate": { diff --git a/packages/system/cilium/charts/cilium/values.yaml b/packages/system/cilium/charts/cilium/values.yaml index 68f73ee8..5fac5be5 100644 --- a/packages/system/cilium/charts/cilium/values.yaml +++ b/packages/system/cilium/charts/cilium/values.yaml @@ -40,6 +40,14 @@ debug: # - datapath # - policy verbose: ~ + # -- Set the agent-internal metrics sampling frequency. This sets the + # frequency of the internal sampling of the agent metrics. These are + # available via the "cilium-dbg shell -- metrics -s" command and are + # part of the metrics HTML page included in the sysdump. + # @schema + # type: [null, string] + # @schema + metricsSamplingInterval: "5m" rbac: # -- Enable creation of Resource-Based Access Control configuration. create: true @@ -52,6 +60,18 @@ iptablesRandomFully: false # -- (string) Kubernetes config path # @default -- `"~/.kube/config"` kubeConfigPath: "" +# -- Configure the Kubernetes service endpoint dynamically using a ConfigMap. Mutually exclusive with `k8sServiceHost`. +k8sServiceHostRef: + # @schema + # type: [string, null] + # @schema + # -- (string) name of the ConfigMap containing the Kubernetes service endpoint + name: + # @schema + # type: [string, null] + # @schema + # -- (string) Key in the ConfigMap containing the Kubernetes service endpoint + key: # -- (string) Kubernetes service host - use "auto" for automatic lookup from the cluster-info ConfigMap k8sServiceHost: "" # @schema @@ -103,6 +123,14 @@ k8sClientRateLimit: # The rate limiter will allow short bursts with a higher rate. # @default -- 200 burst: +# -- Configure exponential backoff for client-go in Cilium agent. +k8sClientExponentialBackoff: + # -- Enable exponential backoff for client-go in Cilium agent. + enabled: true + # -- Configure base (in seconds) for exponential backoff. + backoffBaseSeconds: 1 + # -- Configure maximum duration (in seconds) for exponential backoff. + backoffMaxDurationSeconds: 120 cluster: # -- Name of the cluster. Only required for Cluster Mesh and mutual authentication with SPIRE. # It must respect the following constraints: @@ -180,7 +208,7 @@ serviceAccounts: terminationGracePeriodSeconds: 1 # -- Install the cilium agent resources. agent: true -# -- Agent container name. +# -- Agent daemonset name. name: cilium # -- Roll out cilium agent pods automatically when configmap is updated. rollOutCiliumPods: false @@ -191,10 +219,10 @@ image: # @schema override: ~ repository: "quay.io/cilium/cilium" - tag: "v1.17.8" + tag: "v1.18.5" pullPolicy: "IfNotPresent" # cilium-digest - digest: "sha256:6d7ea72ed311eeca4c75a1f17617a3d596fb6038d30d00799090679f82a01636" + digest: sha256:2c92fb05962a346eaf0ce11b912ba434dc10bd54b9989e970416681f4a069628 useDigest: true # -- Scheduling configurations for cilium pods scheduling: @@ -291,6 +319,8 @@ initResources: {} securityContext: # -- User to run the pod with # runAsUser: 0 + # -- disable privilege escalation + allowPrivilegeEscalation: false # -- Run the pod with elevated privileges privileged: false # -- SELinux options for the `cilium-agent` and init containers @@ -414,15 +444,11 @@ bandwidthManager: enabled: false # -- Activate BBR TCP congestion control for Pods bbr: false + # -- Activate BBR TCP congestion control for Pods in the host namespace only. + bbrHostNamespaceOnly: false # -- Configure standalone NAT46/NAT64 gateway nat46x64Gateway: - # -- Enable RFC8215-prefixed translation - enabled: false -# -- EnableHighScaleIPcache enables the special ipcache mode for high scale -# clusters. The ipcache content will be reduced to the strict minimum and -# traffic will be encapsulated to carry security identities. -highScaleIPcache: - # -- Enable the high scale mode for the ipcache. + # -- Enable RFC6052-prefixed translation enabled: false # -- Configure L2 announcements l2announcements: @@ -440,6 +466,8 @@ l2podAnnouncements: enabled: false # -- Interface used for sending Gratuitous ARP pod announcements 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 # CiliumBGPPeeringPolicy CRDs. bgpControlPlane: @@ -457,6 +485,18 @@ bgpControlPlane: # It is recommended to enable status reporting in general, but if you have any issue # such as high API server load, you can disable it by setting this to false. enabled: true + # -- BGP router-id allocation mode + routerIDAllocation: + # -- BGP router-id allocation mode. In default mode, the router-id is derived from the IPv4 address if it is available, or else it is determined by the lower 32 bits of the MAC address. + mode: "default" + # -- IP pool to allocate the BGP router-id from when the mode is ip-pool. + ipPool: "" + # -- Legacy BGP ORIGIN attribute settings (BGPv2 only) + legacyOriginAttribute: + # -- Enable/Disable advertising LoadBalancerIP routes with the legacy + # BGP ORIGIN attribute value INCOMPLETE (2) instead of the default IGP (0). + # Enable for compatibility with the legacy behavior of MetalLB integration. + enabled: false pmtuDiscovery: # -- Enable path MTU discovery to send ICMP fragmentation-needed replies to # the client. @@ -568,6 +608,11 @@ bpf: # type: [null, integer] # @schema policyMapMax: 16384 + # -- Configure the maximum number of entries in global policy stats map. + # @schema + # type: [null, integer] + # @schema + policyStatsMapMax: 65536 # @schema # type: [null, number, string] # @schema @@ -637,7 +682,7 @@ bpf: # supported kernels. # @default -- `true` enableTCX: true - # -- (string) Mode for Pod devices for the core datapath (veth, netkit, netkit-l2, lb-only) + # -- (string) Mode for Pod devices for the core datapath (veth, netkit, netkit-l2) # @default -- `veth` datapathMode: veth # -- Enable BPF clock source probing for more efficient tick retrieval. @@ -707,12 +752,15 @@ cni: # readCniConf: /host/etc/cni/net.d/05-sample.conflist.input # -- When defined, configMap will mount the provided value as ConfigMap and - # interpret the cniConf variable as CNI configuration file and write it - # when the agent starts up - # configMap: cni-configuration - + # interpret the 'cni.configMapKey' value as CNI configuration file and write it + # when the agent starts up. + configMap: "" # -- Configure the key in the CNI ConfigMap to read the contents of - # the CNI configuration from. + # the CNI configuration from. For this to be effective, the 'cni.configMap' + # parameter must be specified too. + # Note that the 'cni.configMap' parameter is the name of the ConfigMap, while + # 'cni.configMapKey' is the name of the key in the ConfigMap data containing + # the actual configuration. configMapKey: cni-config # -- Configure the path to where to mount the ConfigMap inside the agent pod. confFileMountPath: /tmp/cni-configuration @@ -726,6 +774,16 @@ cni: memory: 10Mi # -- Enable route MTU for pod netns when CNI chaining is used enableRouteMTUForCNIChaining: false + # -- Enable the removal of iptables rules created by the AWS CNI VPC plugin. + iptablesRemoveAWSRules: true +# @schema +# type: [null, number] +# @schema +# -- (float64) Ratio of the connectivity probe frequency vs resource usage, a float in +# [0, 1]. 0 will give more frequent probing, 1 will give less frequent probing. Probing +# frequency is dynamically adjusted based on the cluster size. +# @default -- `0.5` +connectivityProbeFrequencyRatio: ~ # -- (string) Configure how frequently garbage collection should occur for the datapath # connection tracking table. # @default -- `"0s"` @@ -791,13 +849,6 @@ daemon: # a non-local route. This should be used only when autodetection is not suitable. # devices: "" -# -- Enables experimental support for the detection of new and removed datapath -# devices. When devices change the eBPF datapath is reloaded and services updated. -# If "devices" is set then only those devices, or devices matching a wildcard will -# be considered. -# -# This option has been deprecated and is a no-op. -enableRuntimeDeviceDetection: true # -- Forces the auto-detection of devices, even if specific devices are explicitly listed forceDeviceDetection: false # -- Chains to ignore when installing feeder rules. @@ -812,8 +863,7 @@ forceDeviceDetection: false # -- Enable Kubernetes EndpointSlice feature in Cilium if the cluster supports it. # enableK8sEndpointSlice: true -# -- Enable CiliumEndpointSlice feature (deprecated, please use `ciliumEndpointSlice.enabled` instead). -enableCiliumEndpointSlice: false +# -- CiliumEndpointSlice configuration options. ciliumEndpointSlice: # -- Enable Cilium EndpointSlice feature. enabled: false @@ -829,13 +879,13 @@ ciliumEndpointSlice: - nodes: 100 limit: 50 burst: 100 - # @schema - # enum: ["identity", "fcfs"] - # @schema - # -- The slicing mode to use for CiliumEndpointSlices. - # identity groups together CiliumEndpoints that share the same identity. - # fcfs groups together CiliumEndpoints in a first-come-first-serve basis, filling in the largest non-full slice first. - sliceMode: identity +# @schema +# enum: ["agent", "operator", "both"] +# @schema +# -- Control whether CiliumIdentities are created by the agent ("agent"), the operator ("operator") or both ("both"). +# "Both" should be used only to migrate between "agent" and "operator". +# Operator-managed identities is a beta feature. +identityManagementMode: "agent" envoyConfig: # -- Enable CiliumEnvoyConfig CRD # CiliumEnvoyConfig CRD can also be implicitly enabled by other options. @@ -1044,8 +1094,6 @@ endpointLockdownOnMapOverflow: false eni: # -- Enable Elastic Network Interface (ENI) integration. enabled: false - # -- Update ENI Adapter limits from the EC2 API - updateEC2AdapterLimitViaAPI: true # -- Release IPs not used from the ENI awsReleaseExcessIPs: false # -- Enable ENI prefix delegation @@ -1094,9 +1142,6 @@ healthCheckICMPFailureThreshold: 3 hostFirewall: # -- Enables the enforcement of host policies in the eBPF datapath. enabled: false -hostPort: - # -- Enable hostPort service support. - enabled: false # -- Configure socket LB socketLB: # -- Enable socket LB @@ -1120,8 +1165,8 @@ certgen: # @schema override: ~ repository: "quay.io/cilium/certgen" - tag: "v0.2.1" - digest: "sha256:ab6b1928e9c5f424f6b0f51c68065b9fd85e2f8d3e5f21fbd1a3cb27e6fb9321" + tag: "v0.3.1" + digest: "sha256:2825dbfa6f89cbed882fd1d81e46a56c087e35885825139923aa29eb8aec47a9" useDigest: true pullPolicy: "IfNotPresent" # -- Seconds after which the completed job pod will be deleted @@ -1141,6 +1186,9 @@ certgen: # -- Node tolerations for pod assignment on nodes with taints # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ tolerations: [] + # -- Resource limits for certgen + # ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers + resources: {} # -- Additional certgen volumes. extraVolumes: [] # -- Additional certgen volumeMounts. @@ -1236,11 +1284,17 @@ hubble: jobLabel: "" # -- Interval for scrape metrics. interval: "10s" + # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ # -- Relabeling configs for the ServiceMonitor hubble relabelings: - sourceLabels: - __meta_kubernetes_pod_node_name targetLabel: node + action: replace replacement: ${1} # @schema # type: [null, array] @@ -1280,6 +1334,10 @@ hubble: # excludeFilters: [] # -- Unix domain socket path to listen to when Hubble is enabled. socketPath: /var/run/cilium/hubble.sock + # -- Enables network policy correlation of Hubble flows, i.e. populating `egress_allowed_by`, `ingress_denied_by` fields with policy information. + networkPolicyCorrelation: + # @default -- `true` + enabled: true # -- Enables redacting sensitive information present in Layer 7 flows. redact: enabled: false @@ -1341,7 +1399,7 @@ hubble: # --set hubble.redact.http.headers.deny="Authorization,Proxy-Authorization" deny: [] kafka: - # -- Enables redacting Kafka's API key. + # -- Enables redacting Kafka's API key (deprecated, will be removed in v1.19). # Example: # # redact: @@ -1445,9 +1503,9 @@ hubble: # @schema override: ~ repository: "quay.io/cilium/hubble-relay" - tag: "v1.17.8" + tag: "v1.18.5" # hubble-relay-digest - digest: "sha256:2e576bf7a02291c07bffbc1ca0a66a6c70f4c3eb155480e5b3ac027bedd2858b" + digest: sha256:17212962c92ff52384f94e407ffe3698714fcbd35c7575f67f24032d6224e446 useDigest: true pullPolicy: "IfNotPresent" # -- Specifies the resources for the hubble-relay pods @@ -1499,6 +1557,11 @@ hubble: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- The priority class to use for hubble-relay priorityClassName: "" # -- Configure termination grace period for hubble relay Deployment. @@ -1518,12 +1581,17 @@ hubble: # -- hubble-relay pod security context podSecurityContext: fsGroup: 65532 + seccompProfile: + type: RuntimeDefault # -- hubble-relay container security context securityContext: # readOnlyRootFilesystem: true + allowPrivilegeEscalation: false runAsNonRoot: true runAsUser: 65532 runAsGroup: 65532 + seccompProfile: + type: RuntimeDefault capabilities: drop: - ALL @@ -1584,13 +1652,6 @@ hubble: # @schema # type: [null, string] # @schema - # -- Dial timeout to connect to the local hubble instance to receive peer information (e.g. "30s"). - # - # This option has been deprecated and is a no-op. - dialTimeout: ~ - # @schema - # type: [null, string] - # @schema # -- Backoff duration to retry connecting to the local hubble instance in case of failure (e.g. "30s"). retryTimeout: ~ # @schema @@ -1625,6 +1686,11 @@ hubble: annotations: {} # -- Interval for scrape metrics. interval: "10s" + # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ # -- Specify the Kubernetes namespace where Prometheus expects to find # service monitors configured. # namespace: "" @@ -1701,7 +1767,8 @@ hubble: useDigest: true pullPolicy: "IfNotPresent" # -- Hubble-ui backend security context. - securityContext: {} + securityContext: + allowPrivilegeEscalation: false # -- Additional hubble-ui backend environment variables. extraEnv: [] # -- Additional hubble-ui backend volumes. @@ -1735,7 +1802,8 @@ hubble: useDigest: true pullPolicy: "IfNotPresent" # -- Hubble-ui frontend security context. - securityContext: {} + securityContext: + allowPrivilegeEscalation: false # -- Additional hubble-ui frontend environment variables. extraEnv: [] # -- Additional hubble-ui frontend volumes. @@ -1780,6 +1848,11 @@ hubble: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- Affinity for hubble-ui affinity: {} # -- Pod topology spread constraints for hubble-ui @@ -1814,6 +1887,8 @@ hubble: service: # -- Annotations to be added for the Hubble UI service annotations: {} + # -- Labels to be added for the Hubble UI service + labels: {} # --- The type of service used for Hubble UI access, either ClusterIP or NodePort. type: ClusterIP # --- The port to use when the service type is set to NodePort. @@ -1838,10 +1913,6 @@ hubble: # - chart-example.local # -- Hubble flows export. export: - # --- Defines max file size of output file before it gets rotated. - fileMaxSizeMb: 10 - # --- Defines max number of backup/rotated files. - fileMaxBackups: 5 # --- Static exporter configuration. # Static exporter is bound to agent lifecycle. static: @@ -1857,6 +1928,12 @@ hubble: denyList: [] # - '{"source_pod":["kube-system/"]}' # - '{"destination_pod":["kube-system/"]}' + # --- Defines max file size of output file before it gets rotated. + fileMaxSizeMb: 10 + # --- Defines max number of backup/rotated files. + fileMaxBackups: 5 + # --- Enable compression of rotated files. + fileCompress: false # --- Dynamic exporters configuration. # Dynamic exporters may be reconfigured without a need of agent restarts. dynamic: @@ -1874,6 +1951,9 @@ hubble: includeFilters: [] excludeFilters: [] filePath: "/var/run/cilium/hubble/events.log" + fileMaxSizeMb: 10 + fileMaxBackups: 5 + fileCompress: false # - name: "test002" # filePath: "/var/log/network/flow-log/pa/test002.log" # fieldMask: ["source.namespace", "source.pod_name", "destination.namespace", "destination.pod_name", "verdict"] @@ -1883,6 +1963,9 @@ hubble: # - type: 1 # - destination_pod: ["frontend/nginx-975996d4c-7hhgt"] # excludeFilters: [] + # fileMaxSizeMb: 1 + # fileMaxBackups: 10 + # fileCompress: true # end: "2023-10-09T23:59:59-07:00" # -- Emit v1.Events related to pods on detection of packet drops. # This feature is alpha, please provide feedback at https://github.com/cilium/cilium/issues/33975. @@ -1997,14 +2080,17 @@ k8s: # -- requireIPv6PodCIDR enables waiting for Kubernetes to provide the PodCIDR # range via the Kubernetes node resource requireIPv6PodCIDR: false + # -- A space separated list of Kubernetes API server URLs to use with the client. + # For example "https://192.168.0.1:6443 https://192.168.0.2:6443" + # apiServerURLs: "" # -- Keep the deprecated selector labels when deploying Cilium DaemonSet. keepDeprecatedLabels: false # -- Keep the deprecated probes when deploying Cilium DaemonSet keepDeprecatedProbes: false startupProbe: # -- failure threshold of startup probe. - # 105 x 2s translates to the old behaviour of the readiness probe (120s delay + 30 x 3s) - failureThreshold: 105 + # Allow Cilium to take up to 600s to start up (300 attempts with 2s between attempts). + failureThreshold: 300 # -- interval between checks of the startup probe periodSeconds: 2 livenessProbe: @@ -2022,8 +2108,10 @@ readinessProbe: # -- Configure the kube-proxy replacement in Cilium BPF datapath # Valid options are "true" or "false". # ref: https://docs.cilium.io/en/stable/network/kubernetes/kubeproxy-free/ -#kubeProxyReplacement: "false" - +# @schema@ +# type: [string, boolean] +# @schema@ +kubeProxyReplacement: "false" # -- healthz server bind address for the kube-proxy replacement. # To enable set the value to '0.0.0.0:10256' for all ipv4 # addresses and this '[::]:10256' for all ipv6 addresses. @@ -2031,13 +2119,20 @@ readinessProbe: kubeProxyReplacementHealthzBindAddr: "" l2NeighDiscovery: # -- Enable L2 neighbor discovery in the agent - enabled: true - # -- Override the agent's default neighbor resolution refresh period. - refreshPeriod: "30s" + enabled: false # -- Enable Layer 7 network policy. l7Proxy: true -# -- Enable Local Redirect Policy. +# -- Enable Local Redirect Policy (deprecated, please use 'localRedirectPolicies.enabled' instead) localRedirectPolicy: false +localRedirectPolicies: + # -- Enable local redirect policies. + enabled: false + # -- Limit the allowed addresses in Address Matcher rule of + # Local Redirect Policies to the given CIDRs. + # @schema@ + # type: [null, array] + # @schema@ + addressMatcherCIDRs: ~ # To include or exclude matched resources from cilium identity evaluation # labels: "" @@ -2056,8 +2151,12 @@ maglev: {} # -- hashSeed is the cluster-wide base64 encoded seed for the hashing # hashSeed: -# -- Enables masquerading of IPv4 traffic leaving the node from endpoints. -enableIPv4Masquerade: true +# @schema +# type: [null, boolean] +# @schema +# -- (bool) Enables masquerading of IPv4 traffic leaving the node from endpoints. +# @default -- `true` unless ipam eni mode is active +enableIPv4Masquerade: ~ # -- Enables masquerading of IPv6 traffic leaving the node from endpoints. enableIPv6Masquerade: true # -- Enables masquerading to the source of the route for traffic leaving the node from endpoints. @@ -2137,17 +2236,14 @@ loadBalancer: # path), or best-effort (use native mode XDP acceleration on devices # that support it). acceleration: disabled - # -- dsrDispatch configures whether IP option or IPIP encapsulation is - # used to pass a service IP and port to remote backend + # -- dsrDispatch configures whether IP option (opt), IPIP encapsulation (ipip), + # Geneve Class Option (geneve) used to pass a service IP and port to remote backend # dsrDispatch: opt # -- serviceTopology enables K8s Topology Aware Hints -based service # endpoints filtering # serviceTopology: false - # -- experimental enables support for the experimental load-balancing - # control-plane. - experimental: false # -- L7 LoadBalancer l7: # -- Enable L7 service load balancing via envoy proxy. @@ -2232,6 +2328,11 @@ prometheus: jobLabel: "" # -- Interval for scrape metrics. interval: "10s" + # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ # -- Specify the Kubernetes namespace where Prometheus expects to find # service monitors configured. # namespace: "" @@ -2240,6 +2341,7 @@ prometheus: - sourceLabels: - __meta_kubernetes_pod_node_name targetLabel: node + action: replace replacement: ${1} # @schema # type: [null, array] @@ -2342,6 +2444,9 @@ envoy: # -- Set Envoy upstream HTTP idle connection timeout seconds. # Does not apply to connections with pending requests. Default 60s idleTimeoutDurationSeconds: 60 + # -- Set Envoy the amount of time that the connection manager will allow a stream to exist with no upstream or downstream activity. + # default 5 minutes + streamIdleTimeoutDurationSeconds: 300 # -- Number of trusted hops regarding the x-forwarded-for and related HTTP headers for the ingress L7 policy enforcement Envoy listeners. xffNumTrustedHopsL7PolicyIngress: 0 # -- Number of trusted hops regarding the x-forwarded-for and related HTTP headers for the egress L7 policy enforcement Envoy listeners. @@ -2351,6 +2456,8 @@ envoy: # @schema # -- Max duration to wait for endpoint policies to be restored on restart. Default "3m". policyRestoreTimeoutDuration: null + # -- Time in seconds to block Envoy worker thread while an upstream HTTP connection is closing. If set to 0, the connection is closed immediately (with TCP RST). If set to -1, the connection is closed asynchronously in the background. + httpUpstreamLingerTimeout: null # -- Envoy container image. image: # @schema @@ -2358,9 +2465,9 @@ envoy: # @schema override: ~ repository: "quay.io/cilium/cilium-envoy" - tag: "v1.33.9-1757932127-3c04e8f2f1027d106b96f8ef4a0215e81dbaaece" + tag: "v1.34.12-1765374555-6a93b0bbba8d6dc75b651cbafeedb062b2997716" pullPolicy: "IfNotPresent" - digest: "sha256:06fbc4e55d926dd82ff2a0049919248dcc6be5354609b09012b01bc9c5b0ee28" + digest: "sha256:3108521821c6922695ff1f6ef24b09026c94b195283f8bfbfc0fa49356a156e1" useDigest: true # -- Additional containers added to the cilium Envoy DaemonSet. extraContainers: [] @@ -2427,12 +2534,16 @@ envoy: # memory: 512Mi startupProbe: + # -- Enable startup probe for cilium-envoy + enabled: true # -- failure threshold of startup probe. # 105 x 2s translates to the old behaviour of the readiness probe (120s delay + 30 x 3s) failureThreshold: 105 # -- interval between checks of the startup probe periodSeconds: 2 livenessProbe: + # -- Enable liveness probe for cilium-envoy + enabled: true # -- failure threshold of liveness probe failureThreshold: 10 # -- interval between checks of the liveness probe @@ -2545,6 +2656,11 @@ envoy: annotations: {} # -- Interval for scrape metrics. interval: "10s" + # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ # -- Specify the Kubernetes namespace where Prometheus expects to find # service monitors configured. # namespace: "" @@ -2554,6 +2670,7 @@ envoy: - sourceLabels: - __meta_kubernetes_pod_node_name targetLabel: node + action: replace replacement: ${1} # @schema # type: [null, array] @@ -2565,6 +2682,10 @@ envoy: port: "9964" # -- Enable/Disable use of node label based identity nodeSelectorLabels: false +# To include or exclude matched resources from cilium node identity evaluation +# List of labels just like --labels flag (.Values.labels) +# nodeLabels: "" + # -- Enable resource quotas for priority classes used in the cluster. resourceQuotas: enabled: false @@ -2580,6 +2701,8 @@ resourceQuotas: ################## #sessionAffinity: false +# -- Annotations to be added to all cilium-secret namespaces (resources under templates/cilium-secrets-namespace) +secretsNamespaceAnnotations: {} # -- 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. @@ -2667,6 +2790,9 @@ tls: # - geneve # @default -- `"vxlan"` tunnelProtocol: "" +# -- IP family for the underlay. +# @default -- `"ipv4"` +underlayProtocol: "" # -- Enable native-routing mode or tunneling mode. # Possible values: # - "" @@ -2715,15 +2841,15 @@ operator: # @schema override: ~ repository: "quay.io/cilium/operator" - tag: "v1.17.8" + tag: "v1.18.5" # operator-generic-digest - genericDigest: "sha256:5468807b9c31997f3a1a14558ec7c20c5b962a2df6db633b7afbe2f45a15da1c" + genericDigest: sha256:36c3f6f14c8ced7f45b40b0a927639894b44269dd653f9528e7a0dc363a4eb99 # operator-azure-digest - azureDigest: "sha256:619f9febf3efef2724a26522b253e4595cd33c274f5f49925e29a795fdc2d2d7" + azureDigest: sha256:126667e000267f893cb81042bf8a710ad2f219619eb9ce06e8949333bd325ac6 # operator-aws-digest - awsDigest: "sha256:28012f7d0f4f23e9f6c7d6a5dd931afa326bbac3e8103f3f6f22b9670847dffa" + awsDigest: sha256:7608025d8b727a10f21d924d8e4f40beb176cefd690320433452816ad8776f52 # operator-alibabacloud-digest - alibabacloudDigest: "sha256:72c25a405ad8e58d2cf03f7ea2b6696ed1edcfb51716b5f85e45c6c4fcaa6056" + alibabacloudDigest: sha256:2e60f635495eb2837296ced5475875c281a05765d5ddd644a05e126bbb080b3c useDigest: true pullPolicy: "IfNotPresent" suffix: "" @@ -2766,12 +2892,19 @@ operator: kubernetes.io/os: linux # -- Node tolerations for cilium-operator scheduling to nodes with taints # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ + # Toleration for agentNotReadyTaintKey taint is always added to cilium-operator pods. + # @schema + # type: [null, array] + # @schema tolerations: - - operator: Exists - # - key: "key" - # operator: "Equal|Exists" - # value: "value" - # effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)" + - key: "node-role.kubernetes.io/control-plane" + operator: Exists + - key: "node-role.kubernetes.io/master" #deprecated + operator: Exists + - key: "node.kubernetes.io/not-ready" + operator: Exists + - key: "node.cloudprovider.kubernetes.io/uninitialized" + operator: Exists # -- Additional cilium-operator container arguments. extraArgs: [] # -- Additional cilium-operator environment variables. @@ -2794,7 +2927,9 @@ operator: # -- HostNetwork setting hostNetwork: true # -- Security context to be added to cilium-operator pods - podSecurityContext: {} + podSecurityContext: + seccompProfile: + type: RuntimeDefault # -- Annotations to be added to cilium-operator pods podAnnotations: {} # -- Labels to be added to cilium-operator pods @@ -2815,6 +2950,11 @@ operator: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- cilium-operator resource limits & requests # ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: {} @@ -2826,7 +2966,11 @@ operator: # memory: 128Mi # -- Security context to be added to cilium-operator pods - securityContext: {} + securityContext: + capabilities: + drop: + - ALL + allowPrivilegeEscalation: false # runAsUser: 0 # -- Interval for endpoint garbage collection. @@ -2863,6 +3007,11 @@ operator: # -- Interval for scrape metrics. interval: "10s" # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ + # @schema # type: [null, array] # @schema # -- Relabeling configs for the ServiceMonitor cilium-operator @@ -2963,6 +3112,7 @@ nodeinit: memory: 100Mi # -- Security context to be added to nodeinit pods. securityContext: + allowPrivilegeEscalation: false privileged: false seLinuxOptions: level: 's0' @@ -2998,11 +3148,23 @@ preflight: # @schema override: ~ repository: "quay.io/cilium/cilium" - tag: "v1.17.8" + tag: "v1.18.5" # cilium-digest - digest: "sha256:6d7ea72ed311eeca4c75a1f17617a3d596fb6038d30d00799090679f82a01636" + digest: sha256:2c92fb05962a346eaf0ce11b912ba434dc10bd54b9989e970416681f4a069628 useDigest: true pullPolicy: "IfNotPresent" + envoy: + # -- Envoy pre-flight image. + image: + # @schema + # type: [null, string] + # @schema + override: ~ + repository: "quay.io/cilium/cilium-envoy" + tag: "v1.34.12-1765374555-6a93b0bbba8d6dc75b651cbafeedb062b2997716" + pullPolicy: "IfNotPresent" + digest: "sha256:3108521821c6922695ff1f6ef24b09026c94b195283f8bfbfc0fa49356a156e1" + useDigest: true # -- The priority class to use for the preflight pod. priorityClassName: "" # -- preflight update strategy @@ -3058,6 +3220,11 @@ preflight: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- preflight resource limits & requests # ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: {} @@ -3074,7 +3241,8 @@ preflight: # -- interval between checks of the readiness probe periodSeconds: 5 # -- Security context to be added to preflight pods - securityContext: {} + securityContext: + allowPrivilegeEscalation: false # runAsUser: 0 # -- Path to write the `--tofqdns-pre-cache` file to. @@ -3108,6 +3276,8 @@ clustermesh: enableEndpointSliceSynchronization: false # -- Enable Multi-Cluster Services API support enableMCSAPISupport: false + # -- Control whether policy rules assume by default the local cluster if not explicitly selected + 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. @@ -3147,9 +3317,9 @@ clustermesh: # @schema override: ~ repository: "quay.io/cilium/clustermesh-apiserver" - tag: "v1.17.8" + tag: "v1.18.5" # clustermesh-apiserver-digest - digest: "sha256:3ac210d94d37a77ec010f9ac4c705edc8f15f22afa2b9a6f0e2a7d64d2360586" + digest: sha256:952f07c30390847e4d9dfaa19a76c4eca946251ffbc4f6459946570f93ee72f1 useDigest: true pullPolicy: "IfNotPresent" # -- TCP port for the clustermesh-apiserver health API. @@ -3203,7 +3373,7 @@ clustermesh: storageMedium: Disk kvstoremesh: # -- Enable KVStoreMesh. KVStoreMesh caches the information retrieved - # from the remote clusters in the local etcd instance. + # from the remote clusters in the local etcd instance (deprecated - KVStoreMesh will always be enabled once the option is removed). enabled: true # -- TCP port for the KVStoreMesh health API. healthPort: 9881 @@ -3232,6 +3402,11 @@ clustermesh: - ALL # -- lifecycle setting for the KVStoreMesh container lifecycle: {} + # -- Specify the KVStore mode when running KVStoreMesh + # Supported values: + # - "internal": remote cluster identities are cached in etcd that runs as a sidecar within ``clustermesh-apiserver`` pod. + # - "external": ``clustermesh-apiserver`` will sync remote cluster information to the etcd used as kvstore. This can't be enabled with crd identity allocation mode. + kvstoreMode: "internal" service: # -- The type of service used for apiserver access. type: NodePort @@ -3345,6 +3520,11 @@ clustermesh: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- Resource requests and limits for the clustermesh-apiserver resources: {} # requests: @@ -3511,6 +3691,11 @@ clustermesh: # -- Interval for scrape metrics (apiserver metrics) interval: "10s" # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ + # @schema # type: [null, array] # @schema # -- Relabeling configs for the ServiceMonitor clustermesh-apiserver (apiserver metrics) @@ -3524,6 +3709,11 @@ clustermesh: # -- Interval for scrape metrics (KVStoreMesh metrics) interval: "10s" # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ + # @schema # type: [null, array] # @schema # -- Relabeling configs for the ServiceMonitor clustermesh-apiserver (KVStoreMesh metrics) @@ -3537,6 +3727,11 @@ clustermesh: # -- Interval for scrape metrics (etcd metrics) interval: "10s" # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ + # @schema # type: [null, array] # @schema # -- Relabeling configs for the ServiceMonitor clustermesh-apiserver (etcd metrics) @@ -3546,10 +3741,6 @@ clustermesh: # @schema # -- Metrics relabeling configs for the ServiceMonitor clustermesh-apiserver (etcd metrics) metricRelabelings: ~ -# -- Configure external workloads support -externalWorkloads: - # -- Enable support for external workloads, such as VMs (false by default). - enabled: false # -- Configure cgroup related configuration cgroup: autoMount: @@ -3574,9 +3765,6 @@ cgroup: sysctlfix: # -- Enable the sysctl override. When enabled, the init container will mount the /proc of the host so that the `sysctlfix` utility can execute. enabled: true -# -- Configure whether to enable auto detect of terminating state for endpoints -# in order to support graceful termination. -enableK8sTerminatingEndpoint: true # -- Configure whether to unload DNS policy rules on graceful shutdown # dnsPolicyUnloadOnShutdown: false @@ -3609,6 +3797,9 @@ dnsProxy: proxyResponseMaxDelay: 100ms # -- DNS proxy operation mode (true/false, or unset to use version dependent defaults) # enableTransparentMode: true + # -- Pre-allocate ToFQDN identities. This reduces DNS proxy tail latency, at the potential cost of some + # unnecessary policymap entries. Disable this if you have a large (200+) number of unique ToFQDN selectors. + preAllocateIdentities: true # -- SCTP Configuration Values sctp: # -- Enable SCTP support. NOTE: Currently, SCTP support does not support rewriting ports or multihoming. @@ -3658,7 +3849,7 @@ authentication: override: ~ repository: "docker.io/library/busybox" tag: "1.37.0" - digest: "sha256:d82f458899c9696cb26a7c02d5568f81c8c8223f8661bb2a7988b269c8b9051e" + digest: "sha256:d80cd694d3e9467884fcb94b8ca1e20437d8a501096cdf367a5a1918a34fc2fd" useDigest: true pullPolicy: "IfNotPresent" # SPIRE agent configuration @@ -3672,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 @@ -3727,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 diff --git a/packages/system/cilium/charts/cilium/values.yaml.tmpl b/packages/system/cilium/charts/cilium/values.yaml.tmpl index 9ac96556..83b87cfd 100644 --- a/packages/system/cilium/charts/cilium/values.yaml.tmpl +++ b/packages/system/cilium/charts/cilium/values.yaml.tmpl @@ -38,6 +38,15 @@ debug: # - datapath # - policy verbose: ~ + + # -- Set the agent-internal metrics sampling frequency. This sets the + # frequency of the internal sampling of the agent metrics. These are + # available via the "cilium-dbg shell -- metrics -s" command and are + # part of the metrics HTML page included in the sysdump. + # @schema + # type: [null, string] + # @schema + metricsSamplingInterval: "5m" rbac: # -- Enable creation of Resource-Based Access Control configuration. create: true @@ -52,6 +61,18 @@ iptablesRandomFully: false # -- (string) Kubernetes config path # @default -- `"~/.kube/config"` kubeConfigPath: "" +# -- Configure the Kubernetes service endpoint dynamically using a ConfigMap. Mutually exclusive with `k8sServiceHost`. +k8sServiceHostRef: + # @schema + # type: [string, null] + # @schema + # -- (string) name of the ConfigMap containing the Kubernetes service endpoint + name: + # @schema + # type: [string, null] + # @schema + # -- (string) Key in the ConfigMap containing the Kubernetes service endpoint + key: # -- (string) Kubernetes service host - use "auto" for automatic lookup from the cluster-info ConfigMap k8sServiceHost: "" # @schema @@ -104,6 +125,15 @@ k8sClientRateLimit: # @default -- 200 burst: +# -- Configure exponential backoff for client-go in Cilium agent. +k8sClientExponentialBackoff: + # -- Enable exponential backoff for client-go in Cilium agent. + enabled: true + # -- Configure base (in seconds) for exponential backoff. + backoffBaseSeconds: 1 + # -- Configure maximum duration (in seconds) for exponential backoff. + backoffMaxDurationSeconds: 120 + cluster: # -- Name of the cluster. Only required for Cluster Mesh and mutual authentication with SPIRE. # It must respect the following constraints: @@ -181,7 +211,7 @@ serviceAccounts: terminationGracePeriodSeconds: 1 # -- Install the cilium agent resources. agent: true -# -- Agent container name. +# -- Agent daemonset name. name: cilium # -- Roll out cilium agent pods automatically when configmap is updated. rollOutCiliumPods: false @@ -292,6 +322,8 @@ initResources: {} securityContext: # -- User to run the pod with # runAsUser: 0 + # -- disable privilege escalation + allowPrivilegeEscalation: false # -- Run the pod with elevated privileges privileged: false # -- SELinux options for the `cilium-agent` and init containers @@ -419,15 +451,11 @@ bandwidthManager: enabled: false # -- Activate BBR TCP congestion control for Pods bbr: false + # -- Activate BBR TCP congestion control for Pods in the host namespace only. + bbrHostNamespaceOnly: false # -- Configure standalone NAT46/NAT64 gateway nat46x64Gateway: - # -- Enable RFC8215-prefixed translation - enabled: false -# -- EnableHighScaleIPcache enables the special ipcache mode for high scale -# clusters. The ipcache content will be reduced to the strict minimum and -# traffic will be encapsulated to carry security identities. -highScaleIPcache: - # -- Enable the high scale mode for the ipcache. + # -- Enable RFC6052-prefixed translation enabled: false # -- Configure L2 announcements l2announcements: @@ -445,6 +473,8 @@ l2podAnnouncements: enabled: false # -- Interface used for sending Gratuitous ARP pod announcements 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 # CiliumBGPPeeringPolicy CRDs. bgpControlPlane: @@ -462,6 +492,18 @@ bgpControlPlane: # It is recommended to enable status reporting in general, but if you have any issue # such as high API server load, you can disable it by setting this to false. enabled: true + # -- BGP router-id allocation mode + routerIDAllocation: + # -- BGP router-id allocation mode. In default mode, the router-id is derived from the IPv4 address if it is available, or else it is determined by the lower 32 bits of the MAC address. + mode: "default" + # -- IP pool to allocate the BGP router-id from when the mode is ip-pool. + ipPool: "" + # -- Legacy BGP ORIGIN attribute settings (BGPv2 only) + legacyOriginAttribute: + # -- Enable/Disable advertising LoadBalancerIP routes with the legacy + # BGP ORIGIN attribute value INCOMPLETE (2) instead of the default IGP (0). + # Enable for compatibility with the legacy behavior of MetalLB integration. + enabled: false pmtuDiscovery: # -- Enable path MTU discovery to send ICMP fragmentation-needed replies to # the client. @@ -573,6 +615,11 @@ bpf: # type: [null, integer] # @schema policyMapMax: 16384 + # -- Configure the maximum number of entries in global policy stats map. + # @schema + # type: [null, integer] + # @schema + policyStatsMapMax: 65536 # @schema # type: [null, number, string] # @schema @@ -642,7 +689,7 @@ bpf: # supported kernels. # @default -- `true` enableTCX: true - # -- (string) Mode for Pod devices for the core datapath (veth, netkit, netkit-l2, lb-only) + # -- (string) Mode for Pod devices for the core datapath (veth, netkit, netkit-l2) # @default -- `veth` datapathMode: veth # -- Enable BPF clock source probing for more efficient tick retrieval. @@ -712,12 +759,16 @@ cni: # readCniConf: /host/etc/cni/net.d/05-sample.conflist.input # -- When defined, configMap will mount the provided value as ConfigMap and - # interpret the cniConf variable as CNI configuration file and write it - # when the agent starts up - # configMap: cni-configuration + # interpret the 'cni.configMapKey' value as CNI configuration file and write it + # when the agent starts up. + configMap: "" # -- Configure the key in the CNI ConfigMap to read the contents of - # the CNI configuration from. + # the CNI configuration from. For this to be effective, the 'cni.configMap' + # parameter must be specified too. + # Note that the 'cni.configMap' parameter is the name of the ConfigMap, while + # 'cni.configMapKey' is the name of the key in the ConfigMap data containing + # the actual configuration. configMapKey: cni-config # -- Configure the path to where to mount the ConfigMap inside the agent pod. confFileMountPath: /tmp/cni-configuration @@ -731,6 +782,16 @@ cni: memory: 10Mi # -- Enable route MTU for pod netns when CNI chaining is used enableRouteMTUForCNIChaining: false + # -- Enable the removal of iptables rules created by the AWS CNI VPC plugin. + iptablesRemoveAWSRules: true +# @schema +# type: [null, number] +# @schema +# -- (float64) Ratio of the connectivity probe frequency vs resource usage, a float in +# [0, 1]. 0 will give more frequent probing, 1 will give less frequent probing. Probing +# frequency is dynamically adjusted based on the cluster size. +# @default -- `0.5` +connectivityProbeFrequencyRatio: ~ # -- (string) Configure how frequently garbage collection should occur for the datapath # connection tracking table. # @default -- `"0s"` @@ -796,14 +857,6 @@ daemon: # a non-local route. This should be used only when autodetection is not suitable. # devices: "" -# -- Enables experimental support for the detection of new and removed datapath -# devices. When devices change the eBPF datapath is reloaded and services updated. -# If "devices" is set then only those devices, or devices matching a wildcard will -# be considered. -# -# This option has been deprecated and is a no-op. -enableRuntimeDeviceDetection: true - # -- Forces the auto-detection of devices, even if specific devices are explicitly listed forceDeviceDetection: false @@ -819,9 +872,7 @@ forceDeviceDetection: false # -- Enable Kubernetes EndpointSlice feature in Cilium if the cluster supports it. # enableK8sEndpointSlice: true -# -- Enable CiliumEndpointSlice feature (deprecated, please use `ciliumEndpointSlice.enabled` instead). -enableCiliumEndpointSlice: false - +# -- CiliumEndpointSlice configuration options. ciliumEndpointSlice: # -- Enable Cilium EndpointSlice feature. enabled: false @@ -838,13 +889,13 @@ ciliumEndpointSlice: limit: 50 burst: 100 - # @schema - # enum: ["identity", "fcfs"] - # @schema - # -- The slicing mode to use for CiliumEndpointSlices. - # identity groups together CiliumEndpoints that share the same identity. - # fcfs groups together CiliumEndpoints in a first-come-first-serve basis, filling in the largest non-full slice first. - sliceMode: identity +# @schema +# enum: ["agent", "operator", "both"] +# @schema +# -- Control whether CiliumIdentities are created by the agent ("agent"), the operator ("operator") or both ("both"). +# "Both" should be used only to migrate between "agent" and "operator". +# Operator-managed identities is a beta feature. +identityManagementMode: "agent" envoyConfig: # -- Enable CiliumEnvoyConfig CRD @@ -1057,8 +1108,6 @@ endpointLockdownOnMapOverflow: false eni: # -- Enable Elastic Network Interface (ENI) integration. enabled: false - # -- Update ENI Adapter limits from the EC2 API - updateEC2AdapterLimitViaAPI: true # -- Release IPs not used from the ENI awsReleaseExcessIPs: false # -- Enable ENI prefix delegation @@ -1107,9 +1156,6 @@ healthCheckICMPFailureThreshold: 3 hostFirewall: # -- Enables the enforcement of host policies in the eBPF datapath. enabled: false -hostPort: - # -- Enable hostPort service support. - enabled: false # -- Configure socket LB socketLB: # -- Enable socket LB @@ -1154,6 +1200,9 @@ certgen: # -- Node tolerations for pod assignment on nodes with taints # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ tolerations: [] + # -- Resource limits for certgen + # ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers + resources: {} # -- Additional certgen volumes. extraVolumes: [] # -- Additional certgen volumeMounts. @@ -1249,11 +1298,17 @@ hubble: jobLabel: "" # -- Interval for scrape metrics. interval: "10s" + # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ # -- Relabeling configs for the ServiceMonitor hubble relabelings: - sourceLabels: - __meta_kubernetes_pod_node_name targetLabel: node + action: replace replacement: ${1} # @schema # type: [null, array] @@ -1293,6 +1348,10 @@ hubble: # excludeFilters: [] # -- Unix domain socket path to listen to when Hubble is enabled. socketPath: /var/run/cilium/hubble.sock + # -- Enables network policy correlation of Hubble flows, i.e. populating `egress_allowed_by`, `ingress_denied_by` fields with policy information. + networkPolicyCorrelation: + # @default -- `true` + enabled: true # -- Enables redacting sensitive information present in Layer 7 flows. redact: enabled: false @@ -1354,7 +1413,7 @@ hubble: # --set hubble.redact.http.headers.deny="Authorization,Proxy-Authorization" deny: [] kafka: - # -- Enables redacting Kafka's API key. + # -- Enables redacting Kafka's API key (deprecated, will be removed in v1.19). # Example: # # redact: @@ -1512,6 +1571,11 @@ hubble: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- The priority class to use for hubble-relay priorityClassName: "" # -- Configure termination grace period for hubble relay Deployment. @@ -1531,12 +1595,17 @@ hubble: # -- hubble-relay pod security context podSecurityContext: fsGroup: 65532 + seccompProfile: + type: RuntimeDefault # -- hubble-relay container security context securityContext: # readOnlyRootFilesystem: true + allowPrivilegeEscalation: false runAsNonRoot: true runAsUser: 65532 runAsGroup: 65532 + seccompProfile: + type: RuntimeDefault capabilities: drop: - ALL @@ -1597,13 +1666,6 @@ hubble: # @schema # type: [null, string] # @schema - # -- Dial timeout to connect to the local hubble instance to receive peer information (e.g. "30s"). - # - # This option has been deprecated and is a no-op. - dialTimeout: ~ - # @schema - # type: [null, string] - # @schema # -- Backoff duration to retry connecting to the local hubble instance in case of failure (e.g. "30s"). retryTimeout: ~ # @schema @@ -1638,6 +1700,11 @@ hubble: annotations: {} # -- Interval for scrape metrics. interval: "10s" + # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ # -- Specify the Kubernetes namespace where Prometheus expects to find # service monitors configured. # namespace: "" @@ -1714,7 +1781,8 @@ hubble: useDigest: true pullPolicy: "${PULL_POLICY}" # -- Hubble-ui backend security context. - securityContext: {} + securityContext: + allowPrivilegeEscalation: false # -- Additional hubble-ui backend environment variables. extraEnv: [] # -- Additional hubble-ui backend volumes. @@ -1748,7 +1816,8 @@ hubble: useDigest: true pullPolicy: "${PULL_POLICY}" # -- Hubble-ui frontend security context. - securityContext: {} + securityContext: + allowPrivilegeEscalation: false # -- Additional hubble-ui frontend environment variables. extraEnv: [] # -- Additional hubble-ui frontend volumes. @@ -1793,6 +1862,11 @@ hubble: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- Affinity for hubble-ui affinity: {} # -- Pod topology spread constraints for hubble-ui @@ -1827,6 +1901,8 @@ hubble: service: # -- Annotations to be added for the Hubble UI service annotations: {} + # -- Labels to be added for the Hubble UI service + labels: {} # --- The type of service used for Hubble UI access, either ClusterIP or NodePort. type: ClusterIP # --- The port to use when the service type is set to NodePort. @@ -1851,10 +1927,6 @@ hubble: # - chart-example.local # -- Hubble flows export. export: - # --- Defines max file size of output file before it gets rotated. - fileMaxSizeMb: 10 - # --- Defines max number of backup/rotated files. - fileMaxBackups: 5 # --- Static exporter configuration. # Static exporter is bound to agent lifecycle. static: @@ -1870,6 +1942,12 @@ hubble: denyList: [] # - '{"source_pod":["kube-system/"]}' # - '{"destination_pod":["kube-system/"]}' + # --- Defines max file size of output file before it gets rotated. + fileMaxSizeMb: 10 + # --- Defines max number of backup/rotated files. + fileMaxBackups: 5 + # --- Enable compression of rotated files. + fileCompress: false # --- Dynamic exporters configuration. # Dynamic exporters may be reconfigured without a need of agent restarts. dynamic: @@ -1887,6 +1965,9 @@ hubble: includeFilters: [] excludeFilters: [] filePath: "/var/run/cilium/hubble/events.log" + fileMaxSizeMb: 10 + fileMaxBackups: 5 + fileCompress: false # - name: "test002" # filePath: "/var/log/network/flow-log/pa/test002.log" # fieldMask: ["source.namespace", "source.pod_name", "destination.namespace", "destination.pod_name", "verdict"] @@ -1896,6 +1977,9 @@ hubble: # - type: 1 # - destination_pod: ["frontend/nginx-975996d4c-7hhgt"] # excludeFilters: [] + # fileMaxSizeMb: 1 + # fileMaxBackups: 10 + # fileCompress: true # end: "2023-10-09T23:59:59-07:00" # -- Emit v1.Events related to pods on detection of packet drops. @@ -2012,14 +2096,18 @@ k8s: # -- requireIPv6PodCIDR enables waiting for Kubernetes to provide the PodCIDR # range via the Kubernetes node resource requireIPv6PodCIDR: false + # -- A space separated list of Kubernetes API server URLs to use with the client. + # For example "https://192.168.0.1:6443 https://192.168.0.2:6443" + # apiServerURLs: "" + # -- Keep the deprecated selector labels when deploying Cilium DaemonSet. keepDeprecatedLabels: false # -- Keep the deprecated probes when deploying Cilium DaemonSet keepDeprecatedProbes: false startupProbe: # -- failure threshold of startup probe. - # 105 x 2s translates to the old behaviour of the readiness probe (120s delay + 30 x 3s) - failureThreshold: 105 + # Allow Cilium to take up to 600s to start up (300 attempts with 2s between attempts). + failureThreshold: 300 # -- interval between checks of the startup probe periodSeconds: 2 livenessProbe: @@ -2037,7 +2125,10 @@ readinessProbe: # -- Configure the kube-proxy replacement in Cilium BPF datapath # Valid options are "true" or "false". # ref: https://docs.cilium.io/en/stable/network/kubernetes/kubeproxy-free/ -#kubeProxyReplacement: "false" + # @schema@ + # type: [string, boolean] + # @schema@ +kubeProxyReplacement: "false" # -- healthz server bind address for the kube-proxy replacement. # To enable set the value to '0.0.0.0:10256' for all ipv4 @@ -2046,13 +2137,24 @@ readinessProbe: kubeProxyReplacementHealthzBindAddr: "" l2NeighDiscovery: # -- Enable L2 neighbor discovery in the agent - enabled: true - # -- Override the agent's default neighbor resolution refresh period. - refreshPeriod: "30s" + enabled: false # -- Enable Layer 7 network policy. l7Proxy: true -# -- Enable Local Redirect Policy. + +# -- Enable Local Redirect Policy (deprecated, please use 'localRedirectPolicies.enabled' instead) localRedirectPolicy: false + +localRedirectPolicies: + # -- Enable local redirect policies. + enabled: false + + # -- Limit the allowed addresses in Address Matcher rule of + # Local Redirect Policies to the given CIDRs. + # @schema@ + # type: [null, array] + # @schema@ + addressMatcherCIDRs: ~ + # To include or exclude matched resources from cilium identity evaluation # labels: "" @@ -2071,8 +2173,12 @@ maglev: {} # -- hashSeed is the cluster-wide base64 encoded seed for the hashing # hashSeed: -# -- Enables masquerading of IPv4 traffic leaving the node from endpoints. -enableIPv4Masquerade: true +# @schema +# type: [null, boolean] +# @schema +# -- (bool) Enables masquerading of IPv4 traffic leaving the node from endpoints. +# @default -- `true` unless ipam eni mode is active +enableIPv4Masquerade: ~ # -- Enables masquerading of IPv6 traffic leaving the node from endpoints. enableIPv6Masquerade: true # -- Enables masquerading to the source of the route for traffic leaving the node from endpoints. @@ -2154,18 +2260,14 @@ loadBalancer: # path), or best-effort (use native mode XDP acceleration on devices # that support it). acceleration: disabled - # -- dsrDispatch configures whether IP option or IPIP encapsulation is - # used to pass a service IP and port to remote backend + # -- dsrDispatch configures whether IP option (opt), IPIP encapsulation (ipip), + # Geneve Class Option (geneve) used to pass a service IP and port to remote backend # dsrDispatch: opt # -- serviceTopology enables K8s Topology Aware Hints -based service # endpoints filtering # serviceTopology: false - # -- experimental enables support for the experimental load-balancing - # control-plane. - experimental: false - # -- L7 LoadBalancer l7: # -- Enable L7 service load balancing via envoy proxy. @@ -2251,6 +2353,11 @@ prometheus: jobLabel: "" # -- Interval for scrape metrics. interval: "10s" + # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ # -- Specify the Kubernetes namespace where Prometheus expects to find # service monitors configured. # namespace: "" @@ -2259,6 +2366,7 @@ prometheus: - sourceLabels: - __meta_kubernetes_pod_node_name targetLabel: node + action: replace replacement: ${1} # @schema # type: [null, array] @@ -2361,6 +2469,9 @@ envoy: # -- Set Envoy upstream HTTP idle connection timeout seconds. # Does not apply to connections with pending requests. Default 60s idleTimeoutDurationSeconds: 60 + # -- Set Envoy the amount of time that the connection manager will allow a stream to exist with no upstream or downstream activity. + # default 5 minutes + streamIdleTimeoutDurationSeconds: 300 # -- Number of trusted hops regarding the x-forwarded-for and related HTTP headers for the ingress L7 policy enforcement Envoy listeners. xffNumTrustedHopsL7PolicyIngress: 0 # -- Number of trusted hops regarding the x-forwarded-for and related HTTP headers for the egress L7 policy enforcement Envoy listeners. @@ -2370,6 +2481,8 @@ envoy: # @schema # -- Max duration to wait for endpoint policies to be restored on restart. Default "3m". policyRestoreTimeoutDuration: null + # -- Time in seconds to block Envoy worker thread while an upstream HTTP connection is closing. If set to 0, the connection is closed immediately (with TCP RST). If set to -1, the connection is closed asynchronously in the background. + httpUpstreamLingerTimeout: null # -- Envoy container image. image: # @schema @@ -2446,12 +2559,16 @@ envoy: # memory: 512Mi startupProbe: + # -- Enable startup probe for cilium-envoy + enabled: true # -- failure threshold of startup probe. # 105 x 2s translates to the old behaviour of the readiness probe (120s delay + 30 x 3s) failureThreshold: 105 # -- interval between checks of the startup probe periodSeconds: 2 livenessProbe: + # -- Enable liveness probe for cilium-envoy + enabled: true # -- failure threshold of liveness probe failureThreshold: 10 # -- interval between checks of the liveness probe @@ -2564,6 +2681,11 @@ envoy: annotations: {} # -- Interval for scrape metrics. interval: "10s" + # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ # -- Specify the Kubernetes namespace where Prometheus expects to find # service monitors configured. # namespace: "" @@ -2573,6 +2695,7 @@ envoy: - sourceLabels: - __meta_kubernetes_pod_node_name targetLabel: node + action: replace replacement: ${1} # @schema # type: [null, array] @@ -2586,6 +2709,10 @@ envoy: # -- Enable/Disable use of node label based identity nodeSelectorLabels: false +# To include or exclude matched resources from cilium node identity evaluation +# List of labels just like --labels flag (.Values.labels) +# nodeLabels: "" + # -- Enable resource quotas for priority classes used in the cluster. resourceQuotas: enabled: false @@ -2601,6 +2728,9 @@ resourceQuotas: ################## #sessionAffinity: false +# -- Annotations to be added to all cilium-secret namespaces (resources under templates/cilium-secrets-namespace) +secretsNamespaceAnnotations: {} + # -- 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. @@ -2688,6 +2818,9 @@ tls: # - geneve # @default -- `"vxlan"` tunnelProtocol: "" +# -- IP family for the underlay. +# @default -- `"ipv4"` +underlayProtocol: "" # -- Enable native-routing mode or tunneling mode. # Possible values: # - "" @@ -2787,12 +2920,19 @@ operator: kubernetes.io/os: linux # -- Node tolerations for cilium-operator scheduling to nodes with taints # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ - tolerations: - - operator: Exists - # - key: "key" - # operator: "Equal|Exists" - # value: "value" - # effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)" + # Toleration for agentNotReadyTaintKey taint is always added to cilium-operator pods. + # @schema + # type: [null, array] + # @schema + tolerations: + - key: "node-role.kubernetes.io/control-plane" + operator: Exists + - key: "node-role.kubernetes.io/master" #deprecated + operator: Exists + - key: "node.kubernetes.io/not-ready" + operator: Exists + - key: "node.cloudprovider.kubernetes.io/uninitialized" + operator: Exists # -- Additional cilium-operator container arguments. extraArgs: [] # -- Additional cilium-operator environment variables. @@ -2815,7 +2955,9 @@ operator: # -- HostNetwork setting hostNetwork: true # -- Security context to be added to cilium-operator pods - podSecurityContext: {} + podSecurityContext: + seccompProfile: + type: RuntimeDefault # -- Annotations to be added to cilium-operator pods podAnnotations: {} # -- Labels to be added to cilium-operator pods @@ -2836,6 +2978,11 @@ operator: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- cilium-operator resource limits & requests # ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: {} @@ -2847,7 +2994,11 @@ operator: # memory: 128Mi # -- Security context to be added to cilium-operator pods - securityContext: {} + securityContext: + capabilities: + drop: + - ALL + allowPrivilegeEscalation: false # runAsUser: 0 # -- Interval for endpoint garbage collection. @@ -2884,6 +3035,11 @@ operator: # -- Interval for scrape metrics. interval: "10s" # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ + # @schema # type: [null, array] # @schema # -- Relabeling configs for the ServiceMonitor cilium-operator @@ -2984,6 +3140,7 @@ nodeinit: memory: 100Mi # -- Security context to be added to nodeinit pods. securityContext: + allowPrivilegeEscalation: false privileged: false seLinuxOptions: level: 's0' @@ -3026,6 +3183,18 @@ preflight: digest: ${CILIUM_DIGEST} useDigest: ${USE_DIGESTS} pullPolicy: "${PULL_POLICY}" + envoy: + # -- Envoy pre-flight image. + image: + # @schema + # type: [null, string] + # @schema + override: ~ + repository: "${CILIUM_ENVOY_REPO}" + tag: "${CILIUM_ENVOY_VERSION}" + pullPolicy: "${PULL_POLICY}" + digest: "${CILIUM_ENVOY_DIGEST}" + useDigest: true # -- The priority class to use for the preflight pod. priorityClassName: "" # -- preflight update strategy @@ -3081,6 +3250,11 @@ preflight: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- preflight resource limits & requests # ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: {} @@ -3097,7 +3271,8 @@ preflight: # -- interval between checks of the readiness probe periodSeconds: 5 # -- Security context to be added to preflight pods - securityContext: {} + securityContext: + allowPrivilegeEscalation: false # runAsUser: 0 # -- Path to write the `--tofqdns-pre-cache` file to. @@ -3131,6 +3306,8 @@ clustermesh: enableEndpointSliceSynchronization: false # -- Enable Multi-Cluster Services API support enableMCSAPISupport: false + # -- Control whether policy rules assume by default the local cluster if not explicitly selected + policyDefaultLocalCluster: false # -- Annotations to be added to all top-level clustermesh objects (resources under templates/clustermesh-apiserver and templates/clustermesh-config) annotations: {} @@ -3231,7 +3408,7 @@ clustermesh: kvstoremesh: # -- Enable KVStoreMesh. KVStoreMesh caches the information retrieved - # from the remote clusters in the local etcd instance. + # from the remote clusters in the local etcd instance (deprecated - KVStoreMesh will always be enabled once the option is removed). enabled: true # -- TCP port for the KVStoreMesh health API. @@ -3262,6 +3439,11 @@ clustermesh: - ALL # -- lifecycle setting for the KVStoreMesh container lifecycle: {} + # -- Specify the KVStore mode when running KVStoreMesh + # Supported values: + # - "internal": remote cluster identities are cached in etcd that runs as a sidecar within ``clustermesh-apiserver`` pod. + # - "external": ``clustermesh-apiserver`` will sync remote cluster information to the etcd used as kvstore. This can't be enabled with crd identity allocation mode. + kvstoreMode: "internal" service: # -- The type of service used for apiserver access. type: NodePort @@ -3375,6 +3557,11 @@ clustermesh: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- Resource requests and limits for the clustermesh-apiserver resources: {} # requests: @@ -3541,6 +3728,11 @@ clustermesh: # -- Interval for scrape metrics (apiserver metrics) interval: "10s" # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ + # @schema # type: [null, array] # @schema # -- Relabeling configs for the ServiceMonitor clustermesh-apiserver (apiserver metrics) @@ -3554,6 +3746,11 @@ clustermesh: # -- Interval for scrape metrics (KVStoreMesh metrics) interval: "10s" # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ + # @schema # type: [null, array] # @schema # -- Relabeling configs for the ServiceMonitor clustermesh-apiserver (KVStoreMesh metrics) @@ -3567,6 +3764,11 @@ clustermesh: # -- Interval for scrape metrics (etcd metrics) interval: "10s" # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ + # @schema # type: [null, array] # @schema # -- Relabeling configs for the ServiceMonitor clustermesh-apiserver (etcd metrics) @@ -3576,10 +3778,6 @@ clustermesh: # @schema # -- Metrics relabeling configs for the ServiceMonitor clustermesh-apiserver (etcd metrics) metricRelabelings: ~ -# -- Configure external workloads support -externalWorkloads: - # -- Enable support for external workloads, such as VMs (false by default). - enabled: false # -- Configure cgroup related configuration cgroup: autoMount: @@ -3604,9 +3802,6 @@ cgroup: sysctlfix: # -- Enable the sysctl override. When enabled, the init container will mount the /proc of the host so that the `sysctlfix` utility can execute. enabled: true -# -- Configure whether to enable auto detect of terminating state for endpoints -# in order to support graceful termination. -enableK8sTerminatingEndpoint: true # -- Configure whether to unload DNS policy rules on graceful shutdown # dnsPolicyUnloadOnShutdown: false @@ -3639,6 +3834,9 @@ dnsProxy: proxyResponseMaxDelay: 100ms # -- DNS proxy operation mode (true/false, or unset to use version dependent defaults) # enableTransparentMode: true + # -- Pre-allocate ToFQDN identities. This reduces DNS proxy tail latency, at the potential cost of some + # unnecessary policymap entries. Disable this if you have a large (200+) number of unique ToFQDN selectors. + preAllocateIdentities: true # -- SCTP Configuration Values sctp: # -- Enable SCTP support. NOTE: Currently, SCTP support does not support rewriting ports or multihoming. @@ -3843,3 +4041,4 @@ authentication: enableInternalTrafficPolicy: true # -- Enable LoadBalancer IP Address Management enableLBIPAM: true + diff --git a/packages/system/cilium/images/cilium/Dockerfile b/packages/system/cilium/images/cilium/Dockerfile index cd113788..23c3d16a 100644 --- a/packages/system/cilium/images/cilium/Dockerfile +++ b/packages/system/cilium/images/cilium/Dockerfile @@ -1,2 +1,2 @@ -ARG VERSION=v1.17.8 +ARG VERSION=v1.18.5 FROM quay.io/cilium/cilium:${VERSION} diff --git a/packages/system/cilium/values-kubeovn.yaml b/packages/system/cilium/values-kubeovn.yaml index 3a4e3abc..62c75b29 100644 --- a/packages/system/cilium/values-kubeovn.yaml +++ b/packages/system/cilium/values-kubeovn.yaml @@ -15,6 +15,5 @@ cilium: enableIPv4Masquerade: false enableIPv6Masquerade: false enableIdentityMark: false - enableRuntimeDeviceDetection: true forceDeviceDetection: true devices: "ovn0 genev_sys_6081" diff --git a/scripts/common-envs.mk b/scripts/common-envs.mk index 865935ef..56eb5478 100644 --- a/scripts/common-envs.mk +++ b/scripts/common-envs.mk @@ -1,3 +1,10 @@ +# macOS-compatible sed in-place +ifeq ($(shell uname),Darwin) + SED_INPLACE := sed -i '' +else + SED_INPLACE := sed -i +endif + REGISTRY ?= ghcr.io/cozystack/cozystack TAG = $(shell git describe --tags --exact-match 2>/dev/null || echo latest) PUSH := 1 From 12023b7f02070987b465fb6cd45dd021fd3978f8 Mon Sep 17 00:00:00 2001 From: Nikita <166552198+nbykov0@users.noreply.github.com> Date: Tue, 30 Dec 2025 13:55:05 +0300 Subject: [PATCH 30/78] [multus] Increase memory limit (#1773) ## What this PR does Increases multus memory limit. Based on multiple community reports stating that multus tend to consume a lot of memory during startup after a node reboot. ### Release note ```release-note Multus memory limit increased. ``` --- packages/system/multus/Makefile | 5 +- .../multus/patches/customize-deployment.patch | 49 +++++++++++++++++++ .../templates/multus-daemonset-thick.yml | 2 +- 3 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 packages/system/multus/patches/customize-deployment.patch diff --git a/packages/system/multus/Makefile b/packages/system/multus/Makefile index 7825bd5e..b7ae5bfc 100644 --- a/packages/system/multus/Makefile +++ b/packages/system/multus/Makefile @@ -9,6 +9,5 @@ update: mkdir templates $(eval RELEASE := $(shell curl -s https://api.github.com/repos/k8snetworkplumbingwg/multus-cni/releases/latest?per_page=1 | jq -r '.name')) wget -q https://raw.githubusercontent.com/k8snetworkplumbingwg/multus-cni/refs/tags/$(RELEASE)/deployments/multus-daemonset-thick.yml -O templates/multus-daemonset-thick.yml - sed -i 's/namespace: kube-system/namespace: $(NAMESPACE)/;/multus-cni/s/snapshot-thick/$(RELEASE)-thick/' templates/multus-daemonset-thick.yml && \ - sed -i '/name:/s/kube-multus-ds/cozy-multus/;/memory:/s/"50Mi"/"100Mi"/' templates/multus-daemonset-thick.yml - + sed -i '/multus-cni/s/snapshot-thick/$(RELEASE)-thick/' templates/multus-daemonset-thick.yml && \ + patch --no-backup-if-mismatch -p4 < patches/customize-deployment.patch diff --git a/packages/system/multus/patches/customize-deployment.patch b/packages/system/multus/patches/customize-deployment.patch new file mode 100644 index 00000000..7ea3aeeb --- /dev/null +++ b/packages/system/multus/patches/customize-deployment.patch @@ -0,0 +1,49 @@ +--- a/packages/system/multus/templates/multus-daemonset-thick.yml ++++ b/packages/system/multus/templates/multus-daemonset-thick.yml +@@ -93,19 +93,19 @@ roleRef: + subjects: + - kind: ServiceAccount + name: multus +- namespace: kube-system ++ namespace: cozy-multus + --- + apiVersion: v1 + kind: ServiceAccount + metadata: + name: multus +- namespace: kube-system ++ namespace: cozy-multus + --- + kind: ConfigMap + apiVersion: v1 + metadata: + name: multus-daemon-config +- namespace: kube-system ++ namespace: cozy-multus + labels: + tier: node + app: multus +@@ -125,8 +125,8 @@ data: + apiVersion: apps/v1 + kind: DaemonSet + metadata: +- name: kube-multus-ds +- namespace: kube-system ++ name: cozy-multus ++ namespace: cozy-multus + labels: + tier: node + app: multus +@@ -159,10 +159,10 @@ spec: + resources: + requests: + cpu: "100m" +- memory: "50Mi" ++ memory: "100Mi" + limits: + cpu: "100m" +- memory: "50Mi" ++ memory: "900Mi" + securityContext: + privileged: true + terminationMessagePolicy: FallbackToLogsOnError diff --git a/packages/system/multus/templates/multus-daemonset-thick.yml b/packages/system/multus/templates/multus-daemonset-thick.yml index 7d99ab98..ba7eedfb 100644 --- a/packages/system/multus/templates/multus-daemonset-thick.yml +++ b/packages/system/multus/templates/multus-daemonset-thick.yml @@ -162,7 +162,7 @@ spec: memory: "100Mi" limits: cpu: "100m" - memory: "300Mi" + memory: "900Mi" securityContext: privileged: true terminationMessagePolicy: FallbackToLogsOnError From 29bd12d52d45b4d624ec9c33e6452fefeee93cca Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 30 Dec 2025 11:56:59 +0100 Subject: [PATCH 31/78] [installer,dx] Rename cozypkg to cozyhr (#1763) Signed-off-by: Andrei Kvapil ## What this PR does This PR renames cozypkg to cozyhr https://github.com/cozystack/cozyhr ### Release note ```release-note [installer,dx] Rename cozypkg to cozyhr ``` --- docs/agents/changelog.md | 14 +++++++------- docs/agents/overview.md | 2 +- hack/check-optional-repos.sh | 2 +- packages/core/flux-aio/Makefile | 6 +++--- packages/core/installer/Makefile | 6 +++--- .../core/installer/images/cozystack/Dockerfile | 2 +- packages/core/platform/Makefile | 10 +++++----- .../core/testing/images/e2e-sandbox/Dockerfile | 4 ++-- packages/system/fluxcd-operator/Makefile | 2 +- packages/system/fluxcd/Makefile | 2 +- scripts/migrations/15 | 2 +- scripts/migrations/20 | 6 +++--- scripts/package.mk | 12 ++++++------ 13 files changed, 35 insertions(+), 35 deletions(-) diff --git a/docs/agents/changelog.md b/docs/agents/changelog.md index 02cd2eab..feb70597 100644 --- a/docs/agents/changelog.md +++ b/docs/agents/changelog.md @@ -22,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, cozypkg, cozy-proxy) 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) @@ -146,7 +146,7 @@ Cozystack release may include changes from related repositories. Check and inclu **Optional repositories (MUST check ALL of them for tags during release period):** - [https://github.com/cozystack/talm](https://github.com/cozystack/talm) - [https://github.com/cozystack/boot-to-talos](https://github.com/cozystack/boot-to-talos) -- [https://github.com/cozystack/cozypkg](https://github.com/cozystack/cozypkg) +- [https://github.com/cozystack/cozyhr](https://github.com/cozystack/cozyhr) - [https://github.com/cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) **⚠️ 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. @@ -195,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, cozypkg, cozy-proxy). 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 @@ -208,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, cozypkg, cozy-proxy) + - 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 @@ -569,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, cozypkg, cozy-proxy) 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 @@ -628,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, cozypkg, cozy-proxy) 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) @@ -637,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, cozypkg, 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. + - 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/overview.md b/docs/agents/overview.md index 50b9a73c..b6d69e68 100644 --- a/docs/agents/overview.md +++ b/docs/agents/overview.md @@ -10,7 +10,7 @@ Cozystack is an open-source Kubernetes-based platform and framework for building - **Multi-tenancy**: Full isolation and self-service for tenants - **GitOps-driven**: FluxCD-based continuous delivery - **Modular Architecture**: Extensible with custom packages and services -- **Developer Experience**: Simplified local development with cozypkg tool +- **Developer Experience**: Simplified local development with cozyhr tool The platform exposes infrastructure services via the Kubernetes API with ready-made configs, built-in monitoring, and alerts. diff --git a/hack/check-optional-repos.sh b/hack/check-optional-repos.sh index 4bfdbd3a..1faa6d2c 100755 --- a/hack/check-optional-repos.sh +++ b/hack/check-optional-repos.sh @@ -48,7 +48,7 @@ echo " End: $RELEASE_END" echo "" # Loop through ALL optional repositories -for repo_name in talm boot-to-talos cozypkg cozy-proxy; do +for repo_name in talm boot-to-talos cozyhr cozy-proxy; do echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "Checking repository: $repo_name" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" diff --git a/packages/core/flux-aio/Makefile b/packages/core/flux-aio/Makefile index d50f317d..a5f36c82 100644 --- a/packages/core/flux-aio/Makefile +++ b/packages/core/flux-aio/Makefile @@ -4,13 +4,13 @@ NAMESPACE=cozy-$(NAME) include ../../../scripts/common-envs.mk show: - cozypkg show -n $(NAMESPACE) $(NAME) --plain + cozyhr show -n $(NAMESPACE) $(NAME) --plain apply: - cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- --server-side --force-conflicts + cozyhr show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- --server-side --force-conflicts diff: - cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f- + cozyhr show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f- update: timoni bundle build -f flux-aio.cue > templates/fluxcd.yaml diff --git a/packages/core/installer/Makefile b/packages/core/installer/Makefile index 12a3e333..7c264018 100644 --- a/packages/core/installer/Makefile +++ b/packages/core/installer/Makefile @@ -7,13 +7,13 @@ pre-checks: ../../../hack/pre-checks.sh show: - cozypkg show -n $(NAMESPACE) $(NAME) --plain + cozyhr show -n $(NAMESPACE) $(NAME) --plain apply: - cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- + cozyhr show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- diff: - cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f - + cozyhr show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f - image: pre-checks image-cozystack diff --git a/packages/core/installer/images/cozystack/Dockerfile b/packages/core/installer/images/cozystack/Dockerfile index beeed70b..8e1ae219 100644 --- a/packages/core/installer/images/cozystack/Dockerfile +++ b/packages/core/installer/images/cozystack/Dockerfile @@ -28,7 +28,7 @@ RUN go mod download FROM alpine:3.22 -RUN wget -O- https://github.com/cozystack/cozypkg/raw/refs/heads/main/hack/install.sh | sh -s -- -v 1.2.0 +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 diff --git a/packages/core/platform/Makefile b/packages/core/platform/Makefile index 5c0b4786..2ea59153 100644 --- a/packages/core/platform/Makefile +++ b/packages/core/platform/Makefile @@ -4,22 +4,22 @@ NAMESPACE=cozy-system include ../../../scripts/common-envs.mk show: - cozypkg show -n $(NAMESPACE) $(NAME) --plain + cozyhr show -n $(NAMESPACE) $(NAME) --plain apply: - cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- + 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: - cozypkg show -n $(NAMESPACE) $(NAME) --plain -s templates/namespaces.yaml + cozyhr show -n $(NAMESPACE) $(NAME) --plain -s templates/namespaces.yaml namespaces-apply: - cozypkg show -n $(NAMESPACE) $(NAME) --plain -s templates/namespaces.yaml | kubectl apply -f- + cozyhr show -n $(NAMESPACE) $(NAME) --plain -s templates/namespaces.yaml | kubectl apply -f- diff: - cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f- + cozyhr show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f- image: image-assets image-assets: diff --git a/packages/core/testing/images/e2e-sandbox/Dockerfile b/packages/core/testing/images/e2e-sandbox/Dockerfile index 069a1905..ce6cabdd 100755 --- a/packages/core/testing/images/e2e-sandbox/Dockerfile +++ b/packages/core/testing/images/e2e-sandbox/Dockerfile @@ -3,7 +3,7 @@ FROM ubuntu:22.04 ARG KUBECTL_VERSION=1.33.2 ARG TALOSCTL_VERSION=1.10.4 ARG HELM_VERSION=3.18.3 -ARG COZYPKG_VERSION=1.1.0 +ARG COZYHR_VERSION=1.5.0 ARG TARGETOS ARG TARGETARCH @@ -18,7 +18,7 @@ RUN curl -sSL "https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm RUN curl -sSL "https://github.com/mikefarah/yq/releases/download/v4.44.3/yq_${TARGETOS}_${TARGETARCH}" -o /usr/local/bin/yq \ && chmod +x /usr/local/bin/yq RUN curl -sSL "https://fluxcd.io/install.sh" | bash -RUN curl -sSL "https://github.com/cozystack/cozypkg/raw/refs/heads/main/hack/install.sh" | sh -s -- -v "${COZYPKG_VERSION}" +RUN curl -sSL "https://github.com/cozystack/cozyhr/raw/refs/heads/main/hack/install.sh" | sh -s -- -v "${COZYHR_VERSION}" RUN curl https://dl.min.io/client/mc/release/${TARGETOS}-${TARGETARCH}/mc --create-dirs -o /usr/local/bin/mc \ && chmod +x /usr/local/bin/mc COPY entrypoint.sh /usr/local/bin/entrypoint.sh diff --git a/packages/system/fluxcd-operator/Makefile b/packages/system/fluxcd-operator/Makefile index 84ffc6fe..a603b85f 100644 --- a/packages/system/fluxcd-operator/Makefile +++ b/packages/system/fluxcd-operator/Makefile @@ -4,7 +4,7 @@ NAMESPACE=cozy-fluxcd include ../../../scripts/package.mk apply-locally: - cozypkg apply --plain -n $(NAMESPACE) $(NAME) + cozyhr apply --plain -n $(NAMESPACE) $(NAME) update: rm -rf charts diff --git a/packages/system/fluxcd/Makefile b/packages/system/fluxcd/Makefile index b5af8680..2c88b52d 100644 --- a/packages/system/fluxcd/Makefile +++ b/packages/system/fluxcd/Makefile @@ -4,7 +4,7 @@ NAMESPACE=cozy-$(NAME) include ../../../scripts/package.mk apply-locally: - cozypkg apply --plain -n $(NAMESPACE) $(NAME) + cozyhr apply --plain -n $(NAMESPACE) $(NAME) update: rm -rf charts diff --git a/scripts/migrations/15 b/scripts/migrations/15 index e0d78cfb..fe5c69a9 100755 --- a/scripts/migrations/15 +++ b/scripts/migrations/15 @@ -21,7 +21,7 @@ kubectl get kuberneteses.apps.cozystack.io -A --no-headers --output=custom-colum done if kubectl get helmrelease kamaji -n cozy-kamaji; then - cozypkg reconcile kamaji -n cozy-kamaji --force + cozyhr reconcile kamaji -n cozy-kamaji --force fi # Write version to cozystack-version config diff --git a/scripts/migrations/20 b/scripts/migrations/20 index 2b2e1530..a27464ac 100755 --- a/scripts/migrations/20 +++ b/scripts/migrations/20 @@ -22,9 +22,9 @@ done kubectl delete helmrelease -n cozy-dashboard dashboard --ignore-not-found sleep 5 -cozypkg -n cozy-system -C packages/system/cozystack-resource-definition-crd apply cozystack-resource-definition-crd --plain -cozypkg -n cozy-system -C packages/system/cozystack-resource-definitions apply cozystack-resource-definitions --plain -cozypkg -n cozy-system -C packages/system/cozystack-api apply cozystack-api --plain +cozyhr -n cozy-system -C packages/system/cozystack-resource-definition-crd apply cozystack-resource-definition-crd --plain +cozyhr -n cozy-system -C packages/system/cozystack-resource-definitions apply cozystack-resource-definitions --plain +cozyhr -n cozy-system -C packages/system/cozystack-api apply cozystack-api --plain if kubectl get ds cozystack-api -n cozy-system >/dev/null 2>&1; then echo "Waiting for cozystack-api daemonset" kubectl rollout status ds/cozystack-api -n cozy-system --timeout=5m || exit 1 diff --git a/scripts/package.mk b/scripts/package.mk index 6940ad72..cf0f5b72 100644 --- a/scripts/package.mk +++ b/scripts/package.mk @@ -5,22 +5,22 @@ help: ## Show this help. @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {sub("\\\\n",sprintf("\n%22c"," "), $$2);printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) show: check ## Show output of rendered templates - cozypkg show -n $(NAMESPACE) $(NAME) + cozyhr show -n $(NAMESPACE) $(NAME) apply: check suspend ## Apply Helm release to a Kubernetes cluster - cozypkg apply -n $(NAMESPACE) $(NAME) + cozyhr apply -n $(NAMESPACE) $(NAME) diff: check ## Diff Helm release against objects in a Kubernetes cluster - cozypkg diff -n $(NAMESPACE) $(NAME) + cozyhr diff -n $(NAMESPACE) $(NAME) suspend: check ## Suspend reconciliation for an existing Helm release - cozypkg suspend -n $(NAMESPACE) $(NAME) + cozyhr suspend -n $(NAMESPACE) $(NAME) resume: check ## Resume reconciliation for an existing Helm release - cozypkg resume -n $(NAMESPACE) $(NAME) + cozyhr resume -n $(NAMESPACE) $(NAME) delete: check suspend ## Delete Helm release from a Kubernetes cluster - cozypkg delete -n $(NAMESPACE) $(NAME) + cozyhr delete -n $(NAMESPACE) $(NAME) check: @if [ -z "$(NAME)" ]; then echo "env NAME is not set!" >&2; exit 1; fi From fe565aff4a41f05848e74cce46676f6d0fb35734 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 30 Dec 2025 11:58:10 +0100 Subject: [PATCH 32/78] [kubevirt-operator] Fix typo in VMNotRunningFor10Minutes alert (#1770) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does Fix case sensitivity in status check for VMNotRunningFor10Minutes alert rule. The metric `kubevirt_vm_info` uses `status="Running"` (capital R), but the alert rule was checking for `status!="running"` (lowercase), causing false alerts for running VMs. Fixes https://github.com/cozystack/cozystack/issues/1552 ### Release note ```release-note [kubevirt-operator] Fix VMNotRunningFor10Minutes alert false positives ``` ## Summary by CodeRabbit * **Bug Fixes** * Fixed alert rule condition for virtual machine status detection to ensure proper matching of running VMs. ✏️ Tip: You can customize this high-level summary in your review settings. --- packages/system/kubevirt-operator/alerts/PrometheusRule.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/system/kubevirt-operator/alerts/PrometheusRule.yaml b/packages/system/kubevirt-operator/alerts/PrometheusRule.yaml index 73ef3ce4..c4d73cc5 100644 --- a/packages/system/kubevirt-operator/alerts/PrometheusRule.yaml +++ b/packages/system/kubevirt-operator/alerts/PrometheusRule.yaml @@ -10,7 +10,7 @@ spec: expr: | max_over_time( kubevirt_vm_info{ - status!="running", + status!="Running", exported_namespace=~".+", name=~".+" }[10m] From 9a2d39a4b07a6bd26b6c4e5aecf1b8d56107d7b6 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 30 Dec 2025 11:59:33 +0100 Subject: [PATCH 33/78] [tenant] Allow egress to parent ingress pods (#1765) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does Fixes egress policy for nested Kubernetes clusters using `exposeMethod: Proxied`. The clusterwide egress policy blocks traffic from tenant pods to ingress pods in parent namespaces. This breaks: - cert-manager HTTP-01 self-check - Any scenario where pods need to access services exposed through parent ingress Adds egress rule allowing traffic to ingress pods (`cozystack.io/service: ingress`) in parent namespaces, following the same pattern as existing vminsert and etcd rules. ### Release note ```release-note [tenant] Fixed tenant egress policy to allow traffic to parent ingress pods, enabling cert-manager HTTP-01 challenges and external domain access for nested clusters with exposeMethod: Proxied ``` ## Summary by CodeRabbit * **New Features** * Enhanced network policies for multi-tenant environments with improved traffic routing based on namespace hierarchies, enabling more granular egress control. ✏️ Tip: You can customize this high-level summary in your review settings. --- packages/apps/tenant/templates/networkpolicy.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/apps/tenant/templates/networkpolicy.yaml b/packages/apps/tenant/templates/networkpolicy.yaml index b66e85ff..2c15a877 100644 --- a/packages/apps/tenant/templates/networkpolicy.yaml +++ b/packages/apps/tenant/templates/networkpolicy.yaml @@ -67,6 +67,19 @@ spec: {{- end }} {{- end }} {{- end }} + {{- if ne (include "tenant.name" .) "tenant-root" }} + - toEndpoints: + {{- if hasPrefix "tenant-" .Release.Namespace }} + {{- $parts := splitList "-" .Release.Namespace }} + {{- range $i, $v := $parts }} + {{- if ne $i 0 }} + - matchLabels: + cozystack.io/service: ingress + "k8s:io.kubernetes.pod.namespace": {{ join "-" (slice $parts 0 (add $i 1)) }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} --- apiVersion: cilium.io/v2 kind: CiliumClusterwideNetworkPolicy From b65fc64e17bc7e18fb3acd04775f2899dcfa0071 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 30 Dec 2025 12:03:05 +0100 Subject: [PATCH 34/78] [tenant] Run cleanup job from system namespace (#1774) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does The Helm hook that creates a job deleting all applications in a tenant before deleting the tenant itself now runs this job from the cozy-system namespace. This prevents conflicts with resource quotas (not enough resources to run cleanup job) without temporary increases of the quota or similar vulnerability-introducing hacks. ### Release note ```release-note [tenant] Run cleanup job in system namespace to avoid conflicts on resource quotas. ``` ## Summary by CodeRabbit * **Infrastructure Updates** * Updated cleanup job namespace targeting to use a fixed system configuration * Adjusted cleanup job execution priority level ✏️ Tip: You can customize this high-level summary in your review settings. --- packages/apps/tenant/templates/cleanup-job.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/apps/tenant/templates/cleanup-job.yaml b/packages/apps/tenant/templates/cleanup-job.yaml index 9a1bcdd5..9b2f2c50 100644 --- a/packages/apps/tenant/templates/cleanup-job.yaml +++ b/packages/apps/tenant/templates/cleanup-job.yaml @@ -3,7 +3,7 @@ apiVersion: v1 kind: ServiceAccount metadata: name: {{ include "tenant.name" . }}-cleanup - namespace: {{ include "tenant.name" . }} + namespace: cozy-system annotations: helm.sh/hook: pre-delete helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded @@ -39,13 +39,13 @@ roleRef: subjects: - kind: ServiceAccount name: {{ include "tenant.name" . }}-cleanup - namespace: {{ include "tenant.name" . }} + namespace: cozy-system --- apiVersion: batch/v1 kind: Job metadata: name: {{ include "tenant.name" . }}-cleanup - namespace: {{ include "tenant.name" . }} + namespace: cozy-system annotations: helm.sh/hook: pre-delete helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded From 526af294599ba71c911310e224cc0aa4fcaa7628 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 30 Dec 2025 12:20:40 +0100 Subject: [PATCH 35/78] [ci] Fix auto-release workflow Signed-off-by: Andrei Kvapil --- .github/workflows/auto-release.yaml | 32 +++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/.github/workflows/auto-release.yaml b/.github/workflows/auto-release.yaml index c34c53b3..c3597850 100644 --- a/.github/workflows/auto-release.yaml +++ b/.github/workflows/auto-release.yaml @@ -36,11 +36,18 @@ jobs: - name: Process release branches uses: actions/github-script@v7 + env: + GH_PAT: ${{ secrets.GH_PAT }} with: github-token: ${{ secrets.GH_PAT }} script: | const { execSync } = require('child_process'); - + + // 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' }); + // Get all release-X.Y branches const branches = execSync('git branch -r | grep -E "origin/release-[0-9]+\\.[0-9]+$" | sed "s|origin/||" | tr -d " "', { encoding: 'utf8' }) .split('\n') @@ -146,10 +153,27 @@ jobs: console.log(` 🏷️ Creating new tag: ${nextTag} on commit ${latestBranchCommit}`); - // Create and push the tag (force push to update if exists) + // Create and push the tag with base_ref for workflow triggering try { - execSync(`git tag -f ${nextTag} ${latestBranchCommit}`, { encoding: 'utf8' }); - execSync(`git push -f origin ${nextTag}`, { encoding: 'utf8' }); + // Delete local tag if exists to force update + try { + execSync(`git tag -d ${nextTag}`, { encoding: 'utf8' }); + } catch (e) { + // Tag doesn't exist locally, that's fine + } + + // Delete remote tag if exists + try { + execSync(`git push origin :refs/tags/${nextTag}`, { encoding: 'utf8' }); + } catch (e) { + // Tag doesn't exist remotely, that's fine + } + + // Create tag locally + execSync(`git tag ${nextTag} ${latestBranchCommit}`, { encoding: 'utf8' }); + + // Push tag with HEAD reference to preserve base_ref + execSync(`git push origin HEAD:refs/tags/${nextTag}`, { encoding: 'utf8' }); console.log(` ✅ Successfully created and pushed tag ${nextTag}`); } catch (error) { console.log(` ❌ Error creating/pushing tag ${nextTag}: ${error.message}`); From 2bf1168dcf249b1e63db89e797790ea79d58cfc1 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 2 Jan 2026 19:12:30 +0100 Subject: [PATCH 36/78] [system] Add resource requests and limits to etcd-defrag (#1785) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does Added resource requests and limits for etcd-defrag container. ### Release note ```release-note [system] Add resource requests and limits to etcd-defrag ``` ## Summary by CodeRabbit * **Chores** * Enhanced resource configurations for the etcd defragmentation process to ensure optimal performance and system stability. ✏️ Tip: You can customize this high-level summary in your review settings. --- packages/extra/etcd/templates/etcd-defrag.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/extra/etcd/templates/etcd-defrag.yaml b/packages/extra/etcd/templates/etcd-defrag.yaml index 21a8e514..089df920 100644 --- a/packages/extra/etcd/templates/etcd-defrag.yaml +++ b/packages/extra/etcd/templates/etcd-defrag.yaml @@ -12,6 +12,13 @@ spec: containers: - name: etcd-defrag image: ghcr.io/ahrtr/etcd-defrag:v0.13.0 + resources: + requests: + cpu: 200m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi args: - --endpoints={{ range $i, $e := until (int .Values.replicas) }}{{ if $i }},{{ end }}https://{{ $.Release.Name }}-{{ $i }}.{{ $.Release.Name }}-headless.{{ $.Release.Namespace }}.svc:2379{{ end }} - --cacert=/etc/etcd/pki/client/cert/ca.crt From 68a639b32c3a7104e16e3cc466208abb16fa63bb Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 2 Jan 2026 21:10:12 +0100 Subject: [PATCH 37/78] fix(ci): remove GITHUB_TOKEN extraheader to trigger workflows actions/checkout configures http.extraheader with GITHUB_TOKEN which takes priority over URL credentials. This caused tag pushes to authenticate as github-actions instead of cozystack-bot, preventing the Versioned Tag workflow from being triggered. Co-Authored-By: Claude Signed-off-by: Andrei Kvapil --- .github/workflows/auto-release.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/auto-release.yaml b/.github/workflows/auto-release.yaml index c3597850..19d4b460 100644 --- a/.github/workflows/auto-release.yaml +++ b/.github/workflows/auto-release.yaml @@ -33,6 +33,7 @@ jobs: 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 @@ -47,6 +48,8 @@ jobs: 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 const branches = execSync('git branch -r | grep -E "origin/release-[0-9]+\\.[0-9]+$" | sed "s|origin/||" | tr -d " "', { encoding: 'utf8' }) From 30c1041e7a5f3e6b1feecb46a69a1970b4f81113 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 2 Jan 2026 21:20:52 +0100 Subject: [PATCH 38/78] feat(ci): add /retest command to rerun tests from Prepare environment Allows maintainers to trigger test rerun by commenting /retest on a PR. The workflow finds the latest run for the PR and reruns starting from the "Prepare environment" job, skipping the build step. Co-Authored-By: Claude Signed-off-by: Andrei Kvapil --- .github/workflows/retest.yaml | 78 +++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 .github/workflows/retest.yaml diff --git a/.github/workflows/retest.yaml b/.github/workflows/retest.yaml new file mode 100644 index 00000000..46ce8036 --- /dev/null +++ b/.github/workflows/retest.yaml @@ -0,0 +1,78 @@ +name: Retest + +on: + issue_comment: + types: [created] + +jobs: + retest: + name: Retest PR + runs-on: ubuntu-latest + if: | + github.event.issue.pull_request && + contains(github.event.comment.body, '/retest') + permissions: + actions: write + pull-requests: read + + steps: + - name: Rerun from Prepare environment + uses: actions/github-script@v7 + with: + script: | + const prNumber = context.issue.number; + + // Get the PR to find the head SHA + const pr = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber + }); + + // Find the latest workflow run for this PR + const runs = await github.rest.actions.listWorkflowRuns({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'pull-requests.yaml', + head_sha: pr.data.head.sha + }); + + if (runs.data.workflow_runs.length === 0) { + core.setFailed('No workflow runs found for this PR'); + return; + } + + const latestRun = runs.data.workflow_runs[0]; + console.log(`Found workflow run: ${latestRun.id} (${latestRun.status})`); + + // Check if workflow is waiting for approval (fork PRs) + if (latestRun.conclusion === 'action_required') { + core.setFailed('Workflow is waiting for approval. A maintainer must approve the workflow first.'); + return; + } + + // Get jobs for this run + const jobs = await github.rest.actions.listJobsForWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: latestRun.id + }); + + // Find "Prepare environment" job + const prepareJob = jobs.data.jobs.find(j => j.name === 'Prepare environment'); + + if (!prepareJob) { + core.setFailed('Could not find "Prepare environment" job'); + return; + } + + console.log(`Found job: ${prepareJob.name} (id: ${prepareJob.id}, status: ${prepareJob.status})`); + + // Rerun the job + await github.rest.actions.reRunJobForWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + job_id: prepareJob.id + }); + + console.log(`✅ Triggered rerun of job "${prepareJob.name}" (${prepareJob.id})`); From 967f0bdc9f508a1e4cabf930f9f6b6491434da6e Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Sat, 3 Jan 2026 08:30:31 +0100 Subject: [PATCH 39/78] [kubernetes] Add lb tests for tenant k8s (#1783) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does ### Release note ```release-note [kubernetes] Add lb tests for tenant k8s ``` ## Summary by CodeRabbit * **Tests** * Increased readiness and port-forward timeouts to improve stability. * Added full end-to-end provisioning and validation: automated namespace and backend deployment, load balancer provisioning, health checks with retries, reachability validation, and cleanup. * Provisioning sequence now runs earlier and is duplicated within the test flow, altering execution order and adding extra validation/cleanup steps. ✏️ Tip: You can customize this high-level summary in your review settings. --- hack/e2e-apps/run-kubernetes.sh | 98 ++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 2 deletions(-) diff --git a/hack/e2e-apps/run-kubernetes.sh b/hack/e2e-apps/run-kubernetes.sh index f8b20b85..f8f1ce5f 100644 --- a/hack/e2e-apps/run-kubernetes.sh +++ b/hack/e2e-apps/run-kubernetes.sh @@ -72,7 +72,7 @@ EOF kubectl wait --for=condition=TenantControlPlaneCreated kamajicontrolplane -n tenant-test kubernetes-${test_name} --timeout=4m # Wait for Kubernetes resources to be ready (timeout after 2 minutes) - kubectl wait tcp -n tenant-test kubernetes-${test_name} --timeout=2m --for=jsonpath='{.status.kubernetesResources.version.status}'=Ready + kubectl wait tcp -n tenant-test kubernetes-${test_name} --timeout=5m --for=jsonpath='{.status.kubernetesResources.version.status}'=Ready # Wait for all required deployments to be available (timeout after 4 minutes) kubectl wait deploy --timeout=4m --for=condition=available -n tenant-test kubernetes-${test_name} kubernetes-${test_name}-cluster-autoscaler kubernetes-${test_name}-kccm kubernetes-${test_name}-kcsi-controller @@ -87,7 +87,7 @@ EOF # Set up port forwarding to the Kubernetes API server for a 200 second timeout - bash -c 'timeout 300s kubectl port-forward service/kubernetes-'"${test_name}"' -n tenant-test '"${port}"':6443 > /dev/null 2>&1 &' + 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 5; done' @@ -124,6 +124,100 @@ EOF exit 1 fi + + kubectl --kubeconfig tenantkubeconfig-${test_name} apply -f - <&2 + exit 1 +fi + + for i in $(seq 1 20); do + echo "Attempt $i" + curl --silent --fail "http://${LB_ADDR}" && break + sleep 3 + done + + 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 + # 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 From 8d166e07542838d0ba3c57074767cb3f2d53d695 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Sun, 4 Jan 2026 09:06:50 +0100 Subject: [PATCH 40/78] [platform] refactor: split cozystack-resource-definitions into separate packages (#1778) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does This PR splits the monolithic `cozystack-resource-definitions` package into 25 individual resource definition packages (`*-rd`) for better modularity and independent versioning. **Changes:** - Created 25 separate `*-rd` packages (bootbox-rd, bucket-rd, clickhouse-rd, etcd-rd, ferretdb-rd, foundationdb-rd, http-cache-rd, info-rd, ingress-rd, kafka-rd, kubernetes-rd, monitoring-rd, mysql-rd, nats-rd, postgres-rd, rabbitmq-rd, redis-rd, seaweedfs-rd, tcp-balancer-rd, tenant-rd, virtual-machine-rd, virtualprivatecloud-rd, vm-disk-rd, vm-instance-rd, vpn-rd) - Removed `packages/system/cozystack-resource-definitions` - Updated platform bundles (paas-hosted, paas-full, distro-full) to reference individual -rd packages - Updated `hack/update-crd.sh` to use package-specific directories Each `*-rd` package contains: - `Chart.yaml` - package metadata - `values.yaml` - default values - `Makefile` - build instructions - `cozyrds/.yaml` - CRD definition - `templates/cozyrd.yaml` - Helm template **Benefits:** - **Modularity**: Each resource definition is now a standalone package - **Independent versioning**: Resources can be versioned independently - **Maintainability**: Easier to update individual resources - **Build efficiency**: Parallel building of resource packages ### Release note ```release-note [platform] Split cozystack-resource-definitions into 25 separate *-rd packages for better modularity and independent versioning. Each resource definition is now a standalone package. ## Summary by CodeRabbit * **Refactor** * Split the monolithic resource-definitions into many independent resource-definition packages (e.g., bootbox-rd, bucket-rd, clickhouse-rd, etc.) for modular deployment and finer-grained management * Updated deployment bundles to reference the new per-resource releases with uniform cozy-system namespace and CRD dependency * **Chores** * Added packaging/Helm stubs (Chart.yaml, Makefile, values, templates) for each new resource-definition * **Bug Fixes** * Made CRD path resolution dynamic (NAME validated before assignment) ✏️ Tip: You can customize this high-level summary in your review settings. --- hack/update-crd.sh | 3 +- .../core/platform/bundles/distro-full.yaml | 152 +++++++++++++++++- packages/core/platform/bundles/paas-full.yaml | 152 +++++++++++++++++- .../core/platform/bundles/paas-hosted.yaml | 152 +++++++++++++++++- .../Chart.yaml | 2 +- .../Makefile | 2 +- .../cozyrds/bootbox.yaml | 0 .../templates/cozyrd.yaml} | 0 .../values.yaml | 0 packages/system/bucket-rd/Chart.yaml | 3 + packages/system/bucket-rd/Makefile | 4 + .../cozyrds/bucket.yaml | 0 .../system/bucket-rd/templates/cozyrd.yaml | 4 + packages/system/bucket-rd/values.yaml | 1 + packages/system/clickhouse-rd/Chart.yaml | 3 + packages/system/clickhouse-rd/Makefile | 4 + .../cozyrds/clickhouse.yaml | 0 .../clickhouse-rd/templates/cozyrd.yaml | 4 + packages/system/clickhouse-rd/values.yaml | 1 + packages/system/etcd-rd/Chart.yaml | 3 + packages/system/etcd-rd/Makefile | 4 + .../cozyrds/etcd.yaml | 0 packages/system/etcd-rd/templates/cozyrd.yaml | 4 + packages/system/etcd-rd/values.yaml | 1 + packages/system/ferretdb-rd/Chart.yaml | 3 + packages/system/ferretdb-rd/Makefile | 4 + .../cozyrds/ferretdb.yaml | 0 .../system/ferretdb-rd/templates/cozyrd.yaml | 4 + packages/system/ferretdb-rd/values.yaml | 1 + packages/system/foundationdb-rd/Chart.yaml | 3 + packages/system/foundationdb-rd/Makefile | 4 + .../cozyrds/foundationdb.yaml | 0 .../foundationdb-rd/templates/cozyrd.yaml | 4 + packages/system/foundationdb-rd/values.yaml | 1 + packages/system/http-cache-rd/Chart.yaml | 3 + packages/system/http-cache-rd/Makefile | 4 + .../cozyrds/http-cache.yaml | 0 .../http-cache-rd/templates/cozyrd.yaml | 4 + packages/system/http-cache-rd/values.yaml | 1 + packages/system/info-rd/Chart.yaml | 3 + packages/system/info-rd/Makefile | 4 + .../cozyrds/info.yaml | 0 packages/system/info-rd/templates/cozyrd.yaml | 4 + packages/system/info-rd/values.yaml | 1 + packages/system/ingress-rd/Chart.yaml | 3 + packages/system/ingress-rd/Makefile | 4 + .../cozyrds/ingress.yaml | 0 .../system/ingress-rd/templates/cozyrd.yaml | 4 + packages/system/ingress-rd/values.yaml | 1 + packages/system/kafka-rd/Chart.yaml | 3 + packages/system/kafka-rd/Makefile | 4 + .../cozyrds/kafka.yaml | 0 .../system/kafka-rd/templates/cozyrd.yaml | 4 + packages/system/kafka-rd/values.yaml | 1 + packages/system/kubernetes-rd/Chart.yaml | 3 + packages/system/kubernetes-rd/Makefile | 4 + .../cozyrds/kubernetes.yaml | 0 .../kubernetes-rd/templates/cozyrd.yaml | 4 + packages/system/kubernetes-rd/values.yaml | 1 + packages/system/monitoring-rd/Chart.yaml | 3 + packages/system/monitoring-rd/Makefile | 4 + .../cozyrds/monitoring.yaml | 0 .../monitoring-rd/templates/cozyrd.yaml | 4 + packages/system/monitoring-rd/values.yaml | 1 + packages/system/mysql-rd/Chart.yaml | 3 + packages/system/mysql-rd/Makefile | 4 + .../cozyrds/mysql.yaml | 0 .../system/mysql-rd/templates/cozyrd.yaml | 4 + packages/system/mysql-rd/values.yaml | 1 + packages/system/nats-rd/Chart.yaml | 3 + packages/system/nats-rd/Makefile | 4 + .../cozyrds/nats.yaml | 0 packages/system/nats-rd/templates/cozyrd.yaml | 4 + packages/system/nats-rd/values.yaml | 1 + packages/system/postgres-rd/Chart.yaml | 3 + packages/system/postgres-rd/Makefile | 4 + .../cozyrds/postgres.yaml | 0 .../system/postgres-rd/templates/cozyrd.yaml | 4 + packages/system/postgres-rd/values.yaml | 1 + packages/system/rabbitmq-rd/Chart.yaml | 3 + packages/system/rabbitmq-rd/Makefile | 4 + .../cozyrds/rabbitmq.yaml | 0 .../system/rabbitmq-rd/templates/cozyrd.yaml | 4 + packages/system/rabbitmq-rd/values.yaml | 1 + packages/system/redis-rd/Chart.yaml | 3 + packages/system/redis-rd/Makefile | 4 + .../cozyrds/redis.yaml | 0 .../system/redis-rd/templates/cozyrd.yaml | 4 + packages/system/redis-rd/values.yaml | 1 + packages/system/seaweedfs-rd/Chart.yaml | 3 + packages/system/seaweedfs-rd/Makefile | 4 + .../cozyrds/seaweedfs.yaml | 0 .../system/seaweedfs-rd/templates/cozyrd.yaml | 4 + packages/system/seaweedfs-rd/values.yaml | 1 + packages/system/tcp-balancer-rd/Chart.yaml | 3 + packages/system/tcp-balancer-rd/Makefile | 4 + .../cozyrds/tcp-balancer.yaml | 0 .../tcp-balancer-rd/templates/cozyrd.yaml | 4 + packages/system/tcp-balancer-rd/values.yaml | 1 + packages/system/tenant-rd/Chart.yaml | 3 + packages/system/tenant-rd/Makefile | 4 + .../cozyrds/tenant.yaml | 0 .../system/tenant-rd/templates/cozyrd.yaml | 4 + packages/system/tenant-rd/values.yaml | 1 + packages/system/virtual-machine-rd/Chart.yaml | 3 + packages/system/virtual-machine-rd/Makefile | 4 + .../cozyrds/virtual-machine.yaml | 0 .../virtual-machine-rd/templates/cozyrd.yaml | 4 + .../system/virtual-machine-rd/values.yaml | 1 + .../system/virtualprivatecloud-rd/Chart.yaml | 3 + .../system/virtualprivatecloud-rd/Makefile | 4 + .../cozyrds/virtualprivatecloud.yaml | 0 .../templates/cozyrd.yaml | 4 + .../system/virtualprivatecloud-rd/values.yaml | 1 + packages/system/vm-disk-rd/Chart.yaml | 3 + packages/system/vm-disk-rd/Makefile | 4 + .../cozyrds/vm-disk.yaml | 0 .../system/vm-disk-rd/templates/cozyrd.yaml | 4 + packages/system/vm-disk-rd/values.yaml | 1 + packages/system/vm-instance-rd/Chart.yaml | 3 + packages/system/vm-instance-rd/Makefile | 4 + .../cozyrds/vm-instance.yaml | 0 .../vm-instance-rd/templates/cozyrd.yaml | 4 + packages/system/vm-instance-rd/values.yaml | 1 + packages/system/vpn-rd/Chart.yaml | 3 + packages/system/vpn-rd/Makefile | 4 + .../cozyrds/vpn.yaml | 0 packages/system/vpn-rd/templates/cozyrd.yaml | 4 + packages/system/vpn-rd/values.yaml | 1 + 129 files changed, 736 insertions(+), 15 deletions(-) rename packages/system/{cozystack-resource-definitions => bootbox-rd}/Chart.yaml (75%) rename packages/system/{cozystack-resource-definitions => bootbox-rd}/Makefile (60%) rename packages/system/{cozystack-resource-definitions => bootbox-rd}/cozyrds/bootbox.yaml (100%) rename packages/system/{cozystack-resource-definitions/templates/cozyrds.yaml => bootbox-rd/templates/cozyrd.yaml} (100%) rename packages/system/{cozystack-resource-definitions => bootbox-rd}/values.yaml (100%) create mode 100644 packages/system/bucket-rd/Chart.yaml create mode 100644 packages/system/bucket-rd/Makefile rename packages/system/{cozystack-resource-definitions => bucket-rd}/cozyrds/bucket.yaml (100%) create mode 100644 packages/system/bucket-rd/templates/cozyrd.yaml create mode 100644 packages/system/bucket-rd/values.yaml create mode 100644 packages/system/clickhouse-rd/Chart.yaml create mode 100644 packages/system/clickhouse-rd/Makefile rename packages/system/{cozystack-resource-definitions => clickhouse-rd}/cozyrds/clickhouse.yaml (100%) create mode 100644 packages/system/clickhouse-rd/templates/cozyrd.yaml create mode 100644 packages/system/clickhouse-rd/values.yaml create mode 100644 packages/system/etcd-rd/Chart.yaml create mode 100644 packages/system/etcd-rd/Makefile rename packages/system/{cozystack-resource-definitions => etcd-rd}/cozyrds/etcd.yaml (100%) create mode 100644 packages/system/etcd-rd/templates/cozyrd.yaml create mode 100644 packages/system/etcd-rd/values.yaml create mode 100644 packages/system/ferretdb-rd/Chart.yaml create mode 100644 packages/system/ferretdb-rd/Makefile rename packages/system/{cozystack-resource-definitions => ferretdb-rd}/cozyrds/ferretdb.yaml (100%) create mode 100644 packages/system/ferretdb-rd/templates/cozyrd.yaml create mode 100644 packages/system/ferretdb-rd/values.yaml create mode 100644 packages/system/foundationdb-rd/Chart.yaml create mode 100644 packages/system/foundationdb-rd/Makefile rename packages/system/{cozystack-resource-definitions => foundationdb-rd}/cozyrds/foundationdb.yaml (100%) create mode 100644 packages/system/foundationdb-rd/templates/cozyrd.yaml create mode 100644 packages/system/foundationdb-rd/values.yaml create mode 100644 packages/system/http-cache-rd/Chart.yaml create mode 100644 packages/system/http-cache-rd/Makefile rename packages/system/{cozystack-resource-definitions => http-cache-rd}/cozyrds/http-cache.yaml (100%) create mode 100644 packages/system/http-cache-rd/templates/cozyrd.yaml create mode 100644 packages/system/http-cache-rd/values.yaml create mode 100644 packages/system/info-rd/Chart.yaml create mode 100644 packages/system/info-rd/Makefile rename packages/system/{cozystack-resource-definitions => info-rd}/cozyrds/info.yaml (100%) create mode 100644 packages/system/info-rd/templates/cozyrd.yaml create mode 100644 packages/system/info-rd/values.yaml create mode 100644 packages/system/ingress-rd/Chart.yaml create mode 100644 packages/system/ingress-rd/Makefile rename packages/system/{cozystack-resource-definitions => ingress-rd}/cozyrds/ingress.yaml (100%) create mode 100644 packages/system/ingress-rd/templates/cozyrd.yaml create mode 100644 packages/system/ingress-rd/values.yaml create mode 100644 packages/system/kafka-rd/Chart.yaml create mode 100644 packages/system/kafka-rd/Makefile rename packages/system/{cozystack-resource-definitions => kafka-rd}/cozyrds/kafka.yaml (100%) create mode 100644 packages/system/kafka-rd/templates/cozyrd.yaml create mode 100644 packages/system/kafka-rd/values.yaml create mode 100644 packages/system/kubernetes-rd/Chart.yaml create mode 100644 packages/system/kubernetes-rd/Makefile rename packages/system/{cozystack-resource-definitions => kubernetes-rd}/cozyrds/kubernetes.yaml (100%) create mode 100644 packages/system/kubernetes-rd/templates/cozyrd.yaml create mode 100644 packages/system/kubernetes-rd/values.yaml create mode 100644 packages/system/monitoring-rd/Chart.yaml create mode 100644 packages/system/monitoring-rd/Makefile rename packages/system/{cozystack-resource-definitions => monitoring-rd}/cozyrds/monitoring.yaml (100%) create mode 100644 packages/system/monitoring-rd/templates/cozyrd.yaml create mode 100644 packages/system/monitoring-rd/values.yaml create mode 100644 packages/system/mysql-rd/Chart.yaml create mode 100644 packages/system/mysql-rd/Makefile rename packages/system/{cozystack-resource-definitions => mysql-rd}/cozyrds/mysql.yaml (100%) create mode 100644 packages/system/mysql-rd/templates/cozyrd.yaml create mode 100644 packages/system/mysql-rd/values.yaml create mode 100644 packages/system/nats-rd/Chart.yaml create mode 100644 packages/system/nats-rd/Makefile rename packages/system/{cozystack-resource-definitions => nats-rd}/cozyrds/nats.yaml (100%) create mode 100644 packages/system/nats-rd/templates/cozyrd.yaml create mode 100644 packages/system/nats-rd/values.yaml create mode 100644 packages/system/postgres-rd/Chart.yaml create mode 100644 packages/system/postgres-rd/Makefile rename packages/system/{cozystack-resource-definitions => postgres-rd}/cozyrds/postgres.yaml (100%) create mode 100644 packages/system/postgres-rd/templates/cozyrd.yaml create mode 100644 packages/system/postgres-rd/values.yaml create mode 100644 packages/system/rabbitmq-rd/Chart.yaml create mode 100644 packages/system/rabbitmq-rd/Makefile rename packages/system/{cozystack-resource-definitions => rabbitmq-rd}/cozyrds/rabbitmq.yaml (100%) create mode 100644 packages/system/rabbitmq-rd/templates/cozyrd.yaml create mode 100644 packages/system/rabbitmq-rd/values.yaml create mode 100644 packages/system/redis-rd/Chart.yaml create mode 100644 packages/system/redis-rd/Makefile rename packages/system/{cozystack-resource-definitions => redis-rd}/cozyrds/redis.yaml (100%) create mode 100644 packages/system/redis-rd/templates/cozyrd.yaml create mode 100644 packages/system/redis-rd/values.yaml create mode 100644 packages/system/seaweedfs-rd/Chart.yaml create mode 100644 packages/system/seaweedfs-rd/Makefile rename packages/system/{cozystack-resource-definitions => seaweedfs-rd}/cozyrds/seaweedfs.yaml (100%) create mode 100644 packages/system/seaweedfs-rd/templates/cozyrd.yaml create mode 100644 packages/system/seaweedfs-rd/values.yaml create mode 100644 packages/system/tcp-balancer-rd/Chart.yaml create mode 100644 packages/system/tcp-balancer-rd/Makefile rename packages/system/{cozystack-resource-definitions => tcp-balancer-rd}/cozyrds/tcp-balancer.yaml (100%) create mode 100644 packages/system/tcp-balancer-rd/templates/cozyrd.yaml create mode 100644 packages/system/tcp-balancer-rd/values.yaml create mode 100644 packages/system/tenant-rd/Chart.yaml create mode 100644 packages/system/tenant-rd/Makefile rename packages/system/{cozystack-resource-definitions => tenant-rd}/cozyrds/tenant.yaml (100%) create mode 100644 packages/system/tenant-rd/templates/cozyrd.yaml create mode 100644 packages/system/tenant-rd/values.yaml create mode 100644 packages/system/virtual-machine-rd/Chart.yaml create mode 100644 packages/system/virtual-machine-rd/Makefile rename packages/system/{cozystack-resource-definitions => virtual-machine-rd}/cozyrds/virtual-machine.yaml (100%) create mode 100644 packages/system/virtual-machine-rd/templates/cozyrd.yaml create mode 100644 packages/system/virtual-machine-rd/values.yaml create mode 100644 packages/system/virtualprivatecloud-rd/Chart.yaml create mode 100644 packages/system/virtualprivatecloud-rd/Makefile rename packages/system/{cozystack-resource-definitions => virtualprivatecloud-rd}/cozyrds/virtualprivatecloud.yaml (100%) create mode 100644 packages/system/virtualprivatecloud-rd/templates/cozyrd.yaml create mode 100644 packages/system/virtualprivatecloud-rd/values.yaml create mode 100644 packages/system/vm-disk-rd/Chart.yaml create mode 100644 packages/system/vm-disk-rd/Makefile rename packages/system/{cozystack-resource-definitions => vm-disk-rd}/cozyrds/vm-disk.yaml (100%) create mode 100644 packages/system/vm-disk-rd/templates/cozyrd.yaml create mode 100644 packages/system/vm-disk-rd/values.yaml create mode 100644 packages/system/vm-instance-rd/Chart.yaml create mode 100644 packages/system/vm-instance-rd/Makefile rename packages/system/{cozystack-resource-definitions => vm-instance-rd}/cozyrds/vm-instance.yaml (100%) create mode 100644 packages/system/vm-instance-rd/templates/cozyrd.yaml create mode 100644 packages/system/vm-instance-rd/values.yaml create mode 100644 packages/system/vpn-rd/Chart.yaml create mode 100644 packages/system/vpn-rd/Makefile rename packages/system/{cozystack-resource-definitions => vpn-rd}/cozyrds/vpn.yaml (100%) create mode 100644 packages/system/vpn-rd/templates/cozyrd.yaml create mode 100644 packages/system/vpn-rd/values.yaml diff --git a/hack/update-crd.sh b/hack/update-crd.sh index 456bf842..b619b220 100755 --- a/hack/update-crd.sh +++ b/hack/update-crd.sh @@ -8,7 +8,6 @@ need yq; need jq; need base64 CHART_YAML="${CHART_YAML:-Chart.yaml}" VALUES_YAML="${VALUES_YAML:-values.yaml}" SCHEMA_JSON="${SCHEMA_JSON:-values.schema.json}" -CRD_DIR="../../system/cozystack-resource-definitions/cozyrds" [[ -f "$CHART_YAML" ]] || { echo "No $CHART_YAML found"; exit 1; } [[ -f "$SCHEMA_JSON" ]] || { echo "No $SCHEMA_JSON found"; exit 1; } @@ -22,6 +21,8 @@ if [[ -z "$NAME" ]]; then echo "Chart.yaml: .name is empty"; exit 1 fi +CRD_DIR="../../system/${NAME}-rd/cozyrds" + # Resolve icon path # Accepts: # /logos/foo.svg -> ./logos/foo.svg diff --git a/packages/core/platform/bundles/distro-full.yaml b/packages/core/platform/bundles/distro-full.yaml index b3079891..bf915d4e 100644 --- a/packages/core/platform/bundles/distro-full.yaml +++ b/packages/core/platform/bundles/distro-full.yaml @@ -62,11 +62,155 @@ releases: namespace: cozy-system dependsOn: [cilium] -- name: cozystack-resource-definitions - releaseName: cozystack-resource-definitions - chart: cozystack-resource-definitions +- name: bootbox-rd + releaseName: bootbox-rd + chart: bootbox-rd namespace: cozy-system - dependsOn: [cilium,cozystack-controller,cozystack-resource-definition-crd] + 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 diff --git a/packages/core/platform/bundles/paas-full.yaml b/packages/core/platform/bundles/paas-full.yaml index ab618deb..17851e23 100644 --- a/packages/core/platform/bundles/paas-full.yaml +++ b/packages/core/platform/bundles/paas-full.yaml @@ -106,11 +106,155 @@ releases: namespace: cozy-system dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller] -- name: cozystack-resource-definitions - releaseName: cozystack-resource-definitions - chart: cozystack-resource-definitions +- name: bootbox-rd + releaseName: bootbox-rd + chart: bootbox-rd namespace: cozy-system - dependsOn: [cilium,kubeovn,cozystack-api,cozystack-controller,cozystack-resource-definition-crd] + 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 diff --git a/packages/core/platform/bundles/paas-hosted.yaml b/packages/core/platform/bundles/paas-hosted.yaml index 87430468..dac39969 100644 --- a/packages/core/platform/bundles/paas-hosted.yaml +++ b/packages/core/platform/bundles/paas-hosted.yaml @@ -50,11 +50,155 @@ releases: namespace: cozy-system dependsOn: [cozystack-api,cozystack-controller] -- name: cozystack-resource-definitions - releaseName: cozystack-resource-definitions - chart: cozystack-resource-definitions +- name: bootbox-rd + releaseName: bootbox-rd + chart: bootbox-rd namespace: cozy-system - dependsOn: [cozystack-api,cozystack-controller,cozystack-resource-definition-crd] + 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 diff --git a/packages/system/cozystack-resource-definitions/Chart.yaml b/packages/system/bootbox-rd/Chart.yaml similarity index 75% rename from packages/system/cozystack-resource-definitions/Chart.yaml rename to packages/system/bootbox-rd/Chart.yaml index 39cb9431..0a35867d 100644 --- a/packages/system/cozystack-resource-definitions/Chart.yaml +++ b/packages/system/bootbox-rd/Chart.yaml @@ -1,3 +1,3 @@ apiVersion: v2 -name: cozystack-resource-definitions +name: bootbox-rd version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/cozystack-resource-definitions/Makefile b/packages/system/bootbox-rd/Makefile similarity index 60% rename from packages/system/cozystack-resource-definitions/Makefile rename to packages/system/bootbox-rd/Makefile index 00e8bece..b570a84f 100644 --- a/packages/system/cozystack-resource-definitions/Makefile +++ b/packages/system/bootbox-rd/Makefile @@ -1,4 +1,4 @@ -export NAME=cozystack-resource-definitions +export NAME=bootbox-rd export NAMESPACE=cozy-system include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/bootbox.yaml b/packages/system/bootbox-rd/cozyrds/bootbox.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/bootbox.yaml rename to packages/system/bootbox-rd/cozyrds/bootbox.yaml diff --git a/packages/system/cozystack-resource-definitions/templates/cozyrds.yaml b/packages/system/bootbox-rd/templates/cozyrd.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/templates/cozyrds.yaml rename to packages/system/bootbox-rd/templates/cozyrd.yaml diff --git a/packages/system/cozystack-resource-definitions/values.yaml b/packages/system/bootbox-rd/values.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/values.yaml rename to packages/system/bootbox-rd/values.yaml diff --git a/packages/system/bucket-rd/Chart.yaml b/packages/system/bucket-rd/Chart.yaml new file mode 100644 index 00000000..352a949c --- /dev/null +++ b/packages/system/bucket-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: bucket-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/bucket-rd/Makefile b/packages/system/bucket-rd/Makefile new file mode 100644 index 00000000..53e89367 --- /dev/null +++ b/packages/system/bucket-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=bucket-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/bucket.yaml b/packages/system/bucket-rd/cozyrds/bucket.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/bucket.yaml rename to packages/system/bucket-rd/cozyrds/bucket.yaml diff --git a/packages/system/bucket-rd/templates/cozyrd.yaml b/packages/system/bucket-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/bucket-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/bucket-rd/values.yaml b/packages/system/bucket-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/bucket-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/clickhouse-rd/Chart.yaml b/packages/system/clickhouse-rd/Chart.yaml new file mode 100644 index 00000000..583d39a6 --- /dev/null +++ b/packages/system/clickhouse-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: clickhouse-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/clickhouse-rd/Makefile b/packages/system/clickhouse-rd/Makefile new file mode 100644 index 00000000..4ac0738a --- /dev/null +++ b/packages/system/clickhouse-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=clickhouse-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/clickhouse.yaml b/packages/system/clickhouse-rd/cozyrds/clickhouse.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/clickhouse.yaml rename to packages/system/clickhouse-rd/cozyrds/clickhouse.yaml diff --git a/packages/system/clickhouse-rd/templates/cozyrd.yaml b/packages/system/clickhouse-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/clickhouse-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/clickhouse-rd/values.yaml b/packages/system/clickhouse-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/clickhouse-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/etcd-rd/Chart.yaml b/packages/system/etcd-rd/Chart.yaml new file mode 100644 index 00000000..8aa00f9b --- /dev/null +++ b/packages/system/etcd-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: etcd-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/etcd-rd/Makefile b/packages/system/etcd-rd/Makefile new file mode 100644 index 00000000..ad91bad9 --- /dev/null +++ b/packages/system/etcd-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=etcd-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/etcd.yaml b/packages/system/etcd-rd/cozyrds/etcd.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/etcd.yaml rename to packages/system/etcd-rd/cozyrds/etcd.yaml diff --git a/packages/system/etcd-rd/templates/cozyrd.yaml b/packages/system/etcd-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/etcd-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/etcd-rd/values.yaml b/packages/system/etcd-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/etcd-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/ferretdb-rd/Chart.yaml b/packages/system/ferretdb-rd/Chart.yaml new file mode 100644 index 00000000..6e2730f1 --- /dev/null +++ b/packages/system/ferretdb-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: ferretdb-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/ferretdb-rd/Makefile b/packages/system/ferretdb-rd/Makefile new file mode 100644 index 00000000..f6814169 --- /dev/null +++ b/packages/system/ferretdb-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=ferretdb-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/ferretdb.yaml b/packages/system/ferretdb-rd/cozyrds/ferretdb.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/ferretdb.yaml rename to packages/system/ferretdb-rd/cozyrds/ferretdb.yaml diff --git a/packages/system/ferretdb-rd/templates/cozyrd.yaml b/packages/system/ferretdb-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/ferretdb-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/ferretdb-rd/values.yaml b/packages/system/ferretdb-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/ferretdb-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/foundationdb-rd/Chart.yaml b/packages/system/foundationdb-rd/Chart.yaml new file mode 100644 index 00000000..1c8afe3a --- /dev/null +++ b/packages/system/foundationdb-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: foundationdb-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/foundationdb-rd/Makefile b/packages/system/foundationdb-rd/Makefile new file mode 100644 index 00000000..b6e6d41a --- /dev/null +++ b/packages/system/foundationdb-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=foundationdb-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/foundationdb.yaml b/packages/system/foundationdb-rd/cozyrds/foundationdb.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/foundationdb.yaml rename to packages/system/foundationdb-rd/cozyrds/foundationdb.yaml diff --git a/packages/system/foundationdb-rd/templates/cozyrd.yaml b/packages/system/foundationdb-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/foundationdb-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/foundationdb-rd/values.yaml b/packages/system/foundationdb-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/foundationdb-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/http-cache-rd/Chart.yaml b/packages/system/http-cache-rd/Chart.yaml new file mode 100644 index 00000000..c82ad1aa --- /dev/null +++ b/packages/system/http-cache-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: http-cache-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/http-cache-rd/Makefile b/packages/system/http-cache-rd/Makefile new file mode 100644 index 00000000..cf367cf4 --- /dev/null +++ b/packages/system/http-cache-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=http-cache-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/http-cache.yaml b/packages/system/http-cache-rd/cozyrds/http-cache.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/http-cache.yaml rename to packages/system/http-cache-rd/cozyrds/http-cache.yaml diff --git a/packages/system/http-cache-rd/templates/cozyrd.yaml b/packages/system/http-cache-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/http-cache-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/http-cache-rd/values.yaml b/packages/system/http-cache-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/http-cache-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/info-rd/Chart.yaml b/packages/system/info-rd/Chart.yaml new file mode 100644 index 00000000..2f354177 --- /dev/null +++ b/packages/system/info-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: info-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/info-rd/Makefile b/packages/system/info-rd/Makefile new file mode 100644 index 00000000..7cfed08d --- /dev/null +++ b/packages/system/info-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=info-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/info.yaml b/packages/system/info-rd/cozyrds/info.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/info.yaml rename to packages/system/info-rd/cozyrds/info.yaml diff --git a/packages/system/info-rd/templates/cozyrd.yaml b/packages/system/info-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/info-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/info-rd/values.yaml b/packages/system/info-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/info-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/ingress-rd/Chart.yaml b/packages/system/ingress-rd/Chart.yaml new file mode 100644 index 00000000..2e1b77d7 --- /dev/null +++ b/packages/system/ingress-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: ingress-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/ingress-rd/Makefile b/packages/system/ingress-rd/Makefile new file mode 100644 index 00000000..82976cc6 --- /dev/null +++ b/packages/system/ingress-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=ingress-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/ingress.yaml b/packages/system/ingress-rd/cozyrds/ingress.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/ingress.yaml rename to packages/system/ingress-rd/cozyrds/ingress.yaml diff --git a/packages/system/ingress-rd/templates/cozyrd.yaml b/packages/system/ingress-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/ingress-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/ingress-rd/values.yaml b/packages/system/ingress-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/ingress-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/kafka-rd/Chart.yaml b/packages/system/kafka-rd/Chart.yaml new file mode 100644 index 00000000..87b84e32 --- /dev/null +++ b/packages/system/kafka-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: kafka-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/kafka-rd/Makefile b/packages/system/kafka-rd/Makefile new file mode 100644 index 00000000..3c333dcf --- /dev/null +++ b/packages/system/kafka-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=kafka-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/kafka.yaml b/packages/system/kafka-rd/cozyrds/kafka.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/kafka.yaml rename to packages/system/kafka-rd/cozyrds/kafka.yaml diff --git a/packages/system/kafka-rd/templates/cozyrd.yaml b/packages/system/kafka-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/kafka-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/kafka-rd/values.yaml b/packages/system/kafka-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/kafka-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/kubernetes-rd/Chart.yaml b/packages/system/kubernetes-rd/Chart.yaml new file mode 100644 index 00000000..8fad1a45 --- /dev/null +++ b/packages/system/kubernetes-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: kubernetes-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/kubernetes-rd/Makefile b/packages/system/kubernetes-rd/Makefile new file mode 100644 index 00000000..45969603 --- /dev/null +++ b/packages/system/kubernetes-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=kubernetes-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/kubernetes.yaml b/packages/system/kubernetes-rd/cozyrds/kubernetes.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/kubernetes.yaml rename to packages/system/kubernetes-rd/cozyrds/kubernetes.yaml diff --git a/packages/system/kubernetes-rd/templates/cozyrd.yaml b/packages/system/kubernetes-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/kubernetes-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/kubernetes-rd/values.yaml b/packages/system/kubernetes-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/kubernetes-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/monitoring-rd/Chart.yaml b/packages/system/monitoring-rd/Chart.yaml new file mode 100644 index 00000000..cac8a99d --- /dev/null +++ b/packages/system/monitoring-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: monitoring-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/monitoring-rd/Makefile b/packages/system/monitoring-rd/Makefile new file mode 100644 index 00000000..ecce61e3 --- /dev/null +++ b/packages/system/monitoring-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=monitoring-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml b/packages/system/monitoring-rd/cozyrds/monitoring.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/monitoring.yaml rename to packages/system/monitoring-rd/cozyrds/monitoring.yaml diff --git a/packages/system/monitoring-rd/templates/cozyrd.yaml b/packages/system/monitoring-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/monitoring-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/monitoring-rd/values.yaml b/packages/system/monitoring-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/monitoring-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/mysql-rd/Chart.yaml b/packages/system/mysql-rd/Chart.yaml new file mode 100644 index 00000000..d3c6b081 --- /dev/null +++ b/packages/system/mysql-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: mysql-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/mysql-rd/Makefile b/packages/system/mysql-rd/Makefile new file mode 100644 index 00000000..a2d28923 --- /dev/null +++ b/packages/system/mysql-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=mysql-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/mysql.yaml b/packages/system/mysql-rd/cozyrds/mysql.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/mysql.yaml rename to packages/system/mysql-rd/cozyrds/mysql.yaml diff --git a/packages/system/mysql-rd/templates/cozyrd.yaml b/packages/system/mysql-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/mysql-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/mysql-rd/values.yaml b/packages/system/mysql-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/mysql-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/nats-rd/Chart.yaml b/packages/system/nats-rd/Chart.yaml new file mode 100644 index 00000000..9be57a87 --- /dev/null +++ b/packages/system/nats-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: nats-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/nats-rd/Makefile b/packages/system/nats-rd/Makefile new file mode 100644 index 00000000..2b5b232e --- /dev/null +++ b/packages/system/nats-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=nats-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/nats.yaml b/packages/system/nats-rd/cozyrds/nats.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/nats.yaml rename to packages/system/nats-rd/cozyrds/nats.yaml diff --git a/packages/system/nats-rd/templates/cozyrd.yaml b/packages/system/nats-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/nats-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/nats-rd/values.yaml b/packages/system/nats-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/nats-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/postgres-rd/Chart.yaml b/packages/system/postgres-rd/Chart.yaml new file mode 100644 index 00000000..ca2e2d2a --- /dev/null +++ b/packages/system/postgres-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: postgres-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/postgres-rd/Makefile b/packages/system/postgres-rd/Makefile new file mode 100644 index 00000000..0c8b1cb0 --- /dev/null +++ b/packages/system/postgres-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=postgres-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/postgres.yaml b/packages/system/postgres-rd/cozyrds/postgres.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/postgres.yaml rename to packages/system/postgres-rd/cozyrds/postgres.yaml diff --git a/packages/system/postgres-rd/templates/cozyrd.yaml b/packages/system/postgres-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/postgres-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/postgres-rd/values.yaml b/packages/system/postgres-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/postgres-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/rabbitmq-rd/Chart.yaml b/packages/system/rabbitmq-rd/Chart.yaml new file mode 100644 index 00000000..9fa858de --- /dev/null +++ b/packages/system/rabbitmq-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: rabbitmq-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/rabbitmq-rd/Makefile b/packages/system/rabbitmq-rd/Makefile new file mode 100644 index 00000000..9c5be0d5 --- /dev/null +++ b/packages/system/rabbitmq-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=rabbitmq-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/rabbitmq.yaml b/packages/system/rabbitmq-rd/cozyrds/rabbitmq.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/rabbitmq.yaml rename to packages/system/rabbitmq-rd/cozyrds/rabbitmq.yaml diff --git a/packages/system/rabbitmq-rd/templates/cozyrd.yaml b/packages/system/rabbitmq-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/rabbitmq-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/rabbitmq-rd/values.yaml b/packages/system/rabbitmq-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/rabbitmq-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/redis-rd/Chart.yaml b/packages/system/redis-rd/Chart.yaml new file mode 100644 index 00000000..4ccfa4fd --- /dev/null +++ b/packages/system/redis-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: redis-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/redis-rd/Makefile b/packages/system/redis-rd/Makefile new file mode 100644 index 00000000..bed18877 --- /dev/null +++ b/packages/system/redis-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=redis-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/redis.yaml b/packages/system/redis-rd/cozyrds/redis.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/redis.yaml rename to packages/system/redis-rd/cozyrds/redis.yaml diff --git a/packages/system/redis-rd/templates/cozyrd.yaml b/packages/system/redis-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/redis-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/redis-rd/values.yaml b/packages/system/redis-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/redis-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/seaweedfs-rd/Chart.yaml b/packages/system/seaweedfs-rd/Chart.yaml new file mode 100644 index 00000000..5799783b --- /dev/null +++ b/packages/system/seaweedfs-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: seaweedfs-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/seaweedfs-rd/Makefile b/packages/system/seaweedfs-rd/Makefile new file mode 100644 index 00000000..5be03dbb --- /dev/null +++ b/packages/system/seaweedfs-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=seaweedfs-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/seaweedfs.yaml b/packages/system/seaweedfs-rd/cozyrds/seaweedfs.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/seaweedfs.yaml rename to packages/system/seaweedfs-rd/cozyrds/seaweedfs.yaml diff --git a/packages/system/seaweedfs-rd/templates/cozyrd.yaml b/packages/system/seaweedfs-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/seaweedfs-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/seaweedfs-rd/values.yaml b/packages/system/seaweedfs-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/seaweedfs-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/tcp-balancer-rd/Chart.yaml b/packages/system/tcp-balancer-rd/Chart.yaml new file mode 100644 index 00000000..9543455e --- /dev/null +++ b/packages/system/tcp-balancer-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: tcp-balancer-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/tcp-balancer-rd/Makefile b/packages/system/tcp-balancer-rd/Makefile new file mode 100644 index 00000000..39a0495f --- /dev/null +++ b/packages/system/tcp-balancer-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=tcp-balancer-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/tcp-balancer.yaml b/packages/system/tcp-balancer-rd/cozyrds/tcp-balancer.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/tcp-balancer.yaml rename to packages/system/tcp-balancer-rd/cozyrds/tcp-balancer.yaml diff --git a/packages/system/tcp-balancer-rd/templates/cozyrd.yaml b/packages/system/tcp-balancer-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/tcp-balancer-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/tcp-balancer-rd/values.yaml b/packages/system/tcp-balancer-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/tcp-balancer-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/tenant-rd/Chart.yaml b/packages/system/tenant-rd/Chart.yaml new file mode 100644 index 00000000..ad3d27f4 --- /dev/null +++ b/packages/system/tenant-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: tenant-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/tenant-rd/Makefile b/packages/system/tenant-rd/Makefile new file mode 100644 index 00000000..37852fe6 --- /dev/null +++ b/packages/system/tenant-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=tenant-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/tenant.yaml b/packages/system/tenant-rd/cozyrds/tenant.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/tenant.yaml rename to packages/system/tenant-rd/cozyrds/tenant.yaml diff --git a/packages/system/tenant-rd/templates/cozyrd.yaml b/packages/system/tenant-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/tenant-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/tenant-rd/values.yaml b/packages/system/tenant-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/tenant-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/virtual-machine-rd/Chart.yaml b/packages/system/virtual-machine-rd/Chart.yaml new file mode 100644 index 00000000..6228a221 --- /dev/null +++ b/packages/system/virtual-machine-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: virtual-machine-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/virtual-machine-rd/Makefile b/packages/system/virtual-machine-rd/Makefile new file mode 100644 index 00000000..4d59946b --- /dev/null +++ b/packages/system/virtual-machine-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=virtual-machine-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/virtual-machine.yaml b/packages/system/virtual-machine-rd/cozyrds/virtual-machine.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/virtual-machine.yaml rename to packages/system/virtual-machine-rd/cozyrds/virtual-machine.yaml diff --git a/packages/system/virtual-machine-rd/templates/cozyrd.yaml b/packages/system/virtual-machine-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/virtual-machine-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/virtual-machine-rd/values.yaml b/packages/system/virtual-machine-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/virtual-machine-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/virtualprivatecloud-rd/Chart.yaml b/packages/system/virtualprivatecloud-rd/Chart.yaml new file mode 100644 index 00000000..be5235dc --- /dev/null +++ b/packages/system/virtualprivatecloud-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: virtualprivatecloud-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/virtualprivatecloud-rd/Makefile b/packages/system/virtualprivatecloud-rd/Makefile new file mode 100644 index 00000000..9d9b6c50 --- /dev/null +++ b/packages/system/virtualprivatecloud-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=virtualprivatecloud-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/virtualprivatecloud.yaml b/packages/system/virtualprivatecloud-rd/cozyrds/virtualprivatecloud.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/virtualprivatecloud.yaml rename to packages/system/virtualprivatecloud-rd/cozyrds/virtualprivatecloud.yaml diff --git a/packages/system/virtualprivatecloud-rd/templates/cozyrd.yaml b/packages/system/virtualprivatecloud-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/virtualprivatecloud-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/virtualprivatecloud-rd/values.yaml b/packages/system/virtualprivatecloud-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/virtualprivatecloud-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/vm-disk-rd/Chart.yaml b/packages/system/vm-disk-rd/Chart.yaml new file mode 100644 index 00000000..d405b0f0 --- /dev/null +++ b/packages/system/vm-disk-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: vm-disk-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/vm-disk-rd/Makefile b/packages/system/vm-disk-rd/Makefile new file mode 100644 index 00000000..e6de276d --- /dev/null +++ b/packages/system/vm-disk-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=vm-disk-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/vm-disk.yaml b/packages/system/vm-disk-rd/cozyrds/vm-disk.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/vm-disk.yaml rename to packages/system/vm-disk-rd/cozyrds/vm-disk.yaml diff --git a/packages/system/vm-disk-rd/templates/cozyrd.yaml b/packages/system/vm-disk-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/vm-disk-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/vm-disk-rd/values.yaml b/packages/system/vm-disk-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/vm-disk-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/vm-instance-rd/Chart.yaml b/packages/system/vm-instance-rd/Chart.yaml new file mode 100644 index 00000000..270db7d6 --- /dev/null +++ b/packages/system/vm-instance-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: vm-instance-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/vm-instance-rd/Makefile b/packages/system/vm-instance-rd/Makefile new file mode 100644 index 00000000..badc4951 --- /dev/null +++ b/packages/system/vm-instance-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=vm-instance-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/vm-instance.yaml b/packages/system/vm-instance-rd/cozyrds/vm-instance.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/vm-instance.yaml rename to packages/system/vm-instance-rd/cozyrds/vm-instance.yaml diff --git a/packages/system/vm-instance-rd/templates/cozyrd.yaml b/packages/system/vm-instance-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/vm-instance-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/vm-instance-rd/values.yaml b/packages/system/vm-instance-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/vm-instance-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/vpn-rd/Chart.yaml b/packages/system/vpn-rd/Chart.yaml new file mode 100644 index 00000000..fe0a2dd3 --- /dev/null +++ b/packages/system/vpn-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: vpn-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/vpn-rd/Makefile b/packages/system/vpn-rd/Makefile new file mode 100644 index 00000000..c6ee47bb --- /dev/null +++ b/packages/system/vpn-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=vpn-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/cozystack-resource-definitions/cozyrds/vpn.yaml b/packages/system/vpn-rd/cozyrds/vpn.yaml similarity index 100% rename from packages/system/cozystack-resource-definitions/cozyrds/vpn.yaml rename to packages/system/vpn-rd/cozyrds/vpn.yaml diff --git a/packages/system/vpn-rd/templates/cozyrd.yaml b/packages/system/vpn-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/vpn-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/vpn-rd/values.yaml b/packages/system/vpn-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/vpn-rd/values.yaml @@ -0,0 +1 @@ +{} From 666eeffa4706634e1e963797fd2641e520822362 Mon Sep 17 00:00:00 2001 From: Aleksei Sviridkin Date: Mon, 5 Jan 2026 18:19:36 +0300 Subject: [PATCH 41/78] [kubevirt-operator] Revert incorrect case change in VM alerts (#1804) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does Reverts PR #1770 which incorrectly changed status/phase checks from lowercase to uppercase. The actual KubeVirt metrics use **lowercase**: - `kubevirt_vm_info` uses `status="running"` (not `"Running"`) - `kubevirt_vmi_info` uses `phase="running"` (not `"Running"`) ### Verification Queried virt-controller metrics directly in the instories cluster: ``` kubevirt_vm_info{...,status="running",status_group="running",...} 1 kubevirt_vmi_info{...,phase="running",...} 1 ``` Note: `kubectl get vm` shows `STATUS: Running` with capital R, but this is display formatting — the actual metric labels use lowercase. ### Release note ```release-note [kubevirt-operator] Fix VM alert rules to use correct lowercase status values ``` --- packages/system/kubevirt-operator/alerts/PrometheusRule.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/system/kubevirt-operator/alerts/PrometheusRule.yaml b/packages/system/kubevirt-operator/alerts/PrometheusRule.yaml index c4d73cc5..72fabfa0 100644 --- a/packages/system/kubevirt-operator/alerts/PrometheusRule.yaml +++ b/packages/system/kubevirt-operator/alerts/PrometheusRule.yaml @@ -10,7 +10,7 @@ spec: expr: | max_over_time( kubevirt_vm_info{ - status!="Running", + status!="running", exported_namespace=~".+", name=~".+" }[10m] @@ -27,7 +27,7 @@ spec: expr: | max_over_time( kubevirt_vmi_info{ - phase!="Running", + phase!="running", exported_namespace=~".+", name=~".+" }[10m] From 868a7497d0cc26af923340d5fcfb1ffa7aad0235 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 5 Jan 2026 16:29:51 +0100 Subject: [PATCH 42/78] fix(ci): ensure correct latest release after backport publishing (#1800) ## What this PR does Fixes an issue where backport releases incorrectly became marked as "Latest" despite passing `make_latest: 'false'` to the GitHub API. **Root cause:** The `getLatestRelease()` API returns the release with the "Latest" flag, not the highest semver version. Combined with race conditions during parallel release publishing and GitHub API potentially ignoring `make_latest: 'false'`, backport releases were incorrectly marked as latest. **Solution:** - Replace `getLatestRelease()` with semver-based max version detection across all published releases - After publishing a backport release, explicitly restore the latest flag on the highest semver release - Remove unused dead code from `tags.yaml` workflow ### Release note ```release-note [ci] Fix latest release detection to use semver comparison instead of GitHub's "Latest" flag ``` --- .github/workflows/pull-requests-release.yaml | 138 +++++++++++-------- .github/workflows/tags.yaml | 26 ---- 2 files changed, 83 insertions(+), 81 deletions(-) diff --git a/.github/workflows/pull-requests-release.yaml b/.github/workflows/pull-requests-release.yaml index 1e13fa88..72f31b54 100644 --- a/.github/workflows/pull-requests-release.yaml +++ b/.github/workflows/pull-requests-release.yaml @@ -110,67 +110,95 @@ jobs: } } - # Get the latest published release - - name: Get the latest published release - id: latest_release - uses: actions/github-script@v7 - with: - script: | - try { - const rel = await github.rest.repos.getLatestRelease({ - owner: context.repo.owner, - repo: context.repo.repo - }); - core.setOutput('tag', rel.data.tag_name); - } catch (_) { - core.setOutput('tag', ''); - } - - # Compare current tag vs latest using semver-utils - - name: Semver compare - id: semver - uses: madhead/semver-utils@v4.3.0 - with: - version: ${{ steps.get_tag.outputs.tag }} - compare-to: ${{ steps.latest_release.outputs.tag }} - - # Derive flags: prerelease? make_latest? - - name: Calculate publish flags - id: flags - uses: actions/github-script@v7 - with: - script: | - const tag = '${{ steps.get_tag.outputs.tag }}'; // v0.31.5-rc.1 - const m = tag.match(/^v(\d+\.\d+\.\d+)(-(?:alpha|beta|rc)\.\d+)?$/); - if (!m) { - core.setFailed(`❌ tag '${tag}' must match 'vX.Y.Z' or 'vX.Y.Z-(alpha|beta|rc).N'`); - return; - } - const version = m[1] + (m[2] ?? ''); // 0.31.5-rc.1 - const isRc = Boolean(m[2]); - core.setOutput('is_rc', isRc); - const outdated = '${{ steps.semver.outputs.comparison-result }}' === '<'; - core.setOutput('make_latest', isRc || outdated ? 'false' : 'legacy'); - - # Publish draft release with correct flags + # Publish draft release and ensure correct latest flag - name: Publish draft release uses: actions/github-script@v7 with: script: | const tag = '${{ steps.get_tag.outputs.tag }}'; + const m = tag.match(/^v(\d+\.\d+\.\d+)(-(?:alpha|beta|rc)\.\d+)?$/); + if (!m) { + core.setFailed(`❌ tag '${tag}' must match 'vX.Y.Z' or 'vX.Y.Z-(alpha|beta|rc).N'`); + return; + } + const isRc = Boolean(m[2]); + + // Parse semver string to comparable numbers + function parseSemver(v) { + const match = v.replace(/^v/, '').match(/^(\d+)\.(\d+)\.(\d+)/); + if (!match) return null; + return { + major: parseInt(match[1]), + minor: parseInt(match[2]), + patch: parseInt(match[3]) + }; + } + + // Compare two semver objects + function compareSemver(a, b) { + if (a.major !== b.major) return a.major - b.major; + if (a.minor !== b.minor) return a.minor - b.minor; + return a.patch - b.patch; + } + + const currentSemver = parseSemver(tag); + + // Get all releases const releases = await github.rest.repos.listReleases({ owner: context.repo.owner, - repo: context.repo.repo - }); - const draft = releases.data.find(r => r.tag_name === tag && r.draft); - if (!draft) throw new Error(`Draft release for ${tag} not found`); - await github.rest.repos.updateRelease({ - owner: context.repo.owner, - repo: context.repo.repo, - release_id: draft.id, - draft: false, - prerelease: ${{ steps.flags.outputs.is_rc }}, - make_latest: '${{ steps.flags.outputs.make_latest }}' + repo: context.repo.repo, + per_page: 100 }); - console.log(`🚀 Published release for ${tag}`); + // Find draft release to publish + const draft = releases.data.find(r => r.tag_name === tag && r.draft); + if (!draft) throw new Error(`Draft release for ${tag} not found`); + + // Find max semver among published releases (excluding current draft) + const publishedReleases = releases.data + .filter(r => !r.draft && !r.prerelease) + .filter(r => /^v\d+\.\d+\.\d+$/.test(r.tag_name)) + .map(r => ({ id: r.id, tag: r.tag_name, semver: parseSemver(r.tag_name) })) + .filter(r => r.semver !== null); + + let maxRelease = null; + for (const rel of publishedReleases) { + if (!maxRelease || compareSemver(rel.semver, maxRelease.semver) > 0) { + maxRelease = rel; + } + } + + // Determine if this release should be latest + const isOutdated = maxRelease && compareSemver(currentSemver, maxRelease.semver) < 0; + const makeLatest = (isRc || isOutdated) ? 'false' : 'true'; + + if (isRc) { + console.log(`🏷️ ${tag} is a prerelease, make_latest: false`); + } else if (isOutdated) { + console.log(`🏷️ ${tag} < ${maxRelease.tag} (max semver), make_latest: false`); + } else { + console.log(`🏷️ ${tag} is the highest version, make_latest: true`); + } + + // Publish the release + await github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: draft.id, + draft: false, + prerelease: isRc, + make_latest: makeLatest + }); + console.log(`🚀 Published release ${tag}`); + + // If this is a backport/outdated release, ensure the correct release is marked as latest + if (isOutdated && maxRelease) { + console.log(`🔧 Ensuring ${maxRelease.tag} remains the latest release...`); + await github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: maxRelease.id, + make_latest: 'true' + }); + console.log(`✅ Restored ${maxRelease.tag} as latest release`); + } diff --git a/.github/workflows/tags.yaml b/.github/workflows/tags.yaml index 80100f23..16fcbede 100644 --- a/.github/workflows/tags.yaml +++ b/.github/workflows/tags.yaml @@ -123,32 +123,6 @@ jobs: git commit -m "Prepare release ${GITHUB_REF#refs/tags/}" -s || echo "No changes to commit" git push origin HEAD || true - # Get `latest_version` from latest published release - - name: Get latest published release - if: steps.check_release.outputs.skip == 'false' - id: latest_release - uses: actions/github-script@v7 - with: - script: | - try { - const rel = await github.rest.repos.getLatestRelease({ - owner: context.repo.owner, - repo: context.repo.repo - }); - core.setOutput('tag', rel.data.tag_name); - } catch (_) { - core.setOutput('tag', ''); - } - - # 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 if: steps.check_release.outputs.skip == 'false' From e7b62ca3c8aff8d1837f693c8bb13d7b93526434 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 5 Jan 2026 17:53:33 +0100 Subject: [PATCH 43/78] [platform] Replace Helm lookup with valuesFrom mechanism (#1787) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does Replaces Helm lookup functions with FluxCD valuesFrom mechanism for passing configuration to HelmReleases. This provides cleaner config propagation and eliminates the need for force reconcile controllers. ### Changes: **Platform/Tenant charts:** - Add Secret `cozystack-values` creation in platform chart (for tenant-root and system namespaces) - Add Secret `cozystack-values` creation in tenant chart (for child namespaces) **cozystack-api:** - Add `valuesFrom` references to HelmRelease when creating applications - Filter keys starting with `_` when returning Application specs - Validate that user values don't contain `_` prefixed keys **cozystack-controller:** - Add validation that HelmRelease contains correct valuesFrom configuration - Remove `CozystackConfigReconciler` (no longer needed) - Remove `TenantHelmReconciler` (no longer needed) **Helm charts (40+ files):** - Add helper templates in cozy-lib for `_cluster`/`_namespace` access - Replace ConfigMap lookups with `.Values._cluster.*` - Replace Namespace annotation lookups with `.Values._namespace.*` ### Architecture: ``` Secret cozystack-values (in each namespace) ├── _cluster: YAML with data from ConfigMaps (cozystack, cozystack-branding, cozystack-scheduling) └── _namespace: YAML with namespace service references (etcd, host, ingress, monitoring, seaweedfs) HelmRelease └── spec.valuesFrom: ├── Secret/cozystack-values → _namespace → .Values._namespace └── Secret/cozystack-values → _cluster → .Values._cluster ``` ### Release note ```release-note [platform] Replace Helm lookup functions with FluxCD valuesFrom mechanism for configuration propagation ``` ## Summary by CodeRabbit * **New Features** * Helm releases and namespaces now source centralized cluster/namespace configuration via a new secret (cozystack-values), and many templates read values from chart-provided _cluster/_namespace entries. * **Bug Fixes** * API now rejects application specs containing reserved keys prefixed with "_" to prevent invalid configurations. * **Refactor** * Two background reconciler controllers were removed from startup, simplifying controller initialization. ✏️ Tip: You can customize this high-level summary in your review settings. --- cmd/cozystack-controller/main.go | 16 -- ...ystackresourcedefinition_helmreconciler.go | 37 +++- internal/controller/system_helm_reconciler.go | 140 --------------- internal/controller/tenant_helm_reconciler.go | 159 ------------------ .../apps/bucket/templates/bucketclaim.yaml | 3 +- .../apps/bucket/templates/helmrelease.yaml | 3 + .../apps/clickhouse/templates/chkeeper.yaml | 3 +- .../apps/clickhouse/templates/clickhouse.yaml | 3 +- .../apps/ferretdb/templates/postgres.yaml | 5 +- .../apps/foundationdb/templates/cluster.yaml | 3 +- .../apps/kubernetes/templates/cluster.yaml | 12 +- .../helmreleases/monitoring-agents.yaml | 3 +- .../helmreleases/vertical-pod-autoscaler.yaml | 6 +- .../apps/kubernetes/templates/ingress.yaml | 3 +- packages/apps/nats/templates/nats.yaml | 6 +- packages/apps/postgres/templates/db.yaml | 5 +- packages/apps/tenant/templates/etcd.yaml | 3 + packages/apps/tenant/templates/info.yaml | 3 + packages/apps/tenant/templates/ingress.yaml | 3 + .../apps/tenant/templates/keycloakgroups.yaml | 3 +- .../apps/tenant/templates/monitoring.yaml | 3 + packages/apps/tenant/templates/namespace.yaml | 86 +++++++--- packages/apps/tenant/templates/seaweedfs.yaml | 3 + .../virtual-machine/templates/_helpers.tpl | 5 +- .../apps/vm-instance/templates/_helpers.tpl | 5 +- packages/apps/vpn/templates/secret.yaml | 3 +- packages/core/platform/templates/apps.yaml | 51 ++++++ .../core/platform/templates/helmreleases.yaml | 3 + .../core/platform/templates/namespaces.yaml | 36 ++++ .../bootbox/templates/matchbox/ingress.yaml | 9 +- .../bootbox/templates/matchbox/machines.yaml | 7 +- .../extra/etcd/templates/etcd-cluster.yaml | 5 +- .../info/templates/dashboard-resourcemap.yaml | 3 +- packages/extra/info/templates/kubeconfig.yaml | 17 +- .../ingress/templates/nginx-ingress.yaml | 8 +- .../templates/alerta/alerta-db.yaml | 5 +- .../monitoring/templates/alerta/alerta.yaml | 9 +- .../monitoring/templates/grafana/db.yaml | 5 +- .../monitoring/templates/grafana/grafana.yaml | 9 +- .../templates/client/cosi-deployment.yaml | 4 +- .../extra/seaweedfs/templates/ingress.yaml | 8 +- .../extra/seaweedfs/templates/seaweedfs.yaml | 8 +- .../cozy-lib/templates/_cozyconfig.tpl | 127 +++++++++++++- packages/system/bucket/templates/ingress.yaml | 8 +- .../templates/cluster-issuers.yaml | 3 +- .../cozystack-api/templates/api-ingress.yaml | 7 +- .../system/dashboard/templates/configmap.yaml | 14 +- .../dashboard/templates/gatekeeper.yaml | 5 +- .../system/dashboard/templates/ingress.yaml | 9 +- .../dashboard/templates/keycloakclient.yaml | 5 +- .../dashboard/templates/nginx-config.yaml | 3 +- .../templates/configure-kk.yaml | 14 +- packages/system/keycloak/templates/db.yaml | 5 +- .../system/keycloak/templates/ingress.yaml | 7 +- packages/system/keycloak/templates/sts.yaml | 5 +- .../templates/cdi-uploadproxy-ingress.yaml | 7 +- .../templates/vm-exportproxy-ingress.yaml | 7 +- .../cozy-lib-tests/tests/quota_values.yaml | 3 + pkg/registry/apps/application/rest.go | 59 ++++++- 59 files changed, 494 insertions(+), 505 deletions(-) delete mode 100644 internal/controller/system_helm_reconciler.go delete mode 100644 internal/controller/tenant_helm_reconciler.go diff --git a/cmd/cozystack-controller/main.go b/cmd/cozystack-controller/main.go index 91889224..0e7199d3 100644 --- a/cmd/cozystack-controller/main.go +++ b/cmd/cozystack-controller/main.go @@ -200,22 +200,6 @@ func main() { os.Exit(1) } - if err = (&controller.TenantHelmReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "TenantHelmReconciler") - os.Exit(1) - } - - if err = (&controller.CozystackConfigReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "CozystackConfigReconciler") - os.Exit(1) - } - cozyAPIKind := "DaemonSet" if reconcileDeployment { cozyAPIKind = "Deployment" diff --git a/internal/controller/cozystackresourcedefinition_helmreconciler.go b/internal/controller/cozystackresourcedefinition_helmreconciler.go index c086b56f..1ee4a2b7 100644 --- a/internal/controller/cozystackresourcedefinition_helmreconciler.go +++ b/internal/controller/cozystackresourcedefinition_helmreconciler.go @@ -97,7 +97,34 @@ func (r *CozystackResourceDefinitionHelmReconciler) updateHelmReleasesForCRD(ctx return nil } -// updateHelmReleaseChart updates the chart in HelmRelease based on CozystackResourceDefinition +// 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 CozystackResourceDefinition func (r *CozystackResourceDefinitionHelmReconciler) updateHelmReleaseChart(ctx context.Context, hr *helmv2.HelmRelease, crd *cozyv1alpha1.CozystackResourceDefinition) error { logger := log.FromContext(ctx) hrCopy := hr.DeepCopy() @@ -154,6 +181,14 @@ func (r *CozystackResourceDefinitionHelmReconciler) updateHelmReleaseChart(ctx c } } + // 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 { diff --git a/internal/controller/system_helm_reconciler.go b/internal/controller/system_helm_reconciler.go deleted file mode 100644 index 6e40027c..00000000 --- a/internal/controller/system_helm_reconciler.go +++ /dev/null @@ -1,140 +0,0 @@ -package controller - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "fmt" - "sort" - "time" - - helmv2 "github.com/fluxcd/helm-controller/api/v2" - corev1 "k8s.io/api/core/v1" - kerrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/predicate" -) - -type CozystackConfigReconciler struct { - client.Client - Scheme *runtime.Scheme -} - -var configMapNames = []string{"cozystack", "cozystack-branding", "cozystack-scheduling"} - -const configMapNamespace = "cozy-system" -const digestAnnotation = "cozystack.io/cozy-config-digest" -const forceReconcileKey = "reconcile.fluxcd.io/forceAt" -const requestedAt = "reconcile.fluxcd.io/requestedAt" - -func (r *CozystackConfigReconciler) Reconcile(ctx context.Context, _ ctrl.Request) (ctrl.Result, error) { - log := log.FromContext(ctx) - time.Sleep(2 * time.Second) - - digest, err := r.computeDigest(ctx) - if err != nil { - log.Error(err, "failed to compute config digest") - return ctrl.Result{}, nil - } - - var helmList helmv2.HelmReleaseList - if err := r.List(ctx, &helmList); err != nil { - return ctrl.Result{}, fmt.Errorf("failed to list HelmReleases: %w", err) - } - - now := time.Now().Format(time.RFC3339Nano) - updated := 0 - - for _, hr := range helmList.Items { - isSystemApp := hr.Labels["cozystack.io/system-app"] == "true" - isTenantRoot := hr.Namespace == "tenant-root" && hr.Name == "tenant-root" - if !isSystemApp && !isTenantRoot { - continue - } - patchTarget := hr.DeepCopy() - - if hr.Annotations == nil { - hr.Annotations = map[string]string{} - } - - if hr.Annotations[digestAnnotation] == digest { - continue - } - patchTarget.Annotations[digestAnnotation] = digest - patchTarget.Annotations[forceReconcileKey] = now - patchTarget.Annotations[requestedAt] = now - - patch := client.MergeFrom(hr.DeepCopy()) - if err := r.Patch(ctx, patchTarget, patch); err != nil { - log.Error(err, "failed to patch HelmRelease", "name", hr.Name, "namespace", hr.Namespace) - continue - } - updated++ - log.Info("patched HelmRelease with new config digest", "name", hr.Name, "namespace", hr.Namespace) - } - - log.Info("finished reconciliation", "updatedHelmReleases", updated) - return ctrl.Result{}, nil -} - -func (r *CozystackConfigReconciler) computeDigest(ctx context.Context) (string, error) { - hash := sha256.New() - - for _, name := range configMapNames { - var cm corev1.ConfigMap - err := r.Get(ctx, client.ObjectKey{Namespace: configMapNamespace, Name: name}, &cm) - if err != nil { - if kerrors.IsNotFound(err) { - continue // ignore missing - } - return "", err - } - - // Sort keys for consistent hashing - var keys []string - for k := range cm.Data { - keys = append(keys, k) - } - sort.Strings(keys) - - for _, k := range keys { - v := cm.Data[k] - fmt.Fprintf(hash, "%s:%s=%s\n", name, k, v) - } - } - - return hex.EncodeToString(hash.Sum(nil)), nil -} - -func (r *CozystackConfigReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - WithEventFilter(predicate.Funcs{ - UpdateFunc: func(e event.UpdateEvent) bool { - cm, ok := e.ObjectNew.(*corev1.ConfigMap) - return ok && cm.Namespace == configMapNamespace && contains(configMapNames, cm.Name) - }, - CreateFunc: func(e event.CreateEvent) bool { - cm, ok := e.Object.(*corev1.ConfigMap) - return ok && cm.Namespace == configMapNamespace && contains(configMapNames, cm.Name) - }, - DeleteFunc: func(e event.DeleteEvent) bool { - cm, ok := e.Object.(*corev1.ConfigMap) - return ok && cm.Namespace == configMapNamespace && contains(configMapNames, cm.Name) - }, - }). - For(&corev1.ConfigMap{}). - Complete(r) -} - -func contains(slice []string, val string) bool { - for _, s := range slice { - if s == val { - return true - } - } - return false -} diff --git a/internal/controller/tenant_helm_reconciler.go b/internal/controller/tenant_helm_reconciler.go deleted file mode 100644 index 28b4ad16..00000000 --- a/internal/controller/tenant_helm_reconciler.go +++ /dev/null @@ -1,159 +0,0 @@ -package controller - -import ( - "context" - "fmt" - "strings" - "time" - - e "errors" - - helmv2 "github.com/fluxcd/helm-controller/api/v2" - "gopkg.in/yaml.v2" - corev1 "k8s.io/api/core/v1" - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" -) - -type TenantHelmReconciler struct { - client.Client - Scheme *runtime.Scheme -} - -func (r *TenantHelmReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - logger := log.FromContext(ctx) - time.Sleep(2 * time.Second) - - hr := &helmv2.HelmRelease{} - if err := r.Get(ctx, req.NamespacedName, hr); err != nil { - if errors.IsNotFound(err) { - return ctrl.Result{}, nil - } - logger.Error(err, "unable to fetch HelmRelease") - return ctrl.Result{}, err - } - - if !strings.HasPrefix(hr.Name, "tenant-") { - return ctrl.Result{}, nil - } - - if len(hr.Status.Conditions) == 0 || hr.Status.Conditions[0].Type != "Ready" { - return ctrl.Result{}, nil - } - - if len(hr.Status.History) == 0 { - logger.Info("no history in HelmRelease status", "name", hr.Name) - return ctrl.Result{}, nil - } - - if hr.Status.History[0].Status != "deployed" { - return ctrl.Result{}, nil - } - - newDigest := hr.Status.History[0].Digest - var hrList helmv2.HelmReleaseList - childNamespace := getChildNamespace(hr.Namespace, hr.Name) - if childNamespace == "tenant-root" && hr.Name == "tenant-root" { - if hr.Spec.Values == nil { - logger.Error(e.New("hr.Spec.Values is nil"), "cant annotate tenant-root ns") - return ctrl.Result{}, nil - } - err := annotateTenantRootNs(*hr.Spec.Values, r.Client) - if err != nil { - logger.Error(err, "cant annotate tenant-root ns") - return ctrl.Result{}, nil - } - logger.Info("namespace 'tenant-root' annotated") - } - - if err := r.List(ctx, &hrList, client.InNamespace(childNamespace)); err != nil { - logger.Error(err, "unable to list HelmReleases in namespace", "namespace", hr.Name) - return ctrl.Result{}, err - } - - for _, item := range hrList.Items { - if item.Name == hr.Name { - continue - } - oldDigest := item.GetAnnotations()["cozystack.io/tenant-config-digest"] - if oldDigest == newDigest { - continue - } - patchTarget := item.DeepCopy() - - if patchTarget.Annotations == nil { - patchTarget.Annotations = map[string]string{} - } - ts := time.Now().Format(time.RFC3339Nano) - - patchTarget.Annotations["cozystack.io/tenant-config-digest"] = newDigest - patchTarget.Annotations["reconcile.fluxcd.io/forceAt"] = ts - patchTarget.Annotations["reconcile.fluxcd.io/requestedAt"] = ts - - patch := client.MergeFrom(item.DeepCopy()) - if err := r.Patch(ctx, patchTarget, patch); err != nil { - logger.Error(err, "failed to patch HelmRelease", "name", patchTarget.Name) - continue - } - - logger.Info("patched HelmRelease with new digest", "name", patchTarget.Name, "digest", newDigest, "version", hr.Status.History[0].Version) - } - - return ctrl.Result{}, nil -} - -func (r *TenantHelmReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&helmv2.HelmRelease{}). - Complete(r) -} - -func getChildNamespace(currentNamespace, hrName string) string { - tenantName := strings.TrimPrefix(hrName, "tenant-") - - switch { - case currentNamespace == "tenant-root" && hrName == "tenant-root": - // 1) root tenant inside root namespace - return "tenant-root" - - case currentNamespace == "tenant-root": - // 2) any other tenant in root namespace - return fmt.Sprintf("tenant-%s", tenantName) - - default: - // 3) tenant in a dedicated namespace - return fmt.Sprintf("%s-%s", currentNamespace, tenantName) - } -} - -func annotateTenantRootNs(values apiextensionsv1.JSON, c client.Client) error { - var data map[string]interface{} - if err := yaml.Unmarshal(values.Raw, &data); err != nil { - return fmt.Errorf("failed to parse HelmRelease values: %w", err) - } - - host, ok := data["host"].(string) - if !ok || host == "" { - return fmt.Errorf("host field not found or not a string") - } - - var ns corev1.Namespace - if err := c.Get(context.TODO(), client.ObjectKey{Name: "tenant-root"}, &ns); err != nil { - return fmt.Errorf("failed to get namespace tenant-root: %w", err) - } - - if ns.Annotations == nil { - ns.Annotations = map[string]string{} - } - ns.Annotations["namespace.cozystack.io/host"] = host - - if err := c.Update(context.TODO(), &ns); err != nil { - return fmt.Errorf("failed to update namespace: %w", err) - } - - return nil -} diff --git a/packages/apps/bucket/templates/bucketclaim.yaml b/packages/apps/bucket/templates/bucketclaim.yaml index cebf95b4..5cfdc1c1 100644 --- a/packages/apps/bucket/templates/bucketclaim.yaml +++ b/packages/apps/bucket/templates/bucketclaim.yaml @@ -1,5 +1,4 @@ -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $seaweedfs := index $myNS.metadata.annotations "namespace.cozystack.io/seaweedfs" }} +{{- $seaweedfs := .Values._namespace.seaweedfs }} apiVersion: objectstorage.k8s.io/v1alpha1 kind: BucketClaim metadata: diff --git a/packages/apps/bucket/templates/helmrelease.yaml b/packages/apps/bucket/templates/helmrelease.yaml index 45959572..5d242f84 100644 --- a/packages/apps/bucket/templates/helmrelease.yaml +++ b/packages/apps/bucket/templates/helmrelease.yaml @@ -21,5 +21,8 @@ spec: force: true remediation: retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values values: bucketName: {{ .Release.Name }} diff --git a/packages/apps/clickhouse/templates/chkeeper.yaml b/packages/apps/clickhouse/templates/chkeeper.yaml index 54824a44..42d88af4 100644 --- a/packages/apps/clickhouse/templates/chkeeper.yaml +++ b/packages/apps/clickhouse/templates/chkeeper.yaml @@ -1,5 +1,4 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }} {{- if .Values.clickhouseKeeper.enabled }} apiVersion: "clickhouse-keeper.altinity.com/v1" diff --git a/packages/apps/clickhouse/templates/clickhouse.yaml b/packages/apps/clickhouse/templates/clickhouse.yaml index 47e5b56a..b645260b 100644 --- a/packages/apps/clickhouse/templates/clickhouse.yaml +++ b/packages/apps/clickhouse/templates/clickhouse.yaml @@ -1,5 +1,4 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }} {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-credentials" .Release.Name) }} {{- $passwords := dict }} {{- $users := .Values.users }} diff --git a/packages/apps/ferretdb/templates/postgres.yaml b/packages/apps/ferretdb/templates/postgres.yaml index 4d1d8e29..f1b1ce2c 100644 --- a/packages/apps/ferretdb/templates/postgres.yaml +++ b/packages/apps/ferretdb/templates/postgres.yaml @@ -50,9 +50,8 @@ spec: postgresUID: 999 postgresGID: 999 enableSuperuserAccess: true - {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} - {{- if $configMap }} - {{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }} + {{- if .Values._cluster.scheduling }} + {{- $rawConstraints := get .Values._cluster.scheduling "globalAppTopologySpreadConstraints" }} {{- if $rawConstraints }} {{- $rawConstraints | fromYaml | toYaml | nindent 2 }} labelSelector: diff --git a/packages/apps/foundationdb/templates/cluster.yaml b/packages/apps/foundationdb/templates/cluster.yaml index 06992cb5..be804233 100644 --- a/packages/apps/foundationdb/templates/cluster.yaml +++ b/packages/apps/foundationdb/templates/cluster.yaml @@ -1,5 +1,4 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" | default (dict "data" (dict)) }} -{{- $clusterDomain := index $cozyConfig.data "cluster-domain" | default "cozy.local" }} +{{- $clusterDomain := index .Values._cluster "cluster-domain" | default "cozy.local" }} --- apiVersion: apps.foundationdb.org/v1beta2 kind: FoundationDBCluster diff --git a/packages/apps/kubernetes/templates/cluster.yaml b/packages/apps/kubernetes/templates/cluster.yaml index 7edd07f5..6acfb107 100644 --- a/packages/apps/kubernetes/templates/cluster.yaml +++ b/packages/apps/kubernetes/templates/cluster.yaml @@ -1,7 +1,6 @@ -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $etcd := index $myNS.metadata.annotations "namespace.cozystack.io/etcd" }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $etcd := .Values._namespace.etcd }} +{{- $ingress := .Values._namespace.ingress }} +{{- $host := .Values._namespace.host }} {{- $kubevirtmachinetemplateNames := list }} {{- define "kubevirtmachinetemplate" -}} spec: @@ -31,9 +30,8 @@ spec: {{- end }} cluster.x-k8s.io/deployment-name: {{ $.Release.Name }}-{{ .groupName }} spec: - {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} - {{- if $configMap }} - {{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }} + {{- if .Values._cluster.scheduling }} + {{- $rawConstraints := get .Values._cluster.scheduling "globalAppTopologySpreadConstraints" }} {{- if $rawConstraints }} {{- $rawConstraints | fromYaml | toYaml | nindent 10 }} labelSelector: diff --git a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml index cf93f233..73c3a368 100644 --- a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml @@ -1,5 +1,4 @@ -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $targetTenant := index $myNS.metadata.annotations "namespace.cozystack.io/monitoring" }} +{{- $targetTenant := .Values._namespace.monitoring }} {{- if .Values.addons.monitoringAgents.enabled }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease diff --git a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml index 8b615c9c..8a62288d 100644 --- a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml +++ b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml @@ -1,8 +1,6 @@ {{- define "cozystack.defaultVPAValues" -}} -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $targetTenant := index $myNS.metadata.annotations "namespace.cozystack.io/monitoring" }} +{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }} +{{- $targetTenant := .Values._namespace.monitoring }} vpaForVPA: false vertical-pod-autoscaler: recommender: diff --git a/packages/apps/kubernetes/templates/ingress.yaml b/packages/apps/kubernetes/templates/ingress.yaml index 8dd244cb..7993dba8 100644 --- a/packages/apps/kubernetes/templates/ingress.yaml +++ b/packages/apps/kubernetes/templates/ingress.yaml @@ -1,5 +1,4 @@ -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} +{{- $ingress := .Values._namespace.ingress }} {{- if and (eq .Values.addons.ingressNginx.exposeMethod "Proxied") .Values.addons.ingressNginx.hosts }} --- apiVersion: networking.k8s.io/v1 diff --git a/packages/apps/nats/templates/nats.yaml b/packages/apps/nats/templates/nats.yaml index b05c87b5..3e858fd5 100644 --- a/packages/apps/nats/templates/nats.yaml +++ b/packages/apps/nats/templates/nats.yaml @@ -1,5 +1,4 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }} {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-credentials" .Release.Name) }} {{- $passwords := dict }} @@ -53,6 +52,9 @@ spec: force: true remediation: retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values values: nats: container: diff --git a/packages/apps/postgres/templates/db.yaml b/packages/apps/postgres/templates/db.yaml index 92fb34c6..7557c436 100644 --- a/packages/apps/postgres/templates/db.yaml +++ b/packages/apps/postgres/templates/db.yaml @@ -46,9 +46,8 @@ spec: imageName: ghcr.io/cloudnative-pg/postgresql:{{ include "postgres.versionMap" $ | trimPrefix "v" }} enableSuperuserAccess: true - {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} - {{- if $configMap }} - {{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }} + {{- if .Values._cluster.scheduling }} + {{- $rawConstraints := get .Values._cluster.scheduling "globalAppTopologySpreadConstraints" }} {{- if $rawConstraints }} {{- $rawConstraints | fromYaml | toYaml | nindent 2 }} labelSelector: diff --git a/packages/apps/tenant/templates/etcd.yaml b/packages/apps/tenant/templates/etcd.yaml index 8cd720cc..e67ab597 100644 --- a/packages/apps/tenant/templates/etcd.yaml +++ b/packages/apps/tenant/templates/etcd.yaml @@ -31,4 +31,7 @@ spec: force: true remediation: retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values {{- end }} diff --git a/packages/apps/tenant/templates/info.yaml b/packages/apps/tenant/templates/info.yaml index 4a66e422..efa01b87 100644 --- a/packages/apps/tenant/templates/info.yaml +++ b/packages/apps/tenant/templates/info.yaml @@ -30,3 +30,6 @@ spec: force: true remediation: retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values diff --git a/packages/apps/tenant/templates/ingress.yaml b/packages/apps/tenant/templates/ingress.yaml index beb07342..6e870043 100644 --- a/packages/apps/tenant/templates/ingress.yaml +++ b/packages/apps/tenant/templates/ingress.yaml @@ -31,4 +31,7 @@ spec: force: true remediation: retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values {{- end }} diff --git a/packages/apps/tenant/templates/keycloakgroups.yaml b/packages/apps/tenant/templates/keycloakgroups.yaml index 59288ca4..9e25e60d 100644 --- a/packages/apps/tenant/templates/keycloakgroups.yaml +++ b/packages/apps/tenant/templates/keycloakgroups.yaml @@ -1,5 +1,4 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} +{{- $oidcEnabled := index .Values._cluster "oidc-enabled" }} {{- if eq $oidcEnabled "true" }} {{- if .Capabilities.APIVersions.Has "v1.edp.epam.com/v1" }} apiVersion: v1.edp.epam.com/v1 diff --git a/packages/apps/tenant/templates/monitoring.yaml b/packages/apps/tenant/templates/monitoring.yaml index 4986fc21..625670e9 100644 --- a/packages/apps/tenant/templates/monitoring.yaml +++ b/packages/apps/tenant/templates/monitoring.yaml @@ -31,4 +31,7 @@ spec: force: true remediation: retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values {{- end }} diff --git a/packages/apps/tenant/templates/namespace.yaml b/packages/apps/tenant/templates/namespace.yaml index d97ebf42..5942cba3 100644 --- a/packages/apps/tenant/templates/namespace.yaml +++ b/packages/apps/tenant/templates/namespace.yaml @@ -1,46 +1,63 @@ -{{- define "cozystack.namespace-anotations" }} -{{- $context := index . 0 }} -{{- $existingNS := index . 1 }} -{{- range $x := list "etcd" "monitoring" "ingress" "seaweedfs" }} -{{- if (index $context.Values $x) }} -namespace.cozystack.io/{{ $x }}: "{{ include "tenant.name" $context }}" -{{- else }} -namespace.cozystack.io/{{ $x }}: "{{ index $existingNS.metadata.annotations (printf "namespace.cozystack.io/%s" $x) | required (printf "namespace %s has no namespace.cozystack.io/%s annotation" $context.Release.Namespace $x) }}" -{{- end }} -{{- end }} -{{- end }} - +{{/* Lookup for namespace uid (needed for ownerReferences) */}} {{- $existingNS := lookup "v1" "Namespace" "" .Release.Namespace }} {{- if not $existingNS }} {{- fail (printf "error lookup existing namespace: %s" .Release.Namespace) }} {{- end }} {{- if ne (include "tenant.name" .) "tenant-root" }} +{{/* Compute namespace values once for use in both Secret and labels */}} +{{- $tenantName := include "tenant.name" . }} +{{- $parentNamespace := .Values._namespace | default dict }} +{{- $parentHost := $parentNamespace.host | default "" }} + +{{/* Compute host */}} +{{- $computedHost := "" }} +{{- if .Values.host }} +{{- $computedHost = .Values.host }} +{{- else if $parentHost }} +{{- $computedHost = printf "%s.%s" (splitList "-" $tenantName | last) $parentHost }} +{{- end }} + +{{/* Compute service references */}} +{{- $etcd := $parentNamespace.etcd | default "" }} +{{- if .Values.etcd }} +{{- $etcd = $tenantName }} +{{- end }} + +{{- $ingress := $parentNamespace.ingress | default "" }} +{{- if .Values.ingress }} +{{- $ingress = $tenantName }} +{{- end }} + +{{- $monitoring := $parentNamespace.monitoring | default "" }} +{{- if .Values.monitoring }} +{{- $monitoring = $tenantName }} +{{- end }} + +{{- $seaweedfs := $parentNamespace.seaweedfs | default "" }} +{{- if .Values.seaweedfs }} +{{- $seaweedfs = $tenantName }} +{{- end }} --- apiVersion: v1 kind: Namespace metadata: - name: {{ include "tenant.name" . }} + name: {{ $tenantName }} {{- if hasPrefix "tenant-" .Release.Namespace }} - annotations: - {{- if .Values.host }} - namespace.cozystack.io/host: "{{ .Values.host }}" - {{- else }} - {{ $parentHost := index $existingNS.metadata.annotations "namespace.cozystack.io/host" | required (printf "namespace %s has no namespace.cozystack.io/host annotation" .Release.Namespace) }} - namespace.cozystack.io/host: "{{ splitList "-" (include "tenant.name" .) | last }}.{{ $parentHost }}" - {{- end }} - {{- include "cozystack.namespace-anotations" (list . $existingNS) | nindent 4 }} labels: - tenant.cozystack.io/{{ include "tenant.name" $ }}: "" - {{- if hasPrefix "tenant-" .Release.Namespace }} + tenant.cozystack.io/{{ $tenantName }}: "" {{- $parts := splitList "-" .Release.Namespace }} {{- range $i, $v := $parts }} {{- if ne $i 0 }} tenant.cozystack.io/{{ join "-" (slice $parts 0 (add $i 1)) }}: "" {{- end }} {{- end }} - {{- end }} - {{- include "cozystack.namespace-anotations" (list $ $existingNS) | nindent 4 }} + {{/* Labels for network policies */}} + namespace.cozystack.io/etcd: {{ $etcd | quote }} + namespace.cozystack.io/ingress: {{ $ingress | quote }} + namespace.cozystack.io/monitoring: {{ $monitoring | quote }} + namespace.cozystack.io/seaweedfs: {{ $seaweedfs | quote }} + namespace.cozystack.io/host: {{ $computedHost | quote }} alpha.kubevirt.io/auto-memory-limits-ratio: "1.0" ownerReferences: - apiVersion: v1 @@ -50,4 +67,23 @@ metadata: name: {{ .Release.Namespace }} uid: {{ $existingNS.metadata.uid }} {{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: cozystack-values + namespace: {{ $tenantName }} + labels: + reconcile.fluxcd.io/watch: Enabled +type: Opaque +stringData: + values.yaml: | + _cluster: + {{- .Values._cluster | toYaml | nindent 6 }} + _namespace: + etcd: {{ $etcd | quote }} + ingress: {{ $ingress | quote }} + monitoring: {{ $monitoring | quote }} + seaweedfs: {{ $seaweedfs | quote }} + host: {{ $computedHost | quote }} {{- end }} diff --git a/packages/apps/tenant/templates/seaweedfs.yaml b/packages/apps/tenant/templates/seaweedfs.yaml index 9a714b79..ff0db1e4 100644 --- a/packages/apps/tenant/templates/seaweedfs.yaml +++ b/packages/apps/tenant/templates/seaweedfs.yaml @@ -31,4 +31,7 @@ spec: force: true remediation: retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values {{- end }} diff --git a/packages/apps/virtual-machine/templates/_helpers.tpl b/packages/apps/virtual-machine/templates/_helpers.tpl index 7b6929ac..e65cad9d 100644 --- a/packages/apps/virtual-machine/templates/_helpers.tpl +++ b/packages/apps/virtual-machine/templates/_helpers.tpl @@ -74,9 +74,8 @@ Generate a stable UUID for cloud-init re-initialization upon upgrade. Node Affinity for Windows VMs */}} {{- define "virtual-machine.nodeAffinity" -}} -{{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" -}} -{{- if $configMap -}} -{{- $dedicatedNodesForWindowsVMs := get $configMap.data "dedicatedNodesForWindowsVMs" -}} +{{- if .Values._cluster.scheduling -}} +{{- $dedicatedNodesForWindowsVMs := get .Values._cluster.scheduling "dedicatedNodesForWindowsVMs" -}} {{- if eq $dedicatedNodesForWindowsVMs "true" -}} {{- $isWindows := hasPrefix "windows" (toString .Values.instanceProfile) -}} affinity: diff --git a/packages/apps/vm-instance/templates/_helpers.tpl b/packages/apps/vm-instance/templates/_helpers.tpl index 7b6929ac..e65cad9d 100644 --- a/packages/apps/vm-instance/templates/_helpers.tpl +++ b/packages/apps/vm-instance/templates/_helpers.tpl @@ -74,9 +74,8 @@ Generate a stable UUID for cloud-init re-initialization upon upgrade. Node Affinity for Windows VMs */}} {{- define "virtual-machine.nodeAffinity" -}} -{{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" -}} -{{- if $configMap -}} -{{- $dedicatedNodesForWindowsVMs := get $configMap.data "dedicatedNodesForWindowsVMs" -}} +{{- if .Values._cluster.scheduling -}} +{{- $dedicatedNodesForWindowsVMs := get .Values._cluster.scheduling "dedicatedNodesForWindowsVMs" -}} {{- if eq $dedicatedNodesForWindowsVMs "true" -}} {{- $isWindows := hasPrefix "windows" (toString .Values.instanceProfile) -}} affinity: diff --git a/packages/apps/vpn/templates/secret.yaml b/packages/apps/vpn/templates/secret.yaml index 79960096..3ef4ac4b 100644 --- a/packages/apps/vpn/templates/secret.yaml +++ b/packages/apps/vpn/templates/secret.yaml @@ -1,5 +1,4 @@ -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $host := .Values._namespace.host }} {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-vpn" .Release.Name) }} {{- $accessKeys := list }} {{- $passwords := dict }} diff --git a/packages/core/platform/templates/apps.yaml b/packages/core/platform/templates/apps.yaml index 514dcffb..b42aad87 100644 --- a/packages/core/platform/templates/apps.yaml +++ b/packages/core/platform/templates/apps.yaml @@ -1,6 +1,22 @@ {{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $cozystackBranding := lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} +{{- $cozystackScheduling := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} +{{- $kubeRootCa := lookup "v1" "ConfigMap" "kube-system" "kube-root-ca.crt" }} {{- $bundleName := index $cozyConfig.data "bundle-name" }} {{- $bundle := tpl (.Files.Get (printf "bundles/%s.yaml" $bundleName)) . | fromYaml }} +{{/* 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 }} @@ -22,6 +38,8 @@ 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 @@ -29,6 +47,36 @@ metadata: namespace.cozystack.io/host: "{{ $host }}" name: tenant-root --- +apiVersion: v1 +kind: Secret +metadata: + name: cozystack-values + namespace: tenant-root + labels: + reconcile.fluxcd.io/watch: Enabled +type: Opaque +stringData: + values.yaml: | + _cluster: + {{- $clusterConfig | toYaml | nindent 6 }} + {{- with $cozystackBranding.data }} + branding: + {{- . | toYaml | nindent 8 }} + {{- end }} + {{- with $cozystackScheduling.data }} + scheduling: + {{- . | toYaml | nindent 8 }} + {{- end }} + {{- with $kubeRootCa.data }} + kube-root-ca: {{ index . "ca.crt" | b64enc | quote }} + {{- 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: @@ -56,6 +104,9 @@ spec: kind: HelmRepository name: cozystack-apps namespace: cozy-public + valuesFrom: + - kind: Secret + name: cozystack-values values: host: "{{ $host }}" dependsOn: diff --git a/packages/core/platform/templates/helmreleases.yaml b/packages/core/platform/templates/helmreleases.yaml index 6ed61ed8..e3118b70 100644 --- a/packages/core/platform/templates/helmreleases.yaml +++ b/packages/core/platform/templates/helmreleases.yaml @@ -83,6 +83,9 @@ spec: values: {{- toYaml . | nindent 4}} {{- end }} + valuesFrom: + - kind: Secret + name: cozystack-values {{- with $x.dependsOn }} dependsOn: diff --git a/packages/core/platform/templates/namespaces.yaml b/packages/core/platform/templates/namespaces.yaml index 11d00553..2afe3445 100644 --- a/packages/core/platform/templates/namespaces.yaml +++ b/packages/core/platform/templates/namespaces.yaml @@ -1,5 +1,20 @@ {{- $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 "") }} @@ -37,4 +52,25 @@ metadata: 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: + values.yaml: | + _cluster: + {{- $clusterConfig | toYaml | nindent 6 }} + {{- with $cozystackBranding.data }} + branding: + {{- . | toYaml | nindent 8 }} + {{- end }} + {{- with $cozystackScheduling.data }} + scheduling: + {{- . | toYaml | nindent 8 }} + {{- end }} {{- end }} diff --git a/packages/extra/bootbox/templates/matchbox/ingress.yaml b/packages/extra/bootbox/templates/matchbox/ingress.yaml index 31de7716..fa62165b 100644 --- a/packages/extra/bootbox/templates/matchbox/ingress.yaml +++ b/packages/extra/bootbox/templates/matchbox/ingress.yaml @@ -1,9 +1,6 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} - -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $issuerType := (index .Values._cluster "clusterissuer") | default "http01" }} +{{- $ingress := .Values._namespace.ingress }} +{{- $host := .Values._namespace.host }} apiVersion: networking.k8s.io/v1 kind: Ingress metadata: diff --git a/packages/extra/bootbox/templates/matchbox/machines.yaml b/packages/extra/bootbox/templates/matchbox/machines.yaml index e2733b89..a52c4b40 100644 --- a/packages/extra/bootbox/templates/matchbox/machines.yaml +++ b/packages/extra/bootbox/templates/matchbox/machines.yaml @@ -1,9 +1,4 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} - -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $host := .Values._namespace.host }} {{ range $m := .Values.machines }} --- diff --git a/packages/extra/etcd/templates/etcd-cluster.yaml b/packages/extra/etcd/templates/etcd-cluster.yaml index 017a3178..a26ae173 100644 --- a/packages/extra/etcd/templates/etcd-cluster.yaml +++ b/packages/extra/etcd/templates/etcd-cluster.yaml @@ -49,10 +49,9 @@ spec: {{- with .Values.resources }} resources: {{- include "cozy-lib.resources.sanitize" (list . $) | nindent 10 }} {{- end }} - {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} {{- $rawConstraints := "" }} - {{- if $configMap }} - {{- $rawConstraints = get $configMap.data "globalAppTopologySpreadConstraints" }} + {{- if .Values._cluster.scheduling }} + {{- $rawConstraints = get .Values._cluster.scheduling "globalAppTopologySpreadConstraints" }} {{- end }} {{- if $rawConstraints }} {{- $rawConstraints | fromYaml | toYaml | nindent 6 }} diff --git a/packages/extra/info/templates/dashboard-resourcemap.yaml b/packages/extra/info/templates/dashboard-resourcemap.yaml index 39da1b37..aa8b7641 100644 --- a/packages/extra/info/templates/dashboard-resourcemap.yaml +++ b/packages/extra/info/templates/dashboard-resourcemap.yaml @@ -1,5 +1,4 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} +{{- $oidcEnabled := index .Values._cluster "oidc-enabled" }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: diff --git a/packages/extra/info/templates/kubeconfig.yaml b/packages/extra/info/templates/kubeconfig.yaml index d960a587..1557eacd 100644 --- a/packages/extra/info/templates/kubeconfig.yaml +++ b/packages/extra/info/templates/kubeconfig.yaml @@ -1,23 +1,14 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $host := index $cozyConfig.data "root-host" }} +{{- $host := .Values._namespace.host | default (index .Values._cluster "root-host") }} {{- $k8sClientSecret := lookup "v1" "Secret" "cozy-keycloak" "k8s-client" }} {{- if $k8sClientSecret }} -{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} -{{- $managementKubeconfigEndpoint := default "" (get $cozyConfig.data "management-kubeconfig-endpoint") }} +{{- $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 }} - -{{- 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 }} +{{- $k8sCa := index .Values._cluster "kube-root-ca" }} --- apiVersion: v1 kind: Secret diff --git a/packages/extra/ingress/templates/nginx-ingress.yaml b/packages/extra/ingress/templates/nginx-ingress.yaml index e28918e4..d375be2c 100644 --- a/packages/extra/ingress/templates/nginx-ingress.yaml +++ b/packages/extra/ingress/templates/nginx-ingress.yaml @@ -1,6 +1,5 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $exposeIngress := index $cozyConfig.data "expose-ingress" | default "tenant-root" }} -{{- $exposeExternalIPs := (index $cozyConfig.data "expose-external-ips") | default "" | nospace }} +{{- $exposeIngress := (index .Values._cluster "expose-ingress") | default "tenant-root" }} +{{- $exposeExternalIPs := (index .Values._cluster "expose-external-ips") | default "" | nospace }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -24,6 +23,9 @@ spec: force: true remediation: retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values values: ingress-nginx: fullnameOverride: {{ trimPrefix "tenant-" .Release.Namespace }}-ingress diff --git a/packages/extra/monitoring/templates/alerta/alerta-db.yaml b/packages/extra/monitoring/templates/alerta/alerta-db.yaml index a2cca187..845cd8ba 100644 --- a/packages/extra/monitoring/templates/alerta/alerta-db.yaml +++ b/packages/extra/monitoring/templates/alerta/alerta-db.yaml @@ -5,9 +5,8 @@ metadata: name: alerta-db spec: instances: 2 - {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} - {{- if $configMap }} - {{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }} + {{- if .Values._cluster.scheduling }} + {{- $rawConstraints := get .Values._cluster.scheduling "globalAppTopologySpreadConstraints" }} {{- if $rawConstraints }} {{- $rawConstraints | fromYaml | toYaml | nindent 2 }} labelSelector: diff --git a/packages/extra/monitoring/templates/alerta/alerta.yaml b/packages/extra/monitoring/templates/alerta/alerta.yaml index 72500948..76b7a02b 100644 --- a/packages/extra/monitoring/templates/alerta/alerta.yaml +++ b/packages/extra/monitoring/templates/alerta/alerta.yaml @@ -1,9 +1,6 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} - -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $issuerType := (index .Values._cluster "clusterissuer") | default "http01" }} +{{- $ingress := .Values._namespace.ingress }} +{{- $host := .Values._namespace.host }} {{- $apiKey := randAlphaNum 32 }} {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace "alerta" }} diff --git a/packages/extra/monitoring/templates/grafana/db.yaml b/packages/extra/monitoring/templates/grafana/db.yaml index f1781cff..662f5cf4 100644 --- a/packages/extra/monitoring/templates/grafana/db.yaml +++ b/packages/extra/monitoring/templates/grafana/db.yaml @@ -6,9 +6,8 @@ spec: instances: 2 storage: size: {{ .Values.grafana.db.size }} - {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} - {{- if $configMap }} - {{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }} + {{- if .Values._cluster.scheduling }} + {{- $rawConstraints := get .Values._cluster.scheduling "globalAppTopologySpreadConstraints" }} {{- if $rawConstraints }} {{- $rawConstraints | fromYaml | toYaml | nindent 2 }} labelSelector: diff --git a/packages/extra/monitoring/templates/grafana/grafana.yaml b/packages/extra/monitoring/templates/grafana/grafana.yaml index 2397fd10..1eadda9e 100644 --- a/packages/extra/monitoring/templates/grafana/grafana.yaml +++ b/packages/extra/monitoring/templates/grafana/grafana.yaml @@ -1,9 +1,6 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} - -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $issuerType := (index .Values._cluster "clusterissuer") | default "http01" }} +{{- $ingress := .Values._namespace.ingress }} +{{- $host := .Values._namespace.host }} --- apiVersion: grafana.integreatly.org/v1beta1 kind: Grafana diff --git a/packages/extra/seaweedfs/templates/client/cosi-deployment.yaml b/packages/extra/seaweedfs/templates/client/cosi-deployment.yaml index 5307a67f..f73a61bf 100644 --- a/packages/extra/seaweedfs/templates/client/cosi-deployment.yaml +++ b/packages/extra/seaweedfs/templates/client/cosi-deployment.yaml @@ -1,7 +1,5 @@ {{- if eq .Values.topology "Client" }} -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $host := .Values._namespace.host }} --- apiVersion: apps/v1 kind: Deployment diff --git a/packages/extra/seaweedfs/templates/ingress.yaml b/packages/extra/seaweedfs/templates/ingress.yaml index 05bf201d..cf4e837e 100644 --- a/packages/extra/seaweedfs/templates/ingress.yaml +++ b/packages/extra/seaweedfs/templates/ingress.yaml @@ -1,9 +1,5 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} - -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $ingress := .Values._namespace.ingress }} +{{- $host := .Values._namespace.host }} {{- if and (not (eq .Values.topology "Client")) (.Values.filer.grpcHost) }} --- apiVersion: networking.k8s.io/v1 diff --git a/packages/extra/seaweedfs/templates/seaweedfs.yaml b/packages/extra/seaweedfs/templates/seaweedfs.yaml index 02bac375..747fc410 100644 --- a/packages/extra/seaweedfs/templates/seaweedfs.yaml +++ b/packages/extra/seaweedfs/templates/seaweedfs.yaml @@ -34,9 +34,8 @@ {{- end }} {{- if not (eq .Values.topology "Client") }} -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $ingress := .Values._namespace.ingress }} +{{- $host := .Values._namespace.host }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -60,6 +59,9 @@ spec: force: true remediation: retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values values: global: serviceAccountName: "{{ .Release.Namespace }}-seaweedfs" diff --git a/packages/library/cozy-lib/templates/_cozyconfig.tpl b/packages/library/cozy-lib/templates/_cozyconfig.tpl index 559f7415..648b2617 100644 --- a/packages/library/cozy-lib/templates/_cozyconfig.tpl +++ b/packages/library/cozy-lib/templates/_cozyconfig.tpl @@ -1,7 +1,130 @@ +{{/* +Cluster-wide configuration helpers. +These helpers read from .Values._cluster which is populated via valuesFrom from Secret cozystack-values. +*/}} + +{{/* +Get the root host for the cluster. +Usage: {{ include "cozy-lib.root-host" . }} +*/}} +{{- define "cozy-lib.root-host" -}} +{{- (index .Values._cluster "root-host") | default "" }} +{{- end }} + +{{/* +Get the bundle name for the cluster. +Usage: {{ include "cozy-lib.bundle-name" . }} +*/}} +{{- define "cozy-lib.bundle-name" -}} +{{- (index .Values._cluster "bundle-name") | default "" }} +{{- end }} + +{{/* +Get the images registry. +Usage: {{ include "cozy-lib.images-registry" . }} +*/}} +{{- define "cozy-lib.images-registry" -}} +{{- (index .Values._cluster "images-registry") | default "" }} +{{- end }} + +{{/* +Get the ipv4 cluster CIDR. +Usage: {{ include "cozy-lib.ipv4-cluster-cidr" . }} +*/}} +{{- define "cozy-lib.ipv4-cluster-cidr" -}} +{{- (index .Values._cluster "ipv4-cluster-cidr") | default "" }} +{{- end }} + +{{/* +Get the ipv4 service CIDR. +Usage: {{ include "cozy-lib.ipv4-service-cidr" . }} +*/}} +{{- define "cozy-lib.ipv4-service-cidr" -}} +{{- (index .Values._cluster "ipv4-service-cidr") | default "" }} +{{- end }} + +{{/* +Get the ipv4 join CIDR. +Usage: {{ include "cozy-lib.ipv4-join-cidr" . }} +*/}} +{{- define "cozy-lib.ipv4-join-cidr" -}} +{{- (index .Values._cluster "ipv4-join-cidr") | default "" }} +{{- end }} + +{{/* +Get scheduling configuration. +Usage: {{ include "cozy-lib.scheduling" . }} +Returns: YAML string of scheduling configuration +*/}} +{{- define "cozy-lib.scheduling" -}} +{{- if .Values._cluster.scheduling }} +{{- .Values._cluster.scheduling | toYaml }} +{{- end }} +{{- end }} + +{{/* +Get branding configuration. +Usage: {{ include "cozy-lib.branding" . }} +Returns: YAML string of branding configuration +*/}} +{{- define "cozy-lib.branding" -}} +{{- if .Values._cluster.branding }} +{{- .Values._cluster.branding | toYaml }} +{{- end }} +{{- end }} + +{{/* +Namespace-specific configuration helpers. +These helpers read from .Values._namespace which is populated via valuesFrom from Secret cozystack-values. +*/}} + +{{/* +Get the host for this namespace. +Usage: {{ include "cozy-lib.ns-host" . }} +*/}} +{{- define "cozy-lib.ns-host" -}} +{{- .Values._namespace.host | default "" }} +{{- end }} + +{{/* +Get the etcd namespace reference. +Usage: {{ include "cozy-lib.ns-etcd" . }} +*/}} +{{- define "cozy-lib.ns-etcd" -}} +{{- .Values._namespace.etcd | default "" }} +{{- end }} + +{{/* +Get the ingress namespace reference. +Usage: {{ include "cozy-lib.ns-ingress" . }} +*/}} +{{- define "cozy-lib.ns-ingress" -}} +{{- .Values._namespace.ingress | default "" }} +{{- end }} + +{{/* +Get the monitoring namespace reference. +Usage: {{ include "cozy-lib.ns-monitoring" . }} +*/}} +{{- define "cozy-lib.ns-monitoring" -}} +{{- .Values._namespace.monitoring | default "" }} +{{- end }} + +{{/* +Get the seaweedfs namespace reference. +Usage: {{ include "cozy-lib.ns-seaweedfs" . }} +*/}} +{{- define "cozy-lib.ns-seaweedfs" -}} +{{- .Values._namespace.seaweedfs | default "" }} +{{- end }} + +{{/* +Legacy helper - kept for backward compatibility during migration. +Loads config into context. Deprecated: use direct .Values._cluster access instead. +*/}} {{- define "cozy-lib.loadCozyConfig" }} {{- include "cozy-lib.checkInput" . }} {{- if not (hasKey (index . 1) "cozyConfig") }} -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $_ := set (index . 1) "cozyConfig" $cozyConfig }} +{{- $_ := set (index . 1) "cozyConfig" (dict "data" ((index . 1).Values._cluster | default dict)) }} {{- end }} {{- end }} diff --git a/packages/system/bucket/templates/ingress.yaml b/packages/system/bucket/templates/ingress.yaml index d8d659c7..f7b4eed4 100644 --- a/packages/system/bucket/templates/ingress.yaml +++ b/packages/system/bucket/templates/ingress.yaml @@ -1,8 +1,6 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} +{{- $host := .Values._namespace.host }} +{{- $ingress := .Values._namespace.ingress }} +{{- $issuerType := (index .Values._cluster "clusterissuer") | default "http01" }} apiVersion: networking.k8s.io/v1 kind: Ingress diff --git a/packages/system/cert-manager-issuers/templates/cluster-issuers.yaml b/packages/system/cert-manager-issuers/templates/cluster-issuers.yaml index 6a70eef0..e93f3f67 100644 --- a/packages/system/cert-manager-issuers/templates/cluster-issuers.yaml +++ b/packages/system/cert-manager-issuers/templates/cluster-issuers.yaml @@ -1,5 +1,4 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} +{{- $issuerType := (index .Values._cluster "clusterissuer") | default "http01" }} apiVersion: cert-manager.io/v1 kind: ClusterIssuer diff --git a/packages/system/cozystack-api/templates/api-ingress.yaml b/packages/system/cozystack-api/templates/api-ingress.yaml index 54fdf54b..9226d887 100644 --- a/packages/system/cozystack-api/templates/api-ingress.yaml +++ b/packages/system/cozystack-api/templates/api-ingress.yaml @@ -1,7 +1,6 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- $exposeServices := splitList "," ((index $cozyConfig.data "expose-services") | default "") }} -{{- $exposeIngress := index $cozyConfig.data "expose-ingress" | default "tenant-root" }} +{{- $host := index .Values._cluster "root-host" }} +{{- $exposeServices := splitList "," ((index .Values._cluster "expose-services") | default "") }} +{{- $exposeIngress := (index .Values._cluster "expose-ingress") | default "tenant-root" }} {{- if and (has "api" $exposeServices) }} apiVersion: networking.k8s.io/v1 diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index bbf71610..f148109f 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,4 +1,4 @@ -{{- $brandingConfig:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} +{{- $brandingConfig := .Values._cluster.branding | default dict }} {{- $tenantText := "v0.38.2" }} {{- $footerText := "Cozystack" }} @@ -16,9 +16,9 @@ metadata: app.kubernetes.io/instance: incloud-web app.kubernetes.io/name: web data: - CUSTOM_TENANT_TEXT: {{ $brandingConfig | dig "data" "tenantText" $tenantText | quote }} - FOOTER_TEXT: {{ $brandingConfig | dig "data" "footerText" $footerText | quote }} - TITLE_TEXT: {{ $brandingConfig | dig "data" "titleText" $titleText | quote }} - LOGO_TEXT: {{ $brandingConfig | dig "data" "logoText" $logoText | quote }} - CUSTOM_LOGO_SVG: {{ $brandingConfig | dig "data" "logoSvg" $logoSvg | quote }} - ICON_SVG: {{ $brandingConfig | dig "data" "iconSvg" $iconSvg | quote }} + CUSTOM_TENANT_TEXT: {{ $brandingConfig.tenantText | default $tenantText | quote }} + FOOTER_TEXT: {{ $brandingConfig.footerText | default $footerText | quote }} + TITLE_TEXT: {{ $brandingConfig.titleText | default $titleText | quote }} + LOGO_TEXT: {{ $brandingConfig.logoText | default $logoText | quote }} + CUSTOM_LOGO_SVG: {{ $brandingConfig.logoSvg | default $logoSvg | quote }} + ICON_SVG: {{ $brandingConfig.iconSvg | default $iconSvg | quote }} diff --git a/packages/system/dashboard/templates/gatekeeper.yaml b/packages/system/dashboard/templates/gatekeeper.yaml index b4503f4f..40f2565f 100644 --- a/packages/system/dashboard/templates/gatekeeper.yaml +++ b/packages/system/dashboard/templates/gatekeeper.yaml @@ -1,6 +1,5 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} +{{- $host := index .Values._cluster "root-host" }} +{{- $oidcEnabled := index .Values._cluster "oidc-enabled" }} apiVersion: apps/v1 kind: Deployment diff --git a/packages/system/dashboard/templates/ingress.yaml b/packages/system/dashboard/templates/ingress.yaml index 5a634e2c..aacc1bc1 100644 --- a/packages/system/dashboard/templates/ingress.yaml +++ b/packages/system/dashboard/templates/ingress.yaml @@ -1,8 +1,7 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- $exposeServices := splitList "," ((index $cozyConfig.data "expose-services") | default "") }} -{{- $exposeIngress := index $cozyConfig.data "expose-ingress" | default "tenant-root" }} +{{- $issuerType := (index .Values._cluster "clusterissuer") | default "http01" }} +{{- $host := index .Values._cluster "root-host" }} +{{- $exposeServices := splitList "," ((index .Values._cluster "expose-services") | default "") }} +{{- $exposeIngress := (index .Values._cluster "expose-ingress") | default "tenant-root" }} {{- if and (has "dashboard" $exposeServices) }} apiVersion: networking.k8s.io/v1 diff --git a/packages/system/dashboard/templates/keycloakclient.yaml b/packages/system/dashboard/templates/keycloakclient.yaml index 55ebc5d5..80f7332e 100644 --- a/packages/system/dashboard/templates/keycloakclient.yaml +++ b/packages/system/dashboard/templates/keycloakclient.yaml @@ -1,6 +1,5 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- $extraRedirectUris := splitList "," ((index $cozyConfig.data "extra-keycloak-redirect-uri-for-dashboard") | default "") }} +{{- $host := index .Values._cluster "root-host" }} +{{- $extraRedirectUris := splitList "," ((index .Values._cluster "extra-keycloak-redirect-uri-for-dashboard") | default "") }} {{- $existingK8sSecret := lookup "v1" "Secret" .Release.Namespace "k8s-client" }} {{- $existingDashboardSecret := lookup "v1" "Secret" .Release.Namespace "dashboard-client" }} diff --git a/packages/system/dashboard/templates/nginx-config.yaml b/packages/system/dashboard/templates/nginx-config.yaml index c2d6f624..696e9ce9 100644 --- a/packages/system/dashboard/templates/nginx-config.yaml +++ b/packages/system/dashboard/templates/nginx-config.yaml @@ -1,5 +1,4 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $host := index $cozyConfig.data "root-host" }} +{{- $host := index .Values._cluster "root-host" }} apiVersion: v1 data: diff --git a/packages/system/keycloak-configure/templates/configure-kk.yaml b/packages/system/keycloak-configure/templates/configure-kk.yaml index 3fc92c86..e399b374 100644 --- a/packages/system/keycloak-configure/templates/configure-kk.yaml +++ b/packages/system/keycloak-configure/templates/configure-kk.yaml @@ -1,13 +1,11 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- $extraRedirectUris := splitList "," ((index $cozyConfig.data "extra-keycloak-redirect-uri-for-dashboard") | default "") }} -{{- $rootSaConfigMap := lookup "v1" "ConfigMap" "kube-system" "kube-root-ca.crt" }} -{{- $k8sCa := index $rootSaConfigMap.data "ca.crt" | b64enc }} +{{- $host := index .Values._cluster "root-host" }} +{{- $extraRedirectUris := splitList "," ((index .Values._cluster "extra-keycloak-redirect-uri-for-dashboard") | default "") }} +{{- $k8sCa := index .Values._cluster "kube-root-ca" }} {{- $existingK8sSecret := lookup "v1" "Secret" .Release.Namespace "k8s-client" }} {{- $existingKubeappsSecret := lookup "v1" "Secret" .Release.Namespace "kubeapps-client" }} {{- $existingAuthConfig := lookup "v1" "Secret" "cozy-dashboard" "kubeapps-auth-config" }} -{{- $cozystackBranding:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} +{{- $brandingConfig := .Values._cluster.branding | default dict }} {{ $k8sClient := "" }} {{- if $existingK8sSecret }} @@ -17,8 +15,8 @@ {{- end }} {{ $branding := "" }} -{{- if $cozystackBranding }} - {{- $branding = index $cozystackBranding.data "branding" }} +{{- if $brandingConfig }} + {{- $branding = $brandingConfig.branding }} {{- end }} --- diff --git a/packages/system/keycloak/templates/db.yaml b/packages/system/keycloak/templates/db.yaml index 70666d7b..1cd98ffc 100644 --- a/packages/system/keycloak/templates/db.yaml +++ b/packages/system/keycloak/templates/db.yaml @@ -6,9 +6,8 @@ spec: instances: 2 storage: size: 20Gi - {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} - {{- if $configMap }} - {{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }} + {{- if .Values._cluster.scheduling }} + {{- $rawConstraints := get .Values._cluster.scheduling "globalAppTopologySpreadConstraints" }} {{- if $rawConstraints }} {{- $rawConstraints | fromYaml | toYaml | nindent 2 }} labelSelector: diff --git a/packages/system/keycloak/templates/ingress.yaml b/packages/system/keycloak/templates/ingress.yaml index 30120619..0e0f56cb 100644 --- a/packages/system/keycloak/templates/ingress.yaml +++ b/packages/system/keycloak/templates/ingress.yaml @@ -1,7 +1,6 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} -{{- $exposeIngress := index $cozyConfig.data "expose-ingress" | default "tenant-root" }} +{{- $host := index .Values._cluster "root-host" }} +{{- $issuerType := (index .Values._cluster "clusterissuer") | default "http01" }} +{{- $exposeIngress := (index .Values._cluster "expose-ingress") | default "tenant-root" }} apiVersion: networking.k8s.io/v1 kind: Ingress diff --git a/packages/system/keycloak/templates/sts.yaml b/packages/system/keycloak/templates/sts.yaml index 4705f77c..96d30601 100644 --- a/packages/system/keycloak/templates/sts.yaml +++ b/packages/system/keycloak/templates/sts.yaml @@ -1,6 +1,5 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $host := index .Values._cluster "root-host" }} +{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }} {{- $existingPassword := lookup "v1" "Secret" "cozy-keycloak" (printf "%s-credentials" .Release.Name) }} {{- $password := randAlphaNum 16 -}} diff --git a/packages/system/kubevirt-cdi/templates/cdi-uploadproxy-ingress.yaml b/packages/system/kubevirt-cdi/templates/cdi-uploadproxy-ingress.yaml index 58eef4fa..ee89953f 100644 --- a/packages/system/kubevirt-cdi/templates/cdi-uploadproxy-ingress.yaml +++ b/packages/system/kubevirt-cdi/templates/cdi-uploadproxy-ingress.yaml @@ -1,7 +1,6 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- $exposeServices := splitList "," ((index $cozyConfig.data "expose-services") | default "") }} -{{- $exposeIngress := index $cozyConfig.data "expose-ingress" | default "tenant-root" }} +{{- $host := index .Values._cluster "root-host" }} +{{- $exposeServices := splitList "," ((index .Values._cluster "expose-services") | default "") }} +{{- $exposeIngress := (index .Values._cluster "expose-ingress") | default "tenant-root" }} {{- if and (has "cdi-uploadproxy" $exposeServices) }} diff --git a/packages/system/kubevirt/templates/vm-exportproxy-ingress.yaml b/packages/system/kubevirt/templates/vm-exportproxy-ingress.yaml index b77743d0..a089f5ef 100644 --- a/packages/system/kubevirt/templates/vm-exportproxy-ingress.yaml +++ b/packages/system/kubevirt/templates/vm-exportproxy-ingress.yaml @@ -1,7 +1,6 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- $exposeServices := splitList "," ((index $cozyConfig.data "expose-services") | default "") }} -{{- $exposeIngress := index $cozyConfig.data "expose-ingress" | default "tenant-root" }} +{{- $host := index .Values._cluster "root-host" }} +{{- $exposeServices := splitList "," ((index .Values._cluster "expose-services") | default "") }} +{{- $exposeIngress := (index .Values._cluster "expose-ingress") | default "tenant-root" }} {{- if and (has "vm-exportproxy" $exposeServices) }} apiVersion: networking.k8s.io/v1 diff --git a/packages/tests/cozy-lib-tests/tests/quota_values.yaml b/packages/tests/cozy-lib-tests/tests/quota_values.yaml index bcf6a21e..87e5cf17 100644 --- a/packages/tests/cozy-lib-tests/tests/quota_values.yaml +++ b/packages/tests/cozy-lib-tests/tests/quota_values.yaml @@ -3,3 +3,6 @@ quota: cpu: "20" storage: "5Gi" foobar: "3" + +_cluster: {} +_namespace: {} diff --git a/pkg/registry/apps/application/rest.go b/pkg/registry/apps/application/rest.go index ee189e26..9e8fb891 100644 --- a/pkg/registry/apps/application/rest.go +++ b/pkg/registry/apps/application/rest.go @@ -148,6 +148,11 @@ func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation return nil, fmt.Errorf("expected *appsv1alpha1.Application object, got %T", obj) } + // Validate that values don't contain reserved keys (starting with "_") + if err := validateNoInternalKeys(app.Spec); err != nil { + return nil, apierrors.NewBadRequest(err.Error()) + } + // Convert Application to HelmRelease helmRelease, err := r.ConvertApplicationToHelmRelease(app) if err != nil { @@ -442,6 +447,11 @@ func (r *REST) Update(ctx context.Context, name string, objInfo rest.UpdatedObje return nil, false, fmt.Errorf("expected *appsv1alpha1.Application object, got %T", newObj) } + // Validate that values don't contain reserved keys (starting with "_") + if err := validateNoInternalKeys(app.Spec); err != nil { + return nil, false, apierrors.NewBadRequest(err.Error()) + } + // Convert Application to HelmRelease helmRelease, err := r.ConvertApplicationToHelmRelease(app) if err != nil { @@ -851,8 +861,49 @@ func (r *REST) ConvertApplicationToHelmRelease(app *appsv1alpha1.Application) (* return r.convertApplicationToHelmRelease(app) } +// filterInternalKeys removes keys starting with "_" from the JSON values +func filterInternalKeys(values *apiextv1.JSON) *apiextv1.JSON { + if values == nil || len(values.Raw) == 0 { + return values + } + var data map[string]interface{} + if err := json.Unmarshal(values.Raw, &data); err != nil { + return values + } + for key := range data { + if strings.HasPrefix(key, "_") { + delete(data, key) + } + } + filtered, err := json.Marshal(data) + if err != nil { + return values + } + return &apiextv1.JSON{Raw: filtered} +} + +// validateNoInternalKeys checks that values don't contain keys starting with "_" +func validateNoInternalKeys(values *apiextv1.JSON) error { + if values == nil || len(values.Raw) == 0 { + return nil + } + var data map[string]interface{} + if err := json.Unmarshal(values.Raw, &data); err != nil { + return err + } + for key := range data { + if strings.HasPrefix(key, "_") { + return fmt.Errorf("values key %q is reserved (keys starting with '_' are not allowed)", key) + } + } + return nil +} + // convertHelmReleaseToApplication implements the actual conversion logic func (r *REST) convertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1alpha1.Application, error) { + // Filter out internal keys (starting with "_") from spec + filteredSpec := filterInternalKeys(hr.Spec.Values) + app := appsv1alpha1.Application{ TypeMeta: metav1.TypeMeta{ APIVersion: "apps.cozystack.io/v1alpha1", @@ -868,7 +919,7 @@ func (r *REST) convertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1al Labels: filterPrefixedMap(hr.Labels, LabelPrefix), Annotations: filterPrefixedMap(hr.Annotations, AnnotationPrefix), }, - Spec: hr.Spec.Values, + Spec: filteredSpec, Status: appsv1alpha1.ApplicationStatus{ Version: hr.Status.LastAttemptedRevision, }, @@ -935,6 +986,12 @@ func (r *REST) convertApplicationToHelmRelease(app *appsv1alpha1.Application) (* Retries: -1, }, }, + ValuesFrom: []helmv2.ValuesReference{ + { + Kind: "Secret", + Name: "cozystack-values", + }, + }, Values: app.Spec, }, } From 31bcbbd5bf7ad3bc39a31e6b2a5d2654bd0e2890 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 5 Jan 2026 18:11:41 +0100 Subject: [PATCH 44/78] [kubernetes] Fix endpoints for cilium-gateway (#1729) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andrei Kvapil ## What this PR does Integrate fix - https://github.com/kubevirt/cloud-provider-kubevirt/pull/379 ### Release note ```release-note [kubernetes] Fix endpoints for cilium-gateway ``` ## Summary by CodeRabbit * **Bug Fixes** * Improved handling of incomplete endpoint data by introducing fallback detection mechanisms. * Enhanced service discovery to gather endpoints from all available resources when standard detection fails. * Updated logging to provide better visibility into fallback operations and current resource status. ✏️ Tip: You can customize this high-level summary in your review settings. --- .../patches/{354.diff => 379.diff} | 83 ++++++++++++++++++- 1 file changed, 80 insertions(+), 3 deletions(-) rename packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/{354.diff => 379.diff} (63%) diff --git a/packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/354.diff b/packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/379.diff similarity index 63% rename from packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/354.diff rename to packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/379.diff index 3410ea93..ad1ec9c5 100644 --- a/packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/354.diff +++ b/packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/379.diff @@ -1,5 +1,5 @@ diff --git a/pkg/controller/kubevirteps/kubevirteps_controller.go b/pkg/controller/kubevirteps/kubevirteps_controller.go -index 53388eb8e..28644236f 100644 +index 53388eb8e..873060251 100644 --- a/pkg/controller/kubevirteps/kubevirteps_controller.go +++ b/pkg/controller/kubevirteps/kubevirteps_controller.go @@ -12,7 +12,6 @@ import ( @@ -10,12 +10,17 @@ index 53388eb8e..28644236f 100644 "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" utilruntime "k8s.io/apimachinery/pkg/util/runtime" -@@ -669,35 +668,50 @@ func (c *Controller) getDesiredEndpoints(service *v1.Service, tenantSlices []*di +@@ -666,38 +665,62 @@ func (c *Controller) getDesiredEndpoints(service *v1.Service, tenantSlices []*di + // for extracting the nodes it does not matter what type of address we are dealing with + // all nodes with an endpoint for a corresponding slice will be selected. + nodeSet := sets.Set[string]{} ++ hasEndpointsWithoutNodeName := false for _, slice := range tenantSlices { for _, endpoint := range slice.Endpoints { // find all unique nodes that correspond to an endpoint in a tenant slice + if endpoint.NodeName == nil { + klog.Warningf("Skipping endpoint without NodeName in slice %s/%s", slice.Namespace, slice.Name) ++ hasEndpointsWithoutNodeName = true + continue + } nodeSet.Insert(*endpoint.NodeName) @@ -23,6 +28,13 @@ index 53388eb8e..28644236f 100644 } - klog.Infof("Desired nodes for service %s in namespace %s: %v", service.Name, service.Namespace, sets.List(nodeSet)) ++ // Fallback: if no endpoints with NodeName were found, but there are endpoints without NodeName, ++ // distribute traffic to all VMIs (similar to ExternalTrafficPolicy=Cluster behavior) ++ if nodeSet.Len() == 0 && hasEndpointsWithoutNodeName { ++ klog.Infof("No endpoints with NodeName found for service %s/%s, falling back to all VMIs", service.Namespace, service.Name) ++ return c.getAllVMIEndpoints() ++ } ++ + klog.Infof("Desired nodes for service %s/%s: %v", service.Namespace, service.Name, sets.List(nodeSet)) for _, node := range sets.List(nodeSet) { @@ -68,7 +80,7 @@ index 53388eb8e..28644236f 100644 desiredEndpoints = append(desiredEndpoints, &discovery.Endpoint{ Addresses: []string{i.IP}, Conditions: discovery.EndpointConditions{ -@@ -705,9 +719,9 @@ func (c *Controller) getDesiredEndpoints(service *v1.Service, tenantSlices []*di +@@ -705,9 +728,9 @@ func (c *Controller) getDesiredEndpoints(service *v1.Service, tenantSlices []*di Serving: &serving, Terminating: &terminating, }, @@ -80,6 +92,71 @@ index 53388eb8e..28644236f 100644 } } } +@@ -716,6 +739,64 @@ func (c *Controller) getDesiredEndpoints(service *v1.Service, tenantSlices []*di + return desiredEndpoints + } + ++// getAllVMIEndpoints returns endpoints for all VMIs in the infra namespace. ++// This is used as a fallback when tenant endpoints don't have NodeName specified, ++// similar to ExternalTrafficPolicy=Cluster behavior where traffic is distributed to all nodes. ++func (c *Controller) getAllVMIEndpoints() []*discovery.Endpoint { ++ var endpoints []*discovery.Endpoint ++ ++ // List all VMIs in the infra namespace ++ vmiList, err := c.infraDynamic. ++ Resource(kubevirtv1.VirtualMachineInstanceGroupVersionKind.GroupVersion().WithResource("virtualmachineinstances")). ++ Namespace(c.infraNamespace). ++ List(context.TODO(), metav1.ListOptions{}) ++ if err != nil { ++ klog.Errorf("Failed to list VMIs in namespace %q: %v", c.infraNamespace, err) ++ return endpoints ++ } ++ ++ for _, obj := range vmiList.Items { ++ vmi := &kubevirtv1.VirtualMachineInstance{} ++ err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, vmi) ++ if err != nil { ++ klog.Errorf("Failed to convert Unstructured to VirtualMachineInstance: %v", err) ++ continue ++ } ++ ++ if vmi.Status.NodeName == "" { ++ klog.Warningf("Skipping VMI %s/%s: NodeName is empty", vmi.Namespace, vmi.Name) ++ continue ++ } ++ nodeNamePtr := &vmi.Status.NodeName ++ ++ ready := vmi.Status.Phase == kubevirtv1.Running ++ serving := vmi.Status.Phase == kubevirtv1.Running ++ terminating := vmi.Status.Phase == kubevirtv1.Failed || vmi.Status.Phase == kubevirtv1.Succeeded ++ ++ for _, i := range vmi.Status.Interfaces { ++ if i.Name == "default" { ++ if i.IP == "" { ++ klog.Warningf("VMI %s/%s interface %q has no IP, skipping", vmi.Namespace, vmi.Name, i.Name) ++ continue ++ } ++ endpoints = append(endpoints, &discovery.Endpoint{ ++ Addresses: []string{i.IP}, ++ Conditions: discovery.EndpointConditions{ ++ Ready: &ready, ++ Serving: &serving, ++ Terminating: &terminating, ++ }, ++ NodeName: nodeNamePtr, ++ }) ++ break ++ } ++ } ++ } ++ ++ klog.Infof("Fallback: created %d endpoints from all VMIs in namespace %s", len(endpoints), c.infraNamespace) ++ return endpoints ++} ++ + func (c *Controller) ensureEndpointSliceLabels(slice *discovery.EndpointSlice, svc *v1.Service) (map[string]string, bool) { + labels := make(map[string]string) + labelsChanged := false diff --git a/pkg/controller/kubevirteps/kubevirteps_controller_test.go b/pkg/controller/kubevirteps/kubevirteps_controller_test.go index 1c97035b4..d205d0bed 100644 --- a/pkg/controller/kubevirteps/kubevirteps_controller_test.go From e40a95849d43336d0169953c95cfca55f6eaa8ad Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Mon, 5 Jan 2026 22:48:01 +0400 Subject: [PATCH 45/78] [testing] Add aliases and autocomplete (#1803) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does Adds a `k=kubectl` alias and bash completion for kubectl to the e2e-testing sandbox container to maintainers have an easier time exec'ing into the CI container when something needs to be debugged. ### Release note ```release-note [testing] Add k=kubectl alias and enable kubectl completion in the CI container. ``` ## Summary by CodeRabbit * **Chores** * Enhanced the e2e sandbox image to enable shell bash-completion and kubectl command completion. * Added an alias (k) and completion wiring for kubectl to improve interactive command use. * These changes augment the test environment shell during image build to provide a smoother developer/testing experience. ✏️ Tip: You can customize this high-level summary in your review settings. --- packages/core/testing/Chart.yaml | 0 packages/core/testing/Makefile | 0 packages/core/testing/images/e2e-sandbox/Dockerfile | 10 +++++++++- packages/core/testing/values.yaml | 0 4 files changed, 9 insertions(+), 1 deletion(-) mode change 100755 => 100644 packages/core/testing/Chart.yaml mode change 100755 => 100644 packages/core/testing/Makefile mode change 100755 => 100644 packages/core/testing/images/e2e-sandbox/Dockerfile mode change 100755 => 100644 packages/core/testing/values.yaml diff --git a/packages/core/testing/Chart.yaml b/packages/core/testing/Chart.yaml old mode 100755 new mode 100644 diff --git a/packages/core/testing/Makefile b/packages/core/testing/Makefile old mode 100755 new mode 100644 diff --git a/packages/core/testing/images/e2e-sandbox/Dockerfile b/packages/core/testing/images/e2e-sandbox/Dockerfile old mode 100755 new mode 100644 index ce6cabdd..ee57f193 --- a/packages/core/testing/images/e2e-sandbox/Dockerfile +++ b/packages/core/testing/images/e2e-sandbox/Dockerfile @@ -9,7 +9,7 @@ ARG TARGETOS ARG TARGETARCH RUN apt update -q -RUN apt install -yq --no-install-recommends psmisc genisoimage ca-certificates qemu-kvm qemu-utils iproute2 iptables wget xz-utils netcat curl jq make git +RUN apt install -yq --no-install-recommends psmisc genisoimage ca-certificates qemu-kvm qemu-utils iproute2 iptables wget xz-utils netcat curl jq make git bash-completion RUN curl -sSL "https://github.com/siderolabs/talos/releases/download/v${TALOSCTL_VERSION}/talosctl-${TARGETOS}-${TARGETARCH}" -o /usr/local/bin/talosctl \ && chmod +x /usr/local/bin/talosctl RUN curl -sSL "https://dl.k8s.io/release/v${KUBECTL_VERSION}/bin/${TARGETOS}/${TARGETARCH}/kubectl" -o /usr/local/bin/kubectl \ @@ -21,5 +21,13 @@ 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 100755 new mode 100644 From a51e2078a86ffe7b9e19abead7bd66d07b4b7593 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 6 Jan 2026 16:17:25 +0100 Subject: [PATCH 46/78] [linstor] Build linstor-server with custom patches (#1726) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does Build piraeus-server (linstor-server) from source with custom patches: - **adjust-on-resfile-change.diff** — Use actual device path in res file during toggle-disk; fix LUKS data offset - Upstream: [#473](https://github.com/LINBIT/linstor-server/pull/473), [#472](https://github.com/LINBIT/linstor-server/pull/472) - **allow-toggle-disk-retry.diff** — Allow retry and cancellation of failed toggle-disk operations - Upstream: [#475](https://github.com/LINBIT/linstor-server/pull/475) - **force-metadata-check-on-disk-add.diff** — Create metadata during toggle-disk from diskless to diskful - Upstream: [#474](https://github.com/LINBIT/linstor-server/pull/474) - **skip-adjust-when-device-inaccessible.diff** — Skip DRBD adjust/res file regeneration when child layer device is inaccessible - Upstream: [#471](https://github.com/LINBIT/linstor-server/pull/471) Also updates plunger-satellite script and values.yaml for the new build. ### Release note ```release-note [linstor] Build linstor-server with custom patches for improved disk handling ``` ## Summary by CodeRabbit * **New Features** * Added automatic DRBD stall detection and recovery, improving storage resync resilience without manual intervention. * Introduced configurable container image references via Helm values for streamlined deployment. * **Bug Fixes** * Enhanced disk toggle operations with retry and cancellation support for better error handling. * Improved metadata creation during disk state transitions. * Added device accessibility checks to prevent errors when underlying storage devices are unavailable. * Fixed LUKS encryption header sizing for consistent deployment across nodes. ✏️ Tip: You can customize this high-level summary in your review settings. --- Makefile | 1 + packages/system/linstor/Makefile | 19 ++ .../linstor/hack/plunger/plunger-satellite.sh | 122 ++++++++- .../linstor/images/piraeus-server/Dockerfile | 172 +++++++++++++ .../images/piraeus-server/patches/README.md | 12 + .../patches/adjust-on-resfile-change.diff | 48 ++++ .../patches/allow-toggle-disk-retry.diff | 235 ++++++++++++++++++ .../force-metadata-check-on-disk-add.diff | 63 +++++ .../skip-adjust-when-device-inaccessible.diff | 93 +++++++ .../system/linstor/templates/_helpers.tpl | 24 -- .../system/linstor/templates/cluster.yaml | 4 +- .../linstor/templates/satellites-cozy.yaml | 1 + .../linstor/templates/satellites-plunger.yaml | 4 +- packages/system/linstor/values.yaml | 5 +- 14 files changed, 773 insertions(+), 30 deletions(-) create mode 100644 packages/system/linstor/images/piraeus-server/Dockerfile create mode 100644 packages/system/linstor/images/piraeus-server/patches/README.md create mode 100644 packages/system/linstor/images/piraeus-server/patches/adjust-on-resfile-change.diff create mode 100644 packages/system/linstor/images/piraeus-server/patches/allow-toggle-disk-retry.diff create mode 100644 packages/system/linstor/images/piraeus-server/patches/force-metadata-check-on-disk-add.diff create mode 100644 packages/system/linstor/images/piraeus-server/patches/skip-adjust-when-device-inaccessible.diff delete mode 100644 packages/system/linstor/templates/_helpers.tpl diff --git a/Makefile b/Makefile index c1de2a9f..32aef810 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,7 @@ build: build-deps make -C packages/system/cozystack-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/kubeovn-webhook image make -C packages/system/kubeovn-plunger image make -C packages/system/dashboard image diff --git a/packages/system/linstor/Makefile b/packages/system/linstor/Makefile index 5de22194..da895085 100644 --- a/packages/system/linstor/Makefile +++ b/packages/system/linstor/Makefile @@ -1,4 +1,23 @@ export NAME=linstor export NAMESPACE=cozy-$(NAME) +include ../../../scripts/common-envs.mk include ../../../scripts/package.mk + +LINSTOR_VERSION ?= 1.32.3 + +image: + docker buildx build images/piraeus-server \ + --build-arg LINSTOR_VERSION=$(LINSTOR_VERSION) \ + --build-arg K8S_AWAIT_ELECTION_VERSION=v0.4.2 \ + --tag $(REGISTRY)/piraeus-server:$(call settag,$(LINSTOR_VERSION)) \ + --tag $(REGISTRY)/piraeus-server:$(call settag,$(LINSTOR_VERSION)-$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/piraeus-server:latest \ + --cache-to type=inline \ + --metadata-file images/piraeus-server.json \ + $(BUILDX_ARGS) + REPOSITORY="$(REGISTRY)/piraeus-server" \ + yq -i '.piraeusServer.image.repository = strenv(REPOSITORY)' values.yaml + TAG="$(call settag,$(LINSTOR_VERSION))@$$(yq e '."containerimage.digest"' images/piraeus-server.json -o json -r)" \ + yq -i '.piraeusServer.image.tag = strenv(TAG)' values.yaml + rm -f images/piraeus-server.json diff --git a/packages/system/linstor/hack/plunger/plunger-satellite.sh b/packages/system/linstor/hack/plunger/plunger-satellite.sh index 688cfd65..4a488a51 100755 --- a/packages/system/linstor/hack/plunger/plunger-satellite.sh +++ b/packages/system/linstor/hack/plunger/plunger-satellite.sh @@ -10,10 +10,125 @@ trap terminate SIGINT SIGQUIT SIGTERM echo "Starting Linstor per-satellite plunger" +INTERVAL_SEC="${INTERVAL_SEC:-30}" +STALL_ITERS="${STALL_ITERS:-4}" +STATE_FILE="${STATE_FILE:-/run/drbd-sync-watch.state}" + +log() { printf '%s %s\n' "$(date -Is)" "$*" >&2; } + +drbd_status_json() { + drbdsetup status --json 2>/dev/null || true +} + +# Detect DRBD resources where resync is stuck: +# - at least one local device is Inconsistent +# - there is an active SyncTarget peer +# - there are other peers suspended with resync-suspended:dependency +# Output format: " " +drbd_stall_candidates() { + jq -r ' + .[]? + | . as $r + | select(any($r.devices[]?; ."disk-state" == "Inconsistent")) + | ( + [ $r.connections[]? + | . as $c + | $c.peer_devices[]? + | select(."replication-state" == "SyncTarget") + | { peer: $c.name, pct: (."percent-in-sync" // empty) } + ] | .[0]? + ) as $sync + | select($sync != null and ($sync.pct|tostring) != "") + | select(any($r.connections[]?.peer_devices[]?; ."resync-suspended" == "dependency")) + | "\($r.name) \($sync.peer) \($sync.pct)" + ' +} + +drbd_stall_load_state() { + [ -f "$STATE_FILE" ] && cat "$STATE_FILE" || true +} + +drbd_stall_save_state() { + local tmp="${STATE_FILE}.tmp" + cat >"$tmp" + mv "$tmp" "$STATE_FILE" +} + +# Break stalled resync by disconnecting the current SyncTarget peer. +# After reconnect, DRBD will typically pick another eligible peer and continue syncing. +drbd_stall_act() { + local res="$1" + local peer="$2" + local pct="$3" + log "STALL detected: res=$res sync_peer=$peer percent_in_sync=$pct -> disconnect/connect" + drbdadm disconnect "${res}:${peer}" && drbdadm connect "$res" || log "WARN: action failed for ${res}:${peer}" +} + +# Track percent-in-sync progress across iterations. +# If progress does not change for STALL_ITERS loops, trigger reconnect. +drbd_fix_stalled_sync() { + local now prev json out + now="$(date +%s)" + prev="$(drbd_stall_load_state)" + + json="$(drbd_status_json)" + [ -n "$json" ] || return 0 + + out="$(printf '%s' "$json" | drbd_stall_candidates)" + + local new_state="" + local acts="" + + while IFS= read -r line; do + [ -n "$line" ] || continue + set -- $line + local res="$1" peer="$2" pct="$3" + local key="${res} ${peer}" + + local prev_line + prev_line="$(printf '%s\n' "$prev" | awk -v k="$key" '$1" "$2==k {print; exit}')" + + local cnt last_act prev_pct prev_cnt prev_act + if [ -n "$prev_line" ]; then + set -- $prev_line + prev_pct="$3" + prev_cnt="$4" + prev_act="$5" + if [ "$pct" = "$prev_pct" ]; then + cnt=$((prev_cnt + 1)) + else + cnt=1 + fi + last_act="$prev_act" + else + cnt=1 + last_act=0 + fi + + if [ "$cnt" -ge "$STALL_ITERS" ]; then + acts="${acts}${res} ${peer} ${pct}"$'\n' + cnt=0 + last_act="$now" + fi + + new_state="${new_state}${res} ${peer} ${pct} ${cnt} ${last_act}"$'\n' + done <<< "$out" + + if [ -n "$acts" ]; then + while IFS= read -r a; do + [ -n "$a" ] || continue + set -- $a + drbd_stall_act "$1" "$2" "$3" + done <<< "$acts" + fi + + printf '%s' "$new_state" | drbd_stall_save_state +} + while true; do # timeout at the start of the loop to give a chance for the fresh linstor-satellite instance to cleanup itself - sleep 30 & + sleep "$INTERVAL_SEC" & pid=$! wait $pid @@ -21,7 +136,7 @@ while true; do # the `/` path could not be a backing file for a loop device, so it's a good indicator of a stuck loop device # TODO describe the issue in more detail # Using the direct /usr/sbin/losetup as the linstor-satellite image has own wrapper in /usr/local - stale_loopbacks=$(/usr/sbin/losetup --json | jq -r '.[][] | select(."back-file" == "/" or ."back-file" == "/ (deleted)").name' ) + stale_loopbacks=$(/usr/sbin/losetup --json | jq -r '.[][] | select(."back-file" == "/" or ."back-file" == "/ (deleted)").name') for stale_device in $stale_loopbacks; do ( echo "Detaching stuck loop device ${stale_device}" set -x @@ -39,4 +154,7 @@ while true; do drbdadm up "${secondary}" || echo "Command failed" ); done + # Detect and fix stalled DRBD resync by switching SyncTarget peer + drbd_fix_stalled_sync || true + done diff --git a/packages/system/linstor/images/piraeus-server/Dockerfile b/packages/system/linstor/images/piraeus-server/Dockerfile new file mode 100644 index 00000000..049a3f47 --- /dev/null +++ b/packages/system/linstor/images/piraeus-server/Dockerfile @@ -0,0 +1,172 @@ +ARG DISTRO=bookworm +ARG LINSTOR_VERSION + +# ------------------------------------------------------------------------------ +# Build linstor-server from source +FROM debian:bookworm AS builder + +ARG LINSTOR_VERSION +ARG VERSION=${LINSTOR_VERSION} +ARG DISTRO + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update \ + && apt-get -y upgrade \ + && apt-get -y install build-essential git default-jdk-headless python3-all debhelper wget unzip && \ + wget https://services.gradle.org/distributions/gradle-8.9-bin.zip -O /tmp/gradle.zip && \ + unzip -d /opt /tmp/gradle.zip && \ + rm /tmp/gradle.zip && \ + ln -s /opt/gradle-8.9/bin/gradle /usr/local/bin/gradle + +RUN git clone https://github.com/LINBIT/linstor-server.git /linstor-server +WORKDIR /linstor-server +RUN git checkout v${VERSION} + +# Apply patches +COPY patches /patches +RUN git apply /patches/*.diff && \ + git config user.email "build@cozystack.io" && \ + git config user.name "Cozystack Builder" && \ + git add -A && \ + git commit -m "Apply patches" + +# Initialize git submodules +RUN git submodule update --init --recursive || make check-submods + +# Pre-download ALL dependencies before make tarball +# This ensures all transitive dependencies are cached, including optional ones like AWS SDK +RUN ./gradlew getProtoc +RUN ./gradlew generateJava +RUN ./gradlew --no-daemon --gradle-user-home .gradlehome downloadDependencies + +# Manually create tarball without removing caches +# make tarball removes .gradlehome/caches/[0-9]* which deletes dependencies +# So we'll do the steps manually but keep the caches +RUN make check-submods versioninfo gen-java FORCE=1 VERSION=${VERSION} +RUN make server/jar.deps controller/jar.deps satellite/jar.deps jclcrypto/jar.deps FORCE=1 VERSION=${VERSION} +RUN make .filelist FORCE=1 VERSION=${VERSION} PRESERVE_DEBIAN=1 +# Don't remove caches - we need them for offline build +RUN rm -Rf .gradlehome/wrapper .gradlehome/native .gradlehome/.tmp || true +RUN mkdir -p ./libs +RUN make tgz VERSION=${VERSION} + +# Extract tarball and build DEB packages from it +RUN mv linstor-server-${VERSION}.tar.gz /linstor-server_${VERSION}.orig.tar.gz \ + && tar -C / -xvf /linstor-server_${VERSION}.orig.tar.gz + +WORKDIR /linstor-server-${VERSION} +# Verify .gradlehome is present in extracted tarball +RUN test -d .gradlehome && echo ".gradlehome found in tarball" || (echo ".gradlehome not found in tarball!" && exit 1) + +# Build DEB packages from tarball +# Override GRADLE_FLAGS to remove --offline flag, allowing Gradle to download missing dependencies +RUN sed -i 's/GRADLE_FLAGS = --offline/GRADLE_FLAGS =/' debian/rules || true +RUN LD_LIBRARY_PATH='' dpkg-buildpackage -rfakeroot -b -uc + +# Copy built .deb packages to a location accessible from final image +# dpkg-buildpackage creates packages in parent directory +RUN mkdir -p /packages-output && \ + find .. -maxdepth 1 -name "linstor-*.deb" -exec cp {} /packages-output/ \; && \ + test -n "$(ls -A /packages-output)" || (echo "ERROR: No linstor .deb packages found after build." && exit 1) + +# ------------------------------------------------------------------------------ +# Final image +FROM debian:${DISTRO} + +LABEL maintainer="Roland Kammerer " + +ARG LINSTOR_VERSION +ARG DISTRO + +# Copy built .deb packages from builder stage +# dpkg-buildpackage creates packages in parent directory, we copied them to /packages-output +COPY --from=builder /packages-output/ /packages/ + +RUN { echo 'APT::Install-Recommends "false";' ; echo 'APT::Install-Suggests "false";' ; } > /etc/apt/apt.conf.d/99_piraeus + +RUN --mount=type=cache,target=/var/cache,sharing=private \ + --mount=type=cache,target=/var/lib/apt/lists,sharing=private \ + --mount=type=tmpfs,target=/var/log \ + # Install wget first for downloading keyring + apt-get update && apt-get install -y wget ca-certificates && \ + # Enable contrib repos for zfsutils \ + . /etc/os-release && \ + sed -i -r 's/^Components: (.*)$/Components: \1 contrib/' /etc/apt/sources.list.d/debian.sources && \ + echo "deb http://deb.debian.org/debian $VERSION_CODENAME-backports contrib" > /etc/apt/sources.list.d/backports.list && \ + wget https://packages.linbit.com/public/linbit-keyring.deb -O /var/cache/linbit-keyring.deb && \ + dpkg -i /var/cache/linbit-keyring.deb && \ + echo "deb http://packages.linbit.com/public $VERSION_CODENAME misc" > /etc/apt/sources.list.d/linbit.list && \ + apt-get update && \ + # Install useful utilities and general dependencies + apt-get install -y udev drbd-utils jq net-tools iputils-ping iproute2 dnsutils netcat-traditional sysstat curl util-linux && \ + # Install dependencies for optional features \ + apt-get install -y \ + # cryptsetup: luks layer + cryptsetup \ + # e2fsprogs: LINSTOR can create file systems \ + e2fsprogs \ + # lsscsi: exos layer \ + lsscsi \ + # lvm2: manage lvm storage pools \ + lvm2 \ + # multipath-tools: exos layer \ + multipath-tools \ + # nvme-cli: nvme layer + nvme-cli \ + # procps: used by LINSTOR to find orphaned send/receive processes \ + procps \ + # socat: used with thin-send-recv to send snapshots to another LINSTOR cluster + socat \ + # thin-send-recv: used to send/receive snapshots of LVM thin volumes \ + thin-send-recv \ + # xfsprogs: LINSTOR can create file systems; xfs deps \ + xfsprogs \ + # zstd: used with thin-send-recv to send snapshots to another LINSTOR cluster \ + zstd \ + # zfsutils-linux: for zfs storage pools \ + zfsutils-linux/$VERSION_CODENAME-backports \ + && \ + # remove udev, no need for it in the container \ + apt-get remove -y udev && \ + # Install linstor packages from built .deb files and linstor-client from repository + apt-get install -y default-jre-headless python3-all python3-natsort linstor-client \ + && ls packages/*.deb >/dev/null && (dpkg -i packages/*.deb || apt-get install -f -y) \ + && rm -rf /packages \ + && sed -i 's/"-Djdk.tls.acknowledgeCloseNotify=true"//g' /usr/share/linstor-server/bin/Controller \ + && apt-get clean + +# Log directory need to be group writable. OpenShift assigns random UID and GID, without extra RBAC changes we can only influence the GID. +RUN mkdir /var/log/linstor-controller && \ + chown 0:1000 /var/log/linstor-controller && \ + chmod -R 0775 /var/log/linstor-controller && \ + # Ensure we log to files in containers, otherwise SOS reports won't show any logs at all + sed -i 's###' /usr/share/linstor-server/lib/conf/logback.xml + + +RUN lvmconfig --type current --mergedconfig --config 'activation { udev_sync = 0 udev_rules = 0 monitoring = 0 } devices { global_filter = [ "r|^/dev/drbd|" ] obtain_device_list_from_udev = 0}' > /etc/lvm/lvm.conf.new && mv /etc/lvm/lvm.conf.new /etc/lvm/lvm.conf +RUN echo 'global { usage-count no; }' > /etc/drbd.d/global_common.conf + +# controller +EXPOSE 3376/tcp 3377/tcp 3370/tcp 3371/tcp + +# satellite +EXPOSE 3366/tcp 3367/tcp + +RUN wget https://raw.githubusercontent.com/piraeusdatastore/piraeus/refs/heads/master/dockerfiles/piraeus-server/entry.sh -O /usr/bin/piraeus-entry.sh \ + && chmod +x /usr/bin/piraeus-entry.sh + +ARG K8S_AWAIT_ELECTION_VERSION=v0.4.2 +# TARGETARCH is a docker special variable: https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope +ARG TARGETARCH + +RUN wget https://github.com/LINBIT/k8s-await-election/releases/download/${K8S_AWAIT_ELECTION_VERSION}/k8s-await-election-${K8S_AWAIT_ELECTION_VERSION}-linux-${TARGETARCH}.tar.gz -O - | tar -xvz -C /usr/bin/ + +ARG LOSETUP_CONTAINER_VERSION=v1.0.1 +RUN wget "https://github.com/LINBIT/losetup-container/releases/download/${LOSETUP_CONTAINER_VERSION}/losetup-container-$(uname -m)-unknown-linux-gnu.tar.gz" -O - | tar -xvz -C /usr/local/sbin && \ + printf '#!/bin/sh\nLOSETUP_CONTAINER_ORIGINAL_LOSETUP=%s exec /usr/local/sbin/losetup-container "$@"\n' $(command -v losetup) > /usr/local/sbin/losetup && \ + chmod +x /usr/local/sbin/losetup + +RUN wget "https://dl.k8s.io/$(wget -O - https://dl.k8s.io/release/stable.txt)/bin/linux/${TARGETARCH}/kubectl" -O /usr/local/bin/kubectl && chmod +x /usr/local/bin/kubectl + +CMD ["startSatellite"] +ENTRYPOINT ["/usr/bin/k8s-await-election", "/usr/bin/piraeus-entry.sh"] diff --git a/packages/system/linstor/images/piraeus-server/patches/README.md b/packages/system/linstor/images/piraeus-server/patches/README.md new file mode 100644 index 00000000..c219eaf3 --- /dev/null +++ b/packages/system/linstor/images/piraeus-server/patches/README.md @@ -0,0 +1,12 @@ +# LINSTOR Server Patches + +Custom patches for piraeus-server (linstor-server) v1.32.3. + +- **adjust-on-resfile-change.diff** — Use actual device path in res file during toggle-disk; fix LUKS data offset + - Upstream: [#473](https://github.com/LINBIT/linstor-server/pull/473), [#472](https://github.com/LINBIT/linstor-server/pull/472) +- **allow-toggle-disk-retry.diff** — Allow retry and cancellation of failed toggle-disk operations + - Upstream: [#475](https://github.com/LINBIT/linstor-server/pull/475) +- **force-metadata-check-on-disk-add.diff** — Create metadata during toggle-disk from diskless to diskful + - Upstream: [#474](https://github.com/LINBIT/linstor-server/pull/474) +- **skip-adjust-when-device-inaccessible.diff** — Skip DRBD adjust/res file regeneration when child layer device is inaccessible + - Upstream: [#471](https://github.com/LINBIT/linstor-server/pull/471) diff --git a/packages/system/linstor/images/piraeus-server/patches/adjust-on-resfile-change.diff b/packages/system/linstor/images/piraeus-server/patches/adjust-on-resfile-change.diff new file mode 100644 index 00000000..6788efaf --- /dev/null +++ b/packages/system/linstor/images/piraeus-server/patches/adjust-on-resfile-change.diff @@ -0,0 +1,48 @@ +diff --git a/satellite/src/main/java/com/linbit/linstor/layer/drbd/utils/ConfFileBuilder.java b/satellite/src/main/java/com/linbit/linstor/layer/drbd/utils/ConfFileBuilder.java +index 36c52ccf8..c0bb7b967 100644 +--- a/satellite/src/main/java/com/linbit/linstor/layer/drbd/utils/ConfFileBuilder.java ++++ b/satellite/src/main/java/com/linbit/linstor/layer/drbd/utils/ConfFileBuilder.java +@@ -894,12 +894,16 @@ public class ConfFileBuilder + if (((Volume) vlmData.getVolume()).getFlags().isUnset(localAccCtx, Volume.Flags.DELETE)) + { + final String disk; ++ // Check if we're in toggle-disk operation (adding disk to diskless resource) ++ boolean isDiskAdding = vlmData.getVolume().getAbsResource().getStateFlags().isSomeSet( ++ localAccCtx, Resource.Flags.DISK_ADD_REQUESTED, Resource.Flags.DISK_ADDING); + if ((!isPeerRsc && vlmData.getDataDevice() == null) || + (isPeerRsc && + // FIXME: vlmData.getRscLayerObject().getFlags should be used here + vlmData.getVolume().getAbsResource().disklessForDrbdPeers(accCtx) + ) || +- (!isPeerRsc && ++ // For toggle-disk: if dataDevice is set and we're adding disk, use the actual device ++ (!isPeerRsc && !isDiskAdding && + // FIXME: vlmData.getRscLayerObject().getFlags should be used here + vlmData.getVolume().getAbsResource().isDrbdDiskless(accCtx) + ) +diff --git a/satellite/src/main/java/com/linbit/linstor/layer/luks/CryptSetupCommands.java b/satellite/src/main/java/com/linbit/linstor/layer/luks/CryptSetupCommands.java +index 54dd5c19f..018de58cf 100644 +--- a/satellite/src/main/java/com/linbit/linstor/layer/luks/CryptSetupCommands.java ++++ b/satellite/src/main/java/com/linbit/linstor/layer/luks/CryptSetupCommands.java +@@ -34,6 +34,9 @@ public class CryptSetupCommands implements Luks + private static final Version V2_1_0 = new Version(2, 1, 0); + private static final Version V2_0_0 = new Version(2, 0, 0); + private static final String PBDKF_MAX_MEMORY_KIB = "262144"; // 256 MiB ++ // Fixed LUKS2 data offset in 512-byte sectors (16 MiB = 32768 sectors) ++ // This ensures consistent LUKS header size across all nodes regardless of system defaults ++ private static final String LUKS2_DATA_OFFSET_SECTORS = "32768"; + + @SuppressWarnings("unused") + private final ErrorReporter errorReporter; +@@ -78,6 +81,11 @@ public class CryptSetupCommands implements Luks + command.add(CRYPTSETUP); + command.add("-q"); + command.add("luksFormat"); ++ // Always specify explicit offset to ensure consistent LUKS header size across all nodes ++ // Without this, different systems may create LUKS with different header sizes (16MiB vs 32MiB) ++ // which causes "Low.dev. smaller than requested DRBD-dev. size" errors during toggle-disk ++ command.add("--offset"); ++ command.add(LUKS2_DATA_OFFSET_SECTORS); + if (version.greaterOrEqual(V2_0_0)) + { + command.add("--pbkdf-memory"); diff --git a/packages/system/linstor/images/piraeus-server/patches/allow-toggle-disk-retry.diff b/packages/system/linstor/images/piraeus-server/patches/allow-toggle-disk-retry.diff new file mode 100644 index 00000000..4f4f2fc6 --- /dev/null +++ b/packages/system/linstor/images/piraeus-server/patches/allow-toggle-disk-retry.diff @@ -0,0 +1,235 @@ +diff --git a/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java b/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java +index 1a6f7b7f0..bd447e049 100644 +--- a/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java ++++ b/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java +@@ -58,7 +58,9 @@ import com.linbit.linstor.stateflags.StateFlags; + import com.linbit.linstor.storage.StorageException; + import com.linbit.linstor.storage.data.adapter.drbd.DrbdRscData; + import com.linbit.linstor.storage.interfaces.categories.resource.AbsRscLayerObject; ++import com.linbit.linstor.storage.interfaces.categories.resource.VlmProviderObject; + import com.linbit.linstor.storage.kinds.DeviceLayerKind; ++import com.linbit.linstor.storage.kinds.DeviceProviderKind; + import com.linbit.linstor.storage.utils.LayerUtils; + import com.linbit.linstor.tasks.AutoDiskfulTask; + import com.linbit.linstor.utils.layer.LayerRscUtils; +@@ -317,21 +319,90 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL + + Resource rsc = ctrlApiDataLoader.loadRsc(nodeName, rscName, true); + ++ // Allow retry of the same operation if the previous attempt failed ++ // (the requested flag remains set for retry on reconnection, but we should also allow manual retry) ++ // Also allow cancellation of a failed operation by requesting the opposite operation + if (hasDiskAddRequested(rsc)) + { +- throw new ApiRcException(ApiCallRcImpl.simpleEntry( +- ApiConsts.FAIL_RSC_BUSY, +- "Addition of disk to resource already requested", +- true +- )); ++ if (removeDisk) ++ { ++ // User wants to cancel the failed add-disk operation and go back to diskless ++ // Use the existing disk removal flow to properly cleanup storage on satellite ++ errorReporter.logInfo( ++ "Toggle Disk cancel on %s/%s - cancelling failed DISK_ADD_REQUESTED, reverting to diskless", ++ nodeNameStr, rscNameStr); ++ unmarkDiskAddRequested(rsc); ++ // Also clear DISK_ADDING if it was set ++ unmarkDiskAdding(rsc); ++ ++ // Set storage pool to diskless pool (overwrite the diskful pool that was set) ++ Props rscProps = ctrlPropsHelper.getProps(rsc); ++ rscProps.map().put(ApiConsts.KEY_STOR_POOL_NAME, LinStor.DISKLESS_STOR_POOL_NAME); ++ ++ // Set DISK_REMOVE_REQUESTED to use the existing disk removal flow ++ // This will: ++ // 1. updateAndAdjustDisk sets DISK_REMOVING flag ++ // 2. Satellite sees DISK_REMOVING and deletes LUKS/storage devices ++ // 3. finishOperation rebuilds layer stack as diskless ++ // We keep the existing layer data so satellite can properly cleanup ++ markDiskRemoveRequested(rsc); ++ ++ ctrlTransactionHelper.commit(); ++ ++ // Use existing disk removal flow - this will properly cleanup storage on satellite ++ return Flux ++ .just(ApiCallRcImpl.singleApiCallRc( ++ ApiConsts.MODIFIED, ++ "Cancelling disk addition, reverting to diskless" ++ )) ++ .concatWith(updateAndAdjustDisk(nodeName, rscName, true, toggleIntoTiebreakerRef, context)) ++ .concatWith(ctrlRscDfnApiCallHandler.get().updateProps(rsc.getResourceDefinition())); ++ } ++ // If adding disk and DISK_ADD_REQUESTED is already set, treat as retry ++ // First clean up partially created storage by removing and recreating layer data ++ errorReporter.logInfo( ++ "Toggle Disk retry on %s/%s - DISK_ADD_REQUESTED already set, cleaning up and retrying", ++ nodeNameStr, rscNameStr); ++ ++ // Remove old layer data and recreate to ensure clean state ++ // This forces satellite to delete any partially created storage and start fresh ++ LayerPayload payload = new LayerPayload(); ++ copyDrbdNodeIdIfExists(rsc, payload); ++ List layerList = removeLayerData(rsc); ++ ctrlLayerStackHelper.ensureStackDataExists(rsc, layerList, payload); ++ ++ ctrlTransactionHelper.commit(); ++ return Flux ++ .just(new ApiCallRcImpl()) ++ .concatWith(updateAndAdjustDisk(nodeName, rscName, false, toggleIntoTiebreakerRef, context)) ++ .concatWith(ctrlRscDfnApiCallHandler.get().updateProps(rsc.getResourceDefinition())); + } + if (hasDiskRemoveRequested(rsc)) + { +- throw new ApiRcException(ApiCallRcImpl.simpleEntry( +- ApiConsts.FAIL_RSC_BUSY, +- "Removal of disk from resource already requested", +- true +- )); ++ if (!removeDisk) ++ { ++ // User wants to cancel the failed remove-disk operation ++ errorReporter.logInfo( ++ "Toggle Disk cancel on %s/%s - cancelling failed DISK_REMOVE_REQUESTED", ++ nodeNameStr, rscNameStr); ++ unmarkDiskRemoveRequested(rsc); ++ ctrlTransactionHelper.commit(); ++ return Flux.just( ++ ApiCallRcImpl.singleApiCallRc( ++ ApiConsts.MODIFIED, ++ "Cancelled disk removal request" ++ ) ++ ); ++ } ++ // If removing disk and DISK_REMOVE_REQUESTED is already set, treat as retry ++ errorReporter.logInfo( ++ "Toggle Disk retry on %s/%s - DISK_REMOVE_REQUESTED already set, continuing operation", ++ nodeNameStr, rscNameStr); ++ ctrlTransactionHelper.commit(); ++ return Flux ++ .just(new ApiCallRcImpl()) ++ .concatWith(updateAndAdjustDisk(nodeName, rscName, true, toggleIntoTiebreakerRef, context)) ++ .concatWith(ctrlRscDfnApiCallHandler.get().updateProps(rsc.getResourceDefinition())); + } + + if (!removeDisk && !ctrlVlmCrtApiHelper.isDiskless(rsc)) +@@ -342,17 +413,43 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL + true + )); + } ++ ResourceDefinition rscDfn = rsc.getResourceDefinition(); ++ AccessContext peerCtx = peerAccCtx.get(); ++ + if (removeDisk && ctrlVlmCrtApiHelper.isDiskless(rsc)) + { ++ // Resource is marked as diskless - check if it has orphaned storage layers that need cleanup ++ AbsRscLayerObject layerData = getLayerData(peerCtx, rsc); ++ if (layerData != null && (LayerUtils.hasLayer(layerData, DeviceLayerKind.LUKS) || ++ hasNonDisklessStorageLayer(layerData))) ++ { ++ // Resource is marked as diskless but has orphaned storage layers - need cleanup ++ // Use the existing disk removal flow to properly cleanup storage on satellite ++ errorReporter.logInfo( ++ "Toggle Disk cleanup on %s/%s - resource is diskless but has orphaned storage layers, cleaning up", ++ nodeNameStr, rscNameStr); ++ ++ // Set DISK_REMOVE_REQUESTED to use the existing disk removal flow ++ // This will trigger proper satellite cleanup via DISK_REMOVING flag ++ markDiskRemoveRequested(rsc); ++ ++ ctrlTransactionHelper.commit(); ++ ++ // Use existing disk removal flow - this will properly cleanup storage on satellite ++ return Flux ++ .just(ApiCallRcImpl.singleApiCallRc( ++ ApiConsts.MODIFIED, ++ "Cleaning up orphaned storage layers" ++ )) ++ .concatWith(updateAndAdjustDisk(nodeName, rscName, true, toggleIntoTiebreakerRef, context)) ++ .concatWith(ctrlRscDfnApiCallHandler.get().updateProps(rsc.getResourceDefinition())); ++ } + throw new ApiRcException(ApiCallRcImpl.simpleEntry( + ApiConsts.WARN_RSC_ALREADY_DISKLESS, + "Resource already diskless", + true + )); + } +- +- ResourceDefinition rscDfn = rsc.getResourceDefinition(); +- AccessContext peerCtx = peerAccCtx.get(); + if (removeDisk) + { + // Prevent removal of the last disk +@@ -1324,6 +1421,30 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL + } + } + ++ private void unmarkDiskAddRequested(Resource rsc) ++ { ++ try ++ { ++ rsc.getStateFlags().disableFlags(apiCtx, Resource.Flags.DISK_ADD_REQUESTED); ++ } ++ catch (AccessDeniedException | DatabaseException exc) ++ { ++ throw new ImplementationError(exc); ++ } ++ } ++ ++ private void unmarkDiskRemoveRequested(Resource rsc) ++ { ++ try ++ { ++ rsc.getStateFlags().disableFlags(apiCtx, Resource.Flags.DISK_REMOVE_REQUESTED); ++ } ++ catch (AccessDeniedException | DatabaseException exc) ++ { ++ throw new ImplementationError(exc); ++ } ++ } ++ + private void markDiskAdded(Resource rscData) + { + try +@@ -1389,6 +1510,41 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL + return layerData; + } + ++ /** ++ * Check if the layer stack has a non-diskless STORAGE layer. ++ * This is used to detect orphaned storage layers that need cleanup. ++ */ ++ private boolean hasNonDisklessStorageLayer(AbsRscLayerObject layerDataRef) ++ { ++ boolean hasNonDiskless = false; ++ if (layerDataRef != null) ++ { ++ if (layerDataRef.getLayerKind() == DeviceLayerKind.STORAGE) ++ { ++ for (VlmProviderObject vlmData : layerDataRef.getVlmLayerObjects().values()) ++ { ++ if (vlmData.getProviderKind() != DeviceProviderKind.DISKLESS) ++ { ++ hasNonDiskless = true; ++ break; ++ } ++ } ++ } ++ if (!hasNonDiskless) ++ { ++ for (AbsRscLayerObject child : layerDataRef.getChildren()) ++ { ++ if (hasNonDisklessStorageLayer(child)) ++ { ++ hasNonDiskless = true; ++ break; ++ } ++ } ++ } ++ } ++ return hasNonDiskless; ++ } ++ + private LockGuard createLockGuard() + { + return lockGuardFactory.buildDeferred(LockType.WRITE, LockObj.NODES_MAP, LockObj.RSC_DFN_MAP); diff --git a/packages/system/linstor/images/piraeus-server/patches/force-metadata-check-on-disk-add.diff b/packages/system/linstor/images/piraeus-server/patches/force-metadata-check-on-disk-add.diff new file mode 100644 index 00000000..0c413005 --- /dev/null +++ b/packages/system/linstor/images/piraeus-server/patches/force-metadata-check-on-disk-add.diff @@ -0,0 +1,63 @@ +diff --git a/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java b/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java +index a302ee835..01967a31f 100644 +--- a/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java ++++ b/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java +@@ -371,10 +371,13 @@ public class DrbdLayer implements DeviceLayer + boolean isDiskless = drbdRscData.getAbsResource().isDrbdDiskless(workerCtx); + StateFlags rscFlags = drbdRscData.getAbsResource().getStateFlags(); + boolean isDiskRemoving = rscFlags.isSet(workerCtx, Resource.Flags.DISK_REMOVING); ++ // Check if we're in toggle-disk operation (adding disk to diskless resource) ++ boolean isDiskAdding = rscFlags.isSomeSet(workerCtx, Resource.Flags.DISK_ADD_REQUESTED, Resource.Flags.DISK_ADDING); + + boolean contProcess = isDiskless; + +- boolean processChildren = !isDiskless || isDiskRemoving; ++ // Process children when: has disk, removing disk, OR adding disk (toggle-disk) ++ boolean processChildren = !isDiskless || isDiskRemoving || isDiskAdding; + // do not process children when ONLY DRBD_DELETE flag is set (DELETE flag is still unset) + processChildren &= (!rscFlags.isSet(workerCtx, Resource.Flags.DRBD_DELETE) || + rscFlags.isSet(workerCtx, Resource.Flags.DELETE)); +@@ -570,7 +573,11 @@ public class DrbdLayer implements DeviceLayer + { + // hasMetaData needs to be run after child-resource processed + List> createMetaData = new ArrayList<>(); +- if (!drbdRscData.getAbsResource().isDrbdDiskless(workerCtx) && !skipDisk) ++ // Check if we're in toggle-disk operation (adding disk to diskless resource) ++ boolean isDiskAddingForMd = drbdRscData.getAbsResource().getStateFlags() ++ .isSomeSet(workerCtx, Resource.Flags.DISK_ADD_REQUESTED, Resource.Flags.DISK_ADDING); ++ // Create metadata when: has disk OR adding disk (toggle-disk), and skipDisk is disabled ++ if ((!drbdRscData.getAbsResource().isDrbdDiskless(workerCtx) || isDiskAddingForMd) && !skipDisk) + { + // do not try to create meta data while the resource is diskless or skipDisk is enabled + for (DrbdVlmData drbdVlmData : checkMetaData) +@@ -988,8 +995,10 @@ public class DrbdLayer implements DeviceLayer + { + List> checkMetaData = new ArrayList<>(); + Resource rsc = drbdRscData.getAbsResource(); ++ // Include DISK_ADD_REQUESTED/DISK_ADDING for toggle-disk scenario where we need to check/create metadata + if (!rsc.isDrbdDiskless(workerCtx) || +- rsc.getStateFlags().isSet(workerCtx, Resource.Flags.DISK_REMOVING) ++ rsc.getStateFlags().isSet(workerCtx, Resource.Flags.DISK_REMOVING) || ++ rsc.getStateFlags().isSomeSet(workerCtx, Resource.Flags.DISK_ADD_REQUESTED, Resource.Flags.DISK_ADDING) + ) + { + // using a dedicated list to prevent concurrentModificationException +@@ -1177,9 +1186,16 @@ public class DrbdLayer implements DeviceLayer + + boolean hasMetaData; + ++ // Check if we need to verify/create metadata ++ // Force metadata check when: ++ // 1. checkMetaData is enabled ++ // 2. volume doesn't have disk yet (diskless -> diskful transition) ++ // 3. DISK_ADD_REQUESTED/DISK_ADDING flag is set (retry scenario where storage exists but no metadata) ++ boolean isDiskAddingState = drbdVlmData.getRscLayerObject().getAbsResource().getStateFlags() ++ .isSomeSet(workerCtx, Resource.Flags.DISK_ADD_REQUESTED, Resource.Flags.DISK_ADDING); + if (drbdVlmData.checkMetaData() || +- // when adding a disk, DRBD believes that it is diskless but we still need to create metadata +- !drbdVlmData.hasDisk()) ++ !drbdVlmData.hasDisk() || ++ isDiskAddingState) + { + if (mdUtils.hasMetaData()) + { diff --git a/packages/system/linstor/images/piraeus-server/patches/skip-adjust-when-device-inaccessible.diff b/packages/system/linstor/images/piraeus-server/patches/skip-adjust-when-device-inaccessible.diff new file mode 100644 index 00000000..09e7ccf9 --- /dev/null +++ b/packages/system/linstor/images/piraeus-server/patches/skip-adjust-when-device-inaccessible.diff @@ -0,0 +1,93 @@ +diff --git a/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java b/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java +index 01967a3..871d830 100644 +--- a/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java ++++ b/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java +@@ -592,7 +592,29 @@ public class DrbdLayer implements DeviceLayer + // The .res file might not have been generated in the prepare method since it was + // missing information from the child-layers. Now that we have processed them, we + // need to make sure the .res file exists in all circumstances. +- regenerateResFile(drbdRscData); ++ // However, if the underlying devices are not accessible (e.g., LUKS device is closed ++ // during resource deletion), we skip regenerating the res file to avoid errors ++ boolean canRegenerateResFile = true; ++ if (!skipDisk && !drbdRscData.getAbsResource().isDrbdDiskless(workerCtx)) ++ { ++ AbsRscLayerObject dataChild = drbdRscData.getChildBySuffix(RscLayerSuffixes.SUFFIX_DATA); ++ if (dataChild != null) ++ { ++ for (DrbdVlmData drbdVlmData : drbdRscData.getVlmLayerObjects().values()) ++ { ++ VlmProviderObject childVlm = dataChild.getVlmProviderObject(drbdVlmData.getVlmNr()); ++ if (childVlm == null || !childVlm.exists() || childVlm.getDevicePath() == null) ++ { ++ canRegenerateResFile = false; ++ break; ++ } ++ } ++ } ++ } ++ if (canRegenerateResFile) ++ { ++ regenerateResFile(drbdRscData); ++ } + + // createMetaData needs rendered resFile + for (DrbdVlmData drbdVlmData : createMetaData) +@@ -766,19 +788,47 @@ public class DrbdLayer implements DeviceLayer + + if (drbdRscData.isAdjustRequired()) + { +- try ++ // Check if underlying devices are accessible before adjusting ++ // This is important for encrypted resources (LUKS) where the device ++ // might be closed during deletion ++ boolean canAdjust = true; ++ if (!skipDisk && !drbdRscData.getAbsResource().isDrbdDiskless(workerCtx)) + { +- drbdUtils.adjust( +- drbdRscData, +- false, +- skipDisk, +- false +- ); ++ AbsRscLayerObject dataChild = drbdRscData.getChildBySuffix(RscLayerSuffixes.SUFFIX_DATA); ++ if (dataChild != null) ++ { ++ for (DrbdVlmData drbdVlmData : drbdRscData.getVlmLayerObjects().values()) ++ { ++ VlmProviderObject childVlm = dataChild.getVlmProviderObject(drbdVlmData.getVlmNr()); ++ if (childVlm == null || !childVlm.exists() || childVlm.getDevicePath() == null) ++ { ++ canAdjust = false; ++ break; ++ } ++ } ++ } + } +- catch (ExtCmdFailedException extCmdExc) ++ ++ if (canAdjust) ++ { ++ try ++ { ++ drbdUtils.adjust( ++ drbdRscData, ++ false, ++ skipDisk, ++ false ++ ); ++ } ++ catch (ExtCmdFailedException extCmdExc) ++ { ++ restoreBackupResFile(drbdRscData); ++ throw extCmdExc; ++ } ++ } ++ else + { +- restoreBackupResFile(drbdRscData); +- throw extCmdExc; ++ drbdRscData.setAdjustRequired(false); + } + } + diff --git a/packages/system/linstor/templates/_helpers.tpl b/packages/system/linstor/templates/_helpers.tpl deleted file mode 100644 index 20d43863..00000000 --- a/packages/system/linstor/templates/_helpers.tpl +++ /dev/null @@ -1,24 +0,0 @@ -{{- define "cozy.linstor.version" -}} -{{- $piraeusConfigMap := lookup "v1" "ConfigMap" "cozy-linstor" "piraeus-operator-image-config"}} -{{- if not $piraeusConfigMap }} - {{- fail "Piraeus controller is not yet installed, ConfigMap cozy-linstor/piraeus-operator-image-config is missing" }} -{{- end }} -{{- $piraeusImagesConfig := $piraeusConfigMap | dig "data" "0_piraeus_datastore_images.yaml" nil | required "No image config" | fromYaml }} -base: {{ $piraeusImagesConfig.base | required "No image base in piraeus config" }} -controller: - image: {{ $piraeusImagesConfig | dig "components" "linstor-controller" "image" nil | required "No controller image" }} - tag: {{ $piraeusImagesConfig | dig "components" "linstor-controller" "tag" nil | required "No controller tag" }} -satellite: - image: {{ $piraeusImagesConfig | dig "components" "linstor-satellite" "image" nil | required "No satellite image" }} - tag: {{ $piraeusImagesConfig | dig "components" "linstor-satellite" "tag" nil | required "No satellite tag" }} -{{- end -}} - -{{- define "cozy.linstor.version.controller" -}} -{{- $version := (include "cozy.linstor.version" .) | fromYaml }} -{{- printf "%s/%s:%s" $version.base $version.controller.image $version.controller.tag }} -{{- end -}} - -{{- define "cozy.linstor.version.satellite" -}} -{{- $version := (include "cozy.linstor.version" .) | fromYaml }} -{{- printf "%s/%s:%s" $version.base $version.satellite.image $version.satellite.tag }} -{{- end -}} diff --git a/packages/system/linstor/templates/cluster.yaml b/packages/system/linstor/templates/cluster.yaml index 68af90fd..584fd850 100644 --- a/packages/system/linstor/templates/cluster.yaml +++ b/packages/system/linstor/templates/cluster.yaml @@ -27,8 +27,10 @@ spec: podTemplate: spec: containers: + - name: linstor-controller + image: {{ .Values.piraeusServer.image.repository }}:{{ .Values.piraeusServer.image.tag }} - name: plunger - image: {{ include "cozy.linstor.version.controller" . }} + image: {{ .Values.piraeusServer.image.repository }}:{{ .Values.piraeusServer.image.tag }} command: - "/scripts/plunger-controller.sh" securityContext: diff --git a/packages/system/linstor/templates/satellites-cozy.yaml b/packages/system/linstor/templates/satellites-cozy.yaml index a4c1baa7..c621126d 100644 --- a/packages/system/linstor/templates/satellites-cozy.yaml +++ b/packages/system/linstor/templates/satellites-cozy.yaml @@ -13,6 +13,7 @@ spec: hostNetwork: true containers: - name: linstor-satellite + image: {{ .Values.piraeusServer.image.repository }}:{{ .Values.piraeusServer.image.tag }} securityContext: # real-world installations need some debugging from time to time readOnlyRootFilesystem: false diff --git a/packages/system/linstor/templates/satellites-plunger.yaml b/packages/system/linstor/templates/satellites-plunger.yaml index e3cfa3b1..ab71298b 100644 --- a/packages/system/linstor/templates/satellites-plunger.yaml +++ b/packages/system/linstor/templates/satellites-plunger.yaml @@ -11,7 +11,7 @@ spec: spec: containers: - name: plunger - image: {{ include "cozy.linstor.version.satellite" . }} + image: {{ .Values.piraeusServer.image.repository }}:{{ .Values.piraeusServer.image.tag }} command: - "/scripts/plunger-satellite.sh" securityContext: @@ -48,7 +48,7 @@ spec: name: script-volume readOnly: true - name: drbd-logger - image: {{ include "cozy.linstor.version.satellite" . }} + image: {{ .Values.piraeusServer.image.repository }}:{{ .Values.piraeusServer.image.tag }} command: - "/scripts/plunger-drbd-logger.sh" securityContext: diff --git a/packages/system/linstor/values.yaml b/packages/system/linstor/values.yaml index 8b137891..23179bce 100644 --- a/packages/system/linstor/values.yaml +++ b/packages/system/linstor/values.yaml @@ -1 +1,4 @@ - +piraeusServer: + image: + repository: ghcr.io/cozystack/cozystack/piraeus-server + tag: latest@sha256:417532baa2801288147cd9ac9ae260751c1a7754f0b829725d09b72a770c111a From 2bbeb1b474752a48e14d47c32c25a65123ac2915 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 7 Jan 2026 15:00:07 +0100 Subject: [PATCH 47/78] fix(linstor): prevent orphaned DRBD devices during toggle-disk retry (#1823) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fix bug in toggle-disk retry logic that left orphaned DRBD devices in kernel. ## Problem When toggle-disk retry was triggered (e.g., user retries after a failed operation), the code called `removeLayerData()` to clean up and recreate the layer stack. However, `removeLayerData()` only removes data from the controller's database — it does NOT call `drbdadm down` on the satellite. This caused DRBD devices to remain in the kernel (visible in `drbdsetup` but not managed by LINSTOR), occupying ports and blocking subsequent operations. ## Solution Changed retry logic to simply repeat the operation with existing layer data intact. The satellite handles this idempotently without creating orphaned resources. ## Upstream - https://github.com/LINBIT/linstor-server/pull/475 (updated) ```release-note [linstor] Fix orphaned DRBD devices during toggle-disk retry ``` ## Summary by CodeRabbit * **New Features** * Added cancel and retry capabilities for disk addition operations * Added cancel and retry capabilities for disk removal operations * Improved cleanup handling for diskless resources with orphaned storage layers ✏️ Tip: You can customize this high-level summary in your review settings. --- .../patches/allow-toggle-disk-retry.diff | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/packages/system/linstor/images/piraeus-server/patches/allow-toggle-disk-retry.diff b/packages/system/linstor/images/piraeus-server/patches/allow-toggle-disk-retry.diff index 4f4f2fc6..264e0221 100644 --- a/packages/system/linstor/images/piraeus-server/patches/allow-toggle-disk-retry.diff +++ b/packages/system/linstor/images/piraeus-server/patches/allow-toggle-disk-retry.diff @@ -1,8 +1,8 @@ diff --git a/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java b/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java -index 1a6f7b7f0..bd447e049 100644 +index d93a18014..cc8ce4f04 100644 --- a/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java +++ b/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java -@@ -58,7 +58,9 @@ import com.linbit.linstor.stateflags.StateFlags; +@@ -57,7 +57,9 @@ import com.linbit.linstor.stateflags.StateFlags; import com.linbit.linstor.storage.StorageException; import com.linbit.linstor.storage.data.adapter.drbd.DrbdRscData; import com.linbit.linstor.storage.interfaces.categories.resource.AbsRscLayerObject; @@ -12,7 +12,7 @@ index 1a6f7b7f0..bd447e049 100644 import com.linbit.linstor.storage.utils.LayerUtils; import com.linbit.linstor.tasks.AutoDiskfulTask; import com.linbit.linstor.utils.layer.LayerRscUtils; -@@ -317,21 +319,90 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL +@@ -387,21 +389,84 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL Resource rsc = ctrlApiDataLoader.loadRsc(nodeName, rscName, true); @@ -61,18 +61,12 @@ index 1a6f7b7f0..bd447e049 100644 + .concatWith(ctrlRscDfnApiCallHandler.get().updateProps(rsc.getResourceDefinition())); + } + // If adding disk and DISK_ADD_REQUESTED is already set, treat as retry -+ // First clean up partially created storage by removing and recreating layer data ++ // Simply retry the operation with existing layer data - satellite will handle it idempotently ++ // NOTE: We don't remove/recreate layer data here because removeLayerData() only deletes ++ // from controller DB without calling drbdadm down on satellite, leaving orphaned DRBD devices + errorReporter.logInfo( -+ "Toggle Disk retry on %s/%s - DISK_ADD_REQUESTED already set, cleaning up and retrying", ++ "Toggle Disk retry on %s/%s - DISK_ADD_REQUESTED already set, retrying operation", + nodeNameStr, rscNameStr); -+ -+ // Remove old layer data and recreate to ensure clean state -+ // This forces satellite to delete any partially created storage and start fresh -+ LayerPayload payload = new LayerPayload(); -+ copyDrbdNodeIdIfExists(rsc, payload); -+ List layerList = removeLayerData(rsc); -+ ctrlLayerStackHelper.ensureStackDataExists(rsc, layerList, payload); -+ + ctrlTransactionHelper.commit(); + return Flux + .just(new ApiCallRcImpl()) @@ -113,7 +107,7 @@ index 1a6f7b7f0..bd447e049 100644 } if (!removeDisk && !ctrlVlmCrtApiHelper.isDiskless(rsc)) -@@ -342,17 +413,43 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL +@@ -412,17 +477,43 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL true )); } @@ -160,7 +154,7 @@ index 1a6f7b7f0..bd447e049 100644 if (removeDisk) { // Prevent removal of the last disk -@@ -1324,6 +1421,30 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL +@@ -1446,6 +1537,30 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL } } @@ -191,7 +185,7 @@ index 1a6f7b7f0..bd447e049 100644 private void markDiskAdded(Resource rscData) { try -@@ -1389,6 +1510,41 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL +@@ -1511,6 +1626,41 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL return layerData; } From 90390112524c3422febde21528b97776049bf998 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 7 Jan 2026 15:52:12 +0100 Subject: [PATCH 48/78] [api, lineage] Tolerate all taints (#1781) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does Cozystack-api and lineage-webhook tolerate all taints, so they are able to run on masters no matter what. Needed for unschedulable control-plane setup, quorum nodes, etc. ### Release note ```release-note Cozystack-api and lineage-webhook tolerate all taints. ``` ## Summary by CodeRabbit * **Chores** * Updated pod scheduling tolerations to improve deployment flexibility and compatibility across diverse cluster configurations. * Enhanced workload distribution by making pods more resilient to cluster taints, enabling better resource utilization in various environments. ✏️ Tip: You can customize this high-level summary in your review settings. --- packages/system/cozystack-api/templates/deployment.yaml | 2 ++ .../lineage-controller-webhook/templates/daemonset.yaml | 7 +------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/system/cozystack-api/templates/deployment.yaml b/packages/system/cozystack-api/templates/deployment.yaml index 1a63a0e0..ee7e532f 100644 --- a/packages/system/cozystack-api/templates/deployment.yaml +++ b/packages/system/cozystack-api/templates/deployment.yaml @@ -21,6 +21,8 @@ spec: labels: app: cozystack-api spec: + tolerations: + - operator: Exists serviceAccountName: cozystack-api {{- if .Values.cozystackAPI.localK8sAPIEndpoint.enabled }} nodeSelector: diff --git a/packages/system/lineage-controller-webhook/templates/daemonset.yaml b/packages/system/lineage-controller-webhook/templates/daemonset.yaml index 22074e1d..b6b73ac7 100644 --- a/packages/system/lineage-controller-webhook/templates/daemonset.yaml +++ b/packages/system/lineage-controller-webhook/templates/daemonset.yaml @@ -16,12 +16,7 @@ spec: nodeSelector: node-role.kubernetes.io/control-plane: "" tolerations: - - key: "node-role.kubernetes.io/control-plane" - operator: "Exists" - effect: "NoSchedule" - - key: "node-role.kubernetes.io/master" - operator: "Exists" - effect: "NoSchedule" + - operator: Exists serviceAccountName: lineage-controller-webhook containers: - name: lineage-controller-webhook From 33452d65e5a6a476a599f9c93f593f02b899c8d0 Mon Sep 17 00:00:00 2001 From: Nikita <166552198+nbykov0@users.noreply.github.com> Date: Thu, 8 Jan 2026 15:56:22 +0300 Subject: [PATCH 49/78] [seaweedfs] Traffic locality (#1748) ## What this PR does Addes traffic locality capabilities to Seaweedfs. ### Release note ```release-note Added traffic locality capabilities to Seaweedfs --- packages/system/ingress-nginx/values.yaml | 38 +- packages/system/seaweedfs/Makefile | 18 +- .../seaweedfs/charts/seaweedfs/Chart.yaml | 4 +- .../seaweedfs/charts/seaweedfs/README.md | 185 ++++++++++ .../seaweedfs-grafana-dashboard.json | 304 ++++++++++++++- .../templates/admin/admin-ingress.yaml | 52 +++ .../templates/admin/admin-secret.yaml | 20 + .../templates/admin/admin-service.yaml | 39 ++ .../templates/admin/admin-servicemonitor.yaml | 33 ++ .../templates/admin/admin-statefulset.yaml | 345 ++++++++++++++++++ .../seaweedfs/templates/cert/admin-cert.yaml | 43 +++ .../seaweedfs/templates/cert/worker-cert.yaml | 43 +++ .../templates/filer/filer-statefulset.yaml | 2 +- .../templates/master/master-statefulset.yaml | 2 +- .../seaweedfs/templates/s3/s3-ingress.yaml | 28 +- .../seaweedfs/templates/s3/s3-service.yaml | 1 + .../seaweedfs/templates/shared/_helpers.tpl | 54 +++ .../templates/shared/security-configmap.yaml | 8 + .../templates/volume/volume-statefulset.yaml | 5 +- .../templates/worker/worker-deployment.yaml | 288 +++++++++++++++ .../templates/worker/worker-service.yaml | 26 ++ .../worker/worker-servicemonitor.yaml | 33 ++ .../seaweedfs/charts/seaweedfs/values.yaml | 247 ++++++++++++- .../seaweedfs/images/seaweedfs/Dockerfile | 2 - .../patches/s3-traffic-distribution.patch | 12 + packages/system/seaweedfs/values.yaml | 71 +++- 26 files changed, 1864 insertions(+), 39 deletions(-) create mode 100644 packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-ingress.yaml create mode 100644 packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-secret.yaml create mode 100644 packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-service.yaml create mode 100644 packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-servicemonitor.yaml create mode 100644 packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-statefulset.yaml create mode 100644 packages/system/seaweedfs/charts/seaweedfs/templates/cert/admin-cert.yaml create mode 100644 packages/system/seaweedfs/charts/seaweedfs/templates/cert/worker-cert.yaml create mode 100644 packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-deployment.yaml create mode 100644 packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-service.yaml create mode 100644 packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-servicemonitor.yaml delete mode 100644 packages/system/seaweedfs/images/seaweedfs/Dockerfile create mode 100644 packages/system/seaweedfs/patches/s3-traffic-distribution.patch diff --git a/packages/system/ingress-nginx/values.yaml b/packages/system/ingress-nginx/values.yaml index 5571ff37..68436f51 100644 --- a/packages/system/ingress-nginx/values.yaml +++ b/packages/system/ingress-nginx/values.yaml @@ -54,9 +54,45 @@ ingress-nginx: requests: cpu: 100m memory: 90Mi + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 10 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - '{{ include "ingress-nginx.name" . }}' + - key: app.kubernetes.io/instance + operator: In + values: + - '{{ .Release.Name }}' + - key: app.kubernetes.io/component + operator: In + values: + - controller + topologyKey: kubernetes.io/hostname + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - '{{ include "ingress-nginx.name" . }}' + - key: app.kubernetes.io/instance + operator: In + values: + - '{{ .Release.Name }}' + - key: app.kubernetes.io/component + operator: In + values: + - controller + topologyKey: topology.kubernetes.io/zone defaultBackend: - ## enabled: true resources: limits: diff --git a/packages/system/seaweedfs/Makefile b/packages/system/seaweedfs/Makefile index 9d1f47cd..d1f21a80 100644 --- a/packages/system/seaweedfs/Makefile +++ b/packages/system/seaweedfs/Makefile @@ -8,22 +8,8 @@ update: mkdir -p charts version=$$(git ls-remote --tags --sort="v:refname" https://github.com/seaweedfs/seaweedfs | grep -v '\^{}' | grep 'refs/tags/[0-9]' | awk -F'/' 'END{print $$3}') && \ curl -sSL https://github.com/seaweedfs/seaweedfs/archive/refs/tags/$${version}.tar.gz | \ - tar xzvf - --strip 3 -C charts seaweedfs-$${version}/k8s/charts/seaweedfs && \ - sed -i.bak "/ARG VERSION/ s|=.*|=$${version}|g" images/seaweedfs/Dockerfile && \ - rm -f images/seaweedfs/Dockerfile.bak + tar xzvf - --strip 3 -C charts seaweedfs-$${version}/k8s/charts/seaweedfs patch --no-backup-if-mismatch -p4 < patches/resize-api-server-annotation.diff + patch --no-backup-if-mismatch -p4 < patches/s3-traffic-distribution.patch #patch --no-backup-if-mismatch -p4 < patches/retention-policy-delete.yaml -image: - docker buildx build images/seaweedfs \ - --tag $(REGISTRY)/seaweedfs:$(call settag,$(TAG)) \ - --cache-from type=registry,ref=$(REGISTRY)/seaweedfs:latest \ - --cache-to type=inline \ - --metadata-file images/seaweedfs.json \ - $(BUILDX_ARGS) - REGISTRY="$(REGISTRY)" \ - yq -i '.seaweedfs.image.registry = strenv(REGISTRY)' values.yaml - TAG=$(TAG)@$$(yq e '."containerimage.digest"' images/seaweedfs.json -o json -r) \ - yq -i '.seaweedfs.image.tag = strenv(TAG)' values.yaml - yq -i '.global.imageName = "seaweedfs"' values.yaml - rm -f images/seaweedfs.json diff --git a/packages/system/seaweedfs/charts/seaweedfs/Chart.yaml b/packages/system/seaweedfs/charts/seaweedfs/Chart.yaml index 6ea31115..107149cf 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/Chart.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v1 description: SeaweedFS name: seaweedfs -appVersion: "4.02" +appVersion: "4.05" # Dev note: Trigger a helm chart release by `git tag -a helm-` -version: 4.0.402 +version: 4.0.405 diff --git a/packages/system/seaweedfs/charts/seaweedfs/README.md b/packages/system/seaweedfs/charts/seaweedfs/README.md index 30885aee..7f27cb22 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/README.md +++ b/packages/system/seaweedfs/charts/seaweedfs/README.md @@ -145,6 +145,191 @@ stringData: seaweedfs_s3_config: '{"identities":[{"name":"anvAdmin","credentials":[{"accessKey":"snu8yoP6QAlY0ne4","secretKey":"PNzBcmeLNEdR0oviwm04NQAicOrDH1Km"}],"actions":["Admin","Read","Write"]},{"name":"anvReadOnly","credentials":[{"accessKey":"SCigFee6c5lbi04A","secretKey":"kgFhbT38R8WUYVtiFQ1OiSVOrYr3NKku"}],"actions":["Read"]}]}' ``` +## Admin Component + +The admin component provides a modern web-based administration interface for managing SeaweedFS clusters. It includes: + +- **Dashboard**: Real-time cluster status and metrics +- **Volume Management**: Monitor volume servers, capacity, and health +- **File Browser**: Browse and manage files in the filer +- **Maintenance Operations**: Trigger maintenance tasks via workers +- **Object Store Management**: Create and manage buckets with web interface + +### Enabling Admin + +To enable the admin interface, add the following to your values.yaml: + +```yaml +admin: + enabled: true + port: 23646 + grpcPort: 33646 # For worker connections + adminUser: "admin" + adminPassword: "your-secure-password" # Leave empty to disable auth + + # Optional: persist admin data + data: + type: "persistentVolumeClaim" + size: "10Gi" + storageClass: "your-storage-class" + + # Optional: enable ingress + ingress: + enabled: true + host: "admin.seaweedfs.local" + className: "nginx" +``` + +The admin interface will be available at `http://:23646` (or via ingress). Workers connect to the admin server via gRPC on port `33646`. + +### Admin Authentication + +If `adminPassword` is set, the admin interface requires authentication: +- Username: Value of `adminUser` (default: `admin`) +- Password: Value of `adminPassword` + +If `adminPassword` is empty or not set, the admin interface runs without authentication (not recommended for production). + +### Admin Data Persistence + +The admin component can store configuration and maintenance data. You can configure storage in several ways: + +- **emptyDir** (default): Data is lost when pod restarts +- **persistentVolumeClaim**: Data persists across pod restarts +- **hostPath**: Data stored on the host filesystem +- **existingClaim**: Use an existing PVC + +## Worker Component + +Workers are maintenance agents that execute cluster maintenance tasks such as vacuum, volume balancing, and erasure coding. Workers connect to the admin server via gRPC and receive task assignments. + +### Enabling Workers + +To enable workers, add the following to your values.yaml: + +```yaml +worker: + enabled: true + replicas: 2 # Scale based on workload + capabilities: "vacuum,balance,erasure_coding" # Tasks this worker can handle + maxConcurrent: 3 # Maximum concurrent tasks per worker + + # Working directory for task execution + # Default: "/tmp/seaweedfs-worker" + # Note: /tmp is ephemeral - use persistent storage (hostPath/existingClaim) for long-running tasks + workingDir: "/tmp/seaweedfs-worker" + + # Optional: configure admin server address + # If not specified, auto-discovers from admin service in the same namespace by looking for + # a service named "-admin" (e.g., "seaweedfs-admin"). + # Auto-discovery only works if the admin is in the same namespace and same Helm release. + # For cross-namespace or separate release scenarios, explicitly set this value. + # Example: If main SeaweedFS is deployed in "production" namespace: + # adminServer: "seaweedfs-admin.production.svc:33646" + adminServer: "" + + # Workers need storage for task execution + # Note: Workers use a Deployment, which does not support `volumeClaimTemplates` + # for dynamic PVC creation per pod. To use persistent storage, you must + # pre-provision a PersistentVolumeClaim and use `type: "existingClaim"`. + data: + type: "emptyDir" # Options: "emptyDir", "hostPath", or "existingClaim" + hostPathPrefix: /storage # For hostPath + # claimName: "worker-pvc" # For existingClaim with pre-provisioned PVC + + # Resource limits for worker pods + resources: + requests: + cpu: "500m" + memory: "512Mi" + limits: + cpu: "2" + memory: "2Gi" +``` + +### Worker Capabilities + +Workers can be configured with different capabilities: +- **vacuum**: Reclaim deleted file space +- **balance**: Balance volumes across volume servers +- **erasure_coding**: Handle erasure coding operations + +You can configure workers with all capabilities or create specialized worker pools with specific capabilities. + +### Worker Deployment Strategy + +For production deployments, consider: + +1. **Multiple Workers**: Deploy 2+ worker replicas for high availability +2. **Resource Allocation**: Workers need sufficient CPU/memory for maintenance tasks +3. **Storage**: Workers need temporary storage for vacuum and balance operations (size depends on volume size) +4. **Specialized Workers**: Create separate worker deployments for different capabilities if needed + +Example specialized worker configuration: + +For specialized worker pools, deploy separate Helm releases with different capabilities: + +**values-worker-vacuum.yaml** (for vacuum operations): +```yaml +# Disable all other components, enable only workers +master: + enabled: false +volume: + enabled: false +filer: + enabled: false +s3: + enabled: false +admin: + enabled: false + +worker: + enabled: true + replicas: 2 + capabilities: "vacuum" + maxConcurrent: 2 + # REQUIRED: Point to the admin service of your main SeaweedFS release + # Replace with the namespace where your main seaweedfs is deployed + # Example: If deploying in namespace "production": + # adminServer: "seaweedfs-admin.production.svc:33646" + adminServer: "seaweedfs-admin..svc:33646" +``` + +**values-worker-balance.yaml** (for balance operations): +```yaml +# Disable all other components, enable only workers +master: + enabled: false +volume: + enabled: false +filer: + enabled: false +s3: + enabled: false +admin: + enabled: false + +worker: + enabled: true + replicas: 1 + capabilities: "balance" + maxConcurrent: 1 + # REQUIRED: Point to the admin service of your main SeaweedFS release + # Replace with the namespace where your main seaweedfs is deployed + # Example: If deploying in namespace "production": + # adminServer: "seaweedfs-admin.production.svc:33646" + adminServer: "seaweedfs-admin..svc:33646" +``` + +Deploy the specialized workers as separate releases: +```bash +# Deploy vacuum workers +helm install seaweedfs-worker-vacuum seaweedfs/seaweedfs -f values-worker-vacuum.yaml + +# Deploy balance workers +helm install seaweedfs-worker-balance seaweedfs/seaweedfs -f values-worker-balance.yaml +``` + ## Enterprise For enterprise users, please visit [seaweedfs.com](https://seaweedfs.com) for the SeaweedFS Enterprise Edition, diff --git a/packages/system/seaweedfs/charts/seaweedfs/dashboards/seaweedfs-grafana-dashboard.json b/packages/system/seaweedfs/charts/seaweedfs/dashboards/seaweedfs-grafana-dashboard.json index 30b43f86..ca08b7d0 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/dashboards/seaweedfs-grafana-dashboard.json +++ b/packages/system/seaweedfs/charts/seaweedfs/dashboards/seaweedfs-grafana-dashboard.json @@ -1595,6 +1595,101 @@ "title": "S3 Bucket Traffic Sent", "type": "timeseries" }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 41 + }, + "id": 86, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "sum(rate(SeaweedFS_s3_request_total{namespace=\"$NAMESPACE\"}[$__interval])) by (bucket)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{bucket}}", + "refId": "A" + } + ], + "title": "S3 API Calls per Bucket", + "type": "timeseries" + }, { "datasource": { "type": "prometheus", @@ -1659,8 +1754,8 @@ }, "gridPos": { "h": 7, - "w": 24, - "x": 0, + "w": 12, + "x": 12, "y": 41 }, "id": 72, @@ -3266,6 +3361,209 @@ ], "title": "Filer Go Routines", "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 48 + }, + "id": 89, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "max(SeaweedFS_s3_bucket_size_bytes{namespace=\"$NAMESPACE\"}) by (bucket)", + "legendFormat": "{{bucket}} (logical)", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "max(SeaweedFS_s3_bucket_physical_size_bytes{namespace=\"$NAMESPACE\"}) by (bucket)", + "legendFormat": "{{bucket}} (physical)", + "range": true, + "refId": "B" + } + ], + "title": "S3 Bucket Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 48 + }, + "id": 90, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "max(SeaweedFS_s3_bucket_object_count{namespace=\"$NAMESPACE\"}) by (bucket)", + "legendFormat": "{{bucket}}", + "range": true, + "refId": "A" + } + ], + "title": "S3 Bucket Object Count", + "type": "timeseries" } ], "refresh": "", @@ -3356,4 +3654,4 @@ "uid": "a24009d7-cbda-4443-a132-1cc1c4677304", "version": 1, "weekStart": "" -} +} \ No newline at end of file diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-ingress.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-ingress.yaml new file mode 100644 index 00000000..216ef8a8 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-ingress.yaml @@ -0,0 +1,52 @@ +{{- if and .Values.admin.enabled .Values.admin.ingress.enabled }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion }} +apiVersion: networking.k8s.io/v1beta1 +{{- else }} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: ingress-{{ template "seaweedfs.name" . }}-admin + namespace: {{ .Release.Namespace }} + annotations: + {{- if and (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) .Values.admin.ingress.className }} + kubernetes.io/ingress.class: {{ .Values.admin.ingress.className }} + {{- end }} + {{- with .Values.admin.ingress.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin +spec: + {{- if and (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) .Values.admin.ingress.className }} + ingressClassName: {{ .Values.admin.ingress.className | quote }} + {{- end }} + tls: + {{ .Values.admin.ingress.tls | default list | toYaml | nindent 6}} + rules: + - {{- if .Values.admin.ingress.host }} + host: {{ .Values.admin.ingress.host | quote }} + {{- end }} + http: + paths: + - path: {{ .Values.admin.ingress.path | quote }} + {{- if semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion }} + pathType: {{ .Values.admin.ingress.pathType | quote }} + {{- end }} + backend: +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} + service: + name: {{ template "seaweedfs.name" . }}-admin + port: + number: {{ .Values.admin.port }} +{{- else }} + serviceName: {{ template "seaweedfs.name" . }}-admin + servicePort: {{ .Values.admin.port }} +{{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-secret.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-secret.yaml new file mode 100644 index 00000000..bc104456 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-secret.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.admin.enabled .Values.admin.secret.adminPassword (not .Values.admin.secret.existingSecret) }} +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ template "seaweedfs.name" . }}-admin-secret + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/resource-policy": keep + "helm.sh/hook": "pre-install,pre-upgrade" + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin +data: + adminUser: {{ .Values.admin.secret.adminUser | b64enc }} + adminPassword: {{ .Values.admin.secret.adminPassword | b64enc }} +{{- end}} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-service.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-service.yaml new file mode 100644 index 00000000..825049a4 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-service.yaml @@ -0,0 +1,39 @@ +{{- if .Values.admin.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "seaweedfs.name" . }}-admin + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin +{{- if .Values.admin.service.annotations }} + annotations: + {{- toYaml .Values.admin.service.annotations | nindent 4 }} +{{- end }} +spec: + type: {{ .Values.admin.service.type }} + ports: + - name: "http" + port: {{ .Values.admin.port }} + targetPort: {{ .Values.admin.port }} + protocol: TCP + - name: "grpc" + port: {{ .Values.admin.grpcPort }} + targetPort: {{ .Values.admin.grpcPort }} + protocol: TCP + {{- if .Values.admin.metricsPort }} + - name: "metrics" + port: {{ .Values.admin.metricsPort }} + targetPort: {{ .Values.admin.metricsPort }} + protocol: TCP + {{- end }} + selector: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin +{{- end }} + diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-servicemonitor.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-servicemonitor.yaml new file mode 100644 index 00000000..271197a3 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if .Values.admin.enabled }} +{{- if .Values.admin.metricsPort }} +{{- if .Values.global.monitoring.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "seaweedfs.name" . }}-admin + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin + {{- with .Values.global.monitoring.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- with .Values.admin.serviceMonitor.annotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + endpoints: + - interval: 30s + port: metrics + scrapeTimeout: 5s + selector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/component: admin +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-statefulset.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-statefulset.yaml new file mode 100644 index 00000000..208f73d1 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-statefulset.yaml @@ -0,0 +1,345 @@ +{{- if .Values.admin.enabled }} +{{- if and (not .Values.admin.masters) (not .Values.global.masterServer) (not .Values.master.enabled) }} +{{- fail "admin.masters or global.masterServer must be set if master.enabled is false" -}} +{{- end }} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ template "seaweedfs.name" . }}-admin + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin +{{- if .Values.admin.annotations }} + annotations: + {{- toYaml .Values.admin.annotations | nindent 4 }} +{{- end }} +spec: + serviceName: {{ template "seaweedfs.name" . }}-admin + podManagementPolicy: {{ .Values.admin.podManagementPolicy }} + replicas: {{ .Values.admin.replicas }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin + {{ with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.admin.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + annotations: + {{ with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.admin.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + restartPolicy: {{ default .Values.global.restartPolicy .Values.admin.restartPolicy }} + {{- if .Values.admin.affinity }} + affinity: + {{ tpl .Values.admin.affinity . | nindent 8 | trim }} + {{- end }} + {{- if .Values.admin.topologySpreadConstraints }} + topologySpreadConstraints: + {{ tpl .Values.admin.topologySpreadConstraints . | nindent 8 | trim }} + {{- end }} + {{- if .Values.admin.tolerations }} + tolerations: + {{ tpl .Values.admin.tolerations . | nindent 8 | trim }} + {{- end }} + {{- include "seaweedfs.imagePullSecrets" . | nindent 6 }} + terminationGracePeriodSeconds: 30 + {{- if .Values.admin.priorityClassName }} + priorityClassName: {{ .Values.admin.priorityClassName | quote }} + {{- end }} + enableServiceLinks: false + {{- if .Values.admin.serviceAccountName }} + serviceAccountName: {{ .Values.admin.serviceAccountName | quote }} + {{- end }} + {{- if .Values.admin.initContainers }} + initContainers: + {{ tpl .Values.admin.initContainers . | nindent 8 | trim }} + {{- end }} + {{- if .Values.admin.podSecurityContext.enabled }} + securityContext: {{- omit .Values.admin.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: seaweedfs + image: {{ template "admin.image" . }} + imagePullPolicy: {{ default "IfNotPresent" .Values.global.imagePullPolicy }} + {{- $adminAuthEnabled := or .Values.admin.secret.existingSecret .Values.admin.secret.adminPassword }} + {{- if and .Values.admin.secret.existingSecret (not .Values.admin.secret.userKey) -}} + {{- fail "admin.secret.userKey must be set when admin.secret.existingSecret is provided" -}} + {{- end -}} + {{- if and .Values.admin.secret.existingSecret (not .Values.admin.secret.pwKey) -}} + {{- fail "admin.secret.pwKey must be set when admin.secret.existingSecret is provided" -}} + {{- end -}} + {{- $adminSecretName := .Values.admin.secret.existingSecret | default (printf "%s-admin-secret" (include "seaweedfs.name" .)) }} + env: + {{- if $adminAuthEnabled }} + - name: SEAWEEDFS_ADMIN_USER + valueFrom: + secretKeyRef: + name: {{ $adminSecretName }} + key: {{ if .Values.admin.secret.existingSecret }}{{ .Values.admin.secret.userKey }}{{ else }}adminUser{{ end }} + - name: SEAWEEDFS_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: {{ $adminSecretName }} + key: {{ if .Values.admin.secret.existingSecret }}{{ .Values.admin.secret.pwKey }}{{ else }}adminPassword{{ end }} + {{- end }} + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SEAWEEDFS_FULLNAME + value: "{{ template "seaweedfs.name" . }}" + {{- if .Values.admin.extraEnvironmentVars }} + {{- range $key, $value := .Values.admin.extraEnvironmentVars }} + - name: {{ $key }} + {{- if kindIs "string" $value }} + value: {{ $value | quote }} + {{- else }} + valueFrom: + {{ toYaml $value | nindent 16 | trim }} + {{- end -}} + {{- end }} + {{- end }} + {{- if .Values.global.extraEnvironmentVars }} + {{- range $key, $value := .Values.global.extraEnvironmentVars }} + - name: {{ $key }} + {{- if kindIs "string" $value }} + value: {{ $value | quote }} + {{- else }} + valueFrom: + {{ toYaml $value | nindent 16 | trim }} + {{- end -}} + {{- end }} + {{- end }} + command: + - "/bin/sh" + - "-ec" + - | + exec /usr/bin/weed \ + {{- if or (eq .Values.admin.logs.type "hostPath") (eq .Values.admin.logs.type "persistentVolumeClaim") (eq .Values.admin.logs.type "emptyDir") (eq .Values.admin.logs.type "existingClaim") }} + -logdir=/logs \ + {{- else }} + -logtostderr=true \ + {{- end }} + {{- if .Values.admin.loggingOverrideLevel }} + -v={{ .Values.admin.loggingOverrideLevel }} \ + {{- else }} + -v={{ .Values.global.loggingLevel }} \ + {{- end }} + admin \ + -port={{ .Values.admin.port }} \ + -port.grpc={{ .Values.admin.grpcPort }} \ + {{- if or (eq .Values.admin.data.type "hostPath") (eq .Values.admin.data.type "persistentVolumeClaim") (eq .Values.admin.data.type "emptyDir") (eq .Values.admin.data.type "existingClaim") }} + -dataDir=/data \ + {{- else if .Values.admin.dataDir }} + -dataDir={{ .Values.admin.dataDir }} \ + {{- end }} + {{- if $adminAuthEnabled }} + -adminUser="${SEAWEEDFS_ADMIN_USER}" \ + -adminPassword="${SEAWEEDFS_ADMIN_PASSWORD}" \ + {{- end }} + {{- if .Values.admin.masters }} + -masters={{ .Values.admin.masters }}{{- if .Values.admin.extraArgs }} \{{ end }} + {{- else if .Values.global.masterServer }} + -masters={{ .Values.global.masterServer }}{{- if .Values.admin.extraArgs }} \{{ end }} + {{- else }} + -masters={{ range $index := until (.Values.master.replicas | int) }}${SEAWEEDFS_FULLNAME}-master-{{ $index }}.${SEAWEEDFS_FULLNAME}-master.{{ $.Release.Namespace }}:{{ $.Values.master.port }}{{ if lt $index (sub ($.Values.master.replicas | int) 1) }},{{ end }}{{ end }}{{- if .Values.admin.extraArgs }} \{{ end }} + {{- end }} + {{- range $index, $arg := .Values.admin.extraArgs }} + {{ $arg }}{{- if lt $index (sub (len $.Values.admin.extraArgs) 1) }} \{{ end }} + {{- end }} + volumeMounts: + {{- if or (eq .Values.admin.data.type "hostPath") (eq .Values.admin.data.type "persistentVolumeClaim") (eq .Values.admin.data.type "emptyDir") (eq .Values.admin.data.type "existingClaim") }} + - name: admin-data + mountPath: /data + {{- end }} + {{- if or (eq .Values.admin.logs.type "hostPath") (eq .Values.admin.logs.type "persistentVolumeClaim") (eq .Values.admin.logs.type "emptyDir") (eq .Values.admin.logs.type "existingClaim") }} + - name: admin-logs + mountPath: /logs + {{- end }} + {{- if .Values.global.enableSecurity }} + - name: security-config + readOnly: true + mountPath: /etc/seaweedfs/security.toml + subPath: security.toml + - name: ca-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/ca/ + - name: master-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/master/ + - name: volume-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/volume/ + - name: filer-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/filer/ + - name: client-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/client/ + - name: admin-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/admin/ + {{- end }} + {{ tpl .Values.admin.extraVolumeMounts . | nindent 12 | trim }} + ports: + - containerPort: {{ .Values.admin.port }} + name: http + - containerPort: {{ .Values.admin.grpcPort }} + name: grpc + {{- if .Values.admin.metricsPort }} + - containerPort: {{ .Values.admin.metricsPort }} + name: metrics + {{- end }} + {{- if .Values.admin.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: {{ .Values.admin.readinessProbe.httpGet.path }} + port: http + scheme: {{ .Values.admin.readinessProbe.httpGet.scheme }} + initialDelaySeconds: {{ .Values.admin.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.admin.readinessProbe.periodSeconds }} + successThreshold: {{ .Values.admin.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.admin.readinessProbe.failureThreshold }} + timeoutSeconds: {{ .Values.admin.readinessProbe.timeoutSeconds }} + {{- end }} + {{- if .Values.admin.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: {{ .Values.admin.livenessProbe.httpGet.path }} + port: http + scheme: {{ .Values.admin.livenessProbe.httpGet.scheme }} + initialDelaySeconds: {{ .Values.admin.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.admin.livenessProbe.periodSeconds }} + successThreshold: {{ .Values.admin.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.admin.livenessProbe.failureThreshold }} + timeoutSeconds: {{ .Values.admin.livenessProbe.timeoutSeconds }} + {{- end }} + {{- with .Values.admin.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- if .Values.admin.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.admin.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.admin.sidecars }} + {{- include "common.tplvalues.render" (dict "value" .Values.admin.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + {{- if eq .Values.admin.data.type "hostPath" }} + - name: admin-data + hostPath: + path: {{ .Values.admin.data.hostPathPrefix }}/seaweedfs-admin-data + type: DirectoryOrCreate + {{- end }} + {{- if eq .Values.admin.data.type "emptyDir" }} + - name: admin-data + emptyDir: {} + {{- end }} + {{- if eq .Values.admin.data.type "existingClaim" }} + - name: admin-data + persistentVolumeClaim: + claimName: {{ .Values.admin.data.claimName }} + {{- end }} + {{- if eq .Values.admin.logs.type "hostPath" }} + - name: admin-logs + hostPath: + path: {{ .Values.admin.logs.hostPathPrefix }}/logs/seaweedfs/admin + type: DirectoryOrCreate + {{- end }} + {{- if eq .Values.admin.logs.type "emptyDir" }} + - name: admin-logs + emptyDir: {} + {{- end }} + {{- if eq .Values.admin.logs.type "existingClaim" }} + - name: admin-logs + persistentVolumeClaim: + claimName: {{ .Values.admin.logs.claimName }} + {{- end }} + {{- if .Values.global.enableSecurity }} + - name: security-config + configMap: + name: {{ template "seaweedfs.name" . }}-security-config + - name: ca-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-ca-cert + - name: master-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-master-cert + - name: volume-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-volume-cert + - name: filer-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-filer-cert + - name: client-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-client-cert + - name: admin-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-admin-cert + {{- end }} + {{ tpl .Values.admin.extraVolumes . | indent 8 | trim }} + {{- if .Values.admin.nodeSelector }} + nodeSelector: + {{ tpl .Values.admin.nodeSelector . | indent 8 | trim }} + {{- end }} + {{- $pvc_exists := include "admin.pvc_exists" . -}} + {{- if $pvc_exists }} + volumeClaimTemplates: + {{- if eq .Values.admin.data.type "persistentVolumeClaim" }} + - metadata: + name: admin-data + {{- with .Values.admin.data.annotations }} + annotations: + {{- toYaml . | nindent 10 }} + {{- end }} + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: {{ .Values.admin.data.storageClass }} + resources: + requests: + storage: {{ .Values.admin.data.size }} + {{- end }} + {{- if eq .Values.admin.logs.type "persistentVolumeClaim" }} + - metadata: + name: admin-logs + {{- with .Values.admin.logs.annotations }} + annotations: + {{- toYaml . | nindent 10 }} + {{- end }} + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: {{ .Values.admin.logs.storageClass }} + resources: + requests: + storage: {{ .Values.admin.logs.size }} + {{- end }} + {{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cert/admin-cert.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/admin-cert.yaml new file mode 100644 index 00000000..be526601 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/admin-cert.yaml @@ -0,0 +1,43 @@ +{{- if and .Values.global.enableSecurity (not .Values.certificates.externalCertificates.enabled)}} +apiVersion: cert-manager.io/v1{{ if .Values.global.certificates.alphacrds }}alpha1{{ end }} +kind: Certificate +metadata: + name: {{ template "seaweedfs.name" . }}-admin-cert + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin + {{- if .Values.admin.annotations }} + annotations: + {{- toYaml .Values.admin.annotations | nindent 4 }} + {{- end }} +spec: + secretName: {{ template "seaweedfs.name" . }}-admin-cert + issuerRef: + name: {{ template "seaweedfs.name" . }}-ca-issuer + kind: Issuer + commonName: {{ .Values.certificates.commonName }} + subject: + organizations: + - "SeaweedFS CA" + dnsNames: + - '*.{{ template "seaweedfs.name" . }}-admin' + - '*.{{ template "seaweedfs.name" . }}-admin.{{ .Release.Namespace }}' + - '*.{{ template "seaweedfs.name" . }}-admin.{{ .Release.Namespace }}.svc' + - '*.{{ template "seaweedfs.name" . }}-admin.{{ .Release.Namespace }}.svc.cluster.local' +{{- if .Values.certificates.ipAddresses }} + ipAddresses: + {{- range .Values.certificates.ipAddresses }} + - {{ . }} + {{- end }} +{{- end }} + privateKey: + algorithm: {{ .Values.certificates.keyAlgorithm }} + size: {{ .Values.certificates.keySize }} + duration: {{ .Values.certificates.duration }} + renewBefore: {{ .Values.certificates.renewBefore }} +{{- end }} + diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cert/worker-cert.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/worker-cert.yaml new file mode 100644 index 00000000..85edeb33 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/worker-cert.yaml @@ -0,0 +1,43 @@ +{{- if and .Values.global.enableSecurity (not .Values.certificates.externalCertificates.enabled)}} +apiVersion: cert-manager.io/v1{{ if .Values.global.certificates.alphacrds }}alpha1{{ end }} +kind: Certificate +metadata: + name: {{ template "seaweedfs.name" . }}-worker-cert + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: worker + {{- if .Values.worker.annotations }} + annotations: + {{- toYaml .Values.worker.annotations | nindent 4 }} + {{- end }} +spec: + secretName: {{ template "seaweedfs.name" . }}-worker-cert + issuerRef: + name: {{ template "seaweedfs.name" . }}-ca-issuer + kind: Issuer + commonName: {{ .Values.certificates.commonName }} + subject: + organizations: + - "SeaweedFS CA" + dnsNames: + - '*.{{ template "seaweedfs.name" . }}-worker' + - '*.{{ template "seaweedfs.name" . }}-worker.{{ .Release.Namespace }}' + - '*.{{ template "seaweedfs.name" . }}-worker.{{ .Release.Namespace }}.svc' + - '*.{{ template "seaweedfs.name" . }}-worker.{{ .Release.Namespace }}.svc.cluster.local' +{{- if .Values.certificates.ipAddresses }} + ipAddresses: + {{- range .Values.certificates.ipAddresses }} + - {{ . }} + {{- end }} +{{- end }} + privateKey: + algorithm: {{ .Values.certificates.keyAlgorithm }} + size: {{ .Values.certificates.keySize }} + duration: {{ .Values.certificates.duration }} + renewBefore: {{ .Values.certificates.renewBefore }} +{{- end }} + diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-statefulset.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-statefulset.yaml index 2b8c2744..e29239c3 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-statefulset.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-statefulset.yaml @@ -220,7 +220,7 @@ spec: -s3.auditLogConfig=/etc/sw/filer_s3_auditLogConfig.json \ {{- end }} {{- end }} - -master={{ if .Values.global.masterServer }}{{.Values.global.masterServer}}{{ else }}{{ range $index := until (.Values.master.replicas | int) }}${SEAWEEDFS_FULLNAME}-master-{{ $index }}.${SEAWEEDFS_FULLNAME}-master.{{ $.Release.Namespace }}:{{ $.Values.master.port }}{{ if lt $index (sub ($.Values.master.replicas | int) 1) }},{{ end }}{{ end }}{{ end }} \ + -master={{ include "seaweedfs.masterServerArg" . }} \ {{- range .Values.filer.extraArgs }} {{ . }} \ {{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-statefulset.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-statefulset.yaml index a7067345..50e0e97d 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-statefulset.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-statefulset.yaml @@ -184,7 +184,7 @@ spec: -garbageThreshold={{ .Values.master.garbageThreshold }} \ {{- end }} -ip=${POD_NAME}.${SEAWEEDFS_FULLNAME}-master.{{ .Release.Namespace }} \ - -peers={{ range $index := until (.Values.master.replicas | int) }}${SEAWEEDFS_FULLNAME}-master-{{ $index }}.${SEAWEEDFS_FULLNAME}-master.{{ $.Release.Namespace }}:{{ $.Values.master.port }}{{ if lt $index (sub ($.Values.master.replicas | int) 1) }},{{ end }}{{ end }} \ + -peers={{ include "seaweedfs.masterServers" . }} \ {{- range .Values.master.extraArgs }} {{ . }} \ {{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-ingress.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-ingress.yaml index 899773ae..e884f4fc 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-ingress.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-ingress.yaml @@ -4,6 +4,13 @@ {{- /* Determine service name based on deployment mode */}} {{- $serviceName := ternary (printf "%s-all-in-one" (include "seaweedfs.name" .)) (printf "%s-s3" (include "seaweedfs.name" .)) .Values.allInOne.enabled }} {{- $s3Port := .Values.allInOne.s3.port | default .Values.s3.port }} +{{- /* Build hosts list - support both legacy .host (string) and new .hosts (array) for backwards compatibility */}} +{{- $hosts := list }} +{{- if kindIs "slice" .Values.s3.ingress.host }} + {{- $hosts = .Values.s3.ingress.host }} +{{- else if .Values.s3.ingress.host }} + {{- $hosts = list .Values.s3.ingress.host }} +{{- end }} {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} apiVersion: networking.k8s.io/v1 {{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion }} @@ -30,6 +37,25 @@ spec: tls: {{ .Values.s3.ingress.tls | default list | toYaml | nindent 6}} rules: +{{- if $hosts }} +{{- range $hosts }} + - host: {{ . | quote }} + http: + paths: + - path: {{ $.Values.s3.ingress.path | quote }} + pathType: {{ $.Values.s3.ingress.pathType | quote }} + backend: +{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $serviceName }} + port: + number: {{ $s3Port }} +{{- else }} + serviceName: {{ $serviceName }} + servicePort: {{ $s3Port }} +{{- end }} +{{- end }} +{{- else }} - http: paths: - path: {{ .Values.s3.ingress.path | quote }} @@ -44,7 +70,5 @@ spec: serviceName: {{ $serviceName }} servicePort: {{ $s3Port }} {{- end }} -{{- if .Values.s3.ingress.host }} - host: {{ .Values.s3.ingress.host | quote }} {{- end }} {{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml index 8afd4865..86e0424e 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml @@ -14,6 +14,7 @@ metadata: {{- toYaml .Values.s3.annotations | nindent 4 }} {{- end }} spec: + trafficDistribution: PreferClose internalTrafficPolicy: {{ .Values.s3.internalTrafficPolicy | default "Cluster" }} ports: - name: "swfs-s3" diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/shared/_helpers.tpl b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/_helpers.tpl index d22d1422..557bb9d4 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/shared/_helpers.tpl +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/_helpers.tpl @@ -83,6 +83,26 @@ Inject extra environment vars in the format key:value, if populated {{- end -}} {{- end -}} +{{/* Return the proper admin image */}} +{{- define "admin.image" -}} +{{- if .Values.admin.imageOverride -}} +{{- $imageOverride := .Values.admin.imageOverride -}} +{{- printf "%s" $imageOverride -}} +{{- else -}} +{{- include "common.image" . }} +{{- end -}} +{{- end -}} + +{{/* Return the proper worker image */}} +{{- define "worker.image" -}} +{{- if .Values.worker.imageOverride -}} +{{- $imageOverride := .Values.worker.imageOverride -}} +{{- printf "%s" $imageOverride -}} +{{- else -}} +{{- include "common.image" . }} +{{- end -}} +{{- end -}} + {{/* Return the proper volume image */}} {{- define "volume.image" -}} {{- if .Values.volume.imageOverride -}} @@ -136,6 +156,15 @@ Inject extra environment vars in the format key:value, if populated {{- end -}} {{- end -}} +{{/* check if any Admin PVC exists */}} +{{- define "admin.pvc_exists" -}} +{{- if or (eq .Values.admin.data.type "persistentVolumeClaim") (eq .Values.admin.logs.type "persistentVolumeClaim") -}} +{{- printf "true" -}} +{{- else -}} +{{- printf "" -}} +{{- end -}} +{{- end -}} + {{/* check if any InitContainers exist for Volumes */}} {{- define "volume.initContainers_exists" -}} {{- if or (not (empty .Values.volume.idx )) (not (empty .Values.volume.initContainers )) -}} @@ -246,3 +275,28 @@ If allInOne is enabled, point to the all-in-one service; otherwise, point to the {{- end -}} {{- printf "%s%s.%s:%d" (include "seaweedfs.name" .) $serviceNameSuffix .Release.Namespace (int .Values.filer.port) -}} {{- end -}} + +{{/* +Generate comma-separated list of master server addresses. +Usage: {{ include "seaweedfs.masterServers" . }} +Output example: ${SEAWEEDFS_FULLNAME}-master-0.${SEAWEEDFS_FULLNAME}-master.namespace:9333,${SEAWEEDFS_FULLNAME}-master-1... +*/}} +{{- define "seaweedfs.masterServers" -}} +{{- $fullname := include "seaweedfs.name" . -}} +{{- range $index := until (.Values.master.replicas | int) -}} +{{- if $index }},{{ end -}} +${SEAWEEDFS_FULLNAME}-master-{{ $index }}.${SEAWEEDFS_FULLNAME}-master.{{ $.Release.Namespace }}:{{ $.Values.master.port }} +{{- end -}} +{{- end -}} + +{{/* +Generate master server argument value, using global.masterServer if set, otherwise the generated list. +Usage: {{ include "seaweedfs.masterServerArg" . }} +*/}} +{{- define "seaweedfs.masterServerArg" -}} +{{- if .Values.global.masterServer -}} +{{- .Values.global.masterServer -}} +{{- else -}} +{{- include "seaweedfs.masterServers" . -}} +{{- end -}} +{{- end -}} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/shared/security-configmap.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/security-configmap.yaml index 6f229c59..f7fb69ea 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/shared/security-configmap.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/security-configmap.yaml @@ -65,6 +65,14 @@ data: cert = "/usr/local/share/ca-certificates/filer/tls.crt" key = "/usr/local/share/ca-certificates/filer/tls.key" + [grpc.admin] + cert = "/usr/local/share/ca-certificates/admin/tls.crt" + key = "/usr/local/share/ca-certificates/admin/tls.key" + + [grpc.worker] + cert = "/usr/local/share/ca-certificates/worker/tls.crt" + key = "/usr/local/share/ca-certificates/worker/tls.key" + # use this for any place needs a grpc client # i.e., "weed backup|benchmark|filer.copy|filer.replicate|mount|s3|upload" [grpc.client] diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml index 1a8964a5..045b95c2 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml @@ -176,6 +176,9 @@ spec: {{- if $volume.dataCenter }} -dataCenter={{ $volume.dataCenter }} \ {{- end }} + {{- if $volume.id }} + -id={{ $volume.id }} \ + {{- end }} -ip.bind={{ $volume.ipBind }} \ -readMode={{ $volume.readMode }} \ {{- if $volume.whiteList }} @@ -196,7 +199,7 @@ spec: -minFreeSpacePercent={{ $volume.minFreeSpacePercent }} \ -ip=${POD_NAME}.${SEAWEEDFS_FULLNAME}-{{ $volumeName }}.{{ $.Release.Namespace }} \ -compactionMBps={{ $volume.compactionMBps }} \ - -mserver={{ if $.Values.global.masterServer }}{{ $.Values.global.masterServer}}{{ else }}{{ range $index := until ($.Values.master.replicas | int) }}${SEAWEEDFS_FULLNAME}-master-{{ $index }}.${SEAWEEDFS_FULLNAME}-master.{{ $.Release.Namespace }}:{{ $.Values.master.port }}{{ if lt $index (sub ($.Values.master.replicas | int) 1) }},{{ end }}{{ end }}{{ end }} + -master={{ include "seaweedfs.masterServerArg" $ }} \ {{- range $volume.extraArgs }} {{ . }} \ {{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-deployment.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-deployment.yaml new file mode 100644 index 00000000..7a6e0524 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-deployment.yaml @@ -0,0 +1,288 @@ +{{- if .Values.worker.enabled }} +{{- if and (not .Values.worker.adminServer) (not .Values.admin.enabled) }} +{{- fail "worker.adminServer must be set if admin.enabled is false within the same release" -}} +{{- end }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "seaweedfs.name" . }}-worker + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: worker +{{- if .Values.worker.annotations }} + annotations: + {{- toYaml .Values.worker.annotations | nindent 4 }} +{{- end }} +spec: + replicas: {{ .Values.worker.replicas }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: worker + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: worker + {{ with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.worker.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + annotations: + {{ with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.worker.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + restartPolicy: {{ default .Values.global.restartPolicy .Values.worker.restartPolicy }} + {{- if .Values.worker.affinity }} + affinity: + {{ tpl .Values.worker.affinity . | nindent 8 | trim }} + {{- end }} + {{- if .Values.worker.topologySpreadConstraints }} + topologySpreadConstraints: + {{ tpl .Values.worker.topologySpreadConstraints . | nindent 8 | trim }} + {{- end }} + {{- if .Values.worker.tolerations }} + tolerations: + {{ tpl .Values.worker.tolerations . | nindent 8 | trim }} + {{- end }} + {{- include "seaweedfs.imagePullSecrets" . | nindent 6 }} + terminationGracePeriodSeconds: 60 + {{- if .Values.worker.priorityClassName }} + priorityClassName: {{ .Values.worker.priorityClassName | quote }} + {{- end }} + enableServiceLinks: false + {{- if .Values.worker.serviceAccountName }} + serviceAccountName: {{ .Values.worker.serviceAccountName | quote }} + {{- end }} + {{- if .Values.worker.initContainers }} + initContainers: + {{ tpl .Values.worker.initContainers . | nindent 8 | trim }} + {{- end }} + {{- if .Values.worker.podSecurityContext.enabled }} + securityContext: {{- omit .Values.worker.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: seaweedfs + image: {{ template "worker.image" . }} + imagePullPolicy: {{ default "IfNotPresent" .Values.global.imagePullPolicy }} + env: + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SEAWEEDFS_FULLNAME + value: "{{ template "seaweedfs.name" . }}" + {{- if .Values.worker.extraEnvironmentVars }} + {{- range $key, $value := .Values.worker.extraEnvironmentVars }} + - name: {{ $key }} + {{- if kindIs "string" $value }} + value: {{ $value | quote }} + {{- else }} + valueFrom: + {{ toYaml $value | nindent 16 | trim }} + {{- end -}} + {{- end }} + {{- end }} + {{- if .Values.global.extraEnvironmentVars }} + {{- range $key, $value := .Values.global.extraEnvironmentVars }} + - name: {{ $key }} + {{- if kindIs "string" $value }} + value: {{ $value | quote }} + {{- else }} + valueFrom: + {{ toYaml $value | nindent 16 | trim }} + {{- end -}} + {{- end }} + {{- end }} + command: + - "/bin/sh" + - "-ec" + - | + exec /usr/bin/weed \ + {{- if or (eq .Values.worker.logs.type "hostPath") (eq .Values.worker.logs.type "emptyDir") (eq .Values.worker.logs.type "existingClaim") }} + -logdir=/logs \ + {{- else }} + -logtostderr=true \ + {{- end }} + {{- if .Values.worker.loggingOverrideLevel }} + -v={{ .Values.worker.loggingOverrideLevel }} \ + {{- else }} + -v={{ .Values.global.loggingLevel }} \ + {{- end }} + worker \ + {{- if .Values.worker.adminServer }} + -admin={{ .Values.worker.adminServer }} \ + {{- else }} + -admin={{ template "seaweedfs.name" . }}-admin.{{ .Release.Namespace }}:{{ .Values.admin.port }}{{ if .Values.admin.grpcPort }}.{{ .Values.admin.grpcPort }}{{ end }} \ + {{- end }} + -capabilities={{ .Values.worker.capabilities }} \ + -maxConcurrent={{ .Values.worker.maxConcurrent }} \ + -workingDir={{ .Values.worker.workingDir }}{{- if or .Values.worker.metricsPort .Values.worker.extraArgs }} \{{ end }} + {{- if .Values.worker.metricsPort }} + -metricsPort={{ .Values.worker.metricsPort }}{{- if .Values.worker.extraArgs }} \{{ end }} + {{- end }} + {{- range $index, $arg := .Values.worker.extraArgs }} + {{ $arg }}{{- if lt $index (sub (len $.Values.worker.extraArgs) 1) }} \{{ end }} + {{- end }} + volumeMounts: + {{- if or (eq .Values.worker.data.type "hostPath") (eq .Values.worker.data.type "emptyDir") (eq .Values.worker.data.type "existingClaim") }} + - name: worker-data + mountPath: {{ .Values.worker.workingDir }} + {{- end }} + {{- if or (eq .Values.worker.logs.type "hostPath") (eq .Values.worker.logs.type "emptyDir") (eq .Values.worker.logs.type "existingClaim") }} + - name: worker-logs + mountPath: /logs + {{- end }} + {{- if .Values.global.enableSecurity }} + - name: security-config + readOnly: true + mountPath: /etc/seaweedfs/security.toml + subPath: security.toml + - name: ca-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/ca/ + - name: master-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/master/ + - name: volume-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/volume/ + - name: filer-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/filer/ + - name: client-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/client/ + - name: worker-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/worker/ + {{- end }} + {{ tpl .Values.worker.extraVolumeMounts . | nindent 12 | trim }} + ports: + {{- if .Values.worker.metricsPort }} + - containerPort: {{ .Values.worker.metricsPort }} + name: metrics + {{- end }} + {{- with .Values.worker.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- if .Values.worker.livenessProbe.enabled }} + livenessProbe: + {{- if .Values.worker.livenessProbe.httpGet }} + httpGet: + path: {{ .Values.worker.livenessProbe.httpGet.path }} + port: {{ .Values.worker.livenessProbe.httpGet.port }} + {{- else if .Values.worker.livenessProbe.tcpSocket }} + tcpSocket: + port: {{ .Values.worker.livenessProbe.tcpSocket.port }} + {{- end }} + initialDelaySeconds: {{ .Values.worker.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.worker.livenessProbe.periodSeconds }} + successThreshold: {{ .Values.worker.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.worker.livenessProbe.failureThreshold }} + timeoutSeconds: {{ .Values.worker.livenessProbe.timeoutSeconds }} + {{- end }} + {{- if .Values.worker.readinessProbe.enabled }} + readinessProbe: + {{- if .Values.worker.readinessProbe.httpGet }} + httpGet: + path: {{ .Values.worker.readinessProbe.httpGet.path }} + port: {{ .Values.worker.readinessProbe.httpGet.port }} + {{- else if .Values.worker.readinessProbe.tcpSocket }} + tcpSocket: + port: {{ .Values.worker.readinessProbe.tcpSocket.port }} + {{- end }} + initialDelaySeconds: {{ .Values.worker.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.worker.readinessProbe.periodSeconds }} + successThreshold: {{ .Values.worker.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.worker.readinessProbe.failureThreshold }} + timeoutSeconds: {{ .Values.worker.readinessProbe.timeoutSeconds }} + {{- end }} + {{- if .Values.worker.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.worker.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.worker.sidecars }} + {{- include "common.tplvalues.render" (dict "value" .Values.worker.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + {{- if eq .Values.worker.data.type "hostPath" }} + - name: worker-data + hostPath: + path: {{ .Values.worker.data.hostPathPrefix }}/seaweedfs-worker-data + type: DirectoryOrCreate + {{- end }} + {{- if eq .Values.worker.data.type "emptyDir" }} + - name: worker-data + emptyDir: {} + {{- end }} + {{- if eq .Values.worker.data.type "existingClaim" }} + - name: worker-data + persistentVolumeClaim: + claimName: {{ .Values.worker.data.claimName }} + {{- end }} + {{- if eq .Values.worker.logs.type "hostPath" }} + - name: worker-logs + hostPath: + path: {{ .Values.worker.logs.hostPathPrefix }}/logs/seaweedfs/worker + type: DirectoryOrCreate + {{- end }} + {{- if eq .Values.worker.logs.type "emptyDir" }} + - name: worker-logs + emptyDir: {} + {{- end }} + {{- if eq .Values.worker.logs.type "existingClaim" }} + - name: worker-logs + persistentVolumeClaim: + claimName: {{ .Values.worker.logs.claimName }} + {{- end }} + {{- if .Values.global.enableSecurity }} + - name: security-config + configMap: + name: {{ template "seaweedfs.name" . }}-security-config + - name: ca-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-ca-cert + - name: master-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-master-cert + - name: volume-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-volume-cert + - name: filer-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-filer-cert + - name: client-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-client-cert + - name: worker-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-worker-cert + {{- end }} + {{ tpl .Values.worker.extraVolumes . | indent 8 | trim }} + {{- if .Values.worker.nodeSelector }} + nodeSelector: + {{ tpl .Values.worker.nodeSelector . | indent 8 | trim }} + {{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-service.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-service.yaml new file mode 100644 index 00000000..cf9885e2 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-service.yaml @@ -0,0 +1,26 @@ +{{- if .Values.worker.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "seaweedfs.name" . }}-worker + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: worker +spec: + clusterIP: None # Headless service + {{- if .Values.worker.metricsPort }} + ports: + - name: "metrics" + port: {{ .Values.worker.metricsPort }} + targetPort: {{ .Values.worker.metricsPort }} + protocol: TCP + {{- end }} + selector: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: worker +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-servicemonitor.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-servicemonitor.yaml new file mode 100644 index 00000000..7f9590da --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if .Values.worker.enabled }} +{{- if .Values.worker.metricsPort }} +{{- if .Values.global.monitoring.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "seaweedfs.name" . }}-worker + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: worker + {{- with .Values.global.monitoring.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- with .Values.worker.serviceMonitor.annotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + endpoints: + - interval: 30s + port: metrics + scrapeTimeout: 5s + selector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/component: worker +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/values.yaml b/packages/system/seaweedfs/charts/seaweedfs/values.yaml index b71e1071..a2419805 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/values.yaml @@ -401,6 +401,10 @@ volume: # Volume server's rack name rack: null + # Stable identifier for the volume server, independent of IP address + # Useful for Kubernetes environments with hostPath volumes to maintain stable identity + id: null + # Volume server's data center name dataCenter: null @@ -1008,7 +1012,7 @@ s3: ingress: enabled: false className: "" - # host: false for "*" hostname + # host: false for "*" hostname, or an array for multiple hostnames host: "seaweedfs.cluster.local" path: "/" pathType: Prefix @@ -1088,6 +1092,247 @@ sftp: failureThreshold: 100 timeoutSeconds: 10 +admin: + enabled: false + imageOverride: null + restartPolicy: null + replicas: 1 + port: 23646 # Default admin port + grpcPort: 33646 # Default gRPC port for worker connections + metricsPort: 9327 + loggingOverrideLevel: null + + # Admin authentication + secret: + # Name of an existing secret containing admin credentials. If set, adminUser and adminPassword below are ignored. + existingSecret: "" + # Key in the existing secret for the admin username. Required if existingSecret is set. + userKey: "" + # Key in the existing secret for the admin password. Required if existingSecret is set. + pwKey: "" + adminUser: "admin" + adminPassword: "" # If empty, authentication is disabled. + + # Data directory for admin configuration and maintenance data + dataDir: "" # If empty, configuration is kept in memory only + + # Master servers to connect to + # If empty, uses global.masterServer or auto-discovers from master statefulset + masters: "" + + # Custom command line arguments to add to the admin command + # Example: ["-customFlag", "value", "-anotherFlag"] + extraArgs: [] + + # Storage configuration + data: + type: "emptyDir" # Options: "hostPath", "persistentVolumeClaim", "emptyDir", "existingClaim" + size: "10Gi" + storageClass: "" + hostPathPrefix: /storage + claimName: "" + annotations: {} + + logs: + type: "emptyDir" # Options: "hostPath", "persistentVolumeClaim", "emptyDir", "existingClaim" + size: "5Gi" + storageClass: "" + hostPathPrefix: /storage + claimName: "" + annotations: {} + + # Additional resources + sidecars: [] + initContainers: "" + extraVolumes: "" + extraVolumeMounts: "" + podLabels: {} + podAnnotations: {} + annotations: {} + + ## Set podManagementPolicy + podManagementPolicy: Parallel + + # Affinity Settings + # Commenting out or setting as empty the affinity variable, will allow + # deployment to single node services such as Minikube + affinity: | + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin + topologyKey: kubernetes.io/hostname + + # Topology Spread Constraints Settings + # This should map directly to the value of the topologySpreadConstraints + # for a PodSpec. By Default no constraints are set. + topologySpreadConstraints: "" + + resources: {} + tolerations: "" + nodeSelector: "" + priorityClassName: "" + serviceAccountName: "" + podSecurityContext: {} + containerSecurityContext: {} + + extraEnvironmentVars: {} + + # Health checks + livenessProbe: + enabled: true + httpGet: + path: /health + scheme: HTTP + initialDelaySeconds: 20 + periodSeconds: 60 + successThreshold: 1 + failureThreshold: 5 + timeoutSeconds: 10 + + readinessProbe: + enabled: true + httpGet: + path: /health + scheme: HTTP + initialDelaySeconds: 15 + periodSeconds: 15 + successThreshold: 1 + failureThreshold: 3 + timeoutSeconds: 10 + + ingress: + enabled: false + className: "nginx" + # host: false for "*" hostname + host: "admin.seaweedfs.local" + path: "/" + pathType: Prefix + annotations: {} + tls: [] + + service: + type: ClusterIP + annotations: {} + + # ServiceMonitor annotations (separate from pod/deployment annotations) + serviceMonitor: + annotations: {} + +worker: + enabled: false + imageOverride: null + restartPolicy: null + replicas: 1 + loggingOverrideLevel: null + metricsPort: 9327 + + # Admin server to connect to + adminServer: "" + + + # Worker capabilities - comma-separated list + # Available: vacuum, balance, erasure_coding + # Default: "vacuum,balance,erasure_coding" (all capabilities) + capabilities: "vacuum,balance,erasure_coding" + + # Maximum number of concurrent tasks + maxConcurrent: 3 + + # Working directory for task execution + workingDir: "/tmp/seaweedfs-worker" + + # Custom command line arguments to add to the worker command + # Example: ["-customFlag", "value", "-anotherFlag"] + extraArgs: [] + + # Storage configuration for working directory + # Note: Workers use Deployment, so use "emptyDir", "hostPath", or "existingClaim" + # Do NOT use "persistentVolumeClaim" - use "existingClaim" with pre-provisioned PVC instead + data: + type: "emptyDir" # Options: "hostPath", "emptyDir", "existingClaim" + hostPathPrefix: /storage + claimName: "" # For existingClaim type + + logs: + type: "emptyDir" # Options: "hostPath", "emptyDir", "existingClaim" + hostPathPrefix: /storage + claimName: "" # For existingClaim type + + # Additional resources + sidecars: [] + initContainers: "" + extraVolumes: "" + extraVolumeMounts: "" + podLabels: {} + podAnnotations: {} + annotations: {} + + # Affinity Settings + # Commenting out or setting as empty the affinity variable, will allow + # deployment to single node services such as Minikube + affinity: | + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: worker + topologyKey: kubernetes.io/hostname + + # Topology Spread Constraints Settings + # This should map directly to the value of the topologySpreadConstraints + # for a PodSpec. By Default no constraints are set. + topologySpreadConstraints: "" + + resources: + requests: + cpu: "500m" + memory: "512Mi" + limits: + cpu: "2" + memory: "2Gi" + tolerations: "" + nodeSelector: "" + priorityClassName: "" + serviceAccountName: "" + podSecurityContext: {} + containerSecurityContext: {} + + extraEnvironmentVars: {} + + # Health checks for worker pods + # Workers expose /health (liveness) and /ready (readiness) endpoints on the metricsPort + livenessProbe: + enabled: true + httpGet: + path: /health + port: metrics + initialDelaySeconds: 30 + periodSeconds: 60 + successThreshold: 1 + failureThreshold: 5 + timeoutSeconds: 10 + + readinessProbe: + enabled: true + httpGet: + path: /ready + port: metrics + initialDelaySeconds: 20 + periodSeconds: 15 + successThreshold: 1 + failureThreshold: 3 + timeoutSeconds: 10 + + # ServiceMonitor annotations (separate from pod/deployment annotations) + serviceMonitor: + annotations: {} + # All-in-one deployment configuration allInOne: enabled: false diff --git a/packages/system/seaweedfs/images/seaweedfs/Dockerfile b/packages/system/seaweedfs/images/seaweedfs/Dockerfile deleted file mode 100644 index 7177c70f..00000000 --- a/packages/system/seaweedfs/images/seaweedfs/Dockerfile +++ /dev/null @@ -1,2 +0,0 @@ -ARG VERSION=4.02 -FROM chrislusf/seaweedfs:${VERSION} diff --git a/packages/system/seaweedfs/patches/s3-traffic-distribution.patch b/packages/system/seaweedfs/patches/s3-traffic-distribution.patch new file mode 100644 index 00000000..93c72384 --- /dev/null +++ b/packages/system/seaweedfs/patches/s3-traffic-distribution.patch @@ -0,0 +1,12 @@ +diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml +index 8afd4865..86e0424e 100644 +--- a/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml ++++ b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml +@@ -14,6 +14,7 @@ metadata: + {{- toYaml .Values.s3.annotations | nindent 4 }} + {{- end }} + spec: ++ trafficDistribution: PreferClose + internalTrafficPolicy: {{ .Values.s3.internalTrafficPolicy | default "Cluster" }} + ports: + - name: "swfs-s3" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index afe8283d..830c4faa 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -1,16 +1,12 @@ global: enableSecurity: true serviceAccountName: "tenant-foo-seaweedfs" - imageName: "seaweedfs" extraEnvironmentVars: WEED_CLUSTER_SW_MASTER: "seaweedfs-master:9333" WEED_CLUSTER_SW_FILER: "seaweedfs-filer-client:8888" monitoring: enabled: true seaweedfs: - image: - tag: "latest@sha256:944e9bff98b088773847270238b63ce57dc5291054814d08e0226a139b3affb2" - registry: ghcr.io/cozystack/cozystack master: volumeSizeLimitMB: 30000 replicas: 3 @@ -75,7 +71,7 @@ seaweedfs: name: seaweedfs-db-app s3: replicas: 2 - enabled: true + enabled: false port: 8333 httpsPort: 0 # Suffix of the host name, {bucket}.{domainName} @@ -87,20 +83,24 @@ seaweedfs: existingConfigSecret: null auditLogConfig: {} s3: - enabled: false + enabled: true + replicas: 2 + port: 8333 extraArgs: - -idleTimeout=60 enableAuth: false readinessProbe: - scheme: HTTPS + httpGet: + scheme: HTTPS livenessProbe: - scheme: HTTPS + httpGet: + scheme: HTTPS logs: type: "" ingress: enabled: true className: "tenant-root" - host: "seaweedfs2.demo.cozystack.io" + host: "seaweedfs.demo.cozystack.io" annotations: nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/proxy-buffering: "off" @@ -110,12 +110,65 @@ seaweedfs: nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" nginx.ingress.kubernetes.io/client-body-timeout: "3600" nginx.ingress.kubernetes.io/client-header-timeout: "120" + nginx.ingress.kubernetes.io/service-upstream: "true" acme.cert-manager.io/http01-ingress-class: tenant-root cert-manager.io/cluster-issuer: letsencrypt-prod tls: - hosts: - seaweedfs.demo.cozystack.io secretName: seaweedfs-s3-ingress-tls + affinity: | + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 10 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - '{{ template "seaweedfs.name" . }}' + - key: app.kubernetes.io/instance + operator: In + values: + - '{{ .Release.Name }}' + - key: app.kubernetes.io/component + operator: In + values: + - s3 + topologyKey: kubernetes.io/hostname + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - '{{ template "seaweedfs.name" . }}' + - key: app.kubernetes.io/instance + operator: In + values: + - '{{ .Release.Name }}' + - key: app.kubernetes.io/component + operator: In + values: + - s3 + topologyKey: topology.kubernetes.io/zone + podAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 20 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - ingress-nginx + - key: app.kubernetes.io/component + operator: In + values: + - controller + topologyKey: kubernetes.io/hostname cosi: enabled: true podLabels: From c4bf72b44f8261500640a6a0b070879a78256ab4 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 8 Jan 2026 14:17:15 +0100 Subject: [PATCH 50/78] [linstor] Add linstor-scheduler package (#1824) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does Add linstor-scheduler-extender for optimal pod placement on nodes with LINSTOR storage. ### How it works The linstor-scheduler consists of two components: #### 1. Scheduler Extender A custom Kubernetes scheduler that works alongside the default kube-scheduler. When a pod requests LINSTOR-backed storage, the scheduler extender 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. #### 2. Admission Webhook A MutatingWebhookConfiguration that automatically sets `schedulerName: linstor-scheduler` on pods that use LINSTOR CSI driver volumes. This ensures that only pods with LINSTOR PVCs are routed through the custom scheduler, while all other pods continue using the default scheduler. The webhook inspects pod creation requests and checks if any of the pod's PVCs use a StorageClass with the LINSTOR CSI provisioner (`linstor.csi.linbit.com`). If so, it mutates the pod spec to use the linstor-scheduler. ### Components - `linstor-scheduler` package in `packages/system/linstor-scheduler/` - PackageSource definition in `packages/core/platform/sources/linstor-scheduler.yaml` - Integration into `paas-full` and `distro-full` bundles ### Upstream PRs - https://github.com/piraeusdatastore/helm-charts/pull/67 — fix: KubeSchedulerConfiguration v1 support for Kubernetes 1.25+ - https://github.com/piraeusdatastore/helm-charts/pull/68 — feat: admission webhook support with cert-manager - https://github.com/piraeusdatastore/helm-charts/pull/69 — fix chart template issues ### Release note ```release-note [linstor] Add linstor-scheduler for optimal pod placement on nodes with local LINSTOR replicas. Includes admission webhook that automatically routes pods using LINSTOR CSI volumes to the custom scheduler. ``` ## Summary by CodeRabbit * **New Features** * Added LINSTOR scheduler component to the platform, packaged as a Helm chart and installable package. * Includes admission webhook, scheduler extender, autoscaling support, pod disruption budget, RBAC and service account integration, and Helm test hooks. * **Documentation** * Added chart README and default configuration values for easy deployment and customization. ✏️ Tip: You can customize this high-level summary in your review settings. --- .../core/platform/bundles/distro-full.yaml | 6 + packages/core/platform/bundles/paas-full.yaml | 6 + .../platform/sources/linstor-scheduler.yaml | 22 ++ packages/system/linstor-scheduler/.helmignore | 1 + packages/system/linstor-scheduler/Chart.yaml | 3 + packages/system/linstor-scheduler/Makefile | 10 + .../charts/linstor-scheduler/Chart.yaml | 19 ++ .../charts/linstor-scheduler/LICENSE | 201 ++++++++++++++++++ .../charts/linstor-scheduler/README.md | 72 +++++++ .../linstor-scheduler/templates/NOTES.txt | 12 ++ .../linstor-scheduler/templates/_helpers.tpl | 141 ++++++++++++ .../templates/admission-deployment.yaml | 98 +++++++++ .../templates/admission-service.yaml | 20 ++ .../templates/certmanager.yaml | 56 +++++ .../linstor-scheduler/templates/config.yaml | 46 ++++ .../templates/deployment.yaml | 126 +++++++++++ .../linstor-scheduler/templates/hpa.yaml | 32 +++ .../mutatingwebhookconfiguration.yaml | 32 +++ .../templates/poddisruptionbudget.yaml | 18 ++ .../linstor-scheduler/templates/rbac.yaml | 108 ++++++++++ .../templates/serviceaccount.yaml | 12 ++ .../templates/tests/test-scheduler.yaml | 16 ++ .../charts/linstor-scheduler/values.yaml | 106 +++++++++ packages/system/linstor-scheduler/values.yaml | 7 + 24 files changed, 1170 insertions(+) create mode 100644 packages/core/platform/sources/linstor-scheduler.yaml create mode 100644 packages/system/linstor-scheduler/.helmignore create mode 100644 packages/system/linstor-scheduler/Chart.yaml create mode 100644 packages/system/linstor-scheduler/Makefile create mode 100644 packages/system/linstor-scheduler/charts/linstor-scheduler/Chart.yaml create mode 100644 packages/system/linstor-scheduler/charts/linstor-scheduler/LICENSE create mode 100644 packages/system/linstor-scheduler/charts/linstor-scheduler/README.md create mode 100644 packages/system/linstor-scheduler/charts/linstor-scheduler/templates/NOTES.txt create mode 100644 packages/system/linstor-scheduler/charts/linstor-scheduler/templates/_helpers.tpl create mode 100644 packages/system/linstor-scheduler/charts/linstor-scheduler/templates/admission-deployment.yaml create mode 100644 packages/system/linstor-scheduler/charts/linstor-scheduler/templates/admission-service.yaml create mode 100644 packages/system/linstor-scheduler/charts/linstor-scheduler/templates/certmanager.yaml create mode 100644 packages/system/linstor-scheduler/charts/linstor-scheduler/templates/config.yaml create mode 100644 packages/system/linstor-scheduler/charts/linstor-scheduler/templates/deployment.yaml create mode 100644 packages/system/linstor-scheduler/charts/linstor-scheduler/templates/hpa.yaml create mode 100644 packages/system/linstor-scheduler/charts/linstor-scheduler/templates/mutatingwebhookconfiguration.yaml create mode 100644 packages/system/linstor-scheduler/charts/linstor-scheduler/templates/poddisruptionbudget.yaml create mode 100644 packages/system/linstor-scheduler/charts/linstor-scheduler/templates/rbac.yaml create mode 100644 packages/system/linstor-scheduler/charts/linstor-scheduler/templates/serviceaccount.yaml create mode 100644 packages/system/linstor-scheduler/charts/linstor-scheduler/templates/tests/test-scheduler.yaml create mode 100644 packages/system/linstor-scheduler/charts/linstor-scheduler/values.yaml create mode 100644 packages/system/linstor-scheduler/values.yaml diff --git a/packages/core/platform/bundles/distro-full.yaml b/packages/core/platform/bundles/distro-full.yaml index bf915d4e..13d58ded 100644 --- a/packages/core/platform/bundles/distro-full.yaml +++ b/packages/core/platform/bundles/distro-full.yaml @@ -357,6 +357,12 @@ releases: privileged: true dependsOn: [piraeus-operator,cilium,cert-manager,snapshot-controller] +- name: linstor-scheduler + releaseName: linstor-scheduler + chart: cozy-linstor-scheduler + namespace: cozy-linstor + dependsOn: [linstor,cert-manager] + - name: nfs-driver releaseName: nfs-driver chart: cozy-nfs-driver diff --git a/packages/core/platform/bundles/paas-full.yaml b/packages/core/platform/bundles/paas-full.yaml index 17851e23..40951336 100644 --- a/packages/core/platform/bundles/paas-full.yaml +++ b/packages/core/platform/bundles/paas-full.yaml @@ -424,6 +424,12 @@ releases: privileged: true dependsOn: [piraeus-operator,cilium,kubeovn,cert-manager,snapshot-controller] +- name: linstor-scheduler + releaseName: linstor-scheduler + chart: cozy-linstor-scheduler + namespace: cozy-linstor + dependsOn: [linstor,cert-manager] + - name: nfs-driver releaseName: nfs-driver chart: cozy-nfs-driver diff --git a/packages/core/platform/sources/linstor-scheduler.yaml b/packages/core/platform/sources/linstor-scheduler.yaml new file mode 100644 index 00000000..fad3eeb7 --- /dev/null +++ b/packages/core/platform/sources/linstor-scheduler.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.linstor-scheduler +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.linstor + - cozystack.cert-manager + components: + - name: linstor-scheduler + path: system/linstor-scheduler + install: + namespace: cozy-linstor + releaseName: linstor-scheduler diff --git a/packages/system/linstor-scheduler/.helmignore b/packages/system/linstor-scheduler/.helmignore new file mode 100644 index 00000000..1e107f52 --- /dev/null +++ b/packages/system/linstor-scheduler/.helmignore @@ -0,0 +1 @@ +examples diff --git a/packages/system/linstor-scheduler/Chart.yaml b/packages/system/linstor-scheduler/Chart.yaml new file mode 100644 index 00000000..682d263b --- /dev/null +++ b/packages/system/linstor-scheduler/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-linstor-scheduler +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/linstor-scheduler/Makefile b/packages/system/linstor-scheduler/Makefile new file mode 100644 index 00000000..90a31bc8 --- /dev/null +++ b/packages/system/linstor-scheduler/Makefile @@ -0,0 +1,10 @@ +export NAME=linstor-scheduler +export NAMESPACE=cozy-linstor + +include ../../../scripts/package.mk + +update: + rm -rf charts + helm repo add piraeus-charts https://piraeus.io/helm-charts/ + helm repo update piraeus-charts + helm pull piraeus-charts/linstor-scheduler --untar --untardir charts diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/Chart.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/Chart.yaml new file mode 100644 index 00000000..4a521d1f --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/Chart.yaml @@ -0,0 +1,19 @@ +apiVersion: v2 +appVersion: v0.3.2 +deprecated: true +description: 'Deploys a new kubernetes scheduler, configured to take advantage of + storage system information. If a Pod is using a LINSTOR volume, the scheduler will + prefer nodes with local data instead of accessing the data via a DRBD diskless. ' +home: https://github.com/piraeusdatastore/helm-charts +icon: https://raw.githubusercontent.com/piraeusdatastore/piraeus/master/artwork/sandbox-artwork/icon/color.svg +keywords: +- storage +- scheduler +maintainers: +- name: The Piraeus Maintainers + url: https://github.com/piraeusdatastore/ +name: linstor-scheduler +sources: +- https://github.com/piraeusdatastore/linstor-scheduler-extender +type: application +version: 0.2.3 diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/LICENSE b/packages/system/linstor-scheduler/charts/linstor-scheduler/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/README.md b/packages/system/linstor-scheduler/charts/linstor-scheduler/README.md new file mode 100644 index 00000000..ddf92826 --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/README.md @@ -0,0 +1,72 @@ +# linstor-scheduler + +Deploys a new Kubernetes scheduler, extended by +the [linstor-scheduler-extender](https://github.com/piraeusdatastore/linstor-scheduler-extender). + +> [!IMPORTANT] +> The LINSTOR Scheduler is no longer maintained. Prefer using `volumeBindingMode: WaitForFirstConsumer` on your +> StorageClasses. + +The schedule is volume placement aware. That means that it prefers placing Pods on the same nodes as any Persistent +Volume they might use. This works for any setup using LINSTOR, i.e. Piraeus Datastore or LINBIT SDS. + +## Installation + +The scheduler is meant to be installed in the same namespace as LINSTOR itself, otherwise additional steps may be +required. + +If installed along side Piraeus Operator, the LINSTOR endpoint is determined automatically. Otherwise, you need +to set `linstor.endpoint` and `linstor.clientSecret` values as appropriate. + +The following command will install the scheduler for a typical Piraeus Data-Store configuration with TLS enabled: + +``` +helm repo add piraeus-charts https://piraeus.io/helm-charts/ +helm install linstor-scheduler piraeus-charts/linstor-scheduler --set linstorEndpoint=https://piraeus-op-cs.piraeus.svc:3371 --set linstorClientSecret=piraeus-client-secret +``` + +## Usage + +To use the scheduler, you need to configure it on your Pods (or Pod templates): + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: some-pod +spec: + schedulerName: linstor-scheduler + ... +``` + +## Configuration + +The following options are available: + +| Option | Usage | Default | +|-----------------------------------------------|--------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------| +| `replicaCount` | Number of replicas to deploy. | `1` | +| `linstor.endpoint` | URL of the LINSTOR Controller API. | `""` | +| `linstor.clientSecret` | TLS secret to use to authenticate with the LINSTOR API | `""` | +| `extender.image.repository` | Repository to pull the linstor-scheduler-extender image from. | `quay.io/piraeusdatastore/linstor-scheduler-extender` | +| `extender.image.pullPolicy` | Pull policy to use. Possible values: `IfNotPresent`, `Always`, `Never` | `IfNotPresent` | +| `extender.image.tag` | Override the tag to pull. If not given, defaults to charts `AppVersion`. | `""` | +| `extender.resources` | Resources to request and limit on the container. | `{}` | +| `extender.securityContext` | Configure container security context. Defaults to dropping all capabilties and running as user 1000. | `{capabilities: {drop: [ALL]}, readOnlyRootFilesystem: true, runAsNonRoot: true, runAsUser: 1000}` | +| `scheduler.image.repository` | Repository to pull the kubernetes scheduler image from. | `registry.k8s.io/kube-scheduler` | +| `scheduler.image.pullPolicy` | Pull policy to use. Possible values: `IfNotPresent`, `Always`, `Never` | `IfNotPresent` | +| `scheduler.image.tag` | Override the tag to pull. If not given, defaults to kubernetes version. | `""` | +| `scheduler.image.compatibleKubernetesRelease` | Compatible kubernetes version for this scheduler, used to generate configuration in the right version. | `""` | +| `scheduler.resources` | Resources to request and limit on the container. | `{}` | +| `scheduler.securityContext` | Configure container security context. Defaults to dropping all capabilties and running as user 1000. | `{capabilities: {drop: [ALL]}, readOnlyRootFilesystem: true, runAsNonRoot: true, runAsUser: 1000}` | +| `imagePullSecrets` | Image pull secrets to add to the deployment. | `[]` | +| `podAnnotations` | Annotations to add to every pod in the deployment. | `{}` | +| `podSecurityContext` | Security context to set on the webhook pod. | `{}` | +| `nodeSelector` | Node selector to add to each webhook pod. | `{}` | +| `tolerations` | Tolerations to add to each webhook pod. | `[]` | +| `affinity` | Affinity to set on each webhook pod. | `{}` | +| `rbac.create` | Create the necessary roles and bindings for the snapshot controller. | `true` | +| `serviceAccount.create` | Create the service account resource | `true` | +| `serviceAccount.name` | Sets the name of the service account. If left empty, will use the release name as default | `""` | +| `podDisruptionBudget.enabled` | Enable creation of a pod disruption budget to protect the availability of the scheduler | `true` | +| `autoscaling.enabled` | Enable creation of a horizontal pod autoscaler to ensure availability in case of high usage` | `"false` | diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/NOTES.txt b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/NOTES.txt new file mode 100644 index 00000000..5e426f28 --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/NOTES.txt @@ -0,0 +1,12 @@ +Scheduler {{ include "linstor-scheduler.fullname" . }} deployed! + +Used LINSTOR URL: {{ include "linstor-scheduler.linstorEndpoint" .}} + +Please run `helm test {{ .Release.Name }}` to ensure it's properly working. + +Specify the scheduler on your pods to start smart scheduling based on your Persistent Volumes: + +--- +spec: + schedulerName: {{ include "linstor-scheduler.fullname" . }} +--- diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/_helpers.tpl b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/_helpers.tpl new file mode 100644 index 00000000..ad24453b --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/_helpers.tpl @@ -0,0 +1,141 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "linstor-scheduler.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "linstor-scheduler.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "linstor-scheduler.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "linstor-scheduler.labels" -}} +helm.sh/chart: {{ include "linstor-scheduler.chart" . }} +{{ include "linstor-scheduler.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "linstor-scheduler.selectorLabels" -}} +app.kubernetes.io/name: {{ include "linstor-scheduler.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "linstor-scheduler.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "linstor-scheduler.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Get the kubernetes version we should assume for creating scheduler configs +*/}} +{{- define "linstor-scheduler.kubeVersion" }} +{{- .Values.scheduler.image.compatibleKubernetesRelease | default .Capabilities.KubeVersion.Version }} +{{- end }} + +{{/* +Find the linstor client secret containing TLS certificates +*/}} +{{- define "linstor-scheduler.linstorClientSecretName" -}} +{{- if .Values.linstor.clientSecret }} +{{- .Values.linstor.clientSecret }} +{{- else if .Capabilities.APIVersions.Has "piraeus.linbit.com/v1/LinstorController" }} +{{- $crs := (lookup "piraeus.linbit.com/v1" "LinstorController" .Release.Namespace "").items }} +{{- if $crs }} +{{- if eq (len $crs) 1 }} +{{- $item := index $crs 0 }} +{{- $item.spec.linstorHttpsClientSecret }} +{{- end }} +{{- end }} +{{- else if .Capabilities.APIVersions.Has "linstor.linbit.com/v1/LinstorController" }} +{{- $crs := (lookup "linstor.linbit.com/v1" "LinstorController" .Release.Namespace "").items }} +{{- if $crs }} +{{- if eq (len $crs) 1 }} +{{- $item := index $crs 0 }} +{{- $item.spec.linstorHttpsClientSecret }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Find the linstor URL by operator resources +*/}} +{{- define "linstor-scheduler.linstorEndpointFromCRD" -}} +{{- if .Capabilities.APIVersions.Has "piraeus.linbit.com/v1/LinstorController" }} +{{- $crs := (lookup "piraeus.linbit.com/v1" "LinstorController" .Release.Namespace "").items }} +{{- if $crs }} +{{- if eq (len $crs) 1 }} +{{- $item := index $crs 0 }} +{{- if include "linstor-scheduler.linstorClientSecretName" . }} +{{- printf "https://%s.%s.svc:3371" $item.metadata.name $item.metadata.namespace }} +{{- else }} +{{- printf "http://%s.%s.svc:3370" $item.metadata.name $item.metadata.namespace }} +{{- end }} +{{- end }} +{{- end }} +{{- else if .Capabilities.APIVersions.Has "linstor.linbit.com/v1/LinstorController" }} +{{- $crs := (lookup "linstor.linbit.com/v1" "LinstorController" .Release.Namespace "").items }} +{{- if $crs }} +{{- if eq (len $crs) 1 }} +{{- $item := index $crs 0 }} +{{- if include "linstor-scheduler.linstorClientSecretName" . }} +{{- printf "https://%s.%s.svc:3371" $item.metadata.name $item.metadata.namespace }} +{{- else }} +{{- printf "http://%s.%s.svc:3370" $item.metadata.name $item.metadata.namespace }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Find the linstor URL either by override or cluster resources +*/}} +{{- define "linstor-scheduler.linstorEndpoint" -}} +{{- if .Values.linstor.endpoint }} +{{- .Values.linstor.endpoint }} +{{- else }} +{{- $piraeus := include "linstor-scheduler.linstorEndpointFromCRD" . }} +{{- if $piraeus }} +{{- $piraeus }} +{{- else }} +{{- fail "Please specify linstor.endpoint, no default URL could be determined" }} +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/admission-deployment.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/admission-deployment.yaml new file mode 100644 index 00000000..22f5326a --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/admission-deployment.yaml @@ -0,0 +1,98 @@ +{{- if .Values.admission.enabled }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} + app.kubernetes.io/component: admission +spec: + replicas: {{ .Values.admission.replicaCount }} + selector: + matchLabels: + {{- include "linstor-scheduler.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: admission + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "linstor-scheduler.selectorLabels" . | nindent 8 }} + app.kubernetes.io/component: admission + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "linstor-scheduler.serviceAccountName" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + containers: + - name: linstor-scheduler-admission + image: {{ .Values.extender.image.repository }}:{{ .Values.extender.image.tag | default .Chart.AppVersion }} + imagePullPolicy: {{ .Values.extender.image.pullPolicy }} + command: ["/linstor-scheduler-admission"] + args: + - -scheduler={{ include "linstor-scheduler.fullname" . }} + - -tls-cert-file=/etc/webhook/certs/tls.crt + - -tls-key-file=/etc/webhook/certs/tls.key + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + ports: + - containerPort: 8080 + name: https + protocol: TCP + env: + - name: LS_CONTROLLERS + value: {{ include "linstor-scheduler.linstorEndpoint" . }} + {{- if include "linstor-scheduler.linstorClientSecretName" . }} + - name: LS_USER_CERTIFICATE + valueFrom: + secretKeyRef: + name: {{ include "linstor-scheduler.linstorClientSecretName" . }} + key: tls.crt + - name: LS_USER_KEY + valueFrom: + secretKeyRef: + name: {{ include "linstor-scheduler.linstorClientSecretName" . }} + key: tls.key + - name: LS_ROOT_CA + valueFrom: + secretKeyRef: + name: {{ include "linstor-scheduler.linstorClientSecretName" . }} + key: ca.crt + {{- end }} + volumeMounts: + - name: webhook-certs + mountPath: /etc/webhook/certs + readOnly: true + resources: + {{- toYaml .Values.admission.resources | nindent 12 }} + volumes: + - name: webhook-certs + secret: + secretName: {{ include "linstor-scheduler.fullname" . }}-admission-tls + defaultMode: 0400 + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/admission-service.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/admission-service.yaml new file mode 100644 index 00000000..d2abd078 --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/admission-service.yaml @@ -0,0 +1,20 @@ +{{- if .Values.admission.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} + app.kubernetes.io/component: admission +spec: + type: ClusterIP + ports: + - port: 443 + targetPort: 8080 + protocol: TCP + name: https + selector: + {{- include "linstor-scheduler.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: admission +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/certmanager.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/certmanager.yaml new file mode 100644 index 00000000..3942555b --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/certmanager.yaml @@ -0,0 +1,56 @@ +{{- if .Values.admission.enabled }} +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission-selfsigned + namespace: {{ .Release.Namespace }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission-root-ca + namespace: {{ .Release.Namespace }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +spec: + secretName: {{ include "linstor-scheduler.fullname" . }}-admission-root-ca + duration: 43800h # 5 years + commonName: {{ include "linstor-scheduler.fullname" . }}-admission-root-ca + issuerRef: + name: {{ include "linstor-scheduler.fullname" . }}-admission-selfsigned + isCA: true +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission-ca-issuer + namespace: {{ .Release.Namespace }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +spec: + ca: + secretName: {{ include "linstor-scheduler.fullname" . }}-admission-root-ca +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission-cert + namespace: {{ .Release.Namespace }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +spec: + secretName: {{ include "linstor-scheduler.fullname" . }}-admission-tls + duration: 8760h # 1 year + renewBefore: 24h + issuerRef: + name: {{ include "linstor-scheduler.fullname" . }}-admission-ca-issuer + commonName: {{ include "linstor-scheduler.fullname" . }}-admission + dnsNames: + - {{ include "linstor-scheduler.fullname" . }}-admission + - {{ include "linstor-scheduler.fullname" . }}-admission.{{ .Release.Namespace }}.svc +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/config.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/config.yaml new file mode 100644 index 00000000..bff77d0f --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/config.yaml @@ -0,0 +1,46 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "linstor-scheduler.fullname" . }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +data: +{{- if semverCompare ">= 1.22-0" (include "linstor-scheduler.kubeVersion" .) }} + scheduler-config.yaml: |- +{{- if semverCompare ">= 1.25-0" (include "linstor-scheduler.kubeVersion" .) }} + apiVersion: kubescheduler.config.k8s.io/v1 +{{- else if semverCompare ">= 1.23-0" (include "linstor-scheduler.kubeVersion" .) }} + apiVersion: kubescheduler.config.k8s.io/v1beta3 +{{- else }} + apiVersion: kubescheduler.config.k8s.io/v1beta2 +{{- end }} + kind: KubeSchedulerConfiguration + profiles: + - schedulerName: {{ include "linstor-scheduler.fullname" . }} + extenders: + - urlPrefix: http://localhost:8099 + filterVerb: filter + prioritizeVerb: prioritize + weight: 5 + enableHTTPS: false + httpTimeout: 10s + nodeCacheCapable: false +{{- else }} + policy.cfg: |- + { + "kind": "Policy", + "apiVersion": "v1", + "extenders": [ + { + "urlPrefix": "http://localhost:8099", + "apiVersion": "v1beta1", + "filterVerb": "filter", + "prioritizeVerb": "prioritize", + "weight": 5, + "enableHttps": false, + "nodeCacheCapable": false + } + ] + } +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/deployment.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/deployment.yaml new file mode 100644 index 00000000..49898b8d --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/deployment.yaml @@ -0,0 +1,126 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "linstor-scheduler.fullname" . }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "linstor-scheduler.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "linstor-scheduler.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "linstor-scheduler.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: kube-scheduler + image: "{{ .Values.scheduler.image.repository }}:{{ .Values.scheduler.image.tag | default .Capabilities.KubeVersion.Version }}" + securityContext: + {{- toYaml .Values.scheduler.securityContext | nindent 12 }} + command: + - kube-scheduler + {{- if semverCompare ">= 1.22-0" (include "linstor-scheduler.kubeVersion" .) }} + - --config=/etc/kubernetes/scheduler-config.yaml + {{- else }} + - --scheduler-name={{ include "linstor-scheduler.fullname" . }} + - --policy-configmap={{ include "linstor-scheduler.fullname" . }} + - --policy-configmap-namespace=$(NAMESPACE) + {{- end }} + - --leader-elect=true + - --leader-elect-resource-lock=leases + - --leader-elect-resource-name={{ include "linstor-scheduler.fullname" . }} + - --leader-elect-resource-namespace=$(NAMESPACE) + {{- if .Values.scheduler.args }} + {{- toYaml .Values.scheduler.args | nindent 12 }} + {{- end }} + env: + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + imagePullPolicy: {{ .Values.scheduler.image.pullPolicy }} + startupProbe: + httpGet: + path: /healthz + port: 10259 + scheme: HTTPS + livenessProbe: + httpGet: + path: /healthz + port: 10259 + scheme: HTTPS + readinessProbe: + httpGet: + path: /healthz + port: 10259 + scheme: HTTPS + {{- if semverCompare ">= 1.22-0" (include "linstor-scheduler.kubeVersion" .) }} + volumeMounts: + - mountPath: /etc/kubernetes + name: scheduler-config + {{- end }} + resources: + {{- toYaml .Values.scheduler.resources | nindent 12 }} + - name: linstor-scheduler-extender + image: {{ .Values.extender.image.repository }}:{{ .Values.extender.image.tag | default .Chart.AppVersion }} + resources: + {{- toYaml .Values.extender.resources | nindent 12 }} + securityContext: + {{- toYaml .Values.extender.securityContext | nindent 12 }} + imagePullPolicy: {{ .Values.extender.image.pullPolicy }} + args: + - --verbose=true + env: + - name: LS_CONTROLLERS + value: {{ include "linstor-scheduler.linstorEndpoint" . }} + {{- if include "linstor-scheduler.linstorClientSecretName" . }} + - name: LS_USER_CERTIFICATE + valueFrom: + secretKeyRef: + name: {{ include "linstor-scheduler.linstorClientSecretName" . }} + key: tls.crt + - name: LS_USER_KEY + valueFrom: + secretKeyRef: + name: {{ include "linstor-scheduler.linstorClientSecretName" . }} + key: tls.key + - name: LS_ROOT_CA + valueFrom: + secretKeyRef: + name: {{ include "linstor-scheduler.linstorClientSecretName" . }} + key: ca.crt + {{- end }} + {{- if semverCompare ">= 1.22-0" .Capabilities.KubeVersion.Version }} + volumes: + - configMap: + name: {{ include "linstor-scheduler.fullname" . }} + name: scheduler-config + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/hpa.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/hpa.yaml new file mode 100644 index 00000000..d370dc75 --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/hpa.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "linstor-scheduler.fullname" . }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "linstor-scheduler.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/mutatingwebhookconfiguration.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/mutatingwebhookconfiguration.yaml new file mode 100644 index 00000000..fe387dda --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/mutatingwebhookconfiguration.yaml @@ -0,0 +1,32 @@ +{{- if .Values.admission.enabled }} +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission + annotations: + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "linstor-scheduler.fullname" . }}-admission-cert + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +webhooks: + - name: linstor-scheduler-admission.linbit.com + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + failurePolicy: {{ .Values.admission.failurePolicy }} + clientConfig: + service: + name: {{ include "linstor-scheduler.fullname" . }}-admission + namespace: {{ .Release.Namespace }} + path: /mutate + port: 443 + rules: + - operations: ["CREATE"] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + scope: "*" + {{- with .Values.admission.namespaceSelector }} + namespaceSelector: + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/poddisruptionbudget.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/poddisruptionbudget.yaml new file mode 100644 index 00000000..3365f8e6 --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/poddisruptionbudget.yaml @@ -0,0 +1,18 @@ +{{- if .Values.podDisruptionBudget.enabled -}} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "linstor-scheduler.fullname" . }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "linstor-scheduler.selectorLabels" . | nindent 6 }} + {{- if .Values.podDisruptionBudget.minAvailable }} + minAvailable: {{ .Values.podDisruptionBudget.minAvailable }} + {{- end }} + {{- if .Values.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }} + {{- end }} +{{- end -}} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/rbac.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/rbac.yaml new file mode 100644 index 00000000..38bf387b --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/rbac.yaml @@ -0,0 +1,108 @@ +{{- if .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "linstor-scheduler.fullname" . }} + namespace: {{ .Release.Namespace }} +rules: + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - get + - update +{{- if semverCompare "< 1.22-0" (include "linstor-scheduler.kubeVersion" .) }} + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch +{{- end }} +{{- if .Values.admission.enabled }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission +rules: + - apiGroups: [""] + resources: ["pods", "persistentvolumeclaims", "persistentvolumes"] + verbs: ["get"] + - apiGroups: ["storage.k8s.io"] + resources: ["storageclasses"] + verbs: ["get"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "linstor-scheduler.fullname" . }}-admission +subjects: + - kind: ServiceAccount + name: {{ include "linstor-scheduler.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "linstor-scheduler.fullname" . | trunc 57 }}-as-ks +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:kube-scheduler +subjects: + - kind: ServiceAccount + name: {{ include "linstor-scheduler.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "linstor-scheduler.fullname" . | trunc 57 }}-as-vs +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:volume-scheduler +subjects: + - kind: ServiceAccount + name: {{ include "linstor-scheduler.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "linstor-scheduler.fullname" . }} + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "linstor-scheduler.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ include "linstor-scheduler.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "linstor-scheduler.fullname" . | trunc 58 }}-auth + namespace: kube-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: extension-apiserver-authentication-reader +subjects: + - kind: ServiceAccount + name: {{ include "linstor-scheduler.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/serviceaccount.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/serviceaccount.yaml new file mode 100644 index 00000000..2df9a5d5 --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "linstor-scheduler.serviceAccountName" . }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/tests/test-scheduler.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/tests/test-scheduler.yaml new file mode 100644 index 00000000..be95a868 --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/tests/test-scheduler.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "linstor-scheduler.fullname" . | trunc 49 }}-test-schedule" + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + # Smoke test: just test the scheduler without volumes + schedulerName: {{ include "linstor-scheduler.fullname" . }} + containers: + - name: wget + image: busybox + command: [] + restartPolicy: Never diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/values.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/values.yaml new file mode 100644 index 00000000..f0633294 --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/values.yaml @@ -0,0 +1,106 @@ +replicaCount: 1 + +linstor: + endpoint: "" + clientSecret: "" + +scheduler: + args: [] + image: + repository: registry.k8s.io/kube-scheduler + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the kubernetes release + tag: "" + # Overrides which config is written. The default is determined by the current Kubernetes version + compatibleKubernetesRelease: "" + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +extender: + image: + repository: quay.io/piraeusdatastore/linstor-scheduler-extender + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the app version + tag: "" + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + create: true + annotations: {} + name: "" + +rbac: + create: true + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 3 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + + +podDisruptionBudget: + enabled: true + minAvailable: 1 + # maxUnavailable: 1 + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +admission: + enabled: false + replicaCount: 2 + failurePolicy: Ignore + namespaceSelector: {} + # matchExpressions: + # - key: kubernetes.io/metadata.name + # operator: NotIn + # values: + # - kube-system + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 10m + # memory: 64Mi diff --git a/packages/system/linstor-scheduler/values.yaml b/packages/system/linstor-scheduler/values.yaml new file mode 100644 index 00000000..652cb61a --- /dev/null +++ b/packages/system/linstor-scheduler/values.yaml @@ -0,0 +1,7 @@ +linstor-scheduler: + fullnameOverride: linstor-scheduler + linstor: + endpoint: "https://linstor-controller.cozy-linstor.svc:3371" + clientSecret: "linstor-client-tls" + admission: + enabled: true From fe82f663302cc0bd78e81d45d2fe8f7a89d76d3e Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 8 Jan 2026 14:17:27 +0100 Subject: [PATCH 51/78] [linstor] Enable auto-diskful for diskless nodes (#1826) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does Enable DRBD auto-diskful options to automatically convert diskless nodes to diskful when they remain in Primary state for an extended period. ### How it works When LINSTOR is integrated with Kubernetes, the platform may schedule workloads on nodes that don't have local storage replicas. In such cases, DRBD operates in "diskless" mode, accessing data over the network from nodes that have actual disk replicas. The `auto-diskful` feature addresses this by: 1. **Monitoring Primary state duration**: When a diskless node holds a DRBD resource in Primary state (actively using the volume) for more than the configured time (30 minutes), LINSTOR automatically creates a local disk replica on that node. 2. **Automatic cleanup**: With `auto-diskful-allow-cleanup` enabled, when the resource is no longer in Primary state on that node, LINSTOR can automatically remove the disk replica that was created, freeing up storage space. ### Configuration - `DrbdOptions/auto-diskful: 30` — Convert diskless to diskful after 30 minutes in Primary state - `DrbdOptions/auto-diskful-allow-cleanup: true` — Allow automatic removal of auto-created replicas when no longer needed ### Benefits - Improves I/O performance for long-running workloads by creating local replicas - Reduces network traffic for frequently accessed data - Automatic cleanup prevents storage waste from temporary replicas ### Release note ```release-note [linstor] Enable auto-diskful to automatically create local replicas on diskless nodes that hold volumes in Primary state for more than 30 minutes, improving I/O performance for long-running workloads. ``` ## Summary by CodeRabbit * **New Features** * Introduced an "auto diskful" option to automatically manage diskful resources with configurable interval and optional cleanup. * **Chores** * Added default configuration values to enable and time the auto-diskful behavior and to control automatic cleanup. ✏️ Tip: You can customize this high-level summary in your review settings. --- packages/system/linstor/templates/cluster.yaml | 6 ++++++ packages/system/linstor/values.yaml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/packages/system/linstor/templates/cluster.yaml b/packages/system/linstor/templates/cluster.yaml index 584fd850..bde24726 100644 --- a/packages/system/linstor/templates/cluster.yaml +++ b/packages/system/linstor/templates/cluster.yaml @@ -14,6 +14,12 @@ spec: name: linstor-api-ca kind: Issuer properties: + {{- if .Values.linstor.autoDiskful.enabled }} + - name: DrbdOptions/auto-diskful + value: {{ .Values.linstor.autoDiskful.minutes | quote }} + - name: DrbdOptions/auto-diskful-allow-cleanup + value: {{ .Values.linstor.autoDiskful.allowCleanup | quote }} + {{- end }} - name: DrbdOptions/Net/connect-int value: "15" - name: DrbdOptions/Net/ping-int diff --git a/packages/system/linstor/values.yaml b/packages/system/linstor/values.yaml index 23179bce..1a94793b 100644 --- a/packages/system/linstor/values.yaml +++ b/packages/system/linstor/values.yaml @@ -2,3 +2,9 @@ piraeusServer: image: repository: ghcr.io/cozystack/cozystack/piraeus-server tag: latest@sha256:417532baa2801288147cd9ac9ae260751c1a7754f0b829725d09b72a770c111a + +linstor: + autoDiskful: + enabled: true + minutes: 30 + allowCleanup: true From de2bbd35c29cddb7778c1f3907f7c45b9dbbab47 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Thu, 8 Jan 2026 18:05:32 +0400 Subject: [PATCH 52/78] [keycloak] Make kubernetes client public (#1802) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does By its nature, the kubernetes client provisioned in keycloak is public: anyone can read the client secret. Therefore the secret is not necessary and the client should be explicitly provisioned as a public client, not as a confidential client. ### Release note ```release-note [keycloak] Change the kubernetes client to be public, without a client secret. ``` ## Summary by CodeRabbit * **New Features** * Add OIDC enablement flag and optional host derivation from tenant release; allow explicit management kubeconfig endpoint override. * **Refactor** * Convert Keycloak client to public mode and remove reliance on a Kubernetes client secret, simplifying authentication configuration. * Remove secret-based credential plumbing from deployment templates, streamlining kubeconfig generation. ✏️ Tip: You can customize this high-level summary in your review settings. --- packages/extra/info/templates/kubeconfig.yaml | 25 +++++++------ .../dashboard/templates/keycloakclient.yaml | 1 - .../templates/configure-kk.yaml | 37 ++++--------------- 3 files changed, 21 insertions(+), 42 deletions(-) diff --git a/packages/extra/info/templates/kubeconfig.yaml b/packages/extra/info/templates/kubeconfig.yaml index 1557eacd..d2331654 100644 --- a/packages/extra/info/templates/kubeconfig.yaml +++ b/packages/extra/info/templates/kubeconfig.yaml @@ -1,14 +1,18 @@ {{- $host := .Values._namespace.host | default (index .Values._cluster "root-host") }} -{{- $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 }} -{{- $k8sCa := index .Values._cluster "kube-root-ca" }} +{{- $oidcEnabled := index .Values._cluster "oidc-enabled" }} +{{- if $oidcEnabled }} +{{- $apiServerEndpoint := index .Values._cluster "api-server-endpoint" }} +{{- $managementKubeconfigEndpoint := default "" (index .Values._cluster "management-kubeconfig-endpoint") }} +{{- if and $managementKubeconfigEndpoint (ne $managementKubeconfigEndpoint "") }} +{{- $apiServerEndpoint = $managementKubeconfigEndpoint }} +{{- end }} +{{- $k8sCa := index .Values._cluster "kube-root-ca" }} +{{- if .Capabilities.APIVersions.Has "helm.toolkit.fluxcd.io/v2" }} +{{- $tenantRoot := lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" "tenant-root" "tenant-root" }} +{{- if and $tenantRoot $tenantRoot.spec $tenantRoot.spec.values $tenantRoot.spec.values.host }} +{{- $host = $tenantRoot.spec.values.host }} +{{- end }} +{{- end }} --- apiVersion: v1 kind: Secret @@ -39,7 +43,6 @@ stringData: - get-token - --oidc-issuer-url=https://keycloak.{{ $host }}/realms/cozy - --oidc-client-id=kubernetes - - --oidc-client-secret={{ $k8sClient }} - --skip-open-browser command: kubectl {{- end }} diff --git a/packages/system/dashboard/templates/keycloakclient.yaml b/packages/system/dashboard/templates/keycloakclient.yaml index 80f7332e..e1caea71 100644 --- a/packages/system/dashboard/templates/keycloakclient.yaml +++ b/packages/system/dashboard/templates/keycloakclient.yaml @@ -1,7 +1,6 @@ {{- $host := index .Values._cluster "root-host" }} {{- $extraRedirectUris := splitList "," ((index .Values._cluster "extra-keycloak-redirect-uri-for-dashboard") | default "") }} -{{- $existingK8sSecret := lookup "v1" "Secret" .Release.Namespace "k8s-client" }} {{- $existingDashboardSecret := lookup "v1" "Secret" .Release.Namespace "dashboard-client" }} {{ $dashboardClient := "" }} diff --git a/packages/system/keycloak-configure/templates/configure-kk.yaml b/packages/system/keycloak-configure/templates/configure-kk.yaml index e399b374..cc15b161 100644 --- a/packages/system/keycloak-configure/templates/configure-kk.yaml +++ b/packages/system/keycloak-configure/templates/configure-kk.yaml @@ -2,18 +2,10 @@ {{- $extraRedirectUris := splitList "," ((index .Values._cluster "extra-keycloak-redirect-uri-for-dashboard") | default "") }} {{- $k8sCa := index .Values._cluster "kube-root-ca" }} -{{- $existingK8sSecret := lookup "v1" "Secret" .Release.Namespace "k8s-client" }} {{- $existingKubeappsSecret := lookup "v1" "Secret" .Release.Namespace "kubeapps-client" }} {{- $existingAuthConfig := lookup "v1" "Secret" "cozy-dashboard" "kubeapps-auth-config" }} {{- $brandingConfig := .Values._cluster.branding | default dict }} -{{ $k8sClient := "" }} -{{- if $existingK8sSecret }} - {{- $k8sClient = index $existingK8sSecret.data "client-secret-key" | b64dec }} -{{- else }} - {{- $k8sClient = randAlphaNum 32 }} -{{- end }} - {{ $branding := "" }} {{- if $brandingConfig }} {{- $branding = $brandingConfig.branding }} @@ -21,17 +13,6 @@ --- -apiVersion: v1 -kind: Secret -metadata: - name: k8s-client - namespace: {{ .Release.Namespace }} -type: Opaque -data: - client-secret-key: {{ $k8sClient | b64enc }} - ---- - apiVersion: v1.edp.epam.com/v1alpha1 kind: ClusterKeycloak metadata: @@ -90,23 +71,19 @@ kind: KeycloakClient metadata: name: keycloakclient spec: - serviceAccount: - enabled: true + advancedProtocolMappers: true + authorizationServicesEnabled: true + clientId: kubernetes + defaultClientScopes: + - groups + name: kubernetes + public: true realmRef: name: keycloakrealm-cozy kind: ClusterKeycloakRealm - secret: $k8s-client:client-secret-key - advancedProtocolMappers: true - authorizationServicesEnabled: true - name: kubernetes - clientId: kubernetes - directAccess: true - public: false webUrl: https://localhost:8000/oauth2/callback webOrigins: - /* - defaultClientScopes: - - groups redirectUris: - http://localhost:18000 - http://localhost:8000 From 1c42f8bd10cb396389da4c50445dd7791aeacd91 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 8 Jan 2026 21:04:35 +0100 Subject: [PATCH 53/78] [linstor] fix: prevent DRBD device race condition in updateDiscGran (#1829) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem After satellite restart with patched linstor-server, some DRBD resources ended up in **Unknown** state. Investigation revealed a race condition between `drbdadm adjust` completion and `updateDiscGran()` lsblk check: 1. `drbdadm adjust` completes successfully (21:53:49.791) - brings devices up 2. `updateDiscGran()` immediately tries to check discard granularity (21:53:49.799) 3. `/dev/drbd*` device node doesn't exist yet - kernel hasn't created it 4. `lsblk` fails with exit code 32: "not a block device" 5. `StorageException` interrupts DeviceManager cycle (21:53:50.811) 6. DRBD device remains in incomplete state → **Unknown** ### Timeline from logs ``` 21:53:49.791 - [DeviceManager] Resource 'pvc-aafbd92a' [DRBD] adjusted ✓ 21:53:49.799 - [lsblk_parser] ERROR: /dev/drbd1169 not a block device 21:53:49.804-50.807 - [lsblk_parser] 10+ retry errors (every ~100ms) 21:53:50.811 - [DeviceManager] ERROR: Error executing lsblk 21:53:50.878 - [DeviceManager] End cycle 9 (WITH ERROR!) ``` ## Solution Update `skip-adjust-when-device-inaccessible.diff` patch to add physical device path existence check before calling `lsblk`: - Check `Files.exists(devicePath)` in `updateDiscGran()` before lsblk - If device doesn't exist yet → skip check, set `discGran = UNINITIALIZED_SIZE` - Next DeviceManager cycle (few seconds later) → device node available → lsblk succeeds This complements the existing patch which checks **child layer** devices (LUKS/Storage) for deletion scenarios, while this fix addresses the **DRBD device itself** during adjust operations. ## Testing Manual `drbdadm up` on affected devices confirmed they were in down state and brought them back to UpToDate, proving the issue was incomplete device initialization. ## Related - Upstream linstor-server PR: https://github.com/LINBIT/linstor-server/pull/471#issuecomment-3723392917 ## Summary by CodeRabbit * **Bug Fixes** * Enhanced robustness for storage operations by adding device accessibility validation. Operations now gracefully skip when device paths are unavailable or invalid, preventing unnecessary failures and improving system resilience during device access issues. ✏️ Tip: You can customize this high-level summary in your review settings. --- .../skip-adjust-when-device-inaccessible.diff | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/system/linstor/images/piraeus-server/patches/skip-adjust-when-device-inaccessible.diff b/packages/system/linstor/images/piraeus-server/patches/skip-adjust-when-device-inaccessible.diff index 09e7ccf9..18399c41 100644 --- a/packages/system/linstor/images/piraeus-server/patches/skip-adjust-when-device-inaccessible.diff +++ b/packages/system/linstor/images/piraeus-server/patches/skip-adjust-when-device-inaccessible.diff @@ -1,3 +1,28 @@ +diff --git a/satellite/src/main/java/com/linbit/linstor/core/devmgr/DeviceHandlerImpl.java b/satellite/src/main/java/com/linbit/linstor/core/devmgr/DeviceHandlerImpl.java +index abc123def..def456abc 100644 +--- a/satellite/src/main/java/com/linbit/linstor/core/devmgr/DeviceHandlerImpl.java ++++ b/satellite/src/main/java/com/linbit/linstor/core/devmgr/DeviceHandlerImpl.java +@@ -83,6 +83,8 @@ import java.util.TreeMap; + import java.util.TreeSet; + import java.util.concurrent.atomic.AtomicBoolean; + import java.util.function.Function; ++import java.nio.file.Files; ++import java.nio.file.Paths; + + @Singleton + public class DeviceHandlerImpl implements DeviceHandler +@@ -1646,7 +1648,10 @@ public class DeviceHandlerImpl implements DeviceHandler + private void updateDiscGran(VlmProviderObject vlmData) throws DatabaseException, StorageException + { + String devicePath = vlmData.getDevicePath(); +- if (devicePath != null && vlmData.exists()) ++ // Check if device path physically exists before calling lsblk ++ // This is important for DRBD devices which might be temporarily unavailable during adjust ++ // (drbdadm adjust brings devices down/up, and kernel might not have created the device node yet) ++ if (devicePath != null && vlmData.exists() && Files.exists(Paths.get(devicePath))) + { + if (vlmData.getDiscGran() == VlmProviderObject.UNINITIALIZED_SIZE) + { diff --git a/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java b/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java index 01967a3..871d830 100644 --- a/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java From c0b1539d3eff98806f70f2e971d0a4525d81d629 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Thu, 8 Jan 2026 21:04:50 +0100 Subject: [PATCH 54/78] [kube-ovn] Update to v1.14.25 (#1819) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does Update kube-ovn from v1.14.11 to v1.14.25. Changes synced from upstream include: - Updated chart templates - New configuration options in values ### Release note ```release-note [kube-ovn] Update to v1.14.25 ``` ## Summary by CodeRabbit * **New Features** * Added tolerations support for VpcNatGateway resources * Added automatic VLAN subinterface creation capability for provider networks * Enhanced installation documentation with OCI Registry and Talos Linux deployment examples * **Security Improvements** * Applied runtime-default seccomp profiles across deployments * Configured service account token mounting behavior for improved pod security * **Chores** * Updated Kube-OVN to v1.14.25 * Updated Helm chart metadata and dependencies ✏️ Tip: You can customize this high-level summary in your review settings. --- packages/system/kubeovn/Chart.yaml | 2 +- packages/system/kubeovn/Makefile | 2 +- .../system/kubeovn/charts/kube-ovn/Chart.yaml | 4 +- .../system/kubeovn/charts/kube-ovn/README.md | 12 +++++ .../charts/kube-ovn/templates/_helpers.tpl | 5 +- .../kube-ovn/templates/central-deploy.yaml | 4 ++ .../kube-ovn/templates/controller-deploy.yaml | 4 ++ .../templates/ic-controller-deploy.yaml | 4 ++ .../kube-ovn/templates/kube-ovn-crd.yaml | 48 +++++++++++++++++++ .../kube-ovn/templates/monitor-deploy.yaml | 4 ++ .../kube-ovn/templates/ovn-dpdk-ds.yaml | 4 ++ .../charts/kube-ovn/templates/ovn-sa.yaml | 4 ++ .../charts/kube-ovn/templates/ovncni-ds.yaml | 17 +++++-- .../charts/kube-ovn/templates/ovsovn-ds.yaml | 5 ++ .../charts/kube-ovn/templates/pinger-ds.yaml | 6 ++- .../kube-ovn/templates/post-delete-hook.yaml | 6 ++- .../kube-ovn/templates/upgrade-ovs-ovn.yaml | 6 ++- .../kubeovn/charts/kube-ovn/values.yaml | 3 +- packages/system/kubeovn/values.yaml | 2 +- 19 files changed, 129 insertions(+), 13 deletions(-) diff --git a/packages/system/kubeovn/Chart.yaml b/packages/system/kubeovn/Chart.yaml index d1532794..b1a4e05b 100644 --- a/packages/system/kubeovn/Chart.yaml +++ b/packages/system/kubeovn/Chart.yaml @@ -1,3 +1,3 @@ apiVersion: v2 name: cozy-kubeovn -version: 0.39.0 +version: 0.38.0 diff --git a/packages/system/kubeovn/Makefile b/packages/system/kubeovn/Makefile index a4a0d1ed..45c5ab25 100644 --- a/packages/system/kubeovn/Makefile +++ b/packages/system/kubeovn/Makefile @@ -1,4 +1,4 @@ -KUBEOVN_TAG=v0.39.0 +KUBEOVN_TAG=v0.40.0 export NAME=kubeovn export NAMESPACE=cozy-$(NAME) diff --git a/packages/system/kubeovn/charts/kube-ovn/Chart.yaml b/packages/system/kubeovn/charts/kube-ovn/Chart.yaml index f7be2d3b..0621c7c7 100644 --- a/packages/system/kubeovn/charts/kube-ovn/Chart.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/Chart.yaml @@ -15,12 +15,12 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: v1.14.11 +version: v1.14.25 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "1.14.11" +appVersion: "1.14.25" kubeVersion: ">= 1.29.0-0" diff --git a/packages/system/kubeovn/charts/kube-ovn/README.md b/packages/system/kubeovn/charts/kube-ovn/README.md index 3af408e6..74e5c3f1 100644 --- a/packages/system/kubeovn/charts/kube-ovn/README.md +++ b/packages/system/kubeovn/charts/kube-ovn/README.md @@ -2,6 +2,18 @@ Currently supported version: 1.9 +## Installing the Chart + +### From OCI Registry + +The Helm chart is available from GitHub Container Registry: + +```bash +helm install kube-ovn oci://ghcr.io/kubeovn/charts/kube-ovn --version v1.15.0 +``` + +### From Source + Installation : ```bash diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/_helpers.tpl b/packages/system/kubeovn/charts/kube-ovn/templates/_helpers.tpl index e6697c6e..fd6db240 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/_helpers.tpl +++ b/packages/system/kubeovn/charts/kube-ovn/templates/_helpers.tpl @@ -1,8 +1,10 @@ {{/* -Get IP-addresses of master nodes +Get IP-addresses of master nodes. If no nodes are returned, we assume this is +a dry-run/template call and return nothing. */}} {{- define "kubeovn.nodeIPs" -}} {{- $nodes := lookup "v1" "Node" "" "" -}} +{{- if $nodes -}} {{- $ips := list -}} {{- range $node := $nodes.items -}} {{- $label := splitList "=" $.Values.MASTER_NODES_LABEL }} @@ -25,6 +27,7 @@ Get IP-addresses of master nodes {{- end -}} {{ join "," $ips }} {{- end -}} +{{- end -}} {{/* Number of master nodes diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/central-deploy.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/central-deploy.yaml index bbc1e09d..505e0925 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/central-deploy.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/central-deploy.yaml @@ -39,7 +39,11 @@ spec: topologyKey: kubernetes.io/hostname priorityClassName: system-cluster-critical serviceAccountName: ovn-ovs + automountServiceAccountToken: true hostNetwork: true + securityContext: + seccompProfile: + type: RuntimeDefault initContainers: - name: hostpath-init image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/controller-deploy.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/controller-deploy.yaml index 5c4587f9..cd0728b3 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/controller-deploy.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/controller-deploy.yaml @@ -46,7 +46,11 @@ spec: topologyKey: kubernetes.io/hostname priorityClassName: system-cluster-critical serviceAccountName: ovn + automountServiceAccountToken: true hostNetwork: true + securityContext: + seccompProfile: + type: RuntimeDefault initContainers: - name: hostpath-init image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/ic-controller-deploy.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/ic-controller-deploy.yaml index ee3e1461..53ecfa24 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/ic-controller-deploy.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/ic-controller-deploy.yaml @@ -40,7 +40,11 @@ spec: topologyKey: kubernetes.io/hostname priorityClassName: system-cluster-critical serviceAccountName: ovn + automountServiceAccountToken: true hostNetwork: true + securityContext: + seccompProfile: + type: RuntimeDefault initContainers: - name: hostpath-init image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/kube-ovn-crd.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/kube-ovn-crd.yaml index 3bddfbe1..78ac7d38 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/kube-ovn-crd.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/kube-ovn-crd.yaml @@ -1200,6 +1200,52 @@ spec: required: - key - operator + tolerations: + description: optional tolerations applied to the workload pods + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + enum: + - NoSchedule + - PreferNoSchedule + - NoExecute + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists 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 + enum: + - Exists + - Equal + 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 --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -2871,6 +2917,8 @@ spec: type: array items: type: string + autoCreateVlanSubinterfaces: + type: boolean required: - defaultInterface status: diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/monitor-deploy.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/monitor-deploy.yaml index e4c3322c..dc4eac22 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/monitor-deploy.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/monitor-deploy.yaml @@ -37,7 +37,11 @@ spec: topologyKey: kubernetes.io/hostname priorityClassName: system-cluster-critical serviceAccountName: kube-ovn-app + automountServiceAccountToken: true hostNetwork: true + securityContext: + seccompProfile: + type: RuntimeDefault initContainers: - name: hostpath-init image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/ovn-dpdk-ds.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/ovn-dpdk-ds.yaml index 9a1d591f..330c9b6f 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/ovn-dpdk-ds.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/ovn-dpdk-ds.yaml @@ -27,8 +27,12 @@ spec: - operator: Exists priorityClassName: system-node-critical serviceAccountName: ovn-ovs + automountServiceAccountToken: true hostNetwork: true hostPID: true + securityContext: + seccompProfile: + type: RuntimeDefault containers: - name: openvswitch image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.DPDK_IMAGE_TAG }} diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/ovn-sa.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/ovn-sa.yaml index 1e5e9b5c..744b3b90 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/ovn-sa.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/ovn-sa.yaml @@ -3,6 +3,7 @@ kind: ServiceAccount metadata: name: ovn namespace: {{ .Values.namespace }} +automountServiceAccountToken: false {{- if .Values.global.registry.imagePullSecrets }} imagePullSecrets: {{- range $index, $secret := .Values.global.registry.imagePullSecrets }} @@ -18,6 +19,7 @@ kind: ServiceAccount metadata: name: ovn-ovs namespace: {{ .Values.namespace }} +automountServiceAccountToken: false {{- if .Values.global.registry.imagePullSecrets }} imagePullSecrets: {{- range $index, $secret := .Values.global.registry.imagePullSecrets }} @@ -33,6 +35,7 @@ kind: ServiceAccount metadata: name: kube-ovn-cni namespace: {{ .Values.namespace }} +automountServiceAccountToken: false {{- if .Values.global.registry.imagePullSecrets }} imagePullSecrets: {{- range $index, $secret := .Values.global.registry.imagePullSecrets }} @@ -48,6 +51,7 @@ kind: ServiceAccount metadata: name: kube-ovn-app namespace: {{ .Values.namespace }} +automountServiceAccountToken: false {{- if .Values.global.registry.imagePullSecrets }} imagePullSecrets: {{- range $index, $secret := .Values.global.registry.imagePullSecrets }} diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml index 947ec454..c68e041d 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml @@ -26,8 +26,12 @@ spec: operator: Exists priorityClassName: system-node-critical serviceAccountName: kube-ovn-cni + automountServiceAccountToken: true hostNetwork: true hostPID: true + securityContext: + seccompProfile: + type: RuntimeDefault initContainers: - name: hostpath-init image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} @@ -35,7 +39,9 @@ spec: command: - sh - -xec - - iptables -V + - | + chmod +t /usr/local/sbin + iptables -V securityContext: allowPrivilegeEscalation: true capabilities: @@ -60,16 +66,21 @@ spec: imagePullPolicy: {{ .Values.image.pullPolicy }} command: - /kube-ovn/install-cni.sh - - --cni-conf-dir={{ .Values.cni_conf.CNI_CONF_DIR }} + - --cni-conf-dir={{ .Values.cni_conf.MOUNT_CNI_CONF_DIR }} - --cni-conf-file={{ .Values.cni_conf.CNI_CONF_FILE }} - --cni-conf-name={{- .Values.cni_conf.CNI_CONFIG_PRIORITY -}}-kube-ovn.conflist + env: + - name: POD_IPS + valueFrom: + fieldRef: + fieldPath: status.podIPs securityContext: runAsUser: 0 privileged: true volumeMounts: - mountPath: /opt/cni/bin name: cni-bin - - mountPath: /etc/cni/net.d + - mountPath: {{ .Values.cni_conf.MOUNT_CNI_CONF_DIR }} name: cni-conf {{- if .Values.cni_conf.MOUNT_LOCAL_BIN_DIR }} - mountPath: /usr/local/bin diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/ovsovn-ds.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/ovsovn-ds.yaml index 17743d5f..7146ec71 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/ovsovn-ds.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/ovsovn-ds.yaml @@ -34,8 +34,12 @@ spec: operator: Exists priorityClassName: system-node-critical serviceAccountName: ovn-ovs + automountServiceAccountToken: true hostNetwork: true hostPID: true + securityContext: + seccompProfile: + type: RuntimeDefault initContainers: - name: hostpath-init image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} @@ -44,6 +48,7 @@ spec: - sh - -xec - | + chmod +t /usr/local/sbin chown -R nobody: /var/run/ovn /var/log/ovn /etc/openvswitch /var/run/openvswitch /var/log/openvswitch iptables -V {{- if not .Values.DISABLE_MODULES_MANAGEMENT }} diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/pinger-ds.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/pinger-ds.yaml index 66a34853..fbc82171 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/pinger-ds.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/pinger-ds.yaml @@ -28,7 +28,11 @@ spec: - key: CriticalAddonsOnly operator: Exists serviceAccountName: kube-ovn-app - hostPID: true + automountServiceAccountToken: true + hostPID: false + securityContext: + seccompProfile: + type: RuntimeDefault initContainers: - name: hostpath-init image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/post-delete-hook.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/post-delete-hook.yaml index a4c0d618..682b5a96 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/post-delete-hook.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/post-delete-hook.yaml @@ -9,6 +9,7 @@ metadata: "helm.sh/hook": post-delete "helm.sh/hook-weight": "1" "helm.sh/hook-delete-policy": hook-succeeded +automountServiceAccountToken: false --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -102,8 +103,11 @@ spec: hostNetwork: true nodeSelector: kubernetes.io/os: "linux" - serviceAccount: kube-ovn-post-delete-hook serviceAccountName: kube-ovn-post-delete-hook + automountServiceAccountToken: true + securityContext: + seccompProfile: + type: RuntimeDefault containers: - name: remove-subnet-finalizer image: "{{ .Values.global.registry.address}}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }}" diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/upgrade-ovs-ovn.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/upgrade-ovs-ovn.yaml index fc5ac4ba..ab646e03 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/upgrade-ovs-ovn.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/upgrade-ovs-ovn.yaml @@ -11,6 +11,7 @@ metadata: "helm.sh/hook": post-upgrade "helm.sh/hook-weight": "1" "helm.sh/hook-delete-policy": hook-succeeded +automountServiceAccountToken: false --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -133,8 +134,11 @@ spec: hostNetwork: true nodeSelector: kubernetes.io/os: "linux" - serviceAccount: ovs-ovn-upgrade serviceAccountName: ovs-ovn-upgrade + automountServiceAccountToken: true + securityContext: + seccompProfile: + type: RuntimeDefault containers: - name: ovs-ovn-upgrade image: "{{ .Values.global.registry.address}}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }}" diff --git a/packages/system/kubeovn/charts/kube-ovn/values.yaml b/packages/system/kubeovn/charts/kube-ovn/values.yaml index 3652386d..430ea428 100644 --- a/packages/system/kubeovn/charts/kube-ovn/values.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/values.yaml @@ -9,7 +9,7 @@ global: kubeovn: repository: kube-ovn vpcRepository: vpc-nat-gateway - tag: v1.14.11 + tag: v1.14.25 support_arm: true thirdparty: true @@ -111,6 +111,7 @@ debug: cni_conf: CNI_CONFIG_PRIORITY: "01" CNI_CONF_DIR: "/etc/cni/net.d" + MOUNT_CNI_CONF_DIR: "/etc/cni/net.d" CNI_BIN_DIR: "/opt/cni/bin" CNI_CONF_FILE: "/kube-ovn/01-kube-ovn.conflist" LOCAL_BIN_DIR: "/usr/local/bin" diff --git a/packages/system/kubeovn/values.yaml b/packages/system/kubeovn/values.yaml index 89f20e7c..700960ee 100644 --- a/packages/system/kubeovn/values.yaml +++ b/packages/system/kubeovn/values.yaml @@ -65,4 +65,4 @@ global: images: kubeovn: repository: kubeovn - tag: v1.14.11@sha256:0e3e9db960a9600d58c33c0787cabd0e9bf263930fd8c9fe65417e258c383d01 + tag: v1.14.25@sha256:d0b29daaf36e81cac0f9fb15d0ea6b1b49f1abba81a14c73b88a2e60ffcc5978 From 4a83d2c7c8c5e0b07be52cb04b52a69d97d12925 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 9 Jan 2026 15:24:57 +0100 Subject: [PATCH 55/78] [platform] fix migration for removing fluxcd-operator Signed-off-by: Andrei Kvapil --- scripts/migrations/21 | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scripts/migrations/21 b/scripts/migrations/21 index 7a367668..abefdc77 100755 --- a/scripts/migrations/21 +++ b/scripts/migrations/21 @@ -3,7 +3,16 @@ set -euo pipefail +for crd in $(kubectl get crd -o name | grep 'fluxcd.io$'); do + kubectl annotate $crd fluxcd.controlplane.io/prune=disabled +done + kubectl delete hr -n cozy-fluxcd fluxcd --ignore-not-found +kubectl delete hr -n cozy-fluxcd fluxcd-operator --ignore-not-found + +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 800ca3b3d2578e4b8cd5bf00b2c8b3282db05473 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 9 Jan 2026 23:29:10 +0100 Subject: [PATCH 56/78] [main][paas-full] Add multus dependencies similar to other CNIs (#1842) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds multus as a dependency as other CNIs ```release-note Adds multus as a dependency as other CNIs ``` * **Chores** * Updated component initialization ordering to ensure more consistent and reliable platform startup sequencing. * Streamlined dependency requirements for several core system components to improve deployment reliability and reduce startup complexity. ✏️ Tip: You can customize this high-level summary in your review settings. --- packages/core/platform/bundles/paas-full.yaml | 87 ++++++++++--------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/packages/core/platform/bundles/paas-full.yaml b/packages/core/platform/bundles/paas-full.yaml index 40951336..b83dec08 100644 --- a/packages/core/platform/bundles/paas-full.yaml +++ b/packages/core/platform/bundles/paas-full.yaml @@ -69,25 +69,25 @@ releases: releaseName: cozystack chart: cozy-cozy-proxy namespace: cozy-system - dependsOn: [cilium,kubeovn] + dependsOn: [cilium,kubeovn,multus] - name: cert-manager-crds releaseName: cert-manager-crds chart: cozy-cert-manager-crds namespace: cozy-cert-manager - dependsOn: [cilium, kubeovn] + dependsOn: [] - name: cozystack-api releaseName: cozystack-api chart: cozy-cozystack-api namespace: cozy-system - dependsOn: [cilium,kubeovn,cozystack-controller] + dependsOn: [cilium,kubeovn,multus,cozystack-controller] - name: cozystack-controller releaseName: cozystack-controller chart: cozy-cozystack-controller namespace: cozy-system - dependsOn: [cilium,kubeovn] + dependsOn: [cilium,kubeovn,multus] {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} values: cozystackController: @@ -98,13 +98,13 @@ releases: releaseName: lineage-controller-webhook chart: cozy-lineage-controller-webhook namespace: cozy-system - dependsOn: [cozystack-controller,cilium,kubeovn,cert-manager] + dependsOn: [cozystack-controller,cilium,kubeovn,multus,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] + dependsOn: [cilium,kubeovn,multus,cozystack-api,cozystack-controller] - name: bootbox-rd releaseName: bootbox-rd @@ -260,13 +260,13 @@ releases: releaseName: cert-manager chart: cozy-cert-manager namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] + dependsOn: [cilium,kubeovn,multus,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] + dependsOn: [cert-manager] - name: prometheus-operator-crds releaseName: prometheus-operator-crds @@ -278,20 +278,20 @@ releases: releaseName: metrics-server chart: cozy-metrics-server namespace: cozy-monitoring - dependsOn: [cilium,kubeovn,prometheus-operator-crds] + dependsOn: [cilium,kubeovn,multus,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] + dependsOn: [cilium,kubeovn,multus,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] + dependsOn: [victoria-metrics-operator,vertical-pod-autoscaler-crds,metrics-server] values: scrapeRules: etcd: @@ -301,14 +301,14 @@ releases: releaseName: kubevirt-operator chart: cozy-kubevirt-operator namespace: cozy-kubevirt - dependsOn: [cilium,kubeovn,victoria-metrics-operator] + dependsOn: [cilium,kubeovn,multus,victoria-metrics-operator] - name: kubevirt releaseName: kubevirt chart: cozy-kubevirt namespace: cozy-kubevirt privileged: true - dependsOn: [cilium,kubeovn,kubevirt-operator] + dependsOn: [cilium,kubeovn,multus,kubevirt-operator] {{- $cpuAllocationRatio := index $cozyConfig.data "cpu-allocation-ratio" }} {{- if $cpuAllocationRatio }} values: @@ -319,19 +319,19 @@ releases: releaseName: kubevirt-instancetypes chart: cozy-kubevirt-instancetypes namespace: cozy-kubevirt - dependsOn: [cilium,kubeovn,kubevirt-operator,kubevirt] + dependsOn: [cilium,kubeovn,multus,kubevirt-operator,kubevirt] - name: kubevirt-cdi-operator releaseName: kubevirt-cdi-operator chart: cozy-kubevirt-cdi-operator namespace: cozy-kubevirt-cdi - dependsOn: [cilium,kubeovn] + dependsOn: [cilium,kubeovn,multus] - name: kubevirt-cdi releaseName: kubevirt-cdi chart: cozy-kubevirt-cdi namespace: cozy-kubevirt-cdi - dependsOn: [cilium,kubeovn,kubevirt-cdi-operator] + dependsOn: [cilium,kubeovn,multus,kubevirt-cdi-operator] - name: gpu-operator releaseName: gpu-operator @@ -339,7 +339,7 @@ releases: namespace: cozy-gpu-operator privileged: true optional: true - dependsOn: [cilium,kubeovn] + dependsOn: [cilium,kubeovn,multus] valuesFiles: - values.yaml - values-talos.yaml @@ -349,25 +349,25 @@ releases: chart: cozy-metallb namespace: cozy-metallb privileged: true - dependsOn: [cilium,kubeovn] + dependsOn: [cilium,kubeovn,multus] - name: etcd-operator releaseName: etcd-operator chart: cozy-etcd-operator namespace: cozy-etcd-operator - dependsOn: [cilium,kubeovn,cert-manager] + dependsOn: [cilium,kubeovn,multus,cert-manager] - name: grafana-operator releaseName: grafana-operator chart: cozy-grafana-operator namespace: cozy-grafana-operator - dependsOn: [cilium,kubeovn] + dependsOn: [cilium,kubeovn,multus] - name: mariadb-operator releaseName: mariadb-operator chart: cozy-mariadb-operator namespace: cozy-mariadb-operator - dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] + dependsOn: [cilium,kubeovn,multus,cert-manager,victoria-metrics-operator] values: mariadb-operator: clusterName: {{ $clusterDomain }} @@ -376,13 +376,13 @@ releases: releaseName: postgres-operator chart: cozy-postgres-operator namespace: cozy-postgres-operator - dependsOn: [cilium,kubeovn,cert-manager] + dependsOn: [cilium,kubeovn,multus,cert-manager] - name: kafka-operator releaseName: kafka-operator chart: cozy-kafka-operator namespace: cozy-kafka-operator - dependsOn: [cilium,kubeovn,victoria-metrics-operator] + dependsOn: [cilium,kubeovn,multus,victoria-metrics-operator] values: strimzi-kafka-operator: kubernetesServiceDnsDomain: {{ $clusterDomain }} @@ -391,38 +391,38 @@ releases: releaseName: clickhouse-operator chart: cozy-clickhouse-operator namespace: cozy-clickhouse-operator - dependsOn: [cilium,kubeovn,victoria-metrics-operator] + dependsOn: [cilium,kubeovn,multus,victoria-metrics-operator] - name: foundationdb-operator releaseName: foundationdb-operator chart: cozy-foundationdb-operator namespace: cozy-foundationdb-operator - dependsOn: [cilium,kubeovn,cert-manager] + dependsOn: [cilium,kubeovn,multus,cert-manager] - name: rabbitmq-operator releaseName: rabbitmq-operator chart: cozy-rabbitmq-operator namespace: cozy-rabbitmq-operator - dependsOn: [cilium,kubeovn] + dependsOn: [cilium,kubeovn,multus] - name: redis-operator releaseName: redis-operator chart: cozy-redis-operator namespace: cozy-redis-operator - dependsOn: [cilium,kubeovn] + dependsOn: [cilium,kubeovn,multus] - name: piraeus-operator releaseName: piraeus-operator chart: cozy-piraeus-operator namespace: cozy-linstor - dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] + dependsOn: [cilium,kubeovn,multus,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] + dependsOn: [piraeus-operator,cilium,kubeovn,multus,cert-manager,snapshot-controller] - name: linstor-scheduler releaseName: linstor-scheduler @@ -435,27 +435,27 @@ releases: chart: cozy-nfs-driver namespace: cozy-nfs-driver privileged: true - dependsOn: [cilium,kubeovn] + dependsOn: [cilium,kubeovn,multus] optional: true - name: snapshot-controller releaseName: snapshot-controller chart: cozy-snapshot-controller namespace: cozy-snapshot-controller - dependsOn: [cilium,kubeovn,cert-manager-issuers] + dependsOn: [cilium,kubeovn,multus,cert-manager-issuers] - name: objectstorage-controller releaseName: objectstorage-controller chart: cozy-objectstorage-controller namespace: cozy-objectstorage-controller - dependsOn: [cilium,kubeovn] + dependsOn: [cilium,kubeovn,multus] - name: telepresence releaseName: traffic-manager chart: cozy-telepresence namespace: cozy-telepresence optional: true - dependsOn: [cilium,kubeovn] + dependsOn: [cilium,kubeovn,multus] - name: dashboard releaseName: dashboard @@ -468,6 +468,7 @@ releases: dependsOn: - cilium - kubeovn + - multus {{- if eq $oidcEnabled "true" }} - keycloak-configure {{- end }} @@ -476,56 +477,56 @@ releases: releaseName: kamaji chart: cozy-kamaji namespace: cozy-kamaji - dependsOn: [cilium,kubeovn,cert-manager] + dependsOn: [cilium,kubeovn,multus,cert-manager] - name: capi-operator releaseName: capi-operator chart: cozy-capi-operator namespace: cozy-cluster-api privileged: true - dependsOn: [cilium,kubeovn,cert-manager] + dependsOn: [cilium,kubeovn,multus,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] + dependsOn: [cilium,kubeovn,multus,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] + dependsOn: [cilium,kubeovn,multus,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] + dependsOn: [cilium,kubeovn,multus,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] + dependsOn: [cilium,kubeovn,multus,capi-operator] - name: external-dns releaseName: external-dns chart: cozy-external-dns namespace: cozy-external-dns optional: true - dependsOn: [cilium,kubeovn] + dependsOn: [cilium,kubeovn,multus] - name: external-secrets-operator releaseName: external-secrets-operator chart: cozy-external-secrets-operator namespace: cozy-external-secrets-operator optional: true - dependsOn: [cilium,kubeovn] + dependsOn: [cilium,kubeovn,multus] - name: bootbox releaseName: bootbox @@ -533,7 +534,7 @@ releases: namespace: cozy-bootbox privileged: true optional: true - dependsOn: [cilium,kubeovn] + dependsOn: [cilium,kubeovn,multus] {{- if $oidcEnabled }} - name: keycloak @@ -582,7 +583,7 @@ releases: chart: cozy-vertical-pod-autoscaler-crds namespace: cozy-vertical-pod-autoscaler privileged: true - dependsOn: [cilium, kubeovn] + dependsOn: [] - name: reloader releaseName: reloader From 3af7430074cbcad85504a995fbcaad60fc74deac Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Sat, 10 Jan 2026 01:50:53 +0100 Subject: [PATCH 57/78] fix(registry): implement field selector filtering for label-based resources (#1845) ## What this PR does Fixes field selector filtering for registry resources (Applications, TenantModules, TenantSecrets) when using kubectl with field selectors like `--field-selector=metadata.namespace=tenant-kvaps` or `metadata.name=test`. Controller-runtime cache doesn't support field selectors natively, which caused incorrect filtering behavior. This PR implements manual filtering for `metadata.name` and `metadata.namespace` field selectors in List() and Watch() methods. Changes: - Created `pkg/registry/fields` package with `ParseFieldSelector` utility for common field selector parsing - Refactored field selector logic in application, tenantmodule, and tenantsecret registries to use the common implementation - Implemented manual post-processing filtering after label-based queries - Removed `Raw` field usage and field selectors from `client.ListOptions` ### Release note ```release-note [registry] Fix field selector filtering for kubectl queries with metadata.name and metadata.namespace selectors ``` --- pkg/registry/apps/application/rest.go | 132 +++++++++++++------------ pkg/registry/core/tenantmodule/rest.go | 117 +++++++++++----------- pkg/registry/core/tenantsecret/rest.go | 38 ++++--- pkg/registry/fields/filter.go | 70 +++++++++++++ 4 files changed, 227 insertions(+), 130 deletions(-) create mode 100644 pkg/registry/fields/filter.go diff --git a/pkg/registry/apps/application/rest.go b/pkg/registry/apps/application/rest.go index 9e8fb891..4f3204d5 100644 --- a/pkg/registry/apps/application/rest.go +++ b/pkg/registry/apps/application/rest.go @@ -28,7 +28,7 @@ import ( helmv2 "github.com/fluxcd/helm-controller/api/v2" metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - fields "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/fields" labels "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -42,6 +42,7 @@ import ( appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" "github.com/cozystack/cozystack/pkg/config" + fieldfilter "github.com/cozystack/cozystack/pkg/registry/fields" "github.com/cozystack/cozystack/pkg/registry/sorting" internalapiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -257,26 +258,32 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption } // Initialize variables for selector mapping - var helmFieldSelector string - var helmLabelSelector string + var helmLabelSelector labels.Selector - // Process field.selector - if options.FieldSelector != nil { - fs, err := fields.ParseSelector(options.FieldSelector.String()) - if err != nil { - klog.Errorf("Invalid field selector: %v", err) - return nil, fmt.Errorf("invalid field selector: %v", err) - } - // Check if selector is for metadata.name - if name, exists := fs.RequiresExactMatch("metadata.name"); exists { - // Convert Application name to HelmRelease name - mappedName := r.releaseConfig.Prefix + name - // Create new field.selector for HelmRelease - helmFieldSelector = fields.OneTermEqualSelector("metadata.name", mappedName).String() - } else { - // If field.selector contains other fields, map them directly - helmFieldSelector = fs.String() - } + // Parse field selector for manual filtering + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + fieldFilter, err := fieldfilter.ParseFieldSelector(options.FieldSelector) + if err != nil { + klog.Errorf("Error parsing field selector: %v", err) + return nil, err + } + + // If field selector specifies namespace different from context, return empty list + if fieldFilter.Namespace != "" && namespace != "" && namespace != fieldFilter.Namespace { + klog.V(6).Infof("Field selector namespace %s doesn't match context namespace %s, returning empty list", fieldFilter.Namespace, namespace) + return &appsv1alpha1.ApplicationList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: appsv1alpha1.SchemeGroupVersion.String(), + Kind: r.kindName + "List", + }, + }, nil + } + + // Convert Application name to HelmRelease name for manual filtering + var filterByName string + if fieldFilter.Name != "" { + filterByName = r.releaseConfig.Prefix + fieldFilter.Name } // Process label.selector @@ -315,21 +322,16 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption labelRequirements = append(labelRequirements, prefixedReqs...) } } - helmLabelSelector = labels.NewSelector().Add(labelRequirements...).String() + helmLabelSelector = labels.NewSelector().Add(labelRequirements...) klog.V(6).Infof("Using label selector: %s for kind: %s, group: %s", helmLabelSelector, r.kindName, r.gvk.Group) - // Set ListOptions for HelmRelease with selector mapping - metaOptions := metav1.ListOptions{ - FieldSelector: helmFieldSelector, - LabelSelector: helmLabelSelector, - } - - // List HelmReleases with mapped selectors + // List HelmReleases with label selector only + // Field selectors are not supported by controller-runtime cache, so we filter manually below hrList := &helmv2.HelmReleaseList{} err = r.c.List(ctx, hrList, &client.ListOptions{ - Namespace: namespace, - Raw: &metaOptions, + Namespace: namespace, + LabelSelector: helmLabelSelector, }) if err != nil { klog.Errorf("Error listing HelmReleases: %v", err) @@ -346,6 +348,16 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption for i := range hrList.Items { hr := &hrList.Items[i] + // Apply manual field selector filtering (metadata.name and metadata.namespace) + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + if filterByName != "" && hr.Name != filterByName { + continue + } + if !fieldFilter.MatchesNamespace(hr.Namespace) { + continue + } + app, err := r.ConvertHelmReleaseToApplication(hr) if err != nil { klog.Errorf("Error converting HelmRelease %s to Application: %v", hr.GetName(), err) @@ -569,27 +581,21 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio } // Initialize variables for selector mapping - var helmFieldSelector string - var helmLabelSelector string + var helmLabelSelector labels.Selector - // Process field.selector - if options.FieldSelector != nil { - fs, err := fields.ParseSelector(options.FieldSelector.String()) - if err != nil { - klog.Errorf("Invalid field selector: %v", err) - return nil, fmt.Errorf("invalid field selector: %v", err) - } + // Parse field selector for manual filtering + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + fieldFilter, err := fieldfilter.ParseFieldSelector(options.FieldSelector) + if err != nil { + klog.Errorf("Error parsing field selector: %v", err) + return nil, err + } - // Check if selector is for metadata.name - if name, exists := fs.RequiresExactMatch("metadata.name"); exists { - // Convert Application name to HelmRelease name - mappedName := r.releaseConfig.Prefix + name - // Create new field.selector for HelmRelease - helmFieldSelector = fields.OneTermEqualSelector("metadata.name", mappedName).String() - } else { - // If field.selector contains other fields, map them directly - helmFieldSelector = fs.String() - } + // Convert Application name to HelmRelease name for manual filtering + var filterByName string + if fieldFilter.Name != "" { + filterByName = r.releaseConfig.Prefix + fieldFilter.Name } // Process label.selector @@ -628,21 +634,15 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio labelRequirements = append(labelRequirements, prefixedReqs...) } } - helmLabelSelector = labels.NewSelector().Add(labelRequirements...).String() + helmLabelSelector = labels.NewSelector().Add(labelRequirements...) - // Set ListOptions for HelmRelease with selector mapping - metaOptions := metav1.ListOptions{ - Watch: true, - ResourceVersion: options.ResourceVersion, - FieldSelector: helmFieldSelector, - LabelSelector: helmLabelSelector, - } - - // Start watch on HelmRelease with mapped selectors + // Start watch on HelmRelease with label selector only + // Field selectors are not supported by controller-runtime cache + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 hrList := &helmv2.HelmReleaseList{} helmWatcher, err := r.w.Watch(ctx, hrList, &client.ListOptions{ - Namespace: namespace, - Raw: &metaOptions, + Namespace: namespace, + LabelSelector: helmLabelSelector, }) if err != nil { klog.Errorf("Error setting up watch for HelmReleases: %v", err) @@ -682,6 +682,16 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio continue } + // Apply manual field selector filtering (metadata.name and metadata.namespace) + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + if filterByName != "" && hr.Name != filterByName { + continue + } + if !fieldFilter.MatchesNamespace(hr.Namespace) { + continue + } + // Note: All HelmReleases already match the required labels due to server-side label selector filtering // Convert HelmRelease to Application app, err := r.ConvertHelmReleaseToApplication(hr) diff --git a/pkg/registry/core/tenantmodule/rest.go b/pkg/registry/core/tenantmodule/rest.go index 12da0e0d..b2cda2db 100644 --- a/pkg/registry/core/tenantmodule/rest.go +++ b/pkg/registry/core/tenantmodule/rest.go @@ -40,6 +40,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" + fieldfilter "github.com/cozystack/cozystack/pkg/registry/fields" "github.com/cozystack/cozystack/pkg/registry/sorting" apierrors "k8s.io/apimachinery/pkg/api/errors" ) @@ -161,24 +162,26 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption } // Initialize variables for selector mapping - var helmFieldSelector string - var helmLabelSelector string + var helmLabelSelector labels.Selector - // Process field.selector - if options.FieldSelector != nil { - fs, err := fields.ParseSelector(options.FieldSelector.String()) - if err != nil { - klog.Errorf("Invalid field selector: %v", err) - return nil, fmt.Errorf("invalid field selector: %v", err) - } - // Check if selector is for metadata.name - if name, exists := fs.RequiresExactMatch("metadata.name"); exists { - // Create new field.selector for HelmRelease - helmFieldSelector = fields.OneTermEqualSelector("metadata.name", name).String() - } else { - // If field.selector contains other fields, map them directly - helmFieldSelector = fs.String() - } + // Parse field selector for manual filtering + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + fieldFilter, err := fieldfilter.ParseFieldSelector(options.FieldSelector) + if err != nil { + klog.Errorf("Error parsing field selector: %v", err) + return nil, err + } + + // If field selector specifies namespace different from context, return empty list + if fieldFilter.Namespace != "" && namespace != "" && namespace != fieldFilter.Namespace { + klog.V(6).Infof("Field selector namespace %s doesn't match context namespace %s, returning empty list", fieldFilter.Namespace, namespace) + return &corev1alpha1.TenantModuleList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1alpha1.SchemeGroupVersion.String(), + Kind: "TenantModuleList", + }, + }, nil } // Process label.selector - add the tenant module label requirement @@ -202,19 +205,15 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption } } - helmLabelSelector = labels.NewSelector().Add(labelRequirements...).String() + helmLabelSelector = labels.NewSelector().Add(labelRequirements...) - // Set ListOptions for HelmRelease with selector mapping - metaOptions := metav1.ListOptions{ - FieldSelector: helmFieldSelector, - LabelSelector: helmLabelSelector, - } - - // List HelmReleases with mapped selectors + // List HelmReleases with label selector only + // Field selectors are not supported by controller-runtime cache + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 hrList := &helmv2.HelmReleaseList{} err = r.c.List(ctx, hrList, &client.ListOptions{ - Namespace: namespace, - Raw: &metaOptions, + Namespace: namespace, + LabelSelector: helmLabelSelector, }) if err != nil { klog.Errorf("Error listing HelmReleases: %v", err) @@ -226,6 +225,16 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption // Iterate over HelmReleases and convert to TenantModules for i := range hrList.Items { + // Apply manual field selector filtering (metadata.name and metadata.namespace) + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + if !fieldFilter.MatchesName(hrList.Items[i].Name) { + continue + } + if !fieldFilter.MatchesNamespace(hrList.Items[i].Namespace) { + continue + } + // Double-check the label requirement if !r.hasTenantModuleLabel(&hrList.Items[i]) { continue @@ -305,25 +314,15 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio } // Initialize variables for selector mapping - var helmFieldSelector string - var helmLabelSelector string + var helmLabelSelector labels.Selector - // Process field.selector - if options.FieldSelector != nil { - fs, err := fields.ParseSelector(options.FieldSelector.String()) - if err != nil { - klog.Errorf("Invalid field selector: %v", err) - return nil, fmt.Errorf("invalid field selector: %v", err) - } - - // Check if selector is for metadata.name - if name, exists := fs.RequiresExactMatch("metadata.name"); exists { - // Create new field.selector for HelmRelease - helmFieldSelector = fields.OneTermEqualSelector("metadata.name", name).String() - } else { - // If field.selector contains other fields, map them directly - helmFieldSelector = fs.String() - } + // Parse field selector for manual filtering + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + fieldFilter, err := fieldfilter.ParseFieldSelector(options.FieldSelector) + if err != nil { + klog.Errorf("Error parsing field selector: %v", err) + return nil, err } // Process label.selector - add the tenant module label requirement @@ -347,21 +346,15 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio } } - helmLabelSelector = labels.NewSelector().Add(labelRequirements...).String() + helmLabelSelector = labels.NewSelector().Add(labelRequirements...) - // Set ListOptions for HelmRelease with selector mapping - metaOptions := metav1.ListOptions{ - Watch: true, - ResourceVersion: options.ResourceVersion, - FieldSelector: helmFieldSelector, - LabelSelector: helmLabelSelector, - } - - // Start watch on HelmRelease with mapped selectors + // Start watch on HelmRelease with label selector only + // Field selectors are not supported by controller-runtime cache + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 hrList := &helmv2.HelmReleaseList{} helmWatcher, err := r.w.Watch(ctx, hrList, &client.ListOptions{ - Namespace: namespace, - Raw: &metaOptions, + Namespace: namespace, + LabelSelector: helmLabelSelector, }) if err != nil { klog.Errorf("Error setting up watch for HelmReleases: %v", err) @@ -401,6 +394,16 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio continue } + // Apply manual field selector filtering (metadata.name and metadata.namespace) + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + if !fieldFilter.MatchesName(hr.Name) { + continue + } + if !fieldFilter.MatchesNamespace(hr.Namespace) { + continue + } + if !r.hasTenantModuleLabel(hr) { continue } diff --git a/pkg/registry/core/tenantsecret/rest.go b/pkg/registry/core/tenantsecret/rest.go index e5dbf9dd..d069c6ae 100644 --- a/pkg/registry/core/tenantsecret/rest.go +++ b/pkg/registry/core/tenantsecret/rest.go @@ -27,6 +27,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" + fieldfilter "github.com/cozystack/cozystack/pkg/registry/fields" "github.com/cozystack/cozystack/pkg/registry/sorting" ) @@ -248,9 +249,22 @@ func (r *REST) List(ctx context.Context, opts *metainternal.ListOptions) (runtim } } - fieldSel := "" - if opts.FieldSelector != nil { - fieldSel = opts.FieldSelector.String() + // Parse field selector for manual filtering + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + fieldFilter, err := fieldfilter.ParseFieldSelector(opts.FieldSelector) + if err != nil { + return nil, err + } + + // If field selector specifies namespace different from context, return empty list + if fieldFilter.Namespace != "" && ns != "" && ns != fieldFilter.Namespace { + return &corev1alpha1.TenantSecretList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1alpha1.SchemeGroupVersion.String(), + Kind: kindTenantSecretList, + }, + }, nil } list := &corev1.SecretList{} @@ -258,10 +272,6 @@ func (r *REST) List(ctx context.Context, opts *metainternal.ListOptions) (runtim &client.ListOptions{ Namespace: ns, LabelSelector: ls, - Raw: &metav1.ListOptions{ - LabelSelector: ls.String(), - FieldSelector: fieldSel, - }, }) if err != nil { return nil, err @@ -276,6 +286,15 @@ func (r *REST) List(ctx context.Context, opts *metainternal.ListOptions) (runtim } for i := range list.Items { + // Apply manual field selector filtering (metadata.name and metadata.namespace) + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + if !fieldFilter.MatchesName(list.Items[i].Name) { + continue + } + if !fieldFilter.MatchesNamespace(list.Items[i].Namespace) { + continue + } out.Items = append(out.Items, *secretToTenant(&list.Items[i])) } sorting.ByNamespacedName[corev1alpha1.TenantSecret, *corev1alpha1.TenantSecret](out.Items) @@ -413,11 +432,6 @@ func (r *REST) Watch(ctx context.Context, opts *metainternal.ListOptions) (watch base, err := r.w.Watch(ctx, secList, &client.ListOptions{ Namespace: ns, LabelSelector: ls, - Raw: &metav1.ListOptions{ - Watch: true, - LabelSelector: ls.String(), - ResourceVersion: opts.ResourceVersion, - }, }) if err != nil { return nil, err diff --git a/pkg/registry/fields/filter.go b/pkg/registry/fields/filter.go new file mode 100644 index 00000000..9b1fc246 --- /dev/null +++ b/pkg/registry/fields/filter.go @@ -0,0 +1,70 @@ +// Copyright 2024 The Cozystack Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fields + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/fields" +) + +// Filter holds field selector filters extracted from a field selector string. +type Filter struct { + // Name is the value from metadata.name field selector, empty if not specified + Name string + // Namespace is the value from metadata.namespace field selector, empty if not specified + Namespace string +} + +// ParseFieldSelector parses a field selector and extracts metadata.name and metadata.namespace values. +// Other field selectors are silently ignored as controller-runtime cache doesn't support them. +// See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 +func ParseFieldSelector(fieldSelector fields.Selector) (*Filter, error) { + if fieldSelector == nil { + return &Filter{}, nil + } + + fs, err := fields.ParseSelector(fieldSelector.String()) + if err != nil { + return nil, fmt.Errorf("invalid field selector: %v", err) + } + + filter := &Filter{} + + // Check if selector is for metadata.name + if name, exists := fs.RequiresExactMatch("metadata.name"); exists { + filter.Name = name + } + + // Check if selector is for metadata.namespace + if namespace, exists := fs.RequiresExactMatch("metadata.namespace"); exists { + filter.Namespace = namespace + } + + // Note: Other field selectors are silently ignored as controller-runtime cache + // doesn't support them. See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + + return filter, nil +} + +// MatchesName returns true if the filter has no name constraint or if the name matches. +func (f *Filter) MatchesName(name string) bool { + return f.Name == "" || f.Name == name +} + +// MatchesNamespace returns true if the filter has no namespace constraint or if the namespace matches. +func (f *Filter) MatchesNamespace(namespace string) bool { + return f.Namespace == "" || f.Namespace == namespace +} From acc6ed26bb7e4571e50b8d44cb3a9517f0ed6c3b Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Sat, 10 Jan 2026 01:51:15 +0100 Subject: [PATCH 58/78] fix(platform): fix migrations for v0.40 release (#1846) ## What this PR does Fixes migration scripts for v0.40 release to ensure smooth upgrade process. Changes: - **Migration 20**: Replace `helm upgrade --install` with `cozyhr apply` for cozystack-controller and lineage-controller-webhook - **Migration 21**: Improve Flux instance removal process: - Disable reconciliation on FluxInstance before deletion - Delete Flux deployments before HelmReleases - Add `--wait=false` flags to prevent hanging - Fix CRD grep pattern to properly match `fluxcd.io` domains - **Migration 22**: Add new migration tasks: - Migrate Victoria Metrics Operator CRDs to prometheus-operator-crds Helm release - Remove CozyStack Resource Definitions HelmRelease - Add default version v17 to PostgreSQL HelmReleases without explicit version ### Release note ```release-note [platform] Fix migration scripts for v0.40 release: improve Flux removal, add VictoriaMetrics CRD migration, set default PostgreSQL version ``` --- scripts/migrations/20 | 4 ++-- scripts/migrations/21 | 17 ++++++++++++++--- scripts/migrations/22 | 21 +++++++++++++++++++++ 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/scripts/migrations/20 b/scripts/migrations/20 index a27464ac..0c885338 100755 --- a/scripts/migrations/20 +++ b/scripts/migrations/20 @@ -33,11 +33,11 @@ else kubectl rollout status deploy/cozystack-api -n cozy-system --timeout=5m || exit 1 fi -helm upgrade --install -n cozy-system cozystack-controller ./packages/system/cozystack-controller/ --take-ownership +cozyhr -n cozy-system -C ./packages/system/cozystack-controller apply cozystack-controller --take-ownership echo "Waiting for cozystack-controller" kubectl rollout status deploy/cozystack-controller -n cozy-system --timeout=5m || exit 1 -helm upgrade --install -n cozy-system lineage-controller-webhook ./packages/system/lineage-controller-webhook/ --take-ownership +cozyhr -n cozy-system -C ./packages/system/lineage-controller-webhook/ apply lineage-controller-webhook --take-ownership echo "Waiting for lineage-webhook" kubectl rollout status ds/lineage-controller-webhook -n cozy-system --timeout=5m || exit 1 diff --git a/scripts/migrations/21 b/scripts/migrations/21 index abefdc77..bd5fda5f 100755 --- a/scripts/migrations/21 +++ b/scripts/migrations/21 @@ -3,14 +3,25 @@ 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 -kubectl delete hr -n cozy-fluxcd fluxcd --ignore-not-found -kubectl delete hr -n cozy-fluxcd fluxcd-operator --ignore-not-found +# 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 -for crd in $(kubectl get crd -o name | grep 'fluxcd.io$'); do +# 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 diff --git a/scripts/migrations/22 b/scripts/migrations/22 index 192e431c..2dc8f281 100755 --- a/scripts/migrations/22 +++ b/scripts/migrations/22 @@ -3,6 +3,17 @@ set -euo pipefail +# Migrate Victoria Metrics Operator CRDs to prometheus-operator-crds Helm release +for crd in $(kubectl get crd -o name | grep 'coreos\.com$'); do + kubectl annotate $crd meta.helm.sh/release-namespace=cozy-victoria-metrics-operator meta.helm.sh/release-name=prometheus-operator-crds --overwrite + kubectl label $crd app.kubernetes.io/managed-by=Helm helm.toolkit.fluxcd.io/namespace=cozy-victoria-metrics-operator helm.toolkit.fluxcd.io/name=prometheus-operator-crds --overwrite +done +kubectl delete secret -n cozy-victoria-metrics-operator -l name=victoria-metrics-operator,owner=helm --ignore-not-found + +# Remove CozyStack Resource Definitions HR +kubectl delete hr -n cozy-system cozystack-resource-definitions --ignore-not-found --wait=false +kubectl delete cozystackresourcedefinitions.cozystack.io --all --ignore-not-found --wait=false + echo "Migrating HelmReleases: adding application labels for tenant-* namespaces" # Function to determine application type from HelmRelease name @@ -155,6 +166,16 @@ kubectl get helmreleases --all-namespaces -l cozystack.io/ui=true -o json | \ echo "Added application labels to $namespace/$name: $labels" done +echo "Migrating PostgreSQL HelmReleases: adding default version v17" + +# Patch all PostgreSQL HelmReleases to add spec.values.version: v17 +kubectl get helmreleases --all-namespaces -l apps.cozystack.io/application.kind=PostgreSQL -o json | \ + jq -r '.items[] | select(.spec.values.version == null) | "\(.metadata.namespace)|\(.metadata.name)"' | \ + while IFS='|' read -r namespace name; do + echo "Patching PostgreSQL HelmRelease $namespace/$name to add version v17" + kubectl patch helmrelease -n "$namespace" "$name" --type=merge -p '{"spec":{"values":{"version":"v17"}}}' + done + echo "Migration completed" # Stamp version From 2a8317291d2b06dd52ee48b4723ec1834122950a Mon Sep 17 00:00:00 2001 From: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> Date: Sat, 10 Jan 2026 00:57:35 +0000 Subject: [PATCH 59/78] Prepare release v0.40.0 Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> --- packages/apps/http-cache/images/nginx-cache.tag | 2 +- packages/apps/kubernetes/images/cluster-autoscaler.tag | 2 +- packages/apps/kubernetes/images/kubevirt-cloud-provider.tag | 2 +- packages/apps/kubernetes/images/kubevirt-csi-driver.tag | 2 +- packages/apps/kubernetes/images/ubuntu-container-disk.tag | 2 +- packages/apps/mysql/images/mariadb-backup.tag | 2 +- packages/core/installer/values.yaml | 2 +- packages/core/platform/values.yaml | 2 +- packages/core/testing/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- packages/extra/monitoring/images/grafana.tag | 2 +- packages/extra/seaweedfs/images/objectstorage-sidecar.tag | 2 +- packages/system/bucket/images/s3manager.tag | 2 +- packages/system/cilium/values.yaml | 4 ++-- packages/system/cozystack-api/values.yaml | 2 +- packages/system/cozystack-controller/values.yaml | 4 ++-- packages/system/dashboard/templates/configmap.yaml | 2 +- packages/system/dashboard/values.yaml | 6 +++--- packages/system/kamaji/values.yaml | 4 ++-- packages/system/kubeovn-plunger/values.yaml | 2 +- packages/system/kubeovn-webhook/values.yaml | 2 +- packages/system/kubevirt-csi-node/values.yaml | 2 +- packages/system/lineage-controller-webhook/values.yaml | 2 +- packages/system/linstor/values.yaml | 3 +-- packages/system/metallb/values.yaml | 4 ++-- packages/system/objectstorage-controller/values.yaml | 2 +- packages/system/seaweedfs/values.yaml | 2 +- 27 files changed, 33 insertions(+), 34 deletions(-) diff --git a/packages/apps/http-cache/images/nginx-cache.tag b/packages/apps/http-cache/images/nginx-cache.tag index 185dcc66..3f0bbd33 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:e0a07082bb6fc6aeaae2315f335386f1705a646c72f9e0af512aebbca5cb2b15 +ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:31ebc09cfa11d8b438d2bbb32fa61b133aaf4b48b1a1282c9e59b5c127af61c1 diff --git a/packages/apps/kubernetes/images/cluster-autoscaler.tag b/packages/apps/kubernetes/images/cluster-autoscaler.tag index d5ab33d1..b1c2fe04 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:2d39989846c3579dd020b9f6c77e6e314cc81aa344eaac0f6d633e723c17196d +ghcr.io/cozystack/cozystack/cluster-autoscaler:0.0.0@sha256:372ad087ae96bd0cd642e2b0855ec7ffb1369d6cf4f0b92204725557c11bc0ff diff --git a/packages/apps/kubernetes/images/kubevirt-cloud-provider.tag b/packages/apps/kubernetes/images/kubevirt-cloud-provider.tag index 8120dd48..ca661f3a 100644 --- a/packages/apps/kubernetes/images/kubevirt-cloud-provider.tag +++ b/packages/apps/kubernetes/images/kubevirt-cloud-provider.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/kubevirt-cloud-provider:0.0.0@sha256:5335c044313b69ee13b30ca4941687e509005e55f4ae25723861edbf2fbd6dd2 +ghcr.io/cozystack/cozystack/kubevirt-cloud-provider:0.0.0@sha256:dee69d15fa8616aa6a1e5a67fc76370e7698a7f58b25e30650eb39c9fb826de8 diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag index 80d3d2e6..ccb369a3 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:d5c836ba33cf5dbed7e6f866784f668f80ffe69179e7c75847b680111984eefb +ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:b42c6af641ee0eadb7e0a42e368021b4759f443cb7b71b7e745a64f0fc8b752e diff --git a/packages/apps/kubernetes/images/ubuntu-container-disk.tag b/packages/apps/kubernetes/images/ubuntu-container-disk.tag index a35d1278..06de29fa 100644 --- a/packages/apps/kubernetes/images/ubuntu-container-disk.tag +++ b/packages/apps/kubernetes/images/ubuntu-container-disk.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.33@sha256:a09724a7f95283f9130b3da2a89d81c4c6051c6edf0392a81b6fc90f404b76b6 +ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.33@sha256:d25e567bc8b17b596e050f5ff410e36112c7966e33f4b372c752e7350bacc894 diff --git a/packages/apps/mysql/images/mariadb-backup.tag b/packages/apps/mysql/images/mariadb-backup.tag index af6247da..792c010b 100644 --- a/packages/apps/mysql/images/mariadb-backup.tag +++ b/packages/apps/mysql/images/mariadb-backup.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/mariadb-backup:0.0.0@sha256:1c0beb1b23a109b0e13727b4c73d2c74830e11cede92858ab20101b66f45a858 +ghcr.io/cozystack/cozystack/mariadb-backup:0.0.0@sha256:aca403030ff5d831415d72367866fdf291fab73ee2cfddbe4c93c2915a316ab1 diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index dbb7b846..5a90dfed 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.38.2@sha256:9ff92b655de6f9bea3cba4cd42dcffabd9aace6966dcfb1cc02dda2420ea4a15 + image: ghcr.io/cozystack/cozystack/installer:v0.40.0@sha256:0f62cc82d7d5782485ea8345dfba5db7de55e2b1a38095d0ab5a334af7755ea9 diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index 363d1921..2efff01d 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -1,2 +1,2 @@ assets: - image: ghcr.io/cozystack/cozystack/cozystack-assets:latest@sha256:19b166819d0205293c85d8351a3e038dc4c146b876a8e2ae21dce1d54f0b9e33 + image: ghcr.io/cozystack/cozystack/cozystack-assets:v0.40.0@sha256:b643f04707bcea32a152b2df3270907ac743d168e586630cd70f90020f0b0a12 diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index de6bb330..2b8ee06f 100644 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.38.2@sha256:84be9e42bc2c04b0765c8b89e0a9728c49ebf4676a92522b007af96ae9aec68d + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.40.0@sha256:78a556a059411cac89249c2e22596223128a1c74fbfcac4787fd74e4a66f66a6 diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index 2e63d30b..73d5d060 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.38.2@sha256:9cd7f46fcae119a3f8e35b428b018d0cb6da7b0cdd2ce764cc9fbf6dcd903f27 +ghcr.io/cozystack/cozystack/matchbox:v0.40.0@sha256:653cec80b50dd9e6d7110cd20efbdeaac324ba2c638f14e122abf8e6bd436d83 diff --git a/packages/extra/monitoring/images/grafana.tag b/packages/extra/monitoring/images/grafana.tag index 9d53b4f1..06fa403d 100644 --- a/packages/extra/monitoring/images/grafana.tag +++ b/packages/extra/monitoring/images/grafana.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/grafana:0.0.0@sha256:c63978e1ed0304e8518b31ddee56c4e8115541b997d8efbe1c0a74da57140399 +ghcr.io/cozystack/cozystack/grafana:0.0.0@sha256:8ce0cd90c8f614cdabf5a41f8aa50b7dfbd02b31b9a0bd7897927e7f89968e07 diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag index ec59113f..1919ce58 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:v0.38.2@sha256:ff3281fe53a97d2cd5cd94bd4c4d8ff08189508729869bb39b3f60c80da5f919 +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.40.0@sha256:2d1833c78c35b697a3634d4b3be9a3218edae95a77583e9e121c10a92e7433ec diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index 1e12e68b..3574feff 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:3825c9b4b6238f88f1b0de73bd18866a7e5f83f178d28fe2830f3bf24efb187d +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:ecb140d026ed72660306953a7eec140d7ac81e79544d5bbf1aba5f62aa5f8b69 diff --git a/packages/system/cilium/values.yaml b/packages/system/cilium/values.yaml index 95159b1f..1c759ac6 100644 --- a/packages/system/cilium/values.yaml +++ b/packages/system/cilium/values.yaml @@ -15,8 +15,8 @@ cilium: mode: "kubernetes" image: repository: ghcr.io/cozystack/cozystack/cilium - tag: 1.17.8 - digest: "sha256:81262986a41487bfa3d0465091d3a386def5bd1ab476350bd4af2fdee5846fe6" + tag: 1.18.5 + digest: "sha256:c14a0bcb1a1531c72725b3a4c40aefa2bcd5c129810bf58ea8e37d3fcff2a326" envoy: enabled: false rollOutCiliumPods: true diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 8bf0a803..0eff5030 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,5 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.38.2@sha256:d17f1c59658731e5a2063c3db348adbc03b5cd31720052016b68449164cf2f14 + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.40.0@sha256:408885b509d80ca30a85416f87d07112bc7f070374e71e80b64818fbb24ad1ee localK8sAPIEndpoint: enabled: true replicas: 2 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index 1b365a43..b9da9426 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,6 +1,6 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.38.2@sha256:468b2eccbc0aa00bd3d72d56624a46e6ba178fa279cdd19248af74d32ea7d319 + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.40.0@sha256:90cbb2f3fa2d30f9b9c9f623463ef11203a2b8d2105a52166aac566d2b984e59 debug: false disableTelemetry: false - cozystackVersion: "v0.38.2" + cozystackVersion: "v0.40.0" cozystackAPIKind: "DaemonSet" diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index f148109f..abc9f42d 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,6 +1,6 @@ {{- $brandingConfig := .Values._cluster.branding | default dict }} -{{- $tenantText := "v0.38.2" }} +{{- $tenantText := "v0.40.0" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} {{- $logoText := "" }} diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index fed8149b..771ef3dc 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v0.38.2@sha256:5aafb6c864c5523418d021a9fe5b514990d36972b6f1de9c34a1cd41f9d8bf7e + image: ghcr.io/cozystack/cozystack/openapi-ui:v0.40.0@sha256:665d5553d445c71d6007f440841943167a33e403cdca447b510b6f919e16a657 openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.38.2@sha256:7ffd8ae7b9da73fec7ae61a71c9c821a718d89a1b1df0197e09fda57678e1220 + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.40.0@sha256:fda379dce49c2cd8cb8d7d2a1d8ec6f7bedb3419c058c4355ecdece1c1e937f4 tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:v0.38.2@sha256:fad27112617bb17816702571e1f39d0ac3fe5283468d25eb12f79906cdab566b + image: ghcr.io/cozystack/cozystack/token-proxy:v0.40.0@sha256:4fc8a11f8a1a81aa0774ae2b1ed2e05d36d0b3ef1e37979cc4994e65114d93ae diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index b5b77213..d8b15b80 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.38.2@sha256:13741b8f6dfede3ea0fd16d8bbebae810bc19254a81d7e5a139535efa17eabff + tag: v0.40.0@sha256:4588de4380fb70c29c4a762fb19a9bbe210e68bc5ff67035c752c44daf319bfc repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: @@ -13,4 +13,4 @@ kamaji: cpu: 100m memory: 100Mi extraArgs: - - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.38.2@sha256:13741b8f6dfede3ea0fd16d8bbebae810bc19254a81d7e5a139535efa17eabff + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.40.0@sha256:4588de4380fb70c29c4a762fb19a9bbe210e68bc5ff67035c752c44daf319bfc diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml index 2e6fc195..9b12e46d 100644 --- a/packages/system/kubeovn-plunger/values.yaml +++ b/packages/system/kubeovn-plunger/values.yaml @@ -1,4 +1,4 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.38.2@sha256:76c8af24cbec0261718c13c0150aa81c238a956626d4fd7baa8970b47fb3a6f0 +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.40.0@sha256:e1e47c30b2eef93497163e15d94fbddca40e416769705557881d23dd537c5591 ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index 9304c59d..b69f4db2 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.38.2@sha256:8e67b2971f8c079a8b0636be1d091a9545d6cb653d745ff222a5966f56f903bd +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.40.0@sha256:e18f9fd679e38f65362a8d0042f25468272f6d081136ad47027168d8e7e07a4a diff --git a/packages/system/kubevirt-csi-node/values.yaml b/packages/system/kubevirt-csi-node/values.yaml index 8d2a7d45..4111f825 100644 --- a/packages/system/kubevirt-csi-node/values.yaml +++ b/packages/system/kubevirt-csi-node/values.yaml @@ -1,3 +1,3 @@ storageClass: replicated csiDriver: - image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:d5c836ba33cf5dbed7e6f866784f668f80ffe69179e7c75847b680111984eefb + image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:b42c6af641ee0eadb7e0a42e368021b4759f443cb7b71b7e745a64f0fc8b752e diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index ab5ccbbf..b0c47220 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,5 +1,5 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.38.2@sha256:a5c750a0f46e8e25329b3ee2110d5dfb077c73e473195f1ed768d28d6f43902c + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.40.0@sha256:792ca90d9e8d2d03cb10587d5a3570dad6c199e5ad0734d334869b9d595e748f debug: false localK8sAPIEndpoint: enabled: true diff --git a/packages/system/linstor/values.yaml b/packages/system/linstor/values.yaml index 1a94793b..ac9c4fe7 100644 --- a/packages/system/linstor/values.yaml +++ b/packages/system/linstor/values.yaml @@ -1,8 +1,7 @@ piraeusServer: image: repository: ghcr.io/cozystack/cozystack/piraeus-server - tag: latest@sha256:417532baa2801288147cd9ac9ae260751c1a7754f0b829725d09b72a770c111a - + tag: 1.32.3@sha256:c6fbe1825514a3059088175968a651d7e10f477590023a33f1a9e6584fd98e04 linstor: autoDiskful: enabled: true diff --git a/packages/system/metallb/values.yaml b/packages/system/metallb/values.yaml index d392f4c4..dd5f76e6 100644 --- a/packages/system/metallb/values.yaml +++ b/packages/system/metallb/values.yaml @@ -4,8 +4,8 @@ metallb: controller: image: repository: ghcr.io/cozystack/cozystack/metallb-controller - tag: v0.15.2@sha256:0e9080234fc8eedab78ad2831fb38df375c383e901a752d72b353c8d13b9605f + tag: v0.15.2@sha256:623ce74b5802bff6e29f29478ccab29ce4162a64148be006c69e16cc3207e289 speaker: image: repository: ghcr.io/cozystack/cozystack/metallb-speaker - tag: v0.15.2@sha256:e14d4c328c3ab91a6eadfeea90da96388503492d165e7e8582f291b1872e53b2 + tag: v0.15.2@sha256:f264058afd9228452a260ab9c9dd1859404745627a2a38c2ba4671e27f3b3bb2 diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml index 7a5b5c22..e9d9fd81 100644 --- a/packages/system/objectstorage-controller/values.yaml +++ b/packages/system/objectstorage-controller/values.yaml @@ -1,3 +1,3 @@ objectstorage: controller: - image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.38.2@sha256:7d37495cce46d30d4613ecfacaa7b7f140e7ea8f3dbcc3e8c976e271de6cc71b" + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.40.0@sha256:cbf22bcbeed7049340aa41f41cc130596bdb962873116e0c4eb5bab123ae13b0" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index 830c4faa..89474c55 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -177,7 +177,7 @@ seaweedfs: bucketClassName: "seaweedfs" region: "" sidecar: - image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.38.2@sha256:ff3281fe53a97d2cd5cd94bd4c4d8ff08189508729869bb39b3f60c80da5f919" + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.40.0@sha256:2d1833c78c35b697a3634d4b3be9a3218edae95a77583e9e121c10a92e7433ec" certificates: commonName: "SeaweedFS CA" ipAddresses: [] From f900db633869f74f6e67e54e393d6f7e095868f7 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 12 Jan 2026 15:31:46 +0100 Subject: [PATCH 60/78] [linstor] Update piraeus-server patches with critical fixes Update piraeus-server patches to address critical production issues: - Add fix-duplicate-tcp-ports.diff to prevent duplicate TCP ports after toggle-disk operations (upstream PR #476) - Update skip-adjust-when-device-inaccessible.diff with comprehensive fixes for resources stuck in StandAlone after reboot, Unknown state race condition, and encrypted LUKS resource deletion (upstream PR #477) ```release-note [linstor] Fix DRBD resources stuck in StandAlone state after reboot and encrypted resource deletion issues ``` Co-Authored-By: Claude Signed-off-by: Andrei Kvapil (cherry picked from commit dc2773ba267ee82ec5128f3c49d57912483ae0d0) --- .../images/piraeus-server/patches/README.md | 6 +- .../patches/fix-duplicate-tcp-ports.diff | 87 ++++++++ .../skip-adjust-when-device-inaccessible.diff | 192 +++++++++++++++--- 3 files changed, 258 insertions(+), 27 deletions(-) create mode 100644 packages/system/linstor/images/piraeus-server/patches/fix-duplicate-tcp-ports.diff diff --git a/packages/system/linstor/images/piraeus-server/patches/README.md b/packages/system/linstor/images/piraeus-server/patches/README.md index c219eaf3..5ee29318 100644 --- a/packages/system/linstor/images/piraeus-server/patches/README.md +++ b/packages/system/linstor/images/piraeus-server/patches/README.md @@ -8,5 +8,7 @@ Custom patches for piraeus-server (linstor-server) v1.32.3. - Upstream: [#475](https://github.com/LINBIT/linstor-server/pull/475) - **force-metadata-check-on-disk-add.diff** — Create metadata during toggle-disk from diskless to diskful - Upstream: [#474](https://github.com/LINBIT/linstor-server/pull/474) -- **skip-adjust-when-device-inaccessible.diff** — Skip DRBD adjust/res file regeneration when child layer device is inaccessible - - Upstream: [#471](https://github.com/LINBIT/linstor-server/pull/471) +- **fix-duplicate-tcp-ports.diff** — Prevent duplicate TCP ports after toggle-disk operations + - Upstream: [#476](https://github.com/LINBIT/linstor-server/pull/476) +- **skip-adjust-when-device-inaccessible.diff** — Fix resources stuck in StandAlone after reboot, Unknown state race condition, and encrypted resource deletion + - Upstream: [#477](https://github.com/LINBIT/linstor-server/pull/477) diff --git a/packages/system/linstor/images/piraeus-server/patches/fix-duplicate-tcp-ports.diff b/packages/system/linstor/images/piraeus-server/patches/fix-duplicate-tcp-ports.diff new file mode 100644 index 00000000..07cd9eac --- /dev/null +++ b/packages/system/linstor/images/piraeus-server/patches/fix-duplicate-tcp-ports.diff @@ -0,0 +1,87 @@ +From 1250abe99d64a0501795e37d3b6af62410002239 Mon Sep 17 00:00:00 2001 +From: Andrei Kvapil +Date: Mon, 12 Jan 2026 13:44:46 +0100 +Subject: [PATCH] fix(drbd): prevent duplicate TCP ports after toggle-disk + operations + +Remove redundant ensureStackDataExists() call with empty payload from +resetStoragePools() method that was causing TCP port conflicts after +toggle-disk operations. + +Root Cause: +----------- +The resetStoragePools() method, introduced in 2019 (commit 95cc17d0b8), +calls ensureStackDataExists() with an empty LayerPayload. This worked +correctly when TCP ports were stored at RscDfn level. + +After the TCP port migration to per-node level (commit f754943463, May +2025), this empty payload results in DrbdRscData being created without +TCP ports assigned. The controller then sends a Pojo with an empty port +Set to satellites. + +On satellites, when DrbdRscData is initialized with an empty port list, +initPorts() uses preferredNewPortsRef from peer resources. Since +SatelliteDynamicNumberPool.tryAllocate() always returns true (no-op), +any port from preferredNewPortsRef is accepted without conflict checking, +leading to duplicate TCP port assignments. + +Impact: +------- +This regression affects toggle-disk operations, particularly: +- Snapshot creation/restore operations +- Manual toggle-disk operations +- Any operation calling resetStoragePools() + +Symptoms include: +- DRBD resources failing to adjust with "port is also used" errors +- Resources stuck in StandAlone or Connecting states +- Multiple resources on the same node using identical TCP ports + +Solution: +--------- +Remove the ensureStackDataExists() call from resetStoragePools() as it +is redundant. The calling code (e.g., CtrlRscToggleDiskApiCallHandler +line 1071) already invokes ensureStackDataExists() with the correct +payload immediately after resetStoragePools(). + +This fix ensures: +1. resetStoragePools() only resets storage pool assignments +2. Layer data creation with proper TCP ports happens via the caller's + ensureStackDataExists() with correct payload +3. No DrbdRscData objects are created without TCP port assignments + +Related Issues: +--------------- +Fixes #454 - Duplicate TCP ports after backup/restore operations +Related to user reports of resources stuck in StandAlone after node +reboots when toggle-disk or backup operations were in progress. + +Testing: +-------- +Verified that: +- Toggle-disk operations no longer create resources without TCP ports +- Backup/restore operations complete without TCP port conflicts +- Resources maintain unique TCP ports across toggle-disk cycles + +Co-Authored-By: Claude +Signed-off-by: Andrei Kvapil +--- + .../linbit/linstor/layer/resource/CtrlRscLayerDataFactory.java | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/controller/src/main/java/com/linbit/linstor/layer/resource/CtrlRscLayerDataFactory.java b/controller/src/main/java/com/linbit/linstor/layer/resource/CtrlRscLayerDataFactory.java +index 3538b380c..4f589145e 100644 +--- a/controller/src/main/java/com/linbit/linstor/layer/resource/CtrlRscLayerDataFactory.java ++++ b/controller/src/main/java/com/linbit/linstor/layer/resource/CtrlRscLayerDataFactory.java +@@ -276,8 +276,6 @@ public class CtrlRscLayerDataFactory + + rscDataToProcess.addAll(rscData.getChildren()); + } +- +- ensureStackDataExists(rscRef, null, new LayerPayload()); + } + catch (AccessDeniedException exc) + { +-- +2.39.5 (Apple Git-154) + diff --git a/packages/system/linstor/images/piraeus-server/patches/skip-adjust-when-device-inaccessible.diff b/packages/system/linstor/images/piraeus-server/patches/skip-adjust-when-device-inaccessible.diff index 18399c41..65c8be7c 100644 --- a/packages/system/linstor/images/piraeus-server/patches/skip-adjust-when-device-inaccessible.diff +++ b/packages/system/linstor/images/piraeus-server/patches/skip-adjust-when-device-inaccessible.diff @@ -1,30 +1,27 @@ -diff --git a/satellite/src/main/java/com/linbit/linstor/core/devmgr/DeviceHandlerImpl.java b/satellite/src/main/java/com/linbit/linstor/core/devmgr/DeviceHandlerImpl.java -index abc123def..def456abc 100644 ---- a/satellite/src/main/java/com/linbit/linstor/core/devmgr/DeviceHandlerImpl.java -+++ b/satellite/src/main/java/com/linbit/linstor/core/devmgr/DeviceHandlerImpl.java -@@ -83,6 +83,8 @@ import java.util.TreeMap; - import java.util.TreeSet; - import java.util.concurrent.atomic.AtomicBoolean; - import java.util.function.Function; -+import java.nio.file.Files; -+import java.nio.file.Paths; +From 6a556821b9a0996d34389a27b941694ce810a44c Mon Sep 17 00:00:00 2001 +From: Andrei Kvapil +Date: Mon, 12 Jan 2026 14:26:57 +0100 +Subject: [PATCH 1/3] Fix: Skip DRBD adjust/res file regeneration when child + layer device is inaccessible + +When deleting encrypted (LUKS) resources, the LUKS layer may close its device +before the DRBD layer attempts to adjust the resource or regenerate the res +file. This causes 'Failed to adjust DRBD resource' errors. + +This fix adds checks before regenerateResFile() and drbdUtils.adjust() +to verify that child layer devices are accessible. If a child device doesn't +exist or is not accessible (e.g., LUKS device is closed during resource +deletion), these operations are skipped and the adjustRequired flag is cleared, +allowing resource deletion to proceed successfully. + +Co-Authored-By: Claude +Signed-off-by: Andrei Kvapil +--- + .../linbit/linstor/layer/drbd/DrbdLayer.java | 72 ++++++++++++++++--- + 1 file changed, 61 insertions(+), 11 deletions(-) - @Singleton - public class DeviceHandlerImpl implements DeviceHandler -@@ -1646,7 +1648,10 @@ public class DeviceHandlerImpl implements DeviceHandler - private void updateDiscGran(VlmProviderObject vlmData) throws DatabaseException, StorageException - { - String devicePath = vlmData.getDevicePath(); -- if (devicePath != null && vlmData.exists()) -+ // Check if device path physically exists before calling lsblk -+ // This is important for DRBD devices which might be temporarily unavailable during adjust -+ // (drbdadm adjust brings devices down/up, and kernel might not have created the device node yet) -+ if (devicePath != null && vlmData.exists() && Files.exists(Paths.get(devicePath))) - { - if (vlmData.getDiscGran() == VlmProviderObject.UNINITIALIZED_SIZE) - { diff --git a/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java b/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java -index 01967a3..871d830 100644 +index 01967a31f..871d830d1 100644 --- a/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java +++ b/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java @@ -592,7 +592,29 @@ public class DrbdLayer implements DeviceLayer @@ -116,3 +113,148 @@ index 01967a3..871d830 100644 } } +-- +2.39.5 (Apple Git-154) + + +From afe51ea674c4a350c27d1f2cacfecf6fe42b8a7a Mon Sep 17 00:00:00 2001 +From: Andrei Kvapil +Date: Mon, 12 Jan 2026 14:27:52 +0100 +Subject: [PATCH 2/3] fix(satellite): skip lsblk when device path doesn't + physically exist + +Add physical device path existence check before calling lsblk in updateDiscGran(). +This prevents race condition when drbdadm adjust temporarily brings devices down/up +and the kernel hasn't created the device node yet. + +Issue: After satellite restart with patched code, some DRBD resources ended up in +Unknown state because: +1. drbdadm adjust successfully completes (brings devices up) +2. updateDiscGran() immediately tries to check discard granularity +3. /dev/drbd* device node doesn't exist yet (kernel hasn't created it) +4. lsblk fails with exit code 32 "not a block device" +5. StorageException interrupts DeviceManager cycle +6. DRBD device remains in incomplete state + +Solution: Check Files.exists(devicePath) before calling lsblk. If device doesn't +exist yet, skip the check - it will be retried in the next DeviceManager cycle +when the device node is available. + +Co-Authored-By: Claude +Signed-off-by: Andrei Kvapil +--- + .../linbit/linstor/core/devmgr/DeviceHandlerImpl.java | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/satellite/src/main/java/com/linbit/linstor/core/devmgr/DeviceHandlerImpl.java b/satellite/src/main/java/com/linbit/linstor/core/devmgr/DeviceHandlerImpl.java +index 49138a8fd..1c13cfc9d 100644 +--- a/satellite/src/main/java/com/linbit/linstor/core/devmgr/DeviceHandlerImpl.java ++++ b/satellite/src/main/java/com/linbit/linstor/core/devmgr/DeviceHandlerImpl.java +@@ -68,6 +68,8 @@ import javax.inject.Inject; + import javax.inject.Provider; + import javax.inject.Singleton; + ++import java.nio.file.Files; ++import java.nio.file.Paths; + import java.util.ArrayList; + import java.util.Collection; + import java.util.Collections; +@@ -1645,8 +1647,11 @@ public class DeviceHandlerImpl implements DeviceHandler + + private void updateDiscGran(VlmProviderObject vlmData) throws DatabaseException, StorageException + { +- String devicePath = vlmData.getDevicePath(); +- if (devicePath != null && vlmData.exists()) ++ @Nullable String devicePath = vlmData.getDevicePath(); ++ // Check if device path physically exists before calling lsblk ++ // This is important for DRBD devices which might be temporarily unavailable during adjust ++ // (drbdadm adjust brings devices down/up, and kernel might not have created the device node yet) ++ if (devicePath != null && vlmData.exists() && Files.exists(Paths.get(devicePath))) + { + if (vlmData.getDiscGran() == VlmProviderObject.UNINITIALIZED_SIZE) + { +-- +2.39.5 (Apple Git-154) + + +From de1f22e7c008c5479f85a3b1ebdf8461944210f4 Mon Sep 17 00:00:00 2001 +From: Andrei Kvapil +Date: Mon, 12 Jan 2026 14:28:23 +0100 +Subject: [PATCH 3/3] fix(drbd): only check child devices when disk access is + actually needed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The previous implementation blocked `drbdadm adjust` whenever child +device paths were unavailable, even for operations that don't require +disk access (like network reconnect from StandAlone to Connected). + +After node reboot, DRBD resources often remain in StandAlone state +because: +1. updateResourceToCurrentDrbdState() correctly detects StandAlone + and sets adjustRequired=true +2. However, canAdjust check fails because child volumes may have + devicePath=null (due to INACTIVE flag, cloning state, or + initialization race) +3. adjust is skipped → adjustRequired=false → resources stay StandAlone + +Root cause: The canAdjust check was added to protect LUKS deletion +scenarios but was applied to ALL cases, including network reconnect +which doesn't need disk access. + +Fix: Check child device accessibility only when disk access is actually +required (volume creation, resize, metadata operations). Network +reconnect operations (StandAlone → Connected) now proceed without +checking child devices. + +This ensures automatic DRBD reconnection after reboot while preserving +protection for LUKS deletion scenarios. + +Co-Authored-By: Claude +Signed-off-by: Andrei Kvapil +--- + .../linbit/linstor/layer/drbd/DrbdLayer.java | 27 ++++++++++++++++++- + 1 file changed, 26 insertions(+), 1 deletion(-) + +diff --git a/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java b/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java +index 871d830d1..78b8195a4 100644 +--- a/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java ++++ b/satellite/src/main/java/com/linbit/linstor/layer/drbd/DrbdLayer.java +@@ -792,7 +792,32 @@ public class DrbdLayer implements DeviceLayer + // This is important for encrypted resources (LUKS) where the device + // might be closed during deletion + boolean canAdjust = true; +- if (!skipDisk && !drbdRscData.getAbsResource().isDrbdDiskless(workerCtx)) ++ ++ // IMPORTANT: Check child volumes only when disk access is actually needed. ++ // For network reconnect (StandAlone -> Connected), disk access is not required. ++ boolean needsDiskAccess = false; ++ ++ // Check if there are pending operations that require disk access ++ for (DrbdVlmData drbdVlmData : drbdRscData.getVlmLayerObjects().values()) ++ { ++ Volume vlm = (Volume) drbdVlmData.getVolume(); ++ StateFlags vlmFlags = vlm.getFlags(); ++ ++ // Disk access is needed if: ++ // - creating a new volume ++ // - resizing ++ // - checking/creating metadata ++ if (!drbdVlmData.exists() || ++ drbdVlmData.checkMetaData() || ++ vlmFlags.isSomeSet(workerCtx, Volume.Flags.RESIZE, Volume.Flags.DRBD_RESIZE)) ++ { ++ needsDiskAccess = true; ++ break; ++ } ++ } ++ ++ // Check child volumes only if disk access is actually needed ++ if (needsDiskAccess && !skipDisk && !drbdRscData.getAbsResource().isDrbdDiskless(workerCtx)) + { + AbsRscLayerObject dataChild = drbdRscData.getChildBySuffix(RscLayerSuffixes.SUFFIX_DATA); + if (dataChild != null) +-- +2.39.5 (Apple Git-154) + From 9ba76d4839e1bd2407316fa45e28a7df524a03d8 Mon Sep 17 00:00:00 2001 From: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> Date: Tue, 13 Jan 2026 01:39:20 +0000 Subject: [PATCH 61/78] Prepare release v0.40.1 Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> --- packages/apps/kubernetes/images/cluster-autoscaler.tag | 2 +- packages/core/installer/values.yaml | 2 +- packages/core/platform/values.yaml | 2 +- packages/core/testing/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- packages/extra/seaweedfs/images/objectstorage-sidecar.tag | 2 +- packages/system/cozystack-api/values.yaml | 2 +- packages/system/cozystack-controller/values.yaml | 4 ++-- packages/system/dashboard/templates/configmap.yaml | 2 +- packages/system/dashboard/values.yaml | 6 +++--- packages/system/kamaji/values.yaml | 4 ++-- packages/system/kubeovn-plunger/values.yaml | 2 +- packages/system/kubeovn-webhook/values.yaml | 2 +- packages/system/lineage-controller-webhook/values.yaml | 2 +- packages/system/linstor/values.yaml | 2 +- packages/system/objectstorage-controller/values.yaml | 2 +- packages/system/seaweedfs/values.yaml | 2 +- 17 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/apps/kubernetes/images/cluster-autoscaler.tag b/packages/apps/kubernetes/images/cluster-autoscaler.tag index b1c2fe04..03a5ad61 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:372ad087ae96bd0cd642e2b0855ec7ffb1369d6cf4f0b92204725557c11bc0ff +ghcr.io/cozystack/cozystack/cluster-autoscaler:0.0.0@sha256:6f2b1d6b0b2bdc66f1cbb30c59393369cbf070cb8f5fec748f176952273483cc diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index 5a90dfed..d08a5a82 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.40.0@sha256:0f62cc82d7d5782485ea8345dfba5db7de55e2b1a38095d0ab5a334af7755ea9 + image: ghcr.io/cozystack/cozystack/installer:v0.40.1@sha256:69a8f95b8ddcf122a8859a957017b3d9e33c5eca3bfbf30c112c109e355f4f1c diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index 2efff01d..84efcb78 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -1,2 +1,2 @@ assets: - image: ghcr.io/cozystack/cozystack/cozystack-assets:v0.40.0@sha256:b643f04707bcea32a152b2df3270907ac743d168e586630cd70f90020f0b0a12 + image: ghcr.io/cozystack/cozystack/cozystack-assets:v0.40.1@sha256:ee1248692753820fe11139789680fd24dc4dbdba85a6cb70e086447d9b9b1d99 diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index 2b8ee06f..90a9ed18 100644 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.40.0@sha256:78a556a059411cac89249c2e22596223128a1c74fbfcac4787fd74e4a66f66a6 + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.40.1@sha256:78a556a059411cac89249c2e22596223128a1c74fbfcac4787fd74e4a66f66a6 diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index 73d5d060..aa8ecbfd 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.40.0@sha256:653cec80b50dd9e6d7110cd20efbdeaac324ba2c638f14e122abf8e6bd436d83 +ghcr.io/cozystack/cozystack/matchbox:v0.40.1@sha256:293d562c134fc4ee0a9a756df32422b849715fe25a2120b69cb415ca98217363 diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag index 1919ce58..1724acc3 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:v0.40.0@sha256:2d1833c78c35b697a3634d4b3be9a3218edae95a77583e9e121c10a92e7433ec +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.40.1@sha256:4bb47c8adb34543403a16d1ff61b307939850e8cf5fc365388469e30dfb9681b diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 0eff5030..10a79b25 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,5 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.40.0@sha256:408885b509d80ca30a85416f87d07112bc7f070374e71e80b64818fbb24ad1ee + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.40.1@sha256:408885b509d80ca30a85416f87d07112bc7f070374e71e80b64818fbb24ad1ee localK8sAPIEndpoint: enabled: true replicas: 2 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index b9da9426..a28c13c5 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,6 +1,6 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.40.0@sha256:90cbb2f3fa2d30f9b9c9f623463ef11203a2b8d2105a52166aac566d2b984e59 + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.40.1@sha256:75636007f63e1b2cb51fc2e70782b707330d1e728c32642a4edc500b614f0781 debug: false disableTelemetry: false - cozystackVersion: "v0.40.0" + cozystackVersion: "v0.40.1" cozystackAPIKind: "DaemonSet" diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index abc9f42d..861d4eed 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,6 +1,6 @@ {{- $brandingConfig := .Values._cluster.branding | default dict }} -{{- $tenantText := "v0.40.0" }} +{{- $tenantText := "v0.40.1" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} {{- $logoText := "" }} diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index 771ef3dc..94c395bb 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v0.40.0@sha256:665d5553d445c71d6007f440841943167a33e403cdca447b510b6f919e16a657 + image: ghcr.io/cozystack/cozystack/openapi-ui:v0.40.1@sha256:a427114308b9c87ab71b50980cba0d673a730791629164335d2046f7d1740327 openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.40.0@sha256:fda379dce49c2cd8cb8d7d2a1d8ec6f7bedb3419c058c4355ecdece1c1e937f4 + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.40.1@sha256:fda379dce49c2cd8cb8d7d2a1d8ec6f7bedb3419c058c4355ecdece1c1e937f4 tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:v0.40.0@sha256:4fc8a11f8a1a81aa0774ae2b1ed2e05d36d0b3ef1e37979cc4994e65114d93ae + image: ghcr.io/cozystack/cozystack/token-proxy:v0.40.1@sha256:4fc8a11f8a1a81aa0774ae2b1ed2e05d36d0b3ef1e37979cc4994e65114d93ae diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index d8b15b80..35c15ef9 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.40.0@sha256:4588de4380fb70c29c4a762fb19a9bbe210e68bc5ff67035c752c44daf319bfc + tag: v0.40.1@sha256:0bcfb2d376224b18a0627d7b18ba6202bb8a553f71796023e12740d9513740c7 repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: @@ -13,4 +13,4 @@ kamaji: cpu: 100m memory: 100Mi extraArgs: - - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.40.0@sha256:4588de4380fb70c29c4a762fb19a9bbe210e68bc5ff67035c752c44daf319bfc + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.40.1@sha256:0bcfb2d376224b18a0627d7b18ba6202bb8a553f71796023e12740d9513740c7 diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml index 9b12e46d..10d8508a 100644 --- a/packages/system/kubeovn-plunger/values.yaml +++ b/packages/system/kubeovn-plunger/values.yaml @@ -1,4 +1,4 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.40.0@sha256:e1e47c30b2eef93497163e15d94fbddca40e416769705557881d23dd537c5591 +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.40.1@sha256:2a17dfa8eec0fc6b2adb564742e74f35bd68ac0d29e5ab1d007496aff3c0e97d ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index b69f4db2..c60ff144 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.40.0@sha256:e18f9fd679e38f65362a8d0042f25468272f6d081136ad47027168d8e7e07a4a +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.40.1@sha256:e6334c29d3aaf0dea766c88e3e05b53ad623d1bb497b3c836e6f76adade45b29 diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index b0c47220..55cb019b 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,5 +1,5 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.40.0@sha256:792ca90d9e8d2d03cb10587d5a3570dad6c199e5ad0734d334869b9d595e748f + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.40.1@sha256:00650eb92c8b93a0afc382a0c5e46ade453e430867be7dab9647a6fc2896f097 debug: false localK8sAPIEndpoint: enabled: true diff --git a/packages/system/linstor/values.yaml b/packages/system/linstor/values.yaml index ac9c4fe7..21a7aa21 100644 --- a/packages/system/linstor/values.yaml +++ b/packages/system/linstor/values.yaml @@ -1,7 +1,7 @@ piraeusServer: image: repository: ghcr.io/cozystack/cozystack/piraeus-server - tag: 1.32.3@sha256:c6fbe1825514a3059088175968a651d7e10f477590023a33f1a9e6584fd98e04 + tag: 1.32.3@sha256:1138c8dc0a117360ef70e2e2ab97bc2696419b63f46358f7668c7e01a96c419b linstor: autoDiskful: enabled: true diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml index e9d9fd81..aba36be8 100644 --- a/packages/system/objectstorage-controller/values.yaml +++ b/packages/system/objectstorage-controller/values.yaml @@ -1,3 +1,3 @@ objectstorage: controller: - image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.40.0@sha256:cbf22bcbeed7049340aa41f41cc130596bdb962873116e0c4eb5bab123ae13b0" + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.40.1@sha256:e8f605a5ec4b801dfaf49aa7bce8d7a1ce28df578e23a0b859571f60f98efe8c" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index 89474c55..fb3defa6 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -177,7 +177,7 @@ seaweedfs: bucketClassName: "seaweedfs" region: "" sidecar: - image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.40.0@sha256:2d1833c78c35b697a3634d4b3be9a3218edae95a77583e9e121c10a92e7433ec" + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.40.1@sha256:4bb47c8adb34543403a16d1ff61b307939850e8cf5fc365388469e30dfb9681b" certificates: commonName: "SeaweedFS CA" ipAddresses: [] From e176cdec874238b2ae749456132f7fc823fd85c2 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Wed, 7 Jan 2026 21:05:51 +0100 Subject: [PATCH 62/78] feat(linstor): add linstor-csi image build with RWX validation Add custom linstor-csi image build to packages/system/linstor: - Add Dockerfile based on upstream linstor-csi - Import patch from upstream PR #403 for RWX block volume validation (prevents misuse of allow-two-primaries in KubeVirt live migration) - Update Makefile to build both piraeus-server and linstor-csi images - Configure LinstorCluster CR to use custom linstor-csi image in CSI controller and node pods The RWX validation patch ensures that RWX block volumes with allow-two-primaries are only used by pods belonging to the same KubeVirt VM during live migration. Upstream PR: https://github.com/piraeusdatastore/linstor-csi/pull/403 Co-Authored-By: Claude Signed-off-by: Andrei Kvapil --- packages/system/linstor/Makefile | 20 +- .../linstor/images/linstor-csi/Dockerfile | 36 + .../patches/001-rwx-validation.diff | 652 ++++++++++++++++++ .../system/linstor/templates/cluster.yaml | 18 + packages/system/linstor/values.yaml | 5 + 5 files changed, 730 insertions(+), 1 deletion(-) create mode 100644 packages/system/linstor/images/linstor-csi/Dockerfile create mode 100644 packages/system/linstor/images/linstor-csi/patches/001-rwx-validation.diff diff --git a/packages/system/linstor/Makefile b/packages/system/linstor/Makefile index da895085..b5d7c227 100644 --- a/packages/system/linstor/Makefile +++ b/packages/system/linstor/Makefile @@ -5,8 +5,11 @@ include ../../../scripts/common-envs.mk include ../../../scripts/package.mk LINSTOR_VERSION ?= 1.32.3 +LINSTOR_CSI_VERSION ?= v1.10.5 -image: +image: image-piraeus-server image-linstor-csi + +image-piraeus-server: docker buildx build images/piraeus-server \ --build-arg LINSTOR_VERSION=$(LINSTOR_VERSION) \ --build-arg K8S_AWAIT_ELECTION_VERSION=v0.4.2 \ @@ -21,3 +24,18 @@ image: TAG="$(call settag,$(LINSTOR_VERSION))@$$(yq e '."containerimage.digest"' images/piraeus-server.json -o json -r)" \ yq -i '.piraeusServer.image.tag = strenv(TAG)' values.yaml rm -f images/piraeus-server.json + +image-linstor-csi: + docker buildx build images/linstor-csi \ + --build-arg VERSION=$(LINSTOR_CSI_VERSION) \ + --tag $(REGISTRY)/linstor-csi:$(call settag,$(LINSTOR_CSI_VERSION)) \ + --tag $(REGISTRY)/linstor-csi:$(call settag,$(LINSTOR_CSI_VERSION)-$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/linstor-csi:latest \ + --cache-to type=inline \ + --metadata-file images/linstor-csi.json \ + $(BUILDX_ARGS) + REPOSITORY="$(REGISTRY)/linstor-csi" \ + yq -i '.linstorCSI.image.repository = strenv(REPOSITORY)' values.yaml + TAG="$(call settag,$(LINSTOR_CSI_VERSION))@$$(yq e '."containerimage.digest"' images/linstor-csi.json -o json -r)" \ + yq -i '.linstorCSI.image.tag = strenv(TAG)' values.yaml + rm -f images/linstor-csi.json diff --git a/packages/system/linstor/images/linstor-csi/Dockerfile b/packages/system/linstor/images/linstor-csi/Dockerfile new file mode 100644 index 00000000..6cfd44aa --- /dev/null +++ b/packages/system/linstor/images/linstor-csi/Dockerfile @@ -0,0 +1,36 @@ +FROM golang:1.25 AS builder + +ARG VERSION=v1.10.5 +ARG LINSTOR_WAIT_UNTIL_VERSION=v0.3.1 +ARG TARGETARCH +ARG TARGETOS + +WORKDIR /src + +RUN curl -sSL https://github.com/piraeusdatastore/linstor-csi/archive/refs/tags/${VERSION}.tar.gz | tar -xzvf- --strip=1 + +COPY patches /patches +RUN git apply /patches/*.diff + +RUN go mod download + +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 \ + go build \ + -a \ + -ldflags "-X github.com/piraeusdatastore/linstor-csi/pkg/driver.Version=$VERSION -extldflags -static" \ + -o /linstor-csi \ + ./cmd/linstor-csi/linstor-csi.go + +RUN curl -fsSL https://github.com/LINBIT/linstor-wait-until/releases/download/$LINSTOR_WAIT_UNTIL_VERSION/linstor-wait-until-$LINSTOR_WAIT_UNTIL_VERSION-$TARGETOS-$TARGETARCH.tar.gz | tar xvzC / + +FROM debian:trixie-slim + +RUN apt-get update && apt-get install -y --no-install-recommends \ + xfsprogs e2fsprogs nfs-common \ + && apt-get clean && rm -rf /var/lib/apt/lists/* \ + && ln -sf /proc/mounts /etc/mtab + +COPY --from=builder /linstor-csi / +COPY --from=builder /linstor-wait-until /linstor-wait-until + +ENTRYPOINT ["/linstor-csi"] diff --git a/packages/system/linstor/images/linstor-csi/patches/001-rwx-validation.diff b/packages/system/linstor/images/linstor-csi/patches/001-rwx-validation.diff new file mode 100644 index 00000000..f6f0d83d --- /dev/null +++ b/packages/system/linstor/images/linstor-csi/patches/001-rwx-validation.diff @@ -0,0 +1,652 @@ +diff --git a/pkg/driver/driver.go b/pkg/driver/driver.go +index bea69a8..848bd5b 100644 +--- a/pkg/driver/driver.go ++++ b/pkg/driver/driver.go +@@ -401,6 +401,16 @@ func (d Driver) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolum + } + } + ++ // Validate RWX block volumes on node side using local filesystem check ++ // This provides protection for the edge case where two pods from different VMs land on the same node ++ if req.GetVolumeCapability().GetBlock() != nil && ++ req.GetVolumeCapability().GetAccessMode().GetMode() == csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER { ++ if err := d.validateRWXBlockOnNode(ctx, req.GetVolumeId(), req.GetTargetPath()); err != nil { ++ return nil, status.Errorf(codes.FailedPrecondition, ++ "NodePublishVolume failed for %s: %v", req.GetVolumeId(), err) ++ } ++ } ++ + if block := req.GetVolumeCapability().GetBlock(); block != nil { + volCtx.MountOptions = []string{"bind"} + } +@@ -707,6 +717,255 @@ func (d Driver) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest) + return &csi.DeleteVolumeResponse{}, nil + } + ++// KubeVirtVMLabel is the label that KubeVirt adds to pods to identify the VM they belong to. ++const KubeVirtVMLabel = "vm.kubevirt.io/name" ++ ++// KubeVirtHotplugDiskLabel is the label that KubeVirt adds to hotplug disk pods. ++const KubeVirtHotplugDiskLabel = "kubevirt.io" ++ ++// podGVR is the GroupVersionResource for pods. ++var podGVR = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"} ++ ++// pvGVR is the GroupVersionResource for persistent volumes. ++var pvGVR = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "persistentvolumes"} ++ ++// getVMNameFromPod extracts the VM name from a pod, handling both regular virt-launcher pods ++// and hotplug disk pods (which reference the virt-launcher pod via ownerReferences). ++func (d Driver) getVMNameFromPod(ctx context.Context, pod *unstructured.Unstructured) (string, error) { ++ labels := pod.GetLabels() ++ if labels == nil { ++ return "", nil ++ } ++ ++ // Direct case: pod has vm.kubevirt.io/name label (virt-launcher pod) ++ if vmName, ok := labels[KubeVirtVMLabel]; ok && vmName != "" { ++ return vmName, nil ++ } ++ ++ // Hotplug disk case: pod has kubevirt.io: hotplug-disk label ++ // Follow ownerReferences to find the virt-launcher pod ++ if hotplugValue, ok := labels[KubeVirtHotplugDiskLabel]; ok && hotplugValue == "hotplug-disk" { ++ ownerRefs := pod.GetOwnerReferences() ++ for _, owner := range ownerRefs { ++ if owner.Kind != "Pod" || owner.Controller == nil || !*owner.Controller { ++ continue ++ } ++ ++ // Get the owner pod (virt-launcher) ++ ownerPod, err := d.kubeClient.Resource(podGVR).Namespace(pod.GetNamespace()).Get(ctx, owner.Name, metav1.GetOptions{}) ++ if err != nil { ++ return "", fmt.Errorf("failed to get owner pod %s: %w", owner.Name, err) ++ } ++ ++ // Extract VM name from owner pod ++ ownerLabels := ownerPod.GetLabels() ++ if ownerLabels != nil { ++ if vmName, ok := ownerLabels[KubeVirtVMLabel]; ok && vmName != "" { ++ d.log.WithFields(logrus.Fields{ ++ "hotplugPod": pod.GetName(), ++ "virtLauncher": owner.Name, ++ "vmName": vmName, ++ }).Debug("resolved VM name from hotplug disk pod via owner reference") ++ ++ return vmName, nil ++ } ++ } ++ ++ return "", fmt.Errorf("owner pod %s does not have %s label", owner.Name, KubeVirtVMLabel) ++ } ++ ++ return "", fmt.Errorf("hotplug disk pod %s has no controller owner reference", pod.GetName()) ++ } ++ ++ return "", nil ++} ++ ++// validateRWXBlockAttachment checks that RWX block volumes are only used by pods belonging to the same VM. ++// This prevents misuse of allow-two-primaries while still permitting live migration. ++// Returns the VM name if validation passes, or an error if: ++// - Multiple pods from different VMs are trying to use the same volume ++// - A pod without the KubeVirt VM label is trying to use a volume already attached elsewhere (strict mode) ++// Returns empty string for VM name when no pods are using the volume or validation is skipped. ++func (d Driver) validateRWXBlockAttachment(ctx context.Context, volumeID string) (string, error) { ++ d.log.WithField("volumeID", volumeID).Info("validateRWXBlockAttachment called") ++ ++ if d.kubeClient == nil { ++ // Not running in Kubernetes, skip validation ++ d.log.Warn("validateRWXBlockAttachment: kubeClient is nil, skipping validation") ++ return "", nil ++ } ++ ++ // Get PV to find PVC reference (volumeID == PV name in CSI) ++ pv, err := d.kubeClient.Resource(pvGVR).Get(ctx, volumeID, metav1.GetOptions{}) ++ if err != nil { ++ d.log.WithError(err).Warn("cannot validate RWX attachment: failed to get PV") ++ return "", nil ++ } ++ ++ // Extract claimRef from PV ++ claimRef, found, _ := unstructured.NestedMap(pv.Object, "spec", "claimRef") ++ if !found { ++ d.log.Warn("cannot validate RWX attachment: PV has no claimRef") ++ return "", nil ++ } ++ ++ pvcName, _, _ := unstructured.NestedString(claimRef, "name") ++ pvcNamespace, _, _ := unstructured.NestedString(claimRef, "namespace") ++ ++ if pvcNamespace == "" || pvcName == "" { ++ d.log.Warn("cannot validate RWX attachment: PVC name or namespace is empty in claimRef") ++ return "", nil ++ } ++ ++ // List all pods in the namespace ++ podList, err := d.kubeClient.Resource(podGVR).Namespace(pvcNamespace).List(ctx, metav1.ListOptions{}) ++ if err != nil { ++ return "", fmt.Errorf("failed to list pods in namespace %s: %w", pvcNamespace, err) ++ } ++ ++ // Filter pods that use this PVC and are in a running/pending state ++ type podInfo struct { ++ name string ++ vmName string ++ } ++ ++ var podsUsingPVC []podInfo ++ ++ for _, item := range podList.Items { ++ // Get pod phase from status ++ phase, _, _ := unstructured.NestedString(item.Object, "status", "phase") ++ if phase == "Succeeded" || phase == "Failed" { ++ continue ++ } ++ ++ // Check if pod uses the PVC ++ volumes, found, _ := unstructured.NestedSlice(item.Object, "spec", "volumes") ++ if !found { ++ continue ++ } ++ ++ for _, vol := range volumes { ++ volMap, ok := vol.(map[string]interface{}) ++ if !ok { ++ continue ++ } ++ ++ pvc, found, _ := unstructured.NestedMap(volMap, "persistentVolumeClaim") ++ if !found { ++ continue ++ } ++ ++ claimName, _, _ := unstructured.NestedString(pvc, "claimName") ++ if claimName == pvcName { ++ // Extract VM name, handling both regular and hotplug disk pods ++ vmName, err := d.getVMNameFromPod(ctx, &item) ++ if err != nil { ++ d.log.WithError(err).WithField("pod", item.GetName()).Warn("failed to get VM name from pod") ++ // Continue with empty vmName - will be caught by strict mode check ++ vmName = "" ++ } ++ ++ podsUsingPVC = append(podsUsingPVC, podInfo{ ++ name: item.GetName(), ++ vmName: vmName, ++ }) ++ ++ break ++ } ++ } ++ } ++ ++ // If 0 or 1 pod uses the PVC, no conflict possible ++ if len(podsUsingPVC) <= 1 { ++ // Return VM name if there's exactly one pod ++ if len(podsUsingPVC) == 1 { ++ d.log.WithFields(logrus.Fields{ ++ "volumeID": volumeID, ++ "vmName": podsUsingPVC[0].vmName, ++ "podCount": 1, ++ "pvcNamespace": pvcNamespace, ++ "pvcName": pvcName, ++ }).Info("validateRWXBlockAttachment: single pod found, returning VM name") ++ ++ return podsUsingPVC[0].vmName, nil ++ } ++ ++ d.log.WithFields(logrus.Fields{ ++ "volumeID": volumeID, ++ "pvcNamespace": pvcNamespace, ++ "pvcName": pvcName, ++ }).Info("validateRWXBlockAttachment: no pods found using PVC") ++ ++ return "", nil ++ } ++ ++ // Check that all pods belong to the same VM ++ var vmName string ++ for _, pod := range podsUsingPVC { ++ if pod.vmName == "" { ++ // Strict mode: if any pod doesn't have the KubeVirt label and there are multiple pods, ++ // deny the attachment ++ return "", fmt.Errorf("RWX block volume %s/%s is used by multiple pods but pod %s does not have the %s label; "+ ++ "RWX block volumes with allow-two-primaries are only supported for KubeVirt live migration", ++ pvcNamespace, pvcName, pod.name, KubeVirtVMLabel) ++ } ++ ++ if vmName == "" { ++ vmName = pod.vmName ++ } else if vmName != pod.vmName { ++ // Different VMs are trying to use the same volume ++ return "", fmt.Errorf("RWX block volume %s/%s is being used by pods from different VMs (%s and %s); "+ ++ "this is not supported - RWX block volumes with allow-two-primaries are only for live migration of a single VM", ++ pvcNamespace, pvcName, vmName, pod.vmName) ++ } ++ } ++ ++ d.log.WithFields(logrus.Fields{ ++ "pvcNamespace": pvcNamespace, ++ "pvcName": pvcName, ++ "vmName": vmName, ++ "podCount": len(podsUsingPVC), ++ }).Debug("RWX block attachment validated: all pods belong to the same VM (likely live migration)") ++ ++ return vmName, nil ++} ++ ++// validateRWXBlockOnNode performs node-side validation of RWX block volumes using local filesystem check. ++// This provides protection against the edge case where two pods from different VMs land on the same node. ++// Since ControllerPublishVolume is called only once per (volumeID, nodeID) pair, not per pod, ++// we need to check if the volume is already mounted for another pod on this node. ++func (d Driver) validateRWXBlockOnNode(ctx context.Context, volumeID, targetPath string) error { ++ // Extract base directory for this volume (contains subdirectories per pod UID) ++ baseDir := filepath.Dir(targetPath) ++ ++ // List existing mounts for this volume ++ entries, err := os.ReadDir(baseDir) ++ if err != nil { ++ if os.IsNotExist(err) { ++ // Directory doesn't exist yet - first mount ++ return nil ++ } ++ ++ d.log.WithError(err).Warn("cannot check existing mounts for RWX validation") ++ ++ return nil ++ } ++ ++ // If there are already other mounts, block the second one ++ if len(entries) > 0 { ++ d.log.WithFields(logrus.Fields{ ++ "volumeID": volumeID, ++ "existingMounts": len(entries), ++ "baseDir": baseDir, ++ }).Warn("blocking RWX block volume mount: already mounted for another pod on this node") ++ ++ return fmt.Errorf("RWX block volume is already mounted for another pod on this node - " + ++ "multiple pods on the same node sharing a block device is not supported (only for live migration across nodes)") ++ } ++ ++ return nil ++} ++ + // ControllerPublishVolume https://github.com/container-storage-interface/spec/blob/v1.9.0/spec.md#controllerpublishvolume + func (d Driver) ControllerPublishVolume(ctx context.Context, req *csi.ControllerPublishVolumeRequest) (*csi.ControllerPublishVolumeResponse, error) { + if req.GetVolumeId() == "" { +@@ -751,6 +1010,15 @@ func (d Driver) ControllerPublishVolume(ctx context.Context, req *csi.Controller + // ReadWriteMany block volume + rwxBlock := req.VolumeCapability.AccessMode.GetMode() == csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER && req.VolumeCapability.GetBlock() != nil + ++ // Validate RWX block attachment to prevent misuse of allow-two-primaries ++ if rwxBlock { ++ _, err := d.validateRWXBlockAttachment(ctx, req.GetVolumeId()) ++ if err != nil { ++ return nil, status.Errorf(codes.FailedPrecondition, ++ "ControllerPublishVolume failed for %s: %v", req.GetVolumeId(), err) ++ } ++ } ++ + devPath, err := d.Assignments.Attach(ctx, req.GetVolumeId(), req.GetNodeId(), rwxBlock) + if err != nil { + return nil, status.Errorf(codes.Internal, +diff --git a/pkg/driver/rwx_validation_test.go b/pkg/driver/rwx_validation_test.go +new file mode 100644 +index 0000000..92c1046 +--- /dev/null ++++ b/pkg/driver/rwx_validation_test.go +@@ -0,0 +1,353 @@ ++/* ++CSI Driver for Linstor ++Copyright © 2018 LINBIT USA, LLC ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, see . ++*/ ++ ++package driver ++ ++import ( ++ "context" ++ "testing" ++ ++ "github.com/sirupsen/logrus" ++ "github.com/stretchr/testify/assert" ++ "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" ++) ++ ++func TestValidateRWXBlockAttachment(t *testing.T) { ++ testCases := []struct { ++ name string ++ pods []*unstructured.Unstructured ++ pvcName string ++ namespace string ++ expectError bool ++ errorMsg string ++ }{ ++ { ++ name: "no pods using PVC", ++ pods: []*unstructured.Unstructured{}, ++ pvcName: "test-pvc", ++ namespace: "default", ++ expectError: false, ++ }, ++ { ++ name: "single pod using PVC", ++ pods: []*unstructured.Unstructured{ ++ createUnstructuredPod("pod1", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm1"}, "Running"), ++ }, ++ pvcName: "test-pvc", ++ namespace: "default", ++ expectError: false, ++ }, ++ { ++ name: "two pods same VM (live migration)", ++ pods: []*unstructured.Unstructured{ ++ createUnstructuredPod("virt-launcher-vm1-abc", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm1"}, "Running"), ++ createUnstructuredPod("virt-launcher-vm1-xyz", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm1"}, "Running"), ++ }, ++ pvcName: "test-pvc", ++ namespace: "default", ++ expectError: false, ++ }, ++ { ++ name: "two pods different VMs (should fail)", ++ pods: []*unstructured.Unstructured{ ++ createUnstructuredPod("virt-launcher-vm1-abc", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm1"}, "Running"), ++ createUnstructuredPod("virt-launcher-vm2-xyz", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm2"}, "Running"), ++ }, ++ pvcName: "test-pvc", ++ namespace: "default", ++ expectError: true, ++ errorMsg: "different VMs", ++ }, ++ { ++ name: "pod without KubeVirt label when multiple pods exist (strict mode)", ++ pods: []*unstructured.Unstructured{ ++ createUnstructuredPod("pod1", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm1"}, "Running"), ++ createUnstructuredPod("pod2", "default", "test-pvc", map[string]string{}, "Running"), ++ }, ++ pvcName: "test-pvc", ++ namespace: "default", ++ expectError: true, ++ errorMsg: "does not have the vm.kubevirt.io/name label", ++ }, ++ { ++ name: "completed pods should be ignored", ++ pods: []*unstructured.Unstructured{ ++ createUnstructuredPod("pod1", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm1"}, "Running"), ++ createUnstructuredPod("pod2", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm2"}, "Succeeded"), ++ }, ++ pvcName: "test-pvc", ++ namespace: "default", ++ expectError: false, ++ }, ++ { ++ name: "failed pods should be ignored", ++ pods: []*unstructured.Unstructured{ ++ createUnstructuredPod("pod1", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm1"}, "Running"), ++ createUnstructuredPod("pod2", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm2"}, "Failed"), ++ }, ++ pvcName: "test-pvc", ++ namespace: "default", ++ expectError: false, ++ }, ++ { ++ name: "pods in different namespace should not conflict", ++ pods: []*unstructured.Unstructured{ ++ createUnstructuredPod("pod1", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm1"}, "Running"), ++ createUnstructuredPod("pod2", "other", "test-pvc", map[string]string{KubeVirtVMLabel: "vm2"}, "Running"), ++ }, ++ pvcName: "test-pvc", ++ namespace: "default", ++ expectError: false, ++ }, ++ { ++ name: "pods using different PVCs should not conflict", ++ pods: []*unstructured.Unstructured{ ++ createUnstructuredPod("pod1", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm1"}, "Running"), ++ createUnstructuredPod("pod2", "default", "other-pvc", map[string]string{KubeVirtVMLabel: "vm2"}, "Running"), ++ }, ++ pvcName: "test-pvc", ++ namespace: "default", ++ expectError: false, ++ }, ++ { ++ name: "three pods from same VM (multi-node live migration scenario)", ++ pods: []*unstructured.Unstructured{ ++ createUnstructuredPod("virt-launcher-vm1-a", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm1"}, "Running"), ++ createUnstructuredPod("virt-launcher-vm1-b", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm1"}, "Running"), ++ createUnstructuredPod("virt-launcher-vm1-c", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm1"}, "Pending"), ++ }, ++ pvcName: "test-pvc", ++ namespace: "default", ++ expectError: false, ++ }, ++ { ++ name: "hotplug disk pod with virt-launcher (should succeed)", ++ pods: []*unstructured.Unstructured{ ++ createUnstructuredPod("virt-launcher-vm1-abc", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm1"}, "Running"), ++ createHotplugDiskPod("hp-volume-xyz", "default", "test-pvc", "virt-launcher-vm1-abc", "Running"), ++ }, ++ pvcName: "test-pvc", ++ namespace: "default", ++ expectError: false, ++ }, ++ { ++ name: "hotplug disks from different VMs (should fail)", ++ pods: []*unstructured.Unstructured{ ++ createUnstructuredPod("virt-launcher-vm1-abc", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm1"}, "Running"), ++ createHotplugDiskPod("hp-volume-vm1", "default", "test-pvc", "virt-launcher-vm1-abc", "Running"), ++ createUnstructuredPod("virt-launcher-vm2-xyz", "default", "test-pvc", map[string]string{KubeVirtVMLabel: "vm2"}, "Running"), ++ createHotplugDiskPod("hp-volume-vm2", "default", "test-pvc", "virt-launcher-vm2-xyz", "Running"), ++ }, ++ pvcName: "test-pvc", ++ namespace: "default", ++ expectError: true, ++ errorMsg: "different VMs", ++ }, ++ } ++ ++ for _, tc := range testCases { ++ t.Run(tc.name, func(t *testing.T) { ++ // Create fake dynamic client with test pods and PV ++ scheme := runtime.NewScheme() ++ ++ // Create PV object that references the PVC ++ pv := createUnstructuredPV("test-volume-id", tc.namespace, tc.pvcName) ++ ++ objects := make([]runtime.Object, 0, len(tc.pods)+1) ++ objects = append(objects, pv) ++ ++ for _, pod := range tc.pods { ++ objects = append(objects, pod) ++ } ++ ++ gvrToListKind := map[schema.GroupVersionResource]string{ ++ podGVR: "PodList", ++ pvGVR: "PersistentVolumeList", ++ } ++ client := dynamicfake.NewSimpleDynamicClientWithCustomListKinds(scheme, gvrToListKind, objects...) ++ ++ // Create driver with fake client ++ logger := logrus.NewEntry(logrus.New()) ++ logger.Logger.SetLevel(logrus.DebugLevel) ++ ++ driver := &Driver{ ++ kubeClient: client, ++ log: logger, ++ } ++ ++ // Run validation ++ vmName, err := driver.validateRWXBlockAttachment(context.Background(), "test-volume-id") ++ ++ if tc.expectError { ++ assert.Error(t, err) ++ ++ if tc.errorMsg != "" { ++ assert.Contains(t, err.Error(), tc.errorMsg) ++ } ++ } else { ++ assert.NoError(t, err) ++ // VM name is returned when there are pods using the volume ++ if len(tc.pods) > 0 { ++ assert.NotEmpty(t, vmName) ++ } ++ } ++ }) ++ } ++} ++ ++func TestValidateRWXBlockAttachmentNoKubeClient(t *testing.T) { ++ // When not running in Kubernetes (no client), validation should be skipped ++ logger := logrus.NewEntry(logrus.New()) ++ driver := &Driver{ ++ kubeClient: nil, ++ log: logger, ++ } ++ ++ vmName, err := driver.validateRWXBlockAttachment(context.Background(), "test-volume-id") ++ assert.NoError(t, err) ++ assert.Empty(t, vmName) ++} ++ ++func TestValidateRWXBlockAttachmentPVNotFound(t *testing.T) { ++ // When PV is not found, validation should be skipped with warning ++ scheme := runtime.NewScheme() ++ ++ gvrToListKind := map[schema.GroupVersionResource]string{ ++ podGVR: "PodList", ++ pvGVR: "PersistentVolumeList", ++ } ++ client := dynamicfake.NewSimpleDynamicClientWithCustomListKinds(scheme, gvrToListKind) ++ ++ logger := logrus.NewEntry(logrus.New()) ++ logger.Logger.SetLevel(logrus.DebugLevel) ++ ++ driver := &Driver{ ++ kubeClient: client, ++ log: logger, ++ } ++ ++ vmName, err := driver.validateRWXBlockAttachment(context.Background(), "non-existent-pv") ++ assert.NoError(t, err) ++ assert.Empty(t, vmName) ++} ++ ++// createUnstructuredPod creates an unstructured pod object for testing. ++func createUnstructuredPod(name, namespace, pvcName string, labels map[string]string, phase string) *unstructured.Unstructured { ++ pod := &unstructured.Unstructured{ ++ Object: map[string]interface{}{ ++ "apiVersion": "v1", ++ "kind": "Pod", ++ "metadata": map[string]interface{}{ ++ "name": name, ++ "namespace": namespace, ++ "labels": toStringInterfaceMap(labels), ++ }, ++ "spec": map[string]interface{}{ ++ "volumes": []interface{}{ ++ map[string]interface{}{ ++ "name": "data", ++ "persistentVolumeClaim": map[string]interface{}{ ++ "claimName": pvcName, ++ }, ++ }, ++ }, ++ }, ++ "status": map[string]interface{}{ ++ "phase": phase, ++ }, ++ }, ++ } ++ ++ return pod ++} ++ ++// createUnstructuredPV creates an unstructured PersistentVolume object for testing. ++func createUnstructuredPV(name, pvcNamespace, pvcName string) *unstructured.Unstructured { ++ pv := &unstructured.Unstructured{ ++ Object: map[string]interface{}{ ++ "apiVersion": "v1", ++ "kind": "PersistentVolume", ++ "metadata": map[string]interface{}{ ++ "name": name, ++ }, ++ "spec": map[string]interface{}{ ++ "claimRef": map[string]interface{}{ ++ "name": pvcName, ++ "namespace": pvcNamespace, ++ }, ++ }, ++ }, ++ } ++ ++ return pv ++} ++ ++// toStringInterfaceMap converts map[string]string to map[string]interface{}. ++func toStringInterfaceMap(m map[string]string) map[string]interface{} { ++ result := make(map[string]interface{}) ++ ++ for k, v := range m { ++ result[k] = v ++ } ++ ++ return result ++} ++ ++// createHotplugDiskPod creates a hotplug disk pod that references a virt-launcher pod via ownerReferences. ++func createHotplugDiskPod(name, namespace, pvcName, ownerPodName, phase string) *unstructured.Unstructured { ++ pod := &unstructured.Unstructured{ ++ Object: map[string]interface{}{ ++ "apiVersion": "v1", ++ "kind": "Pod", ++ "metadata": map[string]interface{}{ ++ "name": name, ++ "namespace": namespace, ++ "labels": map[string]interface{}{ ++ "kubevirt.io": "hotplug-disk", ++ }, ++ "ownerReferences": []interface{}{ ++ map[string]interface{}{ ++ "apiVersion": "v1", ++ "kind": "Pod", ++ "name": ownerPodName, ++ "controller": true, ++ "blockOwnerDeletion": true, ++ }, ++ }, ++ }, ++ "spec": map[string]interface{}{ ++ "volumes": []interface{}{ ++ map[string]interface{}{ ++ "name": "data", ++ "persistentVolumeClaim": map[string]interface{}{ ++ "claimName": pvcName, ++ }, ++ }, ++ }, ++ }, ++ "status": map[string]interface{}{ ++ "phase": phase, ++ }, ++ }, ++ } ++ ++ return pod ++} diff --git a/packages/system/linstor/templates/cluster.yaml b/packages/system/linstor/templates/cluster.yaml index bde24726..ba611e17 100644 --- a/packages/system/linstor/templates/cluster.yaml +++ b/packages/system/linstor/templates/cluster.yaml @@ -60,6 +60,24 @@ spec: configMap: name: linstor-plunger defaultMode: 0755 + csiController: + podTemplate: + spec: + initContainers: + - name: linstor-wait-api-online + image: {{ .Values.linstorCSI.image.repository }}:{{ .Values.linstorCSI.image.tag }} + containers: + - name: linstor-csi + image: {{ .Values.linstorCSI.image.repository }}:{{ .Values.linstorCSI.image.tag }} + csiNode: + podTemplate: + spec: + initContainers: + - name: linstor-wait-node-online + image: {{ .Values.linstorCSI.image.repository }}:{{ .Values.linstorCSI.image.tag }} + containers: + - name: linstor-csi + image: {{ .Values.linstorCSI.image.repository }}:{{ .Values.linstorCSI.image.tag }} patches: - target: kind: Deployment diff --git a/packages/system/linstor/values.yaml b/packages/system/linstor/values.yaml index 21a7aa21..173aacb4 100644 --- a/packages/system/linstor/values.yaml +++ b/packages/system/linstor/values.yaml @@ -7,3 +7,8 @@ linstor: enabled: true minutes: 30 allowCleanup: true + +linstorCSI: + image: + repository: ghcr.io/cozystack/cozystack/linstor-csi + tag: latest@sha256:e8329b3e07c47ec73a7d9644535639fd80dbe5c27a7e03181b999ebe072a3a2e From c5222aae97b19822939bc51c5f6f77976bb1ac50 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 12 Jan 2026 23:56:53 +0100 Subject: [PATCH 63/78] [linstor] Remove node-level RWX validation (#1851) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What this PR does Removes node-level RWX block validation from linstor-csi as controller-level check is sufficient. The controller already validates that all pods attached to RWX block volume belong to the same VM by extracting vmName from pod owner references (VirtualMachineInstance). This simplifies the validation logic and fixes VM live migration issues. ### Release note ```release-note [linstor] Remove node-level RWX block validation to fix VM live migration ``` ## Summary by CodeRabbit * **Improvements** * Enhanced RWX (read-write-many) block validation with VM-aware checks across node and controller flows, including support for hotplug-disk pods and stricter prevention of cross-VM block sharing. * Improved propagation and resolution of VM identity for attachments to ensure consistent validation. * **Tests** * Added comprehensive unit tests covering single/multiple pod scenarios, VM ownership, hotplug disks, upgrade paths, and legacy volumes. ✏️ Tip: You can customize this high-level summary in your review settings. --- .../patches/001-rwx-validation.diff | 62 ++----------------- 1 file changed, 4 insertions(+), 58 deletions(-) diff --git a/packages/system/linstor/images/linstor-csi/patches/001-rwx-validation.diff b/packages/system/linstor/images/linstor-csi/patches/001-rwx-validation.diff index f6f0d83d..9c26f565 100644 --- a/packages/system/linstor/images/linstor-csi/patches/001-rwx-validation.diff +++ b/packages/system/linstor/images/linstor-csi/patches/001-rwx-validation.diff @@ -1,25 +1,8 @@ diff --git a/pkg/driver/driver.go b/pkg/driver/driver.go -index bea69a8..848bd5b 100644 +index bea69a8..69e71a6 100644 --- a/pkg/driver/driver.go +++ b/pkg/driver/driver.go -@@ -401,6 +401,16 @@ func (d Driver) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolum - } - } - -+ // Validate RWX block volumes on node side using local filesystem check -+ // This provides protection for the edge case where two pods from different VMs land on the same node -+ if req.GetVolumeCapability().GetBlock() != nil && -+ req.GetVolumeCapability().GetAccessMode().GetMode() == csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER { -+ if err := d.validateRWXBlockOnNode(ctx, req.GetVolumeId(), req.GetTargetPath()); err != nil { -+ return nil, status.Errorf(codes.FailedPrecondition, -+ "NodePublishVolume failed for %s: %v", req.GetVolumeId(), err) -+ } -+ } -+ - if block := req.GetVolumeCapability().GetBlock(); block != nil { - volCtx.MountOptions = []string{"bind"} - } -@@ -707,6 +717,255 @@ func (d Driver) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest) +@@ -707,6 +707,219 @@ func (d Driver) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest) return &csi.DeleteVolumeResponse{}, nil } @@ -235,54 +218,17 @@ index bea69a8..848bd5b 100644 + + return vmName, nil +} -+ -+// validateRWXBlockOnNode performs node-side validation of RWX block volumes using local filesystem check. -+// This provides protection against the edge case where two pods from different VMs land on the same node. -+// Since ControllerPublishVolume is called only once per (volumeID, nodeID) pair, not per pod, -+// we need to check if the volume is already mounted for another pod on this node. -+func (d Driver) validateRWXBlockOnNode(ctx context.Context, volumeID, targetPath string) error { -+ // Extract base directory for this volume (contains subdirectories per pod UID) -+ baseDir := filepath.Dir(targetPath) -+ -+ // List existing mounts for this volume -+ entries, err := os.ReadDir(baseDir) -+ if err != nil { -+ if os.IsNotExist(err) { -+ // Directory doesn't exist yet - first mount -+ return nil -+ } -+ -+ d.log.WithError(err).Warn("cannot check existing mounts for RWX validation") -+ -+ return nil -+ } -+ -+ // If there are already other mounts, block the second one -+ if len(entries) > 0 { -+ d.log.WithFields(logrus.Fields{ -+ "volumeID": volumeID, -+ "existingMounts": len(entries), -+ "baseDir": baseDir, -+ }).Warn("blocking RWX block volume mount: already mounted for another pod on this node") -+ -+ return fmt.Errorf("RWX block volume is already mounted for another pod on this node - " + -+ "multiple pods on the same node sharing a block device is not supported (only for live migration across nodes)") -+ } -+ -+ return nil -+} + // ControllerPublishVolume https://github.com/container-storage-interface/spec/blob/v1.9.0/spec.md#controllerpublishvolume func (d Driver) ControllerPublishVolume(ctx context.Context, req *csi.ControllerPublishVolumeRequest) (*csi.ControllerPublishVolumeResponse, error) { if req.GetVolumeId() == "" { -@@ -751,6 +1010,15 @@ func (d Driver) ControllerPublishVolume(ctx context.Context, req *csi.Controller +@@ -751,6 +964,14 @@ func (d Driver) ControllerPublishVolume(ctx context.Context, req *csi.Controller // ReadWriteMany block volume rwxBlock := req.VolumeCapability.AccessMode.GetMode() == csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER && req.VolumeCapability.GetBlock() != nil + // Validate RWX block attachment to prevent misuse of allow-two-primaries + if rwxBlock { -+ _, err := d.validateRWXBlockAttachment(ctx, req.GetVolumeId()) -+ if err != nil { ++ if _, err := d.validateRWXBlockAttachment(ctx, req.GetVolumeId()); err != nil { + return nil, status.Errorf(codes.FailedPrecondition, + "ControllerPublishVolume failed for %s: %v", req.GetVolumeId(), err) + } From e73bf9905da70801bb3a702fb53cf0c07170f089 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Tue, 13 Jan 2026 13:18:13 +0100 Subject: [PATCH 64/78] [linstor] Refactor node-level RWX validation Signed-off-by: Andrei Kvapil (cherry picked from commit 3c4f0cd952e91ec54ddb26aaae2f550ebd93a320) --- .../patches/001-rwx-validation.diff | 386 ++++++++++++------ 1 file changed, 253 insertions(+), 133 deletions(-) diff --git a/packages/system/linstor/images/linstor-csi/patches/001-rwx-validation.diff b/packages/system/linstor/images/linstor-csi/patches/001-rwx-validation.diff index 9c26f565..7da0f137 100644 --- a/packages/system/linstor/images/linstor-csi/patches/001-rwx-validation.diff +++ b/packages/system/linstor/images/linstor-csi/patches/001-rwx-validation.diff @@ -1,100 +1,202 @@ +diff --git a/cmd/linstor-csi/linstor-csi.go b/cmd/linstor-csi/linstor-csi.go +index 143f6cee..bd28e06e 100644 +--- a/cmd/linstor-csi/linstor-csi.go ++++ b/cmd/linstor-csi/linstor-csi.go +@@ -41,22 +41,23 @@ import ( + + func main() { + var ( +- lsEndpoint = flag.String("linstor-endpoint", "", "Controller API endpoint for LINSTOR") +- lsSkipTLSVerification = flag.Bool("linstor-skip-tls-verification", false, "If true, do not verify tls") +- csiEndpoint = flag.String("csi-endpoint", "unix:///var/lib/kubelet/plugins/linstor.csi.linbit.com/csi.sock", "CSI endpoint") +- node = flag.String("node", "", "Node ID to pass to node service") +- logLevel = flag.String("log-level", "info", "Enable debug log output. Choose from: panic, fatal, error, warn, info, debug") +- rps = flag.Float64("linstor-api-requests-per-second", 0, "Maximum allowed number of LINSTOR API requests per second. Default: Unlimited") +- burst = flag.Int("linstor-api-burst", 1, "Maximum number of API requests allowed before being limited by requests-per-second. Default: 1 (no bursting)") +- bearerTokenFile = flag.String("bearer-token", "", "Read the bearer token from the given file and use it for authentication.") +- propNs = flag.String("property-namespace", linstor.NamespcAuxiliary, "Limit the reported topology keys to properties from the given namespace.") +- labelBySP = flag.Bool("label-by-storage-pool", true, "Set to false to disable labeling of nodes based on their configured storage pools.") +- nodeCacheTimeout = flag.Duration("node-cache-timeout", 1*time.Minute, "Duration for which the results of node and storage pool related API responses should be cached.") +- resourceCacheTimeout = flag.Duration("resource-cache-timeout", 30*time.Second, "Duration for which the results of resource related API responses should be cached.") +- resyncAfter = flag.Duration("resync-after", 5*time.Minute, "Duration after which reconciliations (such as for VolumeSnapshotClasses) should be rerun. Set to 0 to disable.") +- enableRWX = flag.Bool("enable-rwx", false, "Enable RWX support via NFS (requires running in Kubernetes).") +- namespace = flag.String("nfs-service-namespace", "", "The namespace the NFS service is running in.") +- reactorConfigMapName = flag.String("nfs-reactor-config-map-name", "linstor-csi-nfs-reactor-config", "Name of the config map used to store promoter configuration") ++ lsEndpoint = flag.String("linstor-endpoint", "", "Controller API endpoint for LINSTOR") ++ lsSkipTLSVerification = flag.Bool("linstor-skip-tls-verification", false, "If true, do not verify tls") ++ csiEndpoint = flag.String("csi-endpoint", "unix:///var/lib/kubelet/plugins/linstor.csi.linbit.com/csi.sock", "CSI endpoint") ++ node = flag.String("node", "", "Node ID to pass to node service") ++ logLevel = flag.String("log-level", "info", "Enable debug log output. Choose from: panic, fatal, error, warn, info, debug") ++ rps = flag.Float64("linstor-api-requests-per-second", 0, "Maximum allowed number of LINSTOR API requests per second. Default: Unlimited") ++ burst = flag.Int("linstor-api-burst", 1, "Maximum number of API requests allowed before being limited by requests-per-second. Default: 1 (no bursting)") ++ bearerTokenFile = flag.String("bearer-token", "", "Read the bearer token from the given file and use it for authentication.") ++ propNs = flag.String("property-namespace", linstor.NamespcAuxiliary, "Limit the reported topology keys to properties from the given namespace.") ++ labelBySP = flag.Bool("label-by-storage-pool", true, "Set to false to disable labeling of nodes based on their configured storage pools.") ++ nodeCacheTimeout = flag.Duration("node-cache-timeout", 1*time.Minute, "Duration for which the results of node and storage pool related API responses should be cached.") ++ resourceCacheTimeout = flag.Duration("resource-cache-timeout", 30*time.Second, "Duration for which the results of resource related API responses should be cached.") ++ resyncAfter = flag.Duration("resync-after", 5*time.Minute, "Duration after which reconciliations (such as for VolumeSnapshotClasses) should be rerun. Set to 0 to disable.") ++ enableRWX = flag.Bool("enable-rwx", false, "Enable RWX support via NFS (requires running in Kubernetes).") ++ namespace = flag.String("nfs-service-namespace", "", "The namespace the NFS service is running in.") ++ reactorConfigMapName = flag.String("nfs-reactor-config-map-name", "linstor-csi-nfs-reactor-config", "Name of the config map used to store promoter configuration") ++ disableRWXBlockValidation = flag.Bool("disable-rwx-block-validation", false, "Disable KubeVirt VM ownership validation for RWX block volumes.") + ) + + flag.Var(&volume.DefaultRemoteAccessPolicy, "default-remote-access-policy", "") +@@ -169,6 +170,10 @@ func main() { + opts = append(opts, driver.ConfigureRWX(*namespace, *reactorConfigMapName)) + } + ++ if *disableRWXBlockValidation { ++ opts = append(opts, driver.DisableRWXBlockValidation()) ++ } ++ + drv, err := driver.NewDriver(opts...) + if err != nil { + log.Fatal(err) diff --git a/pkg/driver/driver.go b/pkg/driver/driver.go -index bea69a8..69e71a6 100644 +index bea69a8b..a39674b6 100644 --- a/pkg/driver/driver.go +++ b/pkg/driver/driver.go -@@ -707,6 +707,219 @@ func (d Driver) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest) - return &csi.DeleteVolumeResponse{}, nil +@@ -83,6 +83,8 @@ type Driver struct { + topologyPrefix string + // resyncAfter is the interval after which reconciliations should be retried + resyncAfter time.Duration ++ // disableRWXBlockValidation disables KubeVirt VM ownership validation for RWX block volumes ++ disableRWXBlockValidation bool + + // Embed for forward compatibility. + csi.UnimplementedIdentityServer +@@ -300,6 +302,17 @@ func ResyncAfter(resyncAfter time.Duration) func(*Driver) error { + } } ++// DisableRWXBlockValidation disables the KubeVirt VM ownership validation for RWX block volumes. ++// When disabled, the driver will not check if multiple pods using the same RWX block volume ++// belong to the same VM. This may be needed in environments where the validation causes issues ++// or when using RWX block volumes outside of KubeVirt. ++func DisableRWXBlockValidation() func(*Driver) error { ++ return func(d *Driver) error { ++ d.disableRWXBlockValidation = true ++ return nil ++ } ++} ++ + // GetPluginInfo https://github.com/container-storage-interface/spec/blob/v1.9.0/spec.md#getplugininfo + func (d Driver) GetPluginInfo(ctx context.Context, req *csi.GetPluginInfoRequest) (*csi.GetPluginInfoResponse, error) { + return &csi.GetPluginInfoResponse{ +@@ -751,6 +764,14 @@ func (d Driver) ControllerPublishVolume(ctx context.Context, req *csi.Controller + // ReadWriteMany block volume + rwxBlock := req.VolumeCapability.AccessMode.GetMode() == csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER && req.VolumeCapability.GetBlock() != nil + ++ // Validate RWX block attachment to prevent misuse of allow-two-primaries ++ if rwxBlock && !d.disableRWXBlockValidation { ++ if _, err := utils.ValidateRWXBlockAttachment(ctx, d.kubeClient, d.log, req.GetVolumeId()); err != nil { ++ return nil, status.Errorf(codes.FailedPrecondition, ++ "ControllerPublishVolume failed for %s: %v", req.GetVolumeId(), err) ++ } ++ } ++ + devPath, err := d.Assignments.Attach(ctx, req.GetVolumeId(), req.GetNodeId(), rwxBlock) + if err != nil { + return nil, status.Errorf(codes.Internal, +diff --git a/pkg/utils/rwx_validation.go b/pkg/utils/rwx_validation.go +new file mode 100644 +index 00000000..9fe82768 +--- /dev/null ++++ b/pkg/utils/rwx_validation.go +@@ -0,0 +1,263 @@ ++/* ++CSI Driver for Linstor ++Copyright © 2018 LINBIT USA, LLC ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, see . ++*/ ++ ++package utils ++ ++import ( ++ "context" ++ "fmt" ++ ++ "github.com/sirupsen/logrus" ++ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ++ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ++ "k8s.io/apimachinery/pkg/runtime/schema" ++ "k8s.io/client-go/dynamic" ++) ++ +// KubeVirtVMLabel is the label that KubeVirt adds to pods to identify the VM they belong to. +const KubeVirtVMLabel = "vm.kubevirt.io/name" + +// KubeVirtHotplugDiskLabel is the label that KubeVirt adds to hotplug disk pods. +const KubeVirtHotplugDiskLabel = "kubevirt.io" + -+// podGVR is the GroupVersionResource for pods. -+var podGVR = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"} ++// PodGVR is the GroupVersionResource for pods. ++var PodGVR = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"} + -+// pvGVR is the GroupVersionResource for persistent volumes. -+var pvGVR = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "persistentvolumes"} ++// PVGVR is the GroupVersionResource for persistent volumes. ++var PVGVR = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "persistentvolumes"} + -+// getVMNameFromPod extracts the VM name from a pod, handling both regular virt-launcher pods -+// and hotplug disk pods (which reference the virt-launcher pod via ownerReferences). -+func (d Driver) getVMNameFromPod(ctx context.Context, pod *unstructured.Unstructured) (string, error) { -+ labels := pod.GetLabels() -+ if labels == nil { -+ return "", nil -+ } -+ -+ // Direct case: pod has vm.kubevirt.io/name label (virt-launcher pod) -+ if vmName, ok := labels[KubeVirtVMLabel]; ok && vmName != "" { -+ return vmName, nil -+ } -+ -+ // Hotplug disk case: pod has kubevirt.io: hotplug-disk label -+ // Follow ownerReferences to find the virt-launcher pod -+ if hotplugValue, ok := labels[KubeVirtHotplugDiskLabel]; ok && hotplugValue == "hotplug-disk" { -+ ownerRefs := pod.GetOwnerReferences() -+ for _, owner := range ownerRefs { -+ if owner.Kind != "Pod" || owner.Controller == nil || !*owner.Controller { -+ continue -+ } -+ -+ // Get the owner pod (virt-launcher) -+ ownerPod, err := d.kubeClient.Resource(podGVR).Namespace(pod.GetNamespace()).Get(ctx, owner.Name, metav1.GetOptions{}) -+ if err != nil { -+ return "", fmt.Errorf("failed to get owner pod %s: %w", owner.Name, err) -+ } -+ -+ // Extract VM name from owner pod -+ ownerLabels := ownerPod.GetLabels() -+ if ownerLabels != nil { -+ if vmName, ok := ownerLabels[KubeVirtVMLabel]; ok && vmName != "" { -+ d.log.WithFields(logrus.Fields{ -+ "hotplugPod": pod.GetName(), -+ "virtLauncher": owner.Name, -+ "vmName": vmName, -+ }).Debug("resolved VM name from hotplug disk pod via owner reference") -+ -+ return vmName, nil -+ } -+ } -+ -+ return "", fmt.Errorf("owner pod %s does not have %s label", owner.Name, KubeVirtVMLabel) -+ } -+ -+ return "", fmt.Errorf("hotplug disk pod %s has no controller owner reference", pod.GetName()) -+ } -+ -+ return "", nil -+} -+ -+// validateRWXBlockAttachment checks that RWX block volumes are only used by pods belonging to the same VM. ++// ValidateRWXBlockAttachment checks that RWX block volumes are only used by pods belonging to the same VM. +// This prevents misuse of allow-two-primaries while still permitting live migration. +// Returns the VM name if validation passes, or an error if: +// - Multiple pods from different VMs are trying to use the same volume +// - A pod without the KubeVirt VM label is trying to use a volume already attached elsewhere (strict mode) +// Returns empty string for VM name when no pods are using the volume or validation is skipped. -+func (d Driver) validateRWXBlockAttachment(ctx context.Context, volumeID string) (string, error) { -+ d.log.WithField("volumeID", volumeID).Info("validateRWXBlockAttachment called") ++func ValidateRWXBlockAttachment(ctx context.Context, kubeClient dynamic.Interface, log *logrus.Entry, volumeID string) (string, error) { ++ log.WithField("volumeID", volumeID).Info("validateRWXBlockAttachment called") + -+ if d.kubeClient == nil { ++ if kubeClient == nil { + // Not running in Kubernetes, skip validation -+ d.log.Warn("validateRWXBlockAttachment: kubeClient is nil, skipping validation") ++ log.Warn("validateRWXBlockAttachment: kubeClient is nil, skipping validation") + return "", nil + } + -+ // Get PV to find PVC reference (volumeID == PV name in CSI) -+ pv, err := d.kubeClient.Resource(pvGVR).Get(ctx, volumeID, metav1.GetOptions{}) ++ // Get PV to find PVC reference ++ pv, err := kubeClient.Resource(PVGVR).Get(ctx, volumeID, metav1.GetOptions{}) + if err != nil { -+ d.log.WithError(err).Warn("cannot validate RWX attachment: failed to get PV") ++ log.WithError(err).Warn("cannot validate RWX attachment: failed to get PV") ++ return "", nil ++ } ++ ++ // Verify that PV's volumeHandle matches the volumeID ++ volumeHandle, found, err := unstructured.NestedString(pv.Object, "spec", "csi", "volumeHandle") ++ if err != nil { ++ log.WithError(err).Warnf("cannot validate RWX attachment: failed to read volumeHandle for PV %s", volumeID) ++ ++ return "", nil ++ } ++ ++ if !found { ++ log.Warnf("cannot validate RWX attachment: volumeHandle not found for PV %s", volumeID) ++ ++ return "", nil ++ } ++ ++ if volumeHandle != volumeID { ++ log.WithFields(logrus.Fields{ ++ "volumeID": volumeID, ++ "volumeHandle": volumeHandle, ++ }).Warn("cannot validate RWX attachment: PV volumeHandle does not match volumeID") ++ + return "", nil + } + + // Extract claimRef from PV + claimRef, found, _ := unstructured.NestedMap(pv.Object, "spec", "claimRef") + if !found { -+ d.log.Warn("cannot validate RWX attachment: PV has no claimRef") ++ log.Warn("cannot validate RWX attachment: PV has no claimRef") + return "", nil + } + @@ -102,12 +204,12 @@ index bea69a8..69e71a6 100644 + pvcNamespace, _, _ := unstructured.NestedString(claimRef, "namespace") + + if pvcNamespace == "" || pvcName == "" { -+ d.log.Warn("cannot validate RWX attachment: PVC name or namespace is empty in claimRef") ++ log.Warn("cannot validate RWX attachment: PVC name or namespace is empty in claimRef") + return "", nil + } + + // List all pods in the namespace -+ podList, err := d.kubeClient.Resource(podGVR).Namespace(pvcNamespace).List(ctx, metav1.ListOptions{}) ++ podList, err := kubeClient.Resource(PodGVR).Namespace(pvcNamespace).List(ctx, metav1.ListOptions{}) + if err != nil { + return "", fmt.Errorf("failed to list pods in namespace %s: %w", pvcNamespace, err) + } @@ -139,28 +241,25 @@ index bea69a8..69e71a6 100644 + continue + } + -+ pvc, found, _ := unstructured.NestedMap(volMap, "persistentVolumeClaim") -+ if !found { ++ claimName, found, _ := unstructured.NestedString(volMap, "persistentVolumeClaim", "claimName") ++ if !found || claimName != pvcName { + continue + } + -+ claimName, _, _ := unstructured.NestedString(pvc, "claimName") -+ if claimName == pvcName { -+ // Extract VM name, handling both regular and hotplug disk pods -+ vmName, err := d.getVMNameFromPod(ctx, &item) -+ if err != nil { -+ d.log.WithError(err).WithField("pod", item.GetName()).Warn("failed to get VM name from pod") -+ // Continue with empty vmName - will be caught by strict mode check -+ vmName = "" -+ } -+ -+ podsUsingPVC = append(podsUsingPVC, podInfo{ -+ name: item.GetName(), -+ vmName: vmName, -+ }) -+ -+ break ++ // Extract VM name, handling both regular and hotplug disk pods ++ vmName, err := GetVMNameFromPod(ctx, kubeClient, log, &item) ++ if err != nil { ++ log.WithError(err).WithField("pod", item.GetName()).Warn("failed to get VM name from pod") ++ // Continue with empty vmName - will be caught by strict mode check ++ vmName = "" + } ++ ++ podsUsingPVC = append(podsUsingPVC, podInfo{ ++ name: item.GetName(), ++ vmName: vmName, ++ }) ++ ++ break + } + } + @@ -168,7 +267,7 @@ index bea69a8..69e71a6 100644 + if len(podsUsingPVC) <= 1 { + // Return VM name if there's exactly one pod + if len(podsUsingPVC) == 1 { -+ d.log.WithFields(logrus.Fields{ ++ log.WithFields(logrus.Fields{ + "volumeID": volumeID, + "vmName": podsUsingPVC[0].vmName, + "podCount": 1, @@ -179,7 +278,7 @@ index bea69a8..69e71a6 100644 + return podsUsingPVC[0].vmName, nil + } + -+ d.log.WithFields(logrus.Fields{ ++ log.WithFields(logrus.Fields{ + "volumeID": volumeID, + "pvcNamespace": pvcNamespace, + "pvcName": pvcName, @@ -209,7 +308,7 @@ index bea69a8..69e71a6 100644 + } + } + -+ d.log.WithFields(logrus.Fields{ ++ log.WithFields(logrus.Fields{ + "pvcNamespace": pvcNamespace, + "pvcName": pvcName, + "vmName": vmName, @@ -219,30 +318,62 @@ index bea69a8..69e71a6 100644 + return vmName, nil +} + - // ControllerPublishVolume https://github.com/container-storage-interface/spec/blob/v1.9.0/spec.md#controllerpublishvolume - func (d Driver) ControllerPublishVolume(ctx context.Context, req *csi.ControllerPublishVolumeRequest) (*csi.ControllerPublishVolumeResponse, error) { - if req.GetVolumeId() == "" { -@@ -751,6 +964,14 @@ func (d Driver) ControllerPublishVolume(ctx context.Context, req *csi.Controller - // ReadWriteMany block volume - rwxBlock := req.VolumeCapability.AccessMode.GetMode() == csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER && req.VolumeCapability.GetBlock() != nil - -+ // Validate RWX block attachment to prevent misuse of allow-two-primaries -+ if rwxBlock { -+ if _, err := d.validateRWXBlockAttachment(ctx, req.GetVolumeId()); err != nil { -+ return nil, status.Errorf(codes.FailedPrecondition, -+ "ControllerPublishVolume failed for %s: %v", req.GetVolumeId(), err) -+ } ++// GetVMNameFromPod extracts the VM name from a pod, handling both regular virt-launcher pods ++// and hotplug disk pods (which reference the virt-launcher pod via ownerReferences). ++func GetVMNameFromPod(ctx context.Context, kubeClient dynamic.Interface, log *logrus.Entry, pod *unstructured.Unstructured) (string, error) { ++ labels := pod.GetLabels() ++ if labels == nil { ++ return "", nil + } + - devPath, err := d.Assignments.Attach(ctx, req.GetVolumeId(), req.GetNodeId(), rwxBlock) - if err != nil { - return nil, status.Errorf(codes.Internal, -diff --git a/pkg/driver/rwx_validation_test.go b/pkg/driver/rwx_validation_test.go ++ // Direct case: pod has vm.kubevirt.io/name label (virt-launcher pod) ++ if vmName, ok := labels[KubeVirtVMLabel]; ok && vmName != "" { ++ return vmName, nil ++ } ++ ++ // Hotplug disk case: pod has kubevirt.io: hotplug-disk label ++ // Follow ownerReferences to find the virt-launcher pod ++ if hotplugValue, ok := labels[KubeVirtHotplugDiskLabel]; ok && hotplugValue == "hotplug-disk" { ++ ownerRefs := pod.GetOwnerReferences() ++ for _, owner := range ownerRefs { ++ if owner.Kind != "Pod" || owner.Controller == nil || !*owner.Controller { ++ continue ++ } ++ ++ // Get the owner pod (virt-launcher) ++ ownerPod, err := kubeClient.Resource(PodGVR).Namespace(pod.GetNamespace()).Get(ctx, owner.Name, metav1.GetOptions{}) ++ if err != nil { ++ return "", fmt.Errorf("failed to get owner pod %s: %w", owner.Name, err) ++ } ++ ++ // Extract VM name from owner pod ++ ownerLabels := ownerPod.GetLabels() ++ if ownerLabels != nil { ++ if vmName, ok := ownerLabels[KubeVirtVMLabel]; ok && vmName != "" { ++ log.WithFields(logrus.Fields{ ++ "hotplugPod": pod.GetName(), ++ "virtLauncher": owner.Name, ++ "vmName": vmName, ++ }).Debug("resolved VM name from hotplug disk pod via owner reference") ++ ++ return vmName, nil ++ } ++ } ++ ++ return "", fmt.Errorf("owner pod %s does not have %s label", owner.Name, KubeVirtVMLabel) ++ } ++ ++ return "", fmt.Errorf("hotplug disk pod %s has no controller owner reference", pod.GetName()) ++ } ++ ++ return "", nil ++} +diff --git a/pkg/utils/rwx_validation_test.go b/pkg/utils/rwx_validation_test.go new file mode 100644 -index 0000000..92c1046 +index 00000000..d75690f9 --- /dev/null -+++ b/pkg/driver/rwx_validation_test.go -@@ -0,0 +1,353 @@ ++++ b/pkg/utils/rwx_validation_test.go +@@ -0,0 +1,342 @@ +/* +CSI Driver for Linstor +Copyright © 2018 LINBIT USA, LLC @@ -261,7 +392,7 @@ index 0000000..92c1046 +along with this program; if not, see . +*/ + -+package driver ++package utils + +import ( + "context" @@ -424,22 +555,17 @@ index 0000000..92c1046 + } + + gvrToListKind := map[schema.GroupVersionResource]string{ -+ podGVR: "PodList", -+ pvGVR: "PersistentVolumeList", ++ PodGVR: "PodList", ++ PVGVR: "PersistentVolumeList", + } + client := dynamicfake.NewSimpleDynamicClientWithCustomListKinds(scheme, gvrToListKind, objects...) + -+ // Create driver with fake client ++ // Create logger + logger := logrus.NewEntry(logrus.New()) + logger.Logger.SetLevel(logrus.DebugLevel) + -+ driver := &Driver{ -+ kubeClient: client, -+ log: logger, -+ } -+ + // Run validation -+ vmName, err := driver.validateRWXBlockAttachment(context.Background(), "test-volume-id") ++ vmName, err := ValidateRWXBlockAttachment(context.Background(), client, logger, "test-volume-id") + + if tc.expectError { + assert.Error(t, err) @@ -461,12 +587,8 @@ index 0000000..92c1046 +func TestValidateRWXBlockAttachmentNoKubeClient(t *testing.T) { + // When not running in Kubernetes (no client), validation should be skipped + logger := logrus.NewEntry(logrus.New()) -+ driver := &Driver{ -+ kubeClient: nil, -+ log: logger, -+ } + -+ vmName, err := driver.validateRWXBlockAttachment(context.Background(), "test-volume-id") ++ vmName, err := ValidateRWXBlockAttachment(context.Background(), nil, logger, "test-volume-id") + assert.NoError(t, err) + assert.Empty(t, vmName) +} @@ -476,20 +598,15 @@ index 0000000..92c1046 + scheme := runtime.NewScheme() + + gvrToListKind := map[schema.GroupVersionResource]string{ -+ podGVR: "PodList", -+ pvGVR: "PersistentVolumeList", ++ PodGVR: "PodList", ++ PVGVR: "PersistentVolumeList", + } + client := dynamicfake.NewSimpleDynamicClientWithCustomListKinds(scheme, gvrToListKind) + + logger := logrus.NewEntry(logrus.New()) + logger.Logger.SetLevel(logrus.DebugLevel) + -+ driver := &Driver{ -+ kubeClient: client, -+ log: logger, -+ } -+ -+ vmName, err := driver.validateRWXBlockAttachment(context.Background(), "non-existent-pv") ++ vmName, err := ValidateRWXBlockAttachment(context.Background(), client, logger, "non-existent-pv") + assert.NoError(t, err) + assert.Empty(t, vmName) +} @@ -538,6 +655,9 @@ index 0000000..92c1046 + "name": pvcName, + "namespace": pvcNamespace, + }, ++ "csi": map[string]interface{}{ ++ "volumeHandle": name, ++ }, + }, + }, + } From 7b932a400dd2fd314a0ecd5a9f79cbfa7828ca5b Mon Sep 17 00:00:00 2001 From: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> Date: Tue, 13 Jan 2026 12:32:18 +0000 Subject: [PATCH 65/78] Prepare release v0.40.2 Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> --- packages/apps/kubernetes/images/kubevirt-csi-driver.tag | 2 +- packages/core/installer/values.yaml | 2 +- packages/core/platform/values.yaml | 2 +- packages/core/testing/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- packages/extra/seaweedfs/images/objectstorage-sidecar.tag | 2 +- packages/system/bucket/images/s3manager.tag | 2 +- packages/system/cozystack-api/values.yaml | 2 +- packages/system/cozystack-controller/values.yaml | 4 ++-- packages/system/dashboard/templates/configmap.yaml | 2 +- packages/system/dashboard/values.yaml | 6 +++--- packages/system/kamaji/values.yaml | 4 ++-- packages/system/kubeovn-plunger/values.yaml | 2 +- packages/system/kubeovn-webhook/values.yaml | 2 +- packages/system/kubevirt-csi-node/values.yaml | 2 +- packages/system/lineage-controller-webhook/values.yaml | 2 +- packages/system/linstor/values.yaml | 3 +-- packages/system/objectstorage-controller/values.yaml | 2 +- packages/system/seaweedfs/values.yaml | 2 +- 19 files changed, 23 insertions(+), 24 deletions(-) diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag index ccb369a3..326da62f 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:b42c6af641ee0eadb7e0a42e368021b4759f443cb7b71b7e745a64f0fc8b752e +ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:0e5d8bbdc587a96e07bbf263f23d4d237dac8bd4528b34f44d31b042c6a0e495 diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index d08a5a82..72d6a32a 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.40.1@sha256:69a8f95b8ddcf122a8859a957017b3d9e33c5eca3bfbf30c112c109e355f4f1c + image: ghcr.io/cozystack/cozystack/installer:v0.40.2@sha256:146e0de9d1208eba8342277fa08e0588d66e51bc637c6b3add8ef63cc54ef351 diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index 84efcb78..26d0859c 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -1,2 +1,2 @@ assets: - image: ghcr.io/cozystack/cozystack/cozystack-assets:v0.40.1@sha256:ee1248692753820fe11139789680fd24dc4dbdba85a6cb70e086447d9b9b1d99 + image: ghcr.io/cozystack/cozystack/cozystack-assets:v0.40.2@sha256:02730e6a434a8367a970c00a1feaa31f19a856641f6c1d085afed88e9c0b8b2b diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index 90a9ed18..b00e9ea3 100644 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.40.1@sha256:78a556a059411cac89249c2e22596223128a1c74fbfcac4787fd74e4a66f66a6 + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.40.2@sha256:78a556a059411cac89249c2e22596223128a1c74fbfcac4787fd74e4a66f66a6 diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index aa8ecbfd..522bb744 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.40.1@sha256:293d562c134fc4ee0a9a756df32422b849715fe25a2120b69cb415ca98217363 +ghcr.io/cozystack/cozystack/matchbox:v0.40.2@sha256:f72d35fc691021d6b473360f2edaf0b1f176f737ca18f8cb9322d16c69705020 diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag index 1724acc3..90d0d249 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:v0.40.1@sha256:4bb47c8adb34543403a16d1ff61b307939850e8cf5fc365388469e30dfb9681b +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.40.2@sha256:6735e6f050355355a13439ff815539a1b92eba09623e500e92dd7d4e600c59b4 diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index 3574feff..b71ecf9e 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:ecb140d026ed72660306953a7eec140d7ac81e79544d5bbf1aba5f62aa5f8b69 +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:07f016720c4692fc270a415a327a88773b90d2821922098496ad1269beac6c94 diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 10a79b25..04e86c7c 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,5 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.40.1@sha256:408885b509d80ca30a85416f87d07112bc7f070374e71e80b64818fbb24ad1ee + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.40.2@sha256:408885b509d80ca30a85416f87d07112bc7f070374e71e80b64818fbb24ad1ee localK8sAPIEndpoint: enabled: true replicas: 2 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index a28c13c5..de8eedd5 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,6 +1,6 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.40.1@sha256:75636007f63e1b2cb51fc2e70782b707330d1e728c32642a4edc500b614f0781 + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.40.2@sha256:1878af4389ee3ddc85f2079cc250bccc14b923fb74c665c9aa902a659a394ba6 debug: false disableTelemetry: false - cozystackVersion: "v0.40.1" + cozystackVersion: "v0.40.2" cozystackAPIKind: "DaemonSet" diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index 861d4eed..a929b0b1 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,6 +1,6 @@ {{- $brandingConfig := .Values._cluster.branding | default dict }} -{{- $tenantText := "v0.40.1" }} +{{- $tenantText := "v0.40.2" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} {{- $logoText := "" }} diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index 94c395bb..091aaa4d 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v0.40.1@sha256:a427114308b9c87ab71b50980cba0d673a730791629164335d2046f7d1740327 + image: ghcr.io/cozystack/cozystack/openapi-ui:v0.40.2@sha256:a8d3770107c0279add903e6b5acdc5ca8a15551fb07514e40772f8010c5386ef openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.40.1@sha256:fda379dce49c2cd8cb8d7d2a1d8ec6f7bedb3419c058c4355ecdece1c1e937f4 + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.40.2@sha256:3071dfc130dbaf185b1a46ed42f0800824e77c2f4e64c5ed87055311f3c5f2b1 tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:v0.40.1@sha256:4fc8a11f8a1a81aa0774ae2b1ed2e05d36d0b3ef1e37979cc4994e65114d93ae + image: ghcr.io/cozystack/cozystack/token-proxy:v0.40.2@sha256:4fc8a11f8a1a81aa0774ae2b1ed2e05d36d0b3ef1e37979cc4994e65114d93ae diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index 35c15ef9..4aea9c22 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.40.1@sha256:0bcfb2d376224b18a0627d7b18ba6202bb8a553f71796023e12740d9513740c7 + tag: v0.40.2@sha256:cf9aae159deb586b1af5e5f6299247fe82f01646d58102bf5ca264c40f9edda2 repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: @@ -13,4 +13,4 @@ kamaji: cpu: 100m memory: 100Mi extraArgs: - - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.40.1@sha256:0bcfb2d376224b18a0627d7b18ba6202bb8a553f71796023e12740d9513740c7 + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.40.2@sha256:cf9aae159deb586b1af5e5f6299247fe82f01646d58102bf5ca264c40f9edda2 diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml index 10d8508a..4229b116 100644 --- a/packages/system/kubeovn-plunger/values.yaml +++ b/packages/system/kubeovn-plunger/values.yaml @@ -1,4 +1,4 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.40.1@sha256:2a17dfa8eec0fc6b2adb564742e74f35bd68ac0d29e5ab1d007496aff3c0e97d +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.40.2@sha256:fdcc081d3c28a023a6950deac4d6124a0290d1bb4bd13c8c723569ac40d6874e ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index c60ff144..6ec8f26e 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.40.1@sha256:e6334c29d3aaf0dea766c88e3e05b53ad623d1bb497b3c836e6f76adade45b29 +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.40.2@sha256:e6334c29d3aaf0dea766c88e3e05b53ad623d1bb497b3c836e6f76adade45b29 diff --git a/packages/system/kubevirt-csi-node/values.yaml b/packages/system/kubevirt-csi-node/values.yaml index 4111f825..d3fac521 100644 --- a/packages/system/kubevirt-csi-node/values.yaml +++ b/packages/system/kubevirt-csi-node/values.yaml @@ -1,3 +1,3 @@ storageClass: replicated csiDriver: - image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:b42c6af641ee0eadb7e0a42e368021b4759f443cb7b71b7e745a64f0fc8b752e + image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:0e5d8bbdc587a96e07bbf263f23d4d237dac8bd4528b34f44d31b042c6a0e495 diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index 55cb019b..554d9ef2 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,5 +1,5 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.40.1@sha256:00650eb92c8b93a0afc382a0c5e46ade453e430867be7dab9647a6fc2896f097 + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.40.2@sha256:16a700334d4d9cebea2516874c04d0799a450052f3652a0c91668c37d1d0e227 debug: false localK8sAPIEndpoint: enabled: true diff --git a/packages/system/linstor/values.yaml b/packages/system/linstor/values.yaml index 173aacb4..da62e9da 100644 --- a/packages/system/linstor/values.yaml +++ b/packages/system/linstor/values.yaml @@ -7,8 +7,7 @@ linstor: enabled: true minutes: 30 allowCleanup: true - linstorCSI: image: repository: ghcr.io/cozystack/cozystack/linstor-csi - tag: latest@sha256:e8329b3e07c47ec73a7d9644535639fd80dbe5c27a7e03181b999ebe072a3a2e + tag: v1.10.5@sha256:276e35e644cc4f1a17bc3842ded84aef4d9a5d750b5bdf3fc7238e369e88ada8 diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml index aba36be8..041c3ad2 100644 --- a/packages/system/objectstorage-controller/values.yaml +++ b/packages/system/objectstorage-controller/values.yaml @@ -1,3 +1,3 @@ objectstorage: controller: - image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.40.1@sha256:e8f605a5ec4b801dfaf49aa7bce8d7a1ce28df578e23a0b859571f60f98efe8c" + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.40.2@sha256:f44845c034643c3b9040b70dc417e633d8ab0cc56a304a88dace733f2b4f1d70" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index fb3defa6..fd8f7ff0 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -177,7 +177,7 @@ seaweedfs: bucketClassName: "seaweedfs" region: "" sidecar: - image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.40.1@sha256:4bb47c8adb34543403a16d1ff61b307939850e8cf5fc365388469e30dfb9681b" + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.40.2@sha256:6735e6f050355355a13439ff815539a1b92eba09623e500e92dd7d4e600c59b4" certificates: commonName: "SeaweedFS CA" ipAddresses: [] From 4ddb374680621881557a24b780d9b56a734ac544 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Fri, 16 Jan 2026 17:16:23 +0100 Subject: [PATCH 66/78] [apiserver] Fix Watch resourceVersion and bookmark handling (#1860) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes aggregated API server Watch implementation to properly work with controller-runtime informers. External controllers watching Tenant resources via the aggregated API were experiencing issues with cache sync timeouts and missing reconciliations on startup. **ResourceVersion handling in List:** - Compute ResourceVersion from items when the cached client doesn't set it on the list itself **Bookmark handling:** - Pass through bookmark events with converted types for proper informer sync **ADDED event filtering (main fix):** - Simplified the filtering logic that was incorrectly skipping initial events - Only skip ADDED events when `startingRV > 0` AND `objRV <= startingRV` (client already has from List) - When `startingRV == 0`, always send ADDED events (client wants full state) - Removed the complex `initialSyncComplete` tracking that had inverted logic When a controller starts watching resources, controller-runtime may call Watch with `resourceVersion=""`. The server should send all existing objects as ADDED events. The previous `initialSyncComplete` logic was inverted and could skip these events, causing objects (like Tenants with lock annotations) to not be reconciled on controller startup. ```release-note [apiserver] Fix Watch resourceVersion and bookmark handling for controller-runtime compatibility ``` * **Improvements** * Enhanced resource watching and synchronization with Kubernetes 1.27+ compatibility, including proper handling of initial events and bookmarks. * Optimized event filtering and resource version tracking for applications, tenant modules, tenant namespaces, and tenant secrets to reduce unnecessary event noise. * Improved list metadata consistency by deriving accurate resource versions when unavailable in responses. ✏️ Tip: You can customize this high-level summary in your review settings. --- pkg/registry/apps/application/rest.go | 147 +++++++++++++++++++--- pkg/registry/core/tenantmodule/rest.go | 65 ++++++++-- pkg/registry/core/tenantnamespace/rest.go | 50 +++++++- pkg/registry/core/tenantsecret/rest.go | 54 +++++++- pkg/registry/utils.go | 57 +++++++++ 5 files changed, 349 insertions(+), 24 deletions(-) create mode 100644 pkg/registry/utils.go diff --git a/pkg/registry/apps/application/rest.go b/pkg/registry/apps/application/rest.go index 4f3204d5..aecf6935 100644 --- a/pkg/registry/apps/application/rest.go +++ b/pkg/registry/apps/application/rest.go @@ -21,6 +21,7 @@ import ( "encoding/json" "fmt" "net/http" + "strconv" "strings" "sync" "time" @@ -42,6 +43,7 @@ import ( appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" "github.com/cozystack/cozystack/pkg/config" + "github.com/cozystack/cozystack/pkg/registry" fieldfilter "github.com/cozystack/cozystack/pkg/registry/fields" "github.com/cozystack/cozystack/pkg/registry/sorting" internalapiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" @@ -249,7 +251,7 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption return nil, err } - klog.V(6).Infof("Attempting to list HelmReleases in namespace %s with options: %v", namespace, options) + klog.V(6).Infof("List called for %s in namespace %q", r.kindName, namespace) // Get resource name from the request (if any) var resourceName string @@ -402,12 +404,20 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption // Create ApplicationList with proper kind appList := r.NewList().(*appsv1alpha1.ApplicationList) - appList.SetResourceVersion(hrList.GetResourceVersion()) + + // Get ResourceVersion from list or compute from items + // controller-runtime cached client may not set ResourceVersion on the list itself + listRV := hrList.GetResourceVersion() + if listRV == "" { + listRV, _ = registry.MaxResourceVersion(hrList) + } + appList.SetResourceVersion(listRV) appList.Items = items sorting.ByNamespacedName[appsv1alpha1.Application, *appsv1alpha1.Application](appList.Items) - klog.V(6).Infof("Successfully listed %d Application resources in namespace %s", len(items), namespace) + klog.V(6).Infof("List returning %d items for %s in namespace %q, resourceVersion=%q", + len(items), r.kindName, namespace, appList.GetResourceVersion()) return appList, nil } @@ -572,7 +582,8 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio return nil, err } - klog.V(6).Infof("Setting up watch for HelmReleases in namespace %s with options: %v", namespace, options) + klog.V(6).Infof("Watch called for %s in namespace %q, resourceVersion=%q", + r.kindName, namespace, options.ResourceVersion) // Get request information, including resource name if specified var resourceName string @@ -636,6 +647,20 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio } helmLabelSelector = labels.NewSelector().Add(labelRequirements...) + // Handle SendInitialEvents for WatchList feature (Kubernetes 1.27+) + // When sendInitialEvents=true, the client expects: + // 1. All existing resources as ADDED events + // 2. A Bookmark event with "k8s.io/initial-events-end": "true" annotation + // controller-runtime cache already sends ADDED events for all cached objects, + // so we just need to send the bookmark after those initial events + sendInitialEvents := options.SendInitialEvents != nil && *options.SendInitialEvents + + // Create a custom watcher to transform events + customW := &customWatcher{ + resultChan: make(chan watch.Event), + stopChan: make(chan struct{}), + } + // Start watch on HelmRelease with label selector only // Field selectors are not supported by controller-runtime cache // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 @@ -648,27 +673,101 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio klog.Errorf("Error setting up watch for HelmReleases: %v", err) return nil, err } - - // Create a custom watcher to transform events - customW := &customWatcher{ - resultChan: make(chan watch.Event), - stopChan: make(chan struct{}), - underlying: helmWatcher, - } + customW.underlying = helmWatcher go func() { defer close(customW.resultChan) defer customW.underlying.Stop() + + // Track whether we've sent the initial-events-end bookmark + initialEventsEndSent := !sendInitialEvents // If not sendInitialEvents, consider it already sent + var lastResourceVersion string + + // Get the starting resourceVersion from options + // If client provides resourceVersion (e.g., from a previous List), we should skip + // objects with resourceVersion <= startingRV (client already has them) + var startingRV uint64 + if options.ResourceVersion != "" { + if rv, err := strconv.ParseUint(options.ResourceVersion, 10, 64); err == nil { + startingRV = rv + } + } + + // Helper function to send initial-events-end bookmark + sendInitialEventsEndBookmark := func() { + if initialEventsEndSent { + return + } + initialEventsEndSent = true + + bookmarkApp := &appsv1alpha1.Application{} + bookmarkApp.SetResourceVersion(lastResourceVersion) + bookmarkApp.TypeMeta = metav1.TypeMeta{ + APIVersion: appsv1alpha1.SchemeGroupVersion.String(), + Kind: r.kindName, + } + bookmarkApp.SetAnnotations(map[string]string{ + "k8s.io/initial-events-end": "true", + }) + bookmarkEvent := watch.Event{ + Type: watch.Bookmark, + Object: bookmarkApp, + } + klog.V(6).Infof("Sending initial-events-end bookmark with RV=%s", lastResourceVersion) + select { + case customW.resultChan <- bookmarkEvent: + case <-customW.stopChan: + case <-ctx.Done(): + } + } + + // Process watch events for { select { case event, ok := <-customW.underlying.ResultChan(): if !ok { - // The watcher has been closed, attempt to re-establish the watch - klog.Warning("HelmRelease watcher closed, attempting to re-establish") - // Implement retry logic or exit based on your requirements + // The watcher has been closed + klog.Warning("HelmRelease watcher closed") + // Send initial-events-end bookmark before closing if not yet sent + sendInitialEventsEndBookmark() return } + // Handle bookmark events - these are critical for informer sync + if event.Type == watch.Bookmark { + if hr, ok := event.Object.(*helmv2.HelmRelease); ok { + lastResourceVersion = hr.GetResourceVersion() + + // If sendInitialEvents and we haven't sent initial-events-end yet, + // add the annotation to this bookmark + bookmarkApp := &appsv1alpha1.Application{} + bookmarkApp.SetResourceVersion(lastResourceVersion) + bookmarkApp.TypeMeta = metav1.TypeMeta{ + APIVersion: appsv1alpha1.SchemeGroupVersion.String(), + Kind: r.kindName, + } + if !initialEventsEndSent { + initialEventsEndSent = true + bookmarkApp.SetAnnotations(map[string]string{ + "k8s.io/initial-events-end": "true", + }) + klog.V(6).Infof("Sending initial-events-end bookmark with RV=%s", lastResourceVersion) + } + bookmarkEvent := watch.Event{ + Type: watch.Bookmark, + Object: bookmarkApp, + } + select { + case customW.resultChan <- bookmarkEvent: + case <-customW.stopChan: + return + case <-ctx.Done(): + return + } + } + continue + } + // Check if the object is a *v1.Status if status, ok := event.Object.(*metav1.Status); ok { klog.V(4).Infof("Received Status object in HelmRelease watch: %v", status.Message) @@ -682,6 +781,9 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio continue } + // Update lastResourceVersion for bookmark + lastResourceVersion = hr.GetResourceVersion() + // Apply manual field selector filtering (metadata.name and metadata.namespace) // controller-runtime cache doesn't support field selectors // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 @@ -717,6 +819,23 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio } } + // If this is not an ADDED event and we haven't sent initial-events-end, send it now + if event.Type != watch.Added && !initialEventsEndSent { + sendInitialEventsEndBookmark() + } + + // Skip ADDED events based on resourceVersion comparison + if event.Type == watch.Added && startingRV > 0 { + objRV, parseErr := strconv.ParseUint(app.ResourceVersion, 10, 64) + // Skip objects client already has (objRV <= startingRV) + if parseErr == nil && objRV <= startingRV { + klog.V(6).Infof("Skipping ADDED event for %s/%s (objRV=%d <= startingRV=%d)", + app.Namespace, app.Name, objRV, startingRV) + continue + } + } + // When startingRV == 0, always send ADDED events (client wants full state) + // Create watch event with Application object appEvent := watch.Event{ Type: event.Type, diff --git a/pkg/registry/core/tenantmodule/rest.go b/pkg/registry/core/tenantmodule/rest.go index b2cda2db..59d4cb8a 100644 --- a/pkg/registry/core/tenantmodule/rest.go +++ b/pkg/registry/core/tenantmodule/rest.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "net/http" + "strconv" "sync" "time" @@ -40,6 +41,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" + "github.com/cozystack/cozystack/pkg/registry" fieldfilter "github.com/cozystack/cozystack/pkg/registry/fields" "github.com/cozystack/cozystack/pkg/registry/sorting" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -288,7 +290,14 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption APIVersion: "core.cozystack.io/v1alpha1", Kind: r.kindName + "List", } - moduleList.SetResourceVersion(hrList.GetResourceVersion()) + + // Get ResourceVersion from list or compute from items + // controller-runtime cached client may not set ResourceVersion on the list itself + listRV := hrList.GetResourceVersion() + if listRV == "" { + listRV, _ = registry.MaxResourceVersion(hrList) + } + moduleList.SetResourceVersion(listRV) moduleList.Items = items sorting.ByNamespacedName[corev1alpha1.TenantModule, *corev1alpha1.TenantModule](moduleList.Items) @@ -348,6 +357,14 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio helmLabelSelector = labels.NewSelector().Add(labelRequirements...) + // Get starting resourceVersion from options + var startingRV uint64 + if options.ResourceVersion != "" { + if rv, err := strconv.ParseUint(options.ResourceVersion, 10, 64); err == nil { + startingRV = rv + } + } + // Start watch on HelmRelease with label selector only // Field selectors are not supported by controller-runtime cache // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 @@ -371,20 +388,43 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio go func() { defer close(customW.resultChan) defer customW.underlying.Stop() + for { select { case event, ok := <-customW.underlying.ResultChan(): if !ok { - // The watcher has been closed, attempt to re-establish the watch - klog.Warning("HelmRelease watcher closed, attempting to re-establish") - // Implement retry logic or exit based on your requirements + klog.Warning("HelmRelease watcher closed") return } + // Handle bookmark events + if event.Type == watch.Bookmark { + if hr, ok := event.Object.(*helmv2.HelmRelease); ok { + bookmarkModule := &corev1alpha1.TenantModule{} + bookmarkModule.SetResourceVersion(hr.GetResourceVersion()) + bookmarkModule.TypeMeta = metav1.TypeMeta{ + APIVersion: corev1alpha1.SchemeGroupVersion.String(), + Kind: r.kindName, + } + bookmarkEvent := watch.Event{ + Type: watch.Bookmark, + Object: bookmarkModule, + } + select { + case customW.resultChan <- bookmarkEvent: + case <-customW.stopChan: + return + case <-ctx.Done(): + return + } + } + continue + } + // Check if the object is a *v1.Status if status, ok := event.Object.(*metav1.Status); ok { klog.V(4).Infof("Received Status object in HelmRelease watch: %v", status.Message) - continue // Skip processing this event + continue } // Proceed with processing HelmRelease objects @@ -394,9 +434,7 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio continue } - // Apply manual field selector filtering (metadata.name and metadata.namespace) - // controller-runtime cache doesn't support field selectors - // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + // Apply manual field selector filtering if !fieldFilter.MatchesName(hr.Name) { continue } @@ -415,6 +453,17 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio continue } + // Skip ADDED events based on resourceVersion comparison + // Only skip when client provided resourceVersion (they already have objects from List) + if event.Type == watch.Added && startingRV > 0 { + objRV, parseErr := strconv.ParseUint(module.ResourceVersion, 10, 64) + // Skip objects client already has (objRV <= startingRV) + if parseErr == nil && objRV <= startingRV { + continue + } + } + // When startingRV == 0, always send ADDED events (client wants full state) + // Apply field.selector by name if specified if resourceName != "" && module.Name != resourceName { continue diff --git a/pkg/registry/core/tenantnamespace/rest.go b/pkg/registry/core/tenantnamespace/rest.go index 90d5920d..f1ed3fab 100644 --- a/pkg/registry/core/tenantnamespace/rest.go +++ b/pkg/registry/core/tenantnamespace/rest.go @@ -8,6 +8,7 @@ import ( "context" "fmt" "net/http" + "strconv" "strings" "time" @@ -26,6 +27,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" + "github.com/cozystack/cozystack/pkg/registry" "github.com/cozystack/cozystack/pkg/registry/sorting" ) @@ -150,16 +152,43 @@ func (r *REST) Watch(ctx context.Context, opts *metainternal.ListOptions) (watch return nil, err } + // Get starting resourceVersion from options + var startingRV uint64 + if opts.ResourceVersion != "" { + if rv, err := strconv.ParseUint(opts.ResourceVersion, 10, 64); err == nil { + startingRV = rv + } + } + events := make(chan watch.Event) pw := watch.NewProxyWatcher(events) go func() { defer pw.Stop() + for ev := range nsWatch.ResultChan() { + // Handle bookmark events + if ev.Type == watch.Bookmark { + if ns, ok := ev.Object.(*corev1.Namespace); ok { + out := &corev1alpha1.TenantNamespace{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1alpha1.SchemeGroupVersion.String(), + Kind: "TenantNamespace", + }, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: ns.ResourceVersion, + }, + } + events <- watch.Event{Type: watch.Bookmark, Object: out} + } + continue + } + ns, ok := ev.Object.(*corev1.Namespace) if !ok || !strings.HasPrefix(ns.Name, prefix) { continue } + out := &corev1alpha1.TenantNamespace{ TypeMeta: metav1.TypeMeta{ APIVersion: corev1alpha1.SchemeGroupVersion.String(), @@ -174,6 +203,18 @@ func (r *REST) Watch(ctx context.Context, opts *metainternal.ListOptions) (watch Annotations: ns.Annotations, }, } + + // Skip ADDED events based on resourceVersion comparison + // Only skip when client provided resourceVersion (they already have objects from List) + if ev.Type == watch.Added && startingRV > 0 { + objRV, parseErr := strconv.ParseUint(out.ResourceVersion, 10, 64) + // Skip objects client already has (objRV <= startingRV) + if parseErr == nil && objRV <= startingRV { + continue + } + } + // When startingRV == 0, always send ADDED events (client wants full state) + events <- watch.Event{Type: ev.Type, Object: out} } }() @@ -227,12 +268,19 @@ func (r *REST) makeList(src *corev1.NamespaceList, allowed []string) *corev1alph set[n] = struct{}{} } + // Get ResourceVersion from list or compute from items + // controller-runtime cached client may not set ResourceVersion on the list itself + listRV := src.ResourceVersion + if listRV == "" { + listRV, _ = registry.MaxResourceVersion(src) + } + out := &corev1alpha1.TenantNamespaceList{ TypeMeta: metav1.TypeMeta{ APIVersion: corev1alpha1.SchemeGroupVersion.String(), Kind: "TenantNamespaceList", }, - ListMeta: metav1.ListMeta{ResourceVersion: src.ResourceVersion}, + ListMeta: metav1.ListMeta{ResourceVersion: listRV}, } for i := range src.Items { diff --git a/pkg/registry/core/tenantsecret/rest.go b/pkg/registry/core/tenantsecret/rest.go index d069c6ae..1f95c397 100644 --- a/pkg/registry/core/tenantsecret/rest.go +++ b/pkg/registry/core/tenantsecret/rest.go @@ -9,6 +9,7 @@ import ( "encoding/base64" "fmt" "net/http" + "strconv" "time" corev1 "k8s.io/api/core/v1" @@ -27,6 +28,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" + "github.com/cozystack/cozystack/pkg/registry" fieldfilter "github.com/cozystack/cozystack/pkg/registry/fields" "github.com/cozystack/cozystack/pkg/registry/sorting" ) @@ -277,12 +279,19 @@ func (r *REST) List(ctx context.Context, opts *metainternal.ListOptions) (runtim return nil, err } + // Get ResourceVersion from list or compute from items + // controller-runtime cached client may not set ResourceVersion on the list itself + listRV := list.ResourceVersion + if listRV == "" { + listRV, _ = registry.MaxResourceVersion(list) + } + out := &corev1alpha1.TenantSecretList{ TypeMeta: metav1.TypeMeta{ APIVersion: corev1alpha1.SchemeGroupVersion.String(), Kind: kindTenantSecretList, }, - ListMeta: list.ListMeta, + ListMeta: metav1.ListMeta{ResourceVersion: listRV}, } for i := range list.Items { @@ -432,22 +441,65 @@ func (r *REST) Watch(ctx context.Context, opts *metainternal.ListOptions) (watch base, err := r.w.Watch(ctx, secList, &client.ListOptions{ Namespace: ns, LabelSelector: ls, + Raw: &metav1.ListOptions{ + Watch: true, + ResourceVersion: opts.ResourceVersion, + }, }) if err != nil { return nil, err } + // Get starting resourceVersion from options + var startingRV uint64 + if opts.ResourceVersion != "" { + if rv, err := strconv.ParseUint(opts.ResourceVersion, 10, 64); err == nil { + startingRV = rv + } + } + ch := make(chan watch.Event) proxy := watch.NewProxyWatcher(ch) go func() { defer proxy.Stop() + for ev := range base.ResultChan() { + // Handle bookmark events + if ev.Type == watch.Bookmark { + if sec, ok := ev.Object.(*corev1.Secret); ok { + out := &corev1alpha1.TenantSecret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1alpha1.SchemeGroupVersion.String(), + Kind: kindTenantSecret, + }, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: sec.ResourceVersion, + }, + } + ch <- watch.Event{Type: watch.Bookmark, Object: out} + } + continue + } + sec, ok := ev.Object.(*corev1.Secret) if !ok || sec == nil { continue } + tenant := secretToTenant(sec) + + // Skip ADDED events based on resourceVersion comparison + // Only skip when client provided resourceVersion (they already have objects from List) + if ev.Type == watch.Added && startingRV > 0 { + objRV, parseErr := strconv.ParseUint(tenant.ResourceVersion, 10, 64) + // Skip objects client already has (objRV <= startingRV) + if parseErr == nil && objRV <= startingRV { + continue + } + } + // When startingRV == 0, always send ADDED events (client wants full state) + ch <- watch.Event{ Type: ev.Type, Object: tenant, diff --git a/pkg/registry/utils.go b/pkg/registry/utils.go new file mode 100644 index 00000000..c5deb422 --- /dev/null +++ b/pkg/registry/utils.go @@ -0,0 +1,57 @@ +/* +Copyright 2024 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package registry + +import ( + "strconv" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" +) + +// MaxResourceVersion returns the maximum resourceVersion from all items in a list. +// This is useful when the list's ResourceVersion is empty (e.g., from controller-runtime cache). +func MaxResourceVersion(list runtime.Object) (string, error) { + var max uint64 + + err := meta.EachListItem(list, func(obj runtime.Object) error { + accessor, err := meta.Accessor(obj) + if err != nil { + return err + } + + rvStr := accessor.GetResourceVersion() + if rvStr == "" { + return nil + } + + rv, err := strconv.ParseUint(rvStr, 10, 64) + if err != nil { + return err + } + + if rv > max { + max = rv + } + return nil + }) + if err != nil { + return "", err + } + + return strconv.FormatUint(max, 10), nil +} From 40683e28a7034cb6fa5728b401f3ed9eb2584b89 Mon Sep 17 00:00:00 2001 From: Kirill Ilin Date: Fri, 16 Jan 2026 21:09:52 +0500 Subject: [PATCH 67/78] [cilium] Update cilium to v1.18.6 Signed-off-by: Kirill Ilin (cherry picked from commit 464b6b3bb63807fab75331804fbc00f02d5d4afd) --- .../system/cilium/charts/cilium/Chart.yaml | 4 +-- .../system/cilium/charts/cilium/README.md | 18 +++++----- .../templates/cilium-envoy/configmap.yaml | 2 +- .../templates/cilium-preflight/daemonset.yaml | 11 ------ .../system/cilium/charts/cilium/values.yaml | 36 +++++++++---------- .../system/cilium/images/cilium/Dockerfile | 2 +- 6 files changed, 31 insertions(+), 42 deletions(-) diff --git a/packages/system/cilium/charts/cilium/Chart.yaml b/packages/system/cilium/charts/cilium/Chart.yaml index 479d2347..0de0d9c7 100644 --- a/packages/system/cilium/charts/cilium/Chart.yaml +++ b/packages/system/cilium/charts/cilium/Chart.yaml @@ -79,7 +79,7 @@ annotations: Cilium Gateway Class Config\n description: |\n CiliumGatewayClassConfig defines a configuration for Gateway API GatewayClass.\n" apiVersion: v2 -appVersion: 1.18.5 +appVersion: 1.18.6 description: eBPF-based Networking, Security, and Observability home: https://cilium.io/ icon: https://cdn.jsdelivr.net/gh/cilium/cilium@main/Documentation/images/logo-solo.svg @@ -95,4 +95,4 @@ kubeVersion: '>= 1.21.0-0' name: cilium sources: - https://github.com/cilium/cilium -version: 1.18.5 +version: 1.18.6 diff --git a/packages/system/cilium/charts/cilium/README.md b/packages/system/cilium/charts/cilium/README.md index 4244e8e0..840d0126 100644 --- a/packages/system/cilium/charts/cilium/README.md +++ b/packages/system/cilium/charts/cilium/README.md @@ -1,6 +1,6 @@ # cilium -![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) +![Version: 1.18.6](https://img.shields.io/badge/Version-1.18.6-informational?style=flat-square) ![AppVersion: 1.18.6](https://img.shields.io/badge/AppVersion-1.18.6-informational?style=flat-square) Cilium is open source software for providing and transparently securing network connectivity and loadbalancing between application workloads such as @@ -85,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: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.initImage | object | `{"digest":"sha256:2383baad1860bbe9d8a7a843775048fd07d8afe292b94bd876df64a69aae7cb1","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 | @@ -205,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:952f07c30390847e4d9dfaa19a76c4eca946251ffbc4f6459946570f93ee72f1","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/clustermesh-apiserver","tag":"v1.18.5","useDigest":true}` | Clustermesh API server image. | +| clustermesh.apiserver.image | object | `{"digest":"sha256:8ee142912a0e261850c0802d9256ddbe3729e1cd35c6bea2d93077f334c3cf3b","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/clustermesh-apiserver","tag":"v1.18.6","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. | @@ -394,7 +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:3108521821c6922695ff1f6ef24b09026c94b195283f8bfbfc0fa49356a156e1","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium-envoy","tag":"v1.34.12-1765374555-6a93b0bbba8d6dc75b651cbafeedb062b2997716","useDigest":true}` | Envoy container image. | +| envoy.image | object | `{"digest":"sha256:81398e449f2d3d0a6a70527e4f641aaa685d3156bea0bb30712fae3fd8822b86","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium-envoy","tag":"v1.35.9-1767794330-db497dd19e346b39d81d7b5c0dedf6c812bcc5c9","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 | @@ -535,7 +535,7 @@ 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:17212962c92ff52384f94e407ffe3698714fcbd35c7575f67f24032d6224e446","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/hubble-relay","tag":"v1.18.5","useDigest":true}` | Hubble-relay container image. | +| hubble.relay.image | object | `{"digest":"sha256:fb6135e34c31e5f175cb5e75f86cea52ef2ff12b49bcefb7088ed93f5009eb8e","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/hubble-relay","tag":"v1.18.6","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.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for pod assignment ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector | @@ -647,7 +647,7 @@ contributors across the globe, there is almost always someone available to help. | 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:2c92fb05962a346eaf0ce11b912ba434dc10bd54b9989e970416681f4a069628","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium","tag":"v1.18.5","useDigest":true}` | Agent container image. | +| image | object | `{"digest":"sha256:42ec562a5ff6c8a860c0639f5a7611685e253fd9eb2d2fcdade693724c9166a4","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium","tag":"v1.18.6","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. | @@ -793,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: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.image | object | `{"alibabacloudDigest":"sha256:212c4cbe27da3772bcb952b8f8cbaa0b0eef72488b52edf90ad2b32072a3ca4c","awsDigest":"sha256:47dbc1a5bd483fec170dab7fb0bf2cca3585a4893675b0324d41d97bac8be5eb","azureDigest":"sha256:a57aff47aeb32eccfedaa2a49d1af984d996d6d6de79609c232e0c4cf9ce97a1","genericDigest":"sha256:34a827ce9ed021c8adf8f0feca131f53b3c54a3ef529053d871d0347ec4d69af","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/operator","suffix":"","tag":"v1.18.6","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 | @@ -842,11 +842,11 @@ contributors across the globe, there is almost always someone available to help. | 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:3108521821c6922695ff1f6ef24b09026c94b195283f8bfbfc0fa49356a156e1","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium-envoy","tag":"v1.34.12-1765374555-6a93b0bbba8d6dc75b651cbafeedb062b2997716","useDigest":true}` | Envoy pre-flight image. | +| preflight.envoy.image | object | `{"digest":"sha256:81398e449f2d3d0a6a70527e4f641aaa685d3156bea0bb30712fae3fd8822b86","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium-envoy","tag":"v1.35.9-1767794330-db497dd19e346b39d81d7b5c0dedf6c812bcc5c9","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:2c92fb05962a346eaf0ce11b912ba434dc10bd54b9989e970416681f4a069628","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium","tag":"v1.18.5","useDigest":true}` | Cilium pre-flight image. | +| preflight.image | object | `{"digest":"sha256:42ec562a5ff6c8a860c0639f5a7611685e253fd9eb2d2fcdade693724c9166a4","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium","tag":"v1.18.6","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/ | 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 91c981cb..4511e7ad 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-envoy/configmap.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-envoy/configmap.yaml @@ -1,5 +1,5 @@ {{- $envoyDS := eq (include "envoyDaemonSetEnabled" .) "true" -}} -{{- if $envoyDS }} +{{- if (and $envoyDS (not .Values.preflight.enabled)) }} --- apiVersion: v1 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 17c39a41..b5418fe5 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-preflight/daemonset.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-preflight/daemonset.yaml @@ -213,9 +213,6 @@ 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 }} @@ -280,14 +277,6 @@ 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/values.yaml b/packages/system/cilium/charts/cilium/values.yaml index 5fac5be5..eff7f902 100644 --- a/packages/system/cilium/charts/cilium/values.yaml +++ b/packages/system/cilium/charts/cilium/values.yaml @@ -219,10 +219,10 @@ image: # @schema override: ~ repository: "quay.io/cilium/cilium" - tag: "v1.18.5" + tag: "v1.18.6" pullPolicy: "IfNotPresent" # cilium-digest - digest: sha256:2c92fb05962a346eaf0ce11b912ba434dc10bd54b9989e970416681f4a069628 + digest: sha256:42ec562a5ff6c8a860c0639f5a7611685e253fd9eb2d2fcdade693724c9166a4 useDigest: true # -- Scheduling configurations for cilium pods scheduling: @@ -1503,9 +1503,9 @@ hubble: # @schema override: ~ repository: "quay.io/cilium/hubble-relay" - tag: "v1.18.5" + tag: "v1.18.6" # hubble-relay-digest - digest: sha256:17212962c92ff52384f94e407ffe3698714fcbd35c7575f67f24032d6224e446 + digest: sha256:fb6135e34c31e5f175cb5e75f86cea52ef2ff12b49bcefb7088ed93f5009eb8e useDigest: true pullPolicy: "IfNotPresent" # -- Specifies the resources for the hubble-relay pods @@ -2465,9 +2465,9 @@ envoy: # @schema override: ~ repository: "quay.io/cilium/cilium-envoy" - tag: "v1.34.12-1765374555-6a93b0bbba8d6dc75b651cbafeedb062b2997716" + tag: "v1.35.9-1767794330-db497dd19e346b39d81d7b5c0dedf6c812bcc5c9" pullPolicy: "IfNotPresent" - digest: "sha256:3108521821c6922695ff1f6ef24b09026c94b195283f8bfbfc0fa49356a156e1" + digest: "sha256:81398e449f2d3d0a6a70527e4f641aaa685d3156bea0bb30712fae3fd8822b86" useDigest: true # -- Additional containers added to the cilium Envoy DaemonSet. extraContainers: [] @@ -2841,15 +2841,15 @@ operator: # @schema override: ~ repository: "quay.io/cilium/operator" - tag: "v1.18.5" + tag: "v1.18.6" # operator-generic-digest - genericDigest: sha256:36c3f6f14c8ced7f45b40b0a927639894b44269dd653f9528e7a0dc363a4eb99 + genericDigest: sha256:34a827ce9ed021c8adf8f0feca131f53b3c54a3ef529053d871d0347ec4d69af # operator-azure-digest - azureDigest: sha256:126667e000267f893cb81042bf8a710ad2f219619eb9ce06e8949333bd325ac6 + azureDigest: sha256:a57aff47aeb32eccfedaa2a49d1af984d996d6d6de79609c232e0c4cf9ce97a1 # operator-aws-digest - awsDigest: sha256:7608025d8b727a10f21d924d8e4f40beb176cefd690320433452816ad8776f52 + awsDigest: sha256:47dbc1a5bd483fec170dab7fb0bf2cca3585a4893675b0324d41d97bac8be5eb # operator-alibabacloud-digest - alibabacloudDigest: sha256:2e60f635495eb2837296ced5475875c281a05765d5ddd644a05e126bbb080b3c + alibabacloudDigest: sha256:212c4cbe27da3772bcb952b8f8cbaa0b0eef72488b52edf90ad2b32072a3ca4c useDigest: true pullPolicy: "IfNotPresent" suffix: "" @@ -3148,9 +3148,9 @@ preflight: # @schema override: ~ repository: "quay.io/cilium/cilium" - tag: "v1.18.5" + tag: "v1.18.6" # cilium-digest - digest: sha256:2c92fb05962a346eaf0ce11b912ba434dc10bd54b9989e970416681f4a069628 + digest: sha256:42ec562a5ff6c8a860c0639f5a7611685e253fd9eb2d2fcdade693724c9166a4 useDigest: true pullPolicy: "IfNotPresent" envoy: @@ -3161,9 +3161,9 @@ preflight: # @schema override: ~ repository: "quay.io/cilium/cilium-envoy" - tag: "v1.34.12-1765374555-6a93b0bbba8d6dc75b651cbafeedb062b2997716" + tag: "v1.35.9-1767794330-db497dd19e346b39d81d7b5c0dedf6c812bcc5c9" pullPolicy: "IfNotPresent" - digest: "sha256:3108521821c6922695ff1f6ef24b09026c94b195283f8bfbfc0fa49356a156e1" + digest: "sha256:81398e449f2d3d0a6a70527e4f641aaa685d3156bea0bb30712fae3fd8822b86" useDigest: true # -- The priority class to use for the preflight pod. priorityClassName: "" @@ -3317,9 +3317,9 @@ clustermesh: # @schema override: ~ repository: "quay.io/cilium/clustermesh-apiserver" - tag: "v1.18.5" + tag: "v1.18.6" # clustermesh-apiserver-digest - digest: sha256:952f07c30390847e4d9dfaa19a76c4eca946251ffbc4f6459946570f93ee72f1 + digest: sha256:8ee142912a0e261850c0802d9256ddbe3729e1cd35c6bea2d93077f334c3cf3b useDigest: true pullPolicy: "IfNotPresent" # -- TCP port for the clustermesh-apiserver health API. @@ -3849,7 +3849,7 @@ authentication: override: ~ repository: "docker.io/library/busybox" tag: "1.37.0" - digest: "sha256:d80cd694d3e9467884fcb94b8ca1e20437d8a501096cdf367a5a1918a34fc2fd" + digest: "sha256:2383baad1860bbe9d8a7a843775048fd07d8afe292b94bd876df64a69aae7cb1" useDigest: true pullPolicy: "IfNotPresent" # SPIRE agent configuration diff --git a/packages/system/cilium/images/cilium/Dockerfile b/packages/system/cilium/images/cilium/Dockerfile index 23c3d16a..ebe65c83 100644 --- a/packages/system/cilium/images/cilium/Dockerfile +++ b/packages/system/cilium/images/cilium/Dockerfile @@ -1,2 +1,2 @@ -ARG VERSION=v1.18.5 +ARG VERSION=v1.18.6 FROM quay.io/cilium/cilium:${VERSION} From 9507f2433253f0e665dc6af6f6ec7499c468da9b Mon Sep 17 00:00:00 2001 From: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> Date: Mon, 19 Jan 2026 01:34:56 +0000 Subject: [PATCH 68/78] Prepare release v0.40.3 Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> --- packages/apps/http-cache/images/nginx-cache.tag | 2 +- packages/apps/kubernetes/images/kubevirt-csi-driver.tag | 2 +- packages/apps/kubernetes/images/ubuntu-container-disk.tag | 2 +- packages/core/installer/values.yaml | 2 +- packages/core/platform/values.yaml | 2 +- packages/core/testing/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- packages/extra/seaweedfs/images/objectstorage-sidecar.tag | 2 +- packages/system/bucket/images/s3manager.tag | 2 +- packages/system/cilium/values.yaml | 4 ++-- packages/system/cozystack-api/values.yaml | 2 +- packages/system/cozystack-controller/values.yaml | 4 ++-- packages/system/dashboard/templates/configmap.yaml | 2 +- packages/system/dashboard/values.yaml | 6 +++--- packages/system/kamaji/values.yaml | 4 ++-- packages/system/kubeovn-plunger/values.yaml | 2 +- packages/system/kubeovn-webhook/values.yaml | 2 +- packages/system/kubevirt-csi-node/values.yaml | 2 +- packages/system/lineage-controller-webhook/values.yaml | 2 +- packages/system/linstor/values.yaml | 2 +- packages/system/objectstorage-controller/values.yaml | 2 +- packages/system/seaweedfs/values.yaml | 2 +- 22 files changed, 27 insertions(+), 27 deletions(-) diff --git a/packages/apps/http-cache/images/nginx-cache.tag b/packages/apps/http-cache/images/nginx-cache.tag index 3f0bbd33..ee4d8890 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:31ebc09cfa11d8b438d2bbb32fa61b133aaf4b48b1a1282c9e59b5c127af61c1 +ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:9e34fd50393b418d9516aadb488067a3a63675b045811beb1c0afc9c61e149e8 diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag index 326da62f..ea6c26b9 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:0e5d8bbdc587a96e07bbf263f23d4d237dac8bd4528b34f44d31b042c6a0e495 +ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:15b94dca216b73336e7f39f4ea1b76b7656890d6be8a8cf0d9a786b4006781f9 diff --git a/packages/apps/kubernetes/images/ubuntu-container-disk.tag b/packages/apps/kubernetes/images/ubuntu-container-disk.tag index 06de29fa..930a3fd2 100644 --- a/packages/apps/kubernetes/images/ubuntu-container-disk.tag +++ b/packages/apps/kubernetes/images/ubuntu-container-disk.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.33@sha256:d25e567bc8b17b596e050f5ff410e36112c7966e33f4b372c752e7350bacc894 +ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.33@sha256:71a74ca30f75967bae309be2758f19aa3d37c60b19426b9b622ff1c33a80362f diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index 72d6a32a..f821a5c6 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.40.2@sha256:146e0de9d1208eba8342277fa08e0588d66e51bc637c6b3add8ef63cc54ef351 + image: ghcr.io/cozystack/cozystack/installer:v0.40.3@sha256:4581c0a80fd31db2988411d96afc77afd315726348468e495c9f5c21b2b2a664 diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index 26d0859c..8c96c8e7 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -1,2 +1,2 @@ assets: - image: ghcr.io/cozystack/cozystack/cozystack-assets:v0.40.2@sha256:02730e6a434a8367a970c00a1feaa31f19a856641f6c1d085afed88e9c0b8b2b + image: ghcr.io/cozystack/cozystack/cozystack-assets:v0.40.3@sha256:48e63ec92d473038e29ea2375f57a449ed9b9295aced53ae27d3944507c076c4 diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index b00e9ea3..f08ce71d 100644 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.40.2@sha256:78a556a059411cac89249c2e22596223128a1c74fbfcac4787fd74e4a66f66a6 + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.40.3@sha256:fde7616aacaf5939388bbe74eb6d946147ce855b9cceb47092f620b75ba2c98a diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index 522bb744..755826a3 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.40.2@sha256:f72d35fc691021d6b473360f2edaf0b1f176f737ca18f8cb9322d16c69705020 +ghcr.io/cozystack/cozystack/matchbox:v0.40.3@sha256:d9674696eb6c59e4564127bb919582ea66bf5b267504ce11ef4f9431db3a247f diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag index 90d0d249..371b1575 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:v0.40.2@sha256:6735e6f050355355a13439ff815539a1b92eba09623e500e92dd7d4e600c59b4 +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.40.3@sha256:d342ac197b97b81ec42712ecd9d762c6c7710a401736e9d09c64a5b8d59774cc diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index b71ecf9e..88b26eac 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:07f016720c4692fc270a415a327a88773b90d2821922098496ad1269beac6c94 +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:79463ccddbbd2a4048863944a858b2aced3f6e1c2d77f7ef4fa57e30624f6e35 diff --git a/packages/system/cilium/values.yaml b/packages/system/cilium/values.yaml index 1c759ac6..49a028f0 100644 --- a/packages/system/cilium/values.yaml +++ b/packages/system/cilium/values.yaml @@ -15,8 +15,8 @@ cilium: mode: "kubernetes" image: repository: ghcr.io/cozystack/cozystack/cilium - tag: 1.18.5 - digest: "sha256:c14a0bcb1a1531c72725b3a4c40aefa2bcd5c129810bf58ea8e37d3fcff2a326" + tag: 1.18.6 + digest: "sha256:4f4585f8adc3b8becd15d3999f3900a4d3d650f2ab7f85ca8c661f3807113d01" envoy: enabled: false rollOutCiliumPods: true diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 04e86c7c..bcde28c5 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,5 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.40.2@sha256:408885b509d80ca30a85416f87d07112bc7f070374e71e80b64818fbb24ad1ee + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.40.3@sha256:1b5109bc4149178084941cf1cb505110c581c9326dbb1ef94ffdcdb026dff0e8 localK8sAPIEndpoint: enabled: true replicas: 2 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index de8eedd5..187f00ef 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,6 +1,6 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.40.2@sha256:1878af4389ee3ddc85f2079cc250bccc14b923fb74c665c9aa902a659a394ba6 + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.40.3@sha256:2b4ad67116c03cd001c495001f9032e6d944199f14a2d80a24d697e2293650c3 debug: false disableTelemetry: false - cozystackVersion: "v0.40.2" + cozystackVersion: "v0.40.3" cozystackAPIKind: "DaemonSet" diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index a929b0b1..cf5f9a57 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,6 +1,6 @@ {{- $brandingConfig := .Values._cluster.branding | default dict }} -{{- $tenantText := "v0.40.2" }} +{{- $tenantText := "v0.40.3" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} {{- $logoText := "" }} diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index 091aaa4d..85613440 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v0.40.2@sha256:a8d3770107c0279add903e6b5acdc5ca8a15551fb07514e40772f8010c5386ef + image: ghcr.io/cozystack/cozystack/openapi-ui:v0.40.3@sha256:9666e61fdf7d4ddfeb9084f49ee9c1297b67a4159c475fe62680a0d84ea4050c openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.40.2@sha256:3071dfc130dbaf185b1a46ed42f0800824e77c2f4e64c5ed87055311f3c5f2b1 + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.40.3@sha256:c905f98598526820bd71e3997fdc62868b9c3d7a4e9700b01d73b017b0953257 tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:v0.40.2@sha256:4fc8a11f8a1a81aa0774ae2b1ed2e05d36d0b3ef1e37979cc4994e65114d93ae + image: ghcr.io/cozystack/cozystack/token-proxy:v0.40.3@sha256:73887f80d96e7e3c16f1cebab521b05b4308bf4662ccc6724e6a8a9745ed8254 diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index 4aea9c22..911fa3d6 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.40.2@sha256:cf9aae159deb586b1af5e5f6299247fe82f01646d58102bf5ca264c40f9edda2 + tag: v0.40.3@sha256:777f1df253dc97da7f42019857e7a893c34bd98da1cf36e38533adbdf601acf7 repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: @@ -13,4 +13,4 @@ kamaji: cpu: 100m memory: 100Mi extraArgs: - - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.40.2@sha256:cf9aae159deb586b1af5e5f6299247fe82f01646d58102bf5ca264c40f9edda2 + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.40.3@sha256:777f1df253dc97da7f42019857e7a893c34bd98da1cf36e38533adbdf601acf7 diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml index 4229b116..219bb243 100644 --- a/packages/system/kubeovn-plunger/values.yaml +++ b/packages/system/kubeovn-plunger/values.yaml @@ -1,4 +1,4 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.40.2@sha256:fdcc081d3c28a023a6950deac4d6124a0290d1bb4bd13c8c723569ac40d6874e +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.40.3@sha256:864a75eb6fb07eedef3b9ff94e6bb6b02e94fe73c1e03bf360bc785fbfbc1170 ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index 6ec8f26e..af6649e7 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.40.2@sha256:e6334c29d3aaf0dea766c88e3e05b53ad623d1bb497b3c836e6f76adade45b29 +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.40.3@sha256:e18f9fd679e38f65362a8d0042f25468272f6d081136ad47027168d8e7e07a4a diff --git a/packages/system/kubevirt-csi-node/values.yaml b/packages/system/kubevirt-csi-node/values.yaml index d3fac521..5644e6d8 100644 --- a/packages/system/kubevirt-csi-node/values.yaml +++ b/packages/system/kubevirt-csi-node/values.yaml @@ -1,3 +1,3 @@ storageClass: replicated csiDriver: - image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:0e5d8bbdc587a96e07bbf263f23d4d237dac8bd4528b34f44d31b042c6a0e495 + image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:15b94dca216b73336e7f39f4ea1b76b7656890d6be8a8cf0d9a786b4006781f9 diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index 554d9ef2..68c78ad9 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,5 +1,5 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.40.2@sha256:16a700334d4d9cebea2516874c04d0799a450052f3652a0c91668c37d1d0e227 + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.40.3@sha256:3556a8ca2ee280dff3991519a5f536ec6ea0a4e5f9be0572f23adb8f59466e56 debug: false localK8sAPIEndpoint: enabled: true diff --git a/packages/system/linstor/values.yaml b/packages/system/linstor/values.yaml index da62e9da..2287181b 100644 --- a/packages/system/linstor/values.yaml +++ b/packages/system/linstor/values.yaml @@ -10,4 +10,4 @@ linstor: linstorCSI: image: repository: ghcr.io/cozystack/cozystack/linstor-csi - tag: v1.10.5@sha256:276e35e644cc4f1a17bc3842ded84aef4d9a5d750b5bdf3fc7238e369e88ada8 + tag: v1.10.5@sha256:68465f120cfeec3d7ccbb389dd9bdbf7df1675da3ab9ba91c3feff21a799bc36 diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml index 041c3ad2..365e7b2c 100644 --- a/packages/system/objectstorage-controller/values.yaml +++ b/packages/system/objectstorage-controller/values.yaml @@ -1,3 +1,3 @@ objectstorage: controller: - image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.40.2@sha256:f44845c034643c3b9040b70dc417e633d8ab0cc56a304a88dace733f2b4f1d70" + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.40.3@sha256:76756860145d49abe1585c8ca600267a07fcdbb0b359bc9c127baf9efb8e006b" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index fd8f7ff0..4885e44f 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -177,7 +177,7 @@ seaweedfs: bucketClassName: "seaweedfs" region: "" sidecar: - image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.40.2@sha256:6735e6f050355355a13439ff815539a1b92eba09623e500e92dd7d4e600c59b4" + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.40.3@sha256:d342ac197b97b81ec42712ecd9d762c6c7710a401736e9d09c64a5b8d59774cc" certificates: commonName: "SeaweedFS CA" ipAddresses: [] From 6169220317991d388738998faff6916954a36c0f Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Sun, 18 Jan 2026 21:50:06 +0100 Subject: [PATCH 69/78] fix(etcd): increase probe thresholds for better recovery Increase startup probe failureThreshold to 300 (25 minutes) to allow etcd members more time to sync with the cluster after restart or recovery. This prevents pods from being killed during initial synchronization when VPA assigns minimal resources. Also increase liveness probe failureThreshold to 10 to reduce unnecessary restarts during temporary network issues. Co-Authored-By: Claude Signed-off-by: Andrei Kvapil (cherry picked from commit c58c959df665d9f672f034f70fd2b7bae70cde21) --- packages/extra/etcd/templates/etcd-cluster.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/extra/etcd/templates/etcd-cluster.yaml b/packages/extra/etcd/templates/etcd-cluster.yaml index a26ae173..44851cc6 100644 --- a/packages/extra/etcd/templates/etcd-cluster.yaml +++ b/packages/extra/etcd/templates/etcd-cluster.yaml @@ -46,6 +46,15 @@ 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 }} From cf0598bcf159f402bbe09027cd419a8c405c7d50 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Mon, 19 Jan 2026 01:04:54 +0100 Subject: [PATCH 70/78] Update Talos Linux v1.11.6 Signed-off-by: Andrei Kvapil --- .../images/talos/profiles/initramfs.yaml | 22 +++++++++---------- .../images/talos/profiles/installer.yaml | 22 +++++++++---------- .../core/talos/images/talos/profiles/iso.yaml | 22 +++++++++---------- .../talos/images/talos/profiles/kernel.yaml | 22 +++++++++---------- .../talos/images/talos/profiles/metal.yaml | 22 +++++++++---------- .../talos/images/talos/profiles/nocloud.yaml | 22 +++++++++---------- 6 files changed, 66 insertions(+), 66 deletions(-) diff --git a/packages/core/talos/images/talos/profiles/initramfs.yaml b/packages/core/talos/images/talos/profiles/initramfs.yaml index 9663d86f..07b81a3e 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.11.3 +version: v1.11.6 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.11.3" + imageRef: "ghcr.io/siderolabs/installer:v1.11.6" systemExtensions: - - 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 + - imageRef: ghcr.io/siderolabs/amd-ucode:20251125@sha256:aa2c684933d28cf10ef785f0d94f91d6d098e164374114648867cf81c2b585fe + - imageRef: ghcr.io/siderolabs/amdgpu:20251125-v1.11.6@sha256:4161f6de768d921a236aee8b06ee3eb18c4b93cfc178e3ae0f756e3a40929a93 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20251125@sha256:a7665b8c96cbdcf15dff6e39495ec389f576adf8a68ecfe20d6760884656d14c + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20251125@sha256:01458f60448e166eeb641ee989b941725cbe6759e10afe2251c6d1b1ca5ba1b7 + - imageRef: ghcr.io/siderolabs/i915:20251125-v1.11.6@sha256:6896f63864d8ceed4a65f00304c1b26d90224127b37312d2e4bf33df14778e84 + - imageRef: ghcr.io/siderolabs/intel-ucode:20250812@sha256:ba7a22ab69dfc8070d52fb70f58955257f0b586419f63573fb1e4618f57790eb + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20251125@sha256:485ef0a0b58328ded511e9a76014c353da24bb147c8b2929068827e5f9a22326 + - imageRef: ghcr.io/siderolabs/drbd:9.2.16-v1.11.6@sha256:f87f92f25e203a3d49ced3d5bfe9d19278c309b157a5c049ff8c1fd53cf77707 + - imageRef: ghcr.io/siderolabs/zfs:2.3.5-v1.11.6@sha256:29122979dce73dfd5c00d0a376de50905a9c4af99e0f18f91d77df2f6bdd0265 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 aedff886..26acdb54 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.11.3 +version: v1.11.6 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.11.3" + imageRef: "ghcr.io/siderolabs/installer:v1.11.6" systemExtensions: - - 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 + - imageRef: ghcr.io/siderolabs/amd-ucode:20251125@sha256:aa2c684933d28cf10ef785f0d94f91d6d098e164374114648867cf81c2b585fe + - imageRef: ghcr.io/siderolabs/amdgpu:20251125-v1.11.6@sha256:4161f6de768d921a236aee8b06ee3eb18c4b93cfc178e3ae0f756e3a40929a93 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20251125@sha256:a7665b8c96cbdcf15dff6e39495ec389f576adf8a68ecfe20d6760884656d14c + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20251125@sha256:01458f60448e166eeb641ee989b941725cbe6759e10afe2251c6d1b1ca5ba1b7 + - imageRef: ghcr.io/siderolabs/i915:20251125-v1.11.6@sha256:6896f63864d8ceed4a65f00304c1b26d90224127b37312d2e4bf33df14778e84 + - imageRef: ghcr.io/siderolabs/intel-ucode:20250812@sha256:ba7a22ab69dfc8070d52fb70f58955257f0b586419f63573fb1e4618f57790eb + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20251125@sha256:485ef0a0b58328ded511e9a76014c353da24bb147c8b2929068827e5f9a22326 + - imageRef: ghcr.io/siderolabs/drbd:9.2.16-v1.11.6@sha256:f87f92f25e203a3d49ced3d5bfe9d19278c309b157a5c049ff8c1fd53cf77707 + - imageRef: ghcr.io/siderolabs/zfs:2.3.5-v1.11.6@sha256:29122979dce73dfd5c00d0a376de50905a9c4af99e0f18f91d77df2f6bdd0265 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 1f46d36a..c7a119cf 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.11.3 +version: v1.11.6 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.11.3" + imageRef: "ghcr.io/siderolabs/installer:v1.11.6" systemExtensions: - - 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 + - imageRef: ghcr.io/siderolabs/amd-ucode:20251125@sha256:aa2c684933d28cf10ef785f0d94f91d6d098e164374114648867cf81c2b585fe + - imageRef: ghcr.io/siderolabs/amdgpu:20251125-v1.11.6@sha256:4161f6de768d921a236aee8b06ee3eb18c4b93cfc178e3ae0f756e3a40929a93 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20251125@sha256:a7665b8c96cbdcf15dff6e39495ec389f576adf8a68ecfe20d6760884656d14c + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20251125@sha256:01458f60448e166eeb641ee989b941725cbe6759e10afe2251c6d1b1ca5ba1b7 + - imageRef: ghcr.io/siderolabs/i915:20251125-v1.11.6@sha256:6896f63864d8ceed4a65f00304c1b26d90224127b37312d2e4bf33df14778e84 + - imageRef: ghcr.io/siderolabs/intel-ucode:20250812@sha256:ba7a22ab69dfc8070d52fb70f58955257f0b586419f63573fb1e4618f57790eb + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20251125@sha256:485ef0a0b58328ded511e9a76014c353da24bb147c8b2929068827e5f9a22326 + - imageRef: ghcr.io/siderolabs/drbd:9.2.16-v1.11.6@sha256:f87f92f25e203a3d49ced3d5bfe9d19278c309b157a5c049ff8c1fd53cf77707 + - imageRef: ghcr.io/siderolabs/zfs:2.3.5-v1.11.6@sha256:29122979dce73dfd5c00d0a376de50905a9c4af99e0f18f91d77df2f6bdd0265 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 4e4f3685..9372f48a 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.11.3 +version: v1.11.6 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.11.3" + imageRef: "ghcr.io/siderolabs/installer:v1.11.6" systemExtensions: - - 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 + - imageRef: ghcr.io/siderolabs/amd-ucode:20251125@sha256:aa2c684933d28cf10ef785f0d94f91d6d098e164374114648867cf81c2b585fe + - imageRef: ghcr.io/siderolabs/amdgpu:20251125-v1.11.6@sha256:4161f6de768d921a236aee8b06ee3eb18c4b93cfc178e3ae0f756e3a40929a93 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20251125@sha256:a7665b8c96cbdcf15dff6e39495ec389f576adf8a68ecfe20d6760884656d14c + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20251125@sha256:01458f60448e166eeb641ee989b941725cbe6759e10afe2251c6d1b1ca5ba1b7 + - imageRef: ghcr.io/siderolabs/i915:20251125-v1.11.6@sha256:6896f63864d8ceed4a65f00304c1b26d90224127b37312d2e4bf33df14778e84 + - imageRef: ghcr.io/siderolabs/intel-ucode:20250812@sha256:ba7a22ab69dfc8070d52fb70f58955257f0b586419f63573fb1e4618f57790eb + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20251125@sha256:485ef0a0b58328ded511e9a76014c353da24bb147c8b2929068827e5f9a22326 + - imageRef: ghcr.io/siderolabs/drbd:9.2.16-v1.11.6@sha256:f87f92f25e203a3d49ced3d5bfe9d19278c309b157a5c049ff8c1fd53cf77707 + - imageRef: ghcr.io/siderolabs/zfs:2.3.5-v1.11.6@sha256:29122979dce73dfd5c00d0a376de50905a9c4af99e0f18f91d77df2f6bdd0265 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 54a5a93d..d2e7b308 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.11.3 +version: v1.11.6 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.11.3" + imageRef: "ghcr.io/siderolabs/installer:v1.11.6" systemExtensions: - - 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 + - imageRef: ghcr.io/siderolabs/amd-ucode:20251125@sha256:aa2c684933d28cf10ef785f0d94f91d6d098e164374114648867cf81c2b585fe + - imageRef: ghcr.io/siderolabs/amdgpu:20251125-v1.11.6@sha256:4161f6de768d921a236aee8b06ee3eb18c4b93cfc178e3ae0f756e3a40929a93 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20251125@sha256:a7665b8c96cbdcf15dff6e39495ec389f576adf8a68ecfe20d6760884656d14c + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20251125@sha256:01458f60448e166eeb641ee989b941725cbe6759e10afe2251c6d1b1ca5ba1b7 + - imageRef: ghcr.io/siderolabs/i915:20251125-v1.11.6@sha256:6896f63864d8ceed4a65f00304c1b26d90224127b37312d2e4bf33df14778e84 + - imageRef: ghcr.io/siderolabs/intel-ucode:20250812@sha256:ba7a22ab69dfc8070d52fb70f58955257f0b586419f63573fb1e4618f57790eb + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20251125@sha256:485ef0a0b58328ded511e9a76014c353da24bb147c8b2929068827e5f9a22326 + - imageRef: ghcr.io/siderolabs/drbd:9.2.16-v1.11.6@sha256:f87f92f25e203a3d49ced3d5bfe9d19278c309b157a5c049ff8c1fd53cf77707 + - imageRef: ghcr.io/siderolabs/zfs:2.3.5-v1.11.6@sha256:29122979dce73dfd5c00d0a376de50905a9c4af99e0f18f91d77df2f6bdd0265 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 5e0f8cf1..c8efac3d 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.11.3 +version: v1.11.6 input: kernel: path: /usr/install/amd64/vmlinuz initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.11.3" + imageRef: "ghcr.io/siderolabs/installer:v1.11.6" systemExtensions: - - 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 + - imageRef: ghcr.io/siderolabs/amd-ucode:20251125@sha256:aa2c684933d28cf10ef785f0d94f91d6d098e164374114648867cf81c2b585fe + - imageRef: ghcr.io/siderolabs/amdgpu:20251125-v1.11.6@sha256:4161f6de768d921a236aee8b06ee3eb18c4b93cfc178e3ae0f756e3a40929a93 + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20251125@sha256:a7665b8c96cbdcf15dff6e39495ec389f576adf8a68ecfe20d6760884656d14c + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20251125@sha256:01458f60448e166eeb641ee989b941725cbe6759e10afe2251c6d1b1ca5ba1b7 + - imageRef: ghcr.io/siderolabs/i915:20251125-v1.11.6@sha256:6896f63864d8ceed4a65f00304c1b26d90224127b37312d2e4bf33df14778e84 + - imageRef: ghcr.io/siderolabs/intel-ucode:20250812@sha256:ba7a22ab69dfc8070d52fb70f58955257f0b586419f63573fb1e4618f57790eb + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20251125@sha256:485ef0a0b58328ded511e9a76014c353da24bb147c8b2929068827e5f9a22326 + - imageRef: ghcr.io/siderolabs/drbd:9.2.16-v1.11.6@sha256:f87f92f25e203a3d49ced3d5bfe9d19278c309b157a5c049ff8c1fd53cf77707 + - imageRef: ghcr.io/siderolabs/zfs:2.3.5-v1.11.6@sha256:29122979dce73dfd5c00d0a376de50905a9c4af99e0f18f91d77df2f6bdd0265 output: kind: image imageOptions: { diskSize: 1306525696, diskFormat: raw } From 6ce60917c73db8e118d33541e003fab9a923f46d Mon Sep 17 00:00:00 2001 From: Aleksei Sviridkin Date: Wed, 7 Jan 2026 15:57:50 +0300 Subject: [PATCH 71/78] feat(apps): add MongoDB managed application Add MongoDB managed service based on Percona Operator for MongoDB with: - Replica set mode (default) and sharded cluster mode - Configurable replicas, storage, and resource presets - Custom users with role-based access control - S3-compatible backup with PITR support - Bootstrap/restore from backup - External access support - WorkloadMonitor integration for dashboard - Comprehensive helm-unittest test coverage (91 tests) Co-Authored-By: Claude Signed-off-by: Aleksei Sviridkin --- hack/e2e-apps/mongodb.bats | 31 + packages/apps/mongodb/.helmignore | 23 + packages/apps/mongodb/Chart.yaml | 7 + packages/apps/mongodb/Makefile | 11 + packages/apps/mongodb/README.md | 113 + packages/apps/mongodb/charts/cozy-lib | 1 + packages/apps/mongodb/files/versions.yaml | 5 + packages/apps/mongodb/hack/update-versions.sh | 125 + packages/apps/mongodb/logos/mongodb.svg | 13 + packages/apps/mongodb/templates/.gitkeep | 0 packages/apps/mongodb/templates/_versions.tpl | 12 + .../apps/mongodb/templates/backup-secret.yaml | 11 + .../apps/mongodb/templates/credentials.yaml | 34 + .../templates/dashboard-resourcemap.yaml | 39 + .../apps/mongodb/templates/external-svc.yaml | 24 + packages/apps/mongodb/templates/mongodb.yaml | 173 + packages/apps/mongodb/templates/restore.yaml | 37 + .../apps/mongodb/templates/user-secrets.yaml | 17 + .../mongodb/tests/backup-secret_test.yaml | 112 + .../apps/mongodb/tests/credentials_test.yaml | 132 + .../tests/dashboard-resourcemap_test.yaml | 106 + .../apps/mongodb/tests/external-svc_test.yaml | 154 + packages/apps/mongodb/tests/mongodb_test.yaml | 703 + packages/apps/mongodb/tests/restore_test.yaml | 349 + .../apps/mongodb/tests/user-secrets_test.yaml | 98 + packages/apps/mongodb/values.schema.json | 309 + packages/apps/mongodb/values.yaml | 147 + packages/core/platform/bundles/paas-full.yaml | 12 + .../platform/sources/mongodb-application.yaml | 27 + .../platform/sources/mongodb-operator.yaml | 23 + packages/system/mongodb-operator/.helmignore | 23 + packages/system/mongodb-operator/Chart.yaml | 3 + packages/system/mongodb-operator/Makefile | 11 + .../charts/psmdb-operator/.helmignore | 22 + .../charts/psmdb-operator/Chart.yaml | 13 + .../charts/psmdb-operator/LICENSE.txt | 13 + .../charts/psmdb-operator/README.md | 77 + .../charts/psmdb-operator/crds/crd.yaml | 25729 ++++++++++++++++ .../charts/psmdb-operator/templates/NOTES.txt | 40 + .../psmdb-operator/templates/_helpers.tpl | 45 + .../psmdb-operator/templates/deployment.yaml | 112 + .../psmdb-operator/templates/namespace.yaml | 11 + .../templates/role-binding.yaml | 41 + .../charts/psmdb-operator/templates/role.yaml | 167 + .../charts/psmdb-operator/values.yaml | 103 + packages/system/mongodb-operator/values.yaml | 2 + packages/system/mongodb-rd/Chart.yaml | 3 + packages/system/mongodb-rd/Makefile | 4 + .../system/mongodb-rd/cozyrds/mongodb.yaml | 42 + .../system/mongodb-rd/templates/cozyrd.yaml | 4 + packages/system/mongodb-rd/values.yaml | 1 + 51 files changed, 29314 insertions(+) create mode 100644 hack/e2e-apps/mongodb.bats create mode 100644 packages/apps/mongodb/.helmignore create mode 100644 packages/apps/mongodb/Chart.yaml create mode 100644 packages/apps/mongodb/Makefile create mode 100644 packages/apps/mongodb/README.md create mode 120000 packages/apps/mongodb/charts/cozy-lib create mode 100644 packages/apps/mongodb/files/versions.yaml create mode 100755 packages/apps/mongodb/hack/update-versions.sh create mode 100644 packages/apps/mongodb/logos/mongodb.svg create mode 100644 packages/apps/mongodb/templates/.gitkeep create mode 100644 packages/apps/mongodb/templates/_versions.tpl create mode 100644 packages/apps/mongodb/templates/backup-secret.yaml create mode 100644 packages/apps/mongodb/templates/credentials.yaml create mode 100644 packages/apps/mongodb/templates/dashboard-resourcemap.yaml create mode 100644 packages/apps/mongodb/templates/external-svc.yaml create mode 100644 packages/apps/mongodb/templates/mongodb.yaml create mode 100644 packages/apps/mongodb/templates/restore.yaml create mode 100644 packages/apps/mongodb/templates/user-secrets.yaml create mode 100644 packages/apps/mongodb/tests/backup-secret_test.yaml create mode 100644 packages/apps/mongodb/tests/credentials_test.yaml create mode 100644 packages/apps/mongodb/tests/dashboard-resourcemap_test.yaml create mode 100644 packages/apps/mongodb/tests/external-svc_test.yaml create mode 100644 packages/apps/mongodb/tests/mongodb_test.yaml create mode 100644 packages/apps/mongodb/tests/restore_test.yaml create mode 100644 packages/apps/mongodb/tests/user-secrets_test.yaml create mode 100644 packages/apps/mongodb/values.schema.json create mode 100644 packages/apps/mongodb/values.yaml create mode 100644 packages/core/platform/sources/mongodb-application.yaml create mode 100644 packages/core/platform/sources/mongodb-operator.yaml create mode 100644 packages/system/mongodb-operator/.helmignore create mode 100644 packages/system/mongodb-operator/Chart.yaml create mode 100644 packages/system/mongodb-operator/Makefile create mode 100644 packages/system/mongodb-operator/charts/psmdb-operator/.helmignore create mode 100644 packages/system/mongodb-operator/charts/psmdb-operator/Chart.yaml create mode 100644 packages/system/mongodb-operator/charts/psmdb-operator/LICENSE.txt create mode 100644 packages/system/mongodb-operator/charts/psmdb-operator/README.md create mode 100644 packages/system/mongodb-operator/charts/psmdb-operator/crds/crd.yaml create mode 100644 packages/system/mongodb-operator/charts/psmdb-operator/templates/NOTES.txt create mode 100644 packages/system/mongodb-operator/charts/psmdb-operator/templates/_helpers.tpl create mode 100644 packages/system/mongodb-operator/charts/psmdb-operator/templates/deployment.yaml create mode 100644 packages/system/mongodb-operator/charts/psmdb-operator/templates/namespace.yaml create mode 100644 packages/system/mongodb-operator/charts/psmdb-operator/templates/role-binding.yaml create mode 100644 packages/system/mongodb-operator/charts/psmdb-operator/templates/role.yaml create mode 100644 packages/system/mongodb-operator/charts/psmdb-operator/values.yaml create mode 100644 packages/system/mongodb-operator/values.yaml create mode 100644 packages/system/mongodb-rd/Chart.yaml create mode 100644 packages/system/mongodb-rd/Makefile create mode 100644 packages/system/mongodb-rd/cozyrds/mongodb.yaml create mode 100644 packages/system/mongodb-rd/templates/cozyrd.yaml create mode 100644 packages/system/mongodb-rd/values.yaml diff --git a/hack/e2e-apps/mongodb.bats b/hack/e2e-apps/mongodb.bats new file mode 100644 index 00000000..61ebada8 --- /dev/null +++ b/hack/e2e-apps/mongodb.bats @@ -0,0 +1,31 @@ +#!/usr/bin/env bats + +@test "Create DB MongoDB" { + name='test' + kubectl apply -f - < +- 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` | + + +### Image configuration + +| Name | Description | Type | Value | +| --------------- | -------------------------------------- | -------- | --------------------------------------- | +| `images` | Container images used by the operator. | `object` | `{}` | +| `images.pmm` | PMM client image for monitoring. | `string` | `percona/pmm-client:2.44.1` | +| `images.backup` | Percona Backup for MongoDB image. | `string` | `percona/percona-backup-mongodb:2.11.0` | + + +### 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` | Custom MongoDB users configuration map. | `map[string]object` | `{}` | +| `users[name].password` | Password for the user (auto-generated if omitted). | `string` | `""` | +| `users[name].db` | Database to authenticate against. | `string` | `""` | +| `users[name].roles` | List of MongoDB roles with database scope. | `[]object` | `[]` | +| `users[name].roles[i].name` | Role name (e.g., readWrite, dbAdmin, clusterAdmin). | `string` | `""` | +| `users[name].roles[i].db` | Database the role applies to. | `string` | `""` | + + +### Backup parameters + +| Name | Description | Type | Value | +| ------------------------ | ------------------------------------------------------ | -------- | ----------------------------------- | +| `backup` | Backup configuration. | `object` | `{}` | +| `backup.enabled` | Enable regular backups. | `bool` | `false` | +| `backup.schedule` | Cron schedule for automated backups. | `string` | `0 2 * * *` | +| `backup.retentionPolicy` | Retention policy (e.g. "30d"). | `string` | `30d` | +| `backup.destinationPath` | Destination path for backups (e.g. s3://bucket/path/). | `string` | `s3://bucket/path/to/folder/` | +| `backup.endpointURL` | S3 endpoint URL for uploads. | `string` | `http://minio-gateway-service:9000` | +| `backup.s3AccessKey` | Access key for S3 authentication. | `string` | `""` | +| `backup.s3SecretKey` | Secret key for S3 authentication. | `string` | `""` | + + +### Bootstrap (recovery) parameters + +| Name | Description | Type | Value | +| ------------------------ | --------------------------------------------------------- | -------- | ------- | +| `bootstrap` | Bootstrap configuration. | `object` | `{}` | +| `bootstrap.enabled` | Whether to restore from a backup. | `bool` | `false` | +| `bootstrap.recoveryTime` | Timestamp for point-in-time recovery; empty means latest. | `string` | `""` | +| `bootstrap.backupName` | Name of backup to restore from. | `string` | `""` | + diff --git a/packages/apps/mongodb/charts/cozy-lib b/packages/apps/mongodb/charts/cozy-lib new file mode 120000 index 00000000..e1813509 --- /dev/null +++ b/packages/apps/mongodb/charts/cozy-lib @@ -0,0 +1 @@ +../../../library/cozy-lib \ No newline at end of file diff --git a/packages/apps/mongodb/files/versions.yaml b/packages/apps/mongodb/files/versions.yaml new file mode 100644 index 00000000..ee1333c5 --- /dev/null +++ b/packages/apps/mongodb/files/versions.yaml @@ -0,0 +1,5 @@ +# MongoDB version mapping (major version -> Percona image tag) +# Auto-generated by hack/update-versions.sh - do not edit manually +"v8": "8.0.17-6" +"v7": "7.0.28-15" +"v6": "6.0.25-20" diff --git a/packages/apps/mongodb/hack/update-versions.sh b/packages/apps/mongodb/hack/update-versions.sh new file mode 100755 index 00000000..832eaf76 --- /dev/null +++ b/packages/apps/mongodb/hack/update-versions.sh @@ -0,0 +1,125 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +MONGODB_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +VALUES_FILE="${MONGODB_DIR}/values.yaml" +VERSIONS_FILE="${MONGODB_DIR}/files/versions.yaml" + +# Supported major versions (newest first) +SUPPORTED_MAJOR_VERSIONS="8 7 6" + +echo "Supported major versions: $SUPPORTED_MAJOR_VERSIONS" + +# Check if skopeo is installed +if ! command -v skopeo &> /dev/null; then + echo "Error: skopeo is not installed. Please install skopeo and try again." >&2 + exit 1 +fi + +# Check if jq is installed +if ! command -v jq &> /dev/null; then + echo "Error: jq is not installed. Please install jq and try again." >&2 + exit 1 +fi + +# Get available image tags from Percona registry +echo "Fetching available image tags from registry..." +AVAILABLE_TAGS=$(skopeo list-tags docker://percona/percona-server-mongodb | jq -r '.Tags[]' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+-[0-9]+$' | sort -V) + +if [ -z "$AVAILABLE_TAGS" ]; then + echo "Error: Could not fetch available image tags" >&2 + exit 1 +fi + +# Build versions map: major version -> latest tag +declare -A VERSION_MAP +MAJOR_VERSIONS=() + +for major_version in $SUPPORTED_MAJOR_VERSIONS; do + # Find all tags that match this major version + matching_tags=$(echo "$AVAILABLE_TAGS" | grep "^${major_version}\\.") + + if [ -n "$matching_tags" ]; then + # Get the latest tag for this major version + latest_tag=$(echo "$matching_tags" | tail -n1) + VERSION_MAP["v${major_version}"]="${latest_tag}" + MAJOR_VERSIONS+=("v${major_version}") + echo "Found version: v${major_version} -> ${latest_tag}" + fi +done + +if [ ${#MAJOR_VERSIONS[@]} -eq 0 ]; then + echo "Error: No matching versions found" >&2 + exit 1 +fi + +echo "Major versions to add: ${MAJOR_VERSIONS[*]}" + +# Create/update versions.yaml file +echo "Updating $VERSIONS_FILE..." +{ + echo "# MongoDB version mapping (major version -> Percona image tag)" + echo "# Auto-generated by hack/update-versions.sh - do not edit manually" + for major_ver in "${MAJOR_VERSIONS[@]}"; do + echo "\"${major_ver}\": \"${VERSION_MAP[$major_ver]}\"" + done +} > "$VERSIONS_FILE" + +echo "Successfully updated $VERSIONS_FILE" + +# Update values.yaml - enum with major versions only +TEMP_FILE=$(mktemp) +trap 'rm -f "$TEMP_FILE" "${TEMP_FILE}.tmp"' EXIT + +# Build new version section +NEW_VERSION_SECTION="## @enum {string} Version" +for major_ver in "${MAJOR_VERSIONS[@]}"; do + NEW_VERSION_SECTION="${NEW_VERSION_SECTION} +## @value $major_ver" +done +NEW_VERSION_SECTION="${NEW_VERSION_SECTION} + +## @param {Version} version - MongoDB major version to deploy. +version: ${MAJOR_VERSIONS[0]}" + +# Check if version section already exists +if grep -q "^## @enum {string} Version" "$VALUES_FILE"; then + # Version section exists, update it using awk + echo "Updating existing version section in $VALUES_FILE..." + + # Use awk to replace the section from "## @enum {string} Version" to "version: " (inclusive) + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @enum {string} Version/ { + in_section = 1 + print new_section + next + } + in_section && /^version: / { + in_section = 0 + next + } + in_section { + next + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +else + # Version section doesn't exist, insert it before Sharding section + echo "Inserting new version section in $VALUES_FILE..." + + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @section Sharding configuration/ { + print new_section + print "" + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +fi + +echo "Successfully updated $VALUES_FILE with major versions: ${MAJOR_VERSIONS[*]}" diff --git a/packages/apps/mongodb/logos/mongodb.svg b/packages/apps/mongodb/logos/mongodb.svg new file mode 100644 index 00000000..3c76d2d6 --- /dev/null +++ b/packages/apps/mongodb/logos/mongodb.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/packages/apps/mongodb/templates/.gitkeep b/packages/apps/mongodb/templates/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/packages/apps/mongodb/templates/_versions.tpl b/packages/apps/mongodb/templates/_versions.tpl new file mode 100644 index 00000000..6afc6457 --- /dev/null +++ b/packages/apps/mongodb/templates/_versions.tpl @@ -0,0 +1,12 @@ +{{/* +MongoDB version mapping +*/}} +{{- define "mongodb.versionMap" -}} +{{- $versions := .Files.Get "files/versions.yaml" | fromYaml -}} +{{- $version := .Values.version -}} +{{- if hasKey $versions $version -}} +{{- index $versions $version -}} +{{- else -}} +{{- fail (printf "Unsupported MongoDB version: %s. Supported versions: %s" $version (keys $versions | sortAlpha | join ", ")) -}} +{{- end -}} +{{- end -}} diff --git a/packages/apps/mongodb/templates/backup-secret.yaml b/packages/apps/mongodb/templates/backup-secret.yaml new file mode 100644 index 00000000..f7b2ba01 --- /dev/null +++ b/packages/apps/mongodb/templates/backup-secret.yaml @@ -0,0 +1,11 @@ +{{- if or .Values.backup.enabled .Values.bootstrap.enabled }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Release.Name }}-s3-creds +type: Opaque +stringData: + AWS_ACCESS_KEY_ID: {{ required "backup.s3AccessKey is required when backup or bootstrap is enabled" .Values.backup.s3AccessKey | quote }} + AWS_SECRET_ACCESS_KEY: {{ required "backup.s3SecretKey is required when backup or bootstrap is enabled" .Values.backup.s3SecretKey | quote }} +{{- end }} diff --git a/packages/apps/mongodb/templates/credentials.yaml b/packages/apps/mongodb/templates/credentials.yaml new file mode 100644 index 00000000..561f7672 --- /dev/null +++ b/packages/apps/mongodb/templates/credentials.yaml @@ -0,0 +1,34 @@ +{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }} +{{- $operatorSecret := lookup "v1" "Secret" .Release.Namespace (printf "internal-%s-users" .Release.Name) }} +{{- $password := "" }} +{{- if and $operatorSecret (hasKey $operatorSecret.data "MONGODB_DATABASE_ADMIN_PASSWORD") }} +{{- $password = index $operatorSecret.data "MONGODB_DATABASE_ADMIN_PASSWORD" | b64dec }} +{{- end }} +--- +# Dashboard credentials - lookup from operator-created secret +# Operator creates secret named "internal--users" with system user passwords +# Note: On first install, password/uri will be empty until operator creates the secret. +# Run 'helm upgrade' after MongoDB is ready to populate credentials. +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Release.Name }}-credentials +type: Opaque +stringData: + username: databaseAdmin + password: {{ $password | quote }} + {{- if .Values.sharding }} + host: {{ .Release.Name }}-mongos.{{ .Release.Namespace }}.svc.{{ $clusterDomain }} + {{- else }} + host: {{ .Release.Name }}-rs0.{{ .Release.Namespace }}.svc.{{ $clusterDomain }} + {{- end }} + port: "27017" + {{- if $password }} + {{- if .Values.sharding }} + uri: mongodb://databaseAdmin:{{ $password | urlquery }}@{{ .Release.Name }}-mongos.{{ .Release.Namespace }}.svc.{{ $clusterDomain }}:27017/admin + {{- else }} + uri: mongodb://databaseAdmin:{{ $password | urlquery }}@{{ .Release.Name }}-rs0.{{ .Release.Namespace }}.svc.{{ $clusterDomain }}:27017/admin?replicaSet=rs0 + {{- end }} + {{- else }} + uri: "" + {{- end }} diff --git a/packages/apps/mongodb/templates/dashboard-resourcemap.yaml b/packages/apps/mongodb/templates/dashboard-resourcemap.yaml new file mode 100644 index 00000000..33a6a4ef --- /dev/null +++ b/packages/apps/mongodb/templates/dashboard-resourcemap.yaml @@ -0,0 +1,39 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ .Release.Name }}-dashboard-resources +rules: +- apiGroups: + - "" + resources: + - services + resourceNames: + - {{ .Release.Name }}-rs0 + - {{ .Release.Name }}-mongos + - {{ .Release.Name }}-external + 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/mongodb/templates/external-svc.yaml b/packages/apps/mongodb/templates/external-svc.yaml new file mode 100644 index 00000000..22324514 --- /dev/null +++ b/packages/apps/mongodb/templates/external-svc.yaml @@ -0,0 +1,24 @@ +{{- if .Values.external }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-external +spec: + type: LoadBalancer + externalTrafficPolicy: Local + {{- if (include "cozy-lib.network.disableLoadBalancerNodePorts" $ | fromYaml) }} + allocateLoadBalancerNodePorts: false + {{- end }} + ports: + - name: mongodb + port: 27017 + selector: + app.kubernetes.io/name: percona-server-mongodb + app.kubernetes.io/instance: {{ .Release.Name }} + {{- if .Values.sharding }} + app.kubernetes.io/component: mongos + {{- else }} + app.kubernetes.io/component: mongod + app.kubernetes.io/replset: rs0 + {{- end }} +{{- end }} diff --git a/packages/apps/mongodb/templates/mongodb.yaml b/packages/apps/mongodb/templates/mongodb.yaml new file mode 100644 index 00000000..ffd358f4 --- /dev/null +++ b/packages/apps/mongodb/templates/mongodb.yaml @@ -0,0 +1,173 @@ +{{- $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: {{ .Values.images.pmm }} + 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 }} + users: + {{- range $username, $user := .Values.users }} + {{- if not $user.roles }} + {{- fail (printf "users.%s.roles is required and cannot be empty" $username) }} + {{- end }} + - name: {{ $username }} + db: {{ $user.db }} + passwordSecretRef: + name: {{ $.Release.Name }}-user-{{ $username }} + key: password + roles: + {{- range $user.roles }} + - name: {{ .name }} + db: {{ .db }} + {{- end }} + {{- end }} + {{- end }} + + backup: + enabled: {{ .Values.backup.enabled | default false }} + image: {{ .Values.images.backup }} + {{- 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 }} +spec: + {{- if .Values.sharding }} + {{- $totalReplicas := 0 }} + {{- range .Values.shardingConfig.shards }} + {{- $totalReplicas = add $totalReplicas .replicas }} + {{- end }} + replicas: {{ $totalReplicas }} + {{- else }} + replicas: {{ .Values.replicas }} + {{- end }} + minReplicas: 1 + kind: mongodb + type: mongodb + selector: + app.kubernetes.io/name: percona-server-mongodb + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: mongod + version: {{ .Chart.Version }} diff --git a/packages/apps/mongodb/templates/restore.yaml b/packages/apps/mongodb/templates/restore.yaml new file mode 100644 index 00000000..56e2150b --- /dev/null +++ b/packages/apps/mongodb/templates/restore.yaml @@ -0,0 +1,37 @@ +{{- if .Values.bootstrap.enabled }} +{{- if not .Values.bootstrap.backupName }} +{{- fail "bootstrap.backupName is required when bootstrap.enabled is true" }} +{{- end }} +{{- if not .Values.backup.destinationPath }} +{{- fail "backup.destinationPath is required when bootstrap.enabled is true" }} +{{- end }} +{{- if not .Values.backup.endpointURL }} +{{- fail "backup.endpointURL is required when bootstrap.enabled is true" }} +{{- end }} +{{- if not .Values.backup.s3AccessKey }} +{{- fail "backup.s3AccessKey is required when bootstrap.enabled is true" }} +{{- end }} +{{- if not .Values.backup.s3SecretKey }} +{{- fail "backup.s3SecretKey is required when bootstrap.enabled is true" }} +{{- end }} +--- +apiVersion: psmdb.percona.com/v1 +kind: PerconaServerMongoDBRestore +metadata: + name: {{ .Release.Name }}-restore +spec: + clusterName: {{ .Release.Name }} + {{- if .Values.bootstrap.recoveryTime }} + pitr: + type: date + date: {{ .Values.bootstrap.recoveryTime | quote }} + {{- end }} + backupSource: + type: logical + destination: {{ .Values.backup.destinationPath | trimSuffix "/" }}/{{ .Values.bootstrap.backupName }} + s3: + credentialsSecret: {{ .Release.Name }}-s3-creds + endpointUrl: {{ .Values.backup.endpointURL }} + insecureSkipTLSVerify: false + forcePathStyle: true +{{- end }} diff --git a/packages/apps/mongodb/templates/user-secrets.yaml b/packages/apps/mongodb/templates/user-secrets.yaml new file mode 100644 index 00000000..8212e95f --- /dev/null +++ b/packages/apps/mongodb/templates/user-secrets.yaml @@ -0,0 +1,17 @@ +{{- range $username, $user := .Values.users }} +{{- $existingSecret := lookup "v1" "Secret" $.Release.Namespace (printf "%s-user-%s" $.Release.Name $username) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ $.Release.Name }}-user-{{ $username }} +type: Opaque +stringData: + {{- if $user.password }} + password: {{ $user.password | quote }} + {{- else if and $existingSecret (hasKey $existingSecret.data "password") }} + password: {{ index $existingSecret.data "password" | b64dec | quote }} + {{- else }} + password: {{ randAlphaNum 16 | quote }} + {{- end }} +{{- end }} diff --git a/packages/apps/mongodb/tests/backup-secret_test.yaml b/packages/apps/mongodb/tests/backup-secret_test.yaml new file mode 100644 index 00000000..f3eca410 --- /dev/null +++ b/packages/apps/mongodb/tests/backup-secret_test.yaml @@ -0,0 +1,112 @@ +suite: backup secret tests + +templates: + - templates/backup-secret.yaml + +tests: + # Not rendered when both backup and bootstrap disabled + - it: does not render when backup and bootstrap disabled + release: + name: test-mongodb + namespace: tenant-test + set: + backup: + enabled: false + bootstrap: + enabled: false + asserts: + - hasDocuments: + count: 0 + + # Rendered when backup enabled + - it: renders when backup enabled + release: + name: test-mongodb + namespace: tenant-test + set: + backup: + enabled: true + s3AccessKey: "AKIAIOSFODNN7EXAMPLE" + s3SecretKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + asserts: + - hasDocuments: + count: 1 + - isKind: + of: Secret + + # Rendered when bootstrap enabled (for restore) + - it: renders when bootstrap enabled + release: + name: test-mongodb + namespace: tenant-test + set: + backup: + enabled: false + s3AccessKey: "AKIAIOSFODNN7EXAMPLE" + s3SecretKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + bootstrap: + enabled: true + asserts: + - hasDocuments: + count: 1 + + # Secret name + - it: uses correct secret name + release: + name: mydb + namespace: tenant-test + set: + backup: + enabled: true + s3AccessKey: "accesskey" + s3SecretKey: "secretkey" + asserts: + - equal: + path: metadata.name + value: mydb-s3-creds + + # Contains AWS credentials + - it: contains AWS credentials + release: + name: test-mongodb + namespace: tenant-test + set: + backup: + enabled: true + s3AccessKey: "MYACCESSKEY" + s3SecretKey: "MYSECRETKEY" + asserts: + - equal: + path: stringData.AWS_ACCESS_KEY_ID + value: "MYACCESSKEY" + - equal: + path: stringData.AWS_SECRET_ACCESS_KEY + value: "MYSECRETKEY" + + # Fails without s3AccessKey + - it: fails when s3AccessKey missing + release: + name: test-mongodb + namespace: tenant-test + set: + backup: + enabled: true + s3AccessKey: "" + s3SecretKey: "secretkey" + asserts: + - failedTemplate: + errorMessage: "backup.s3AccessKey is required when backup or bootstrap is enabled" + + # Fails without s3SecretKey + - it: fails when s3SecretKey missing + release: + name: test-mongodb + namespace: tenant-test + set: + backup: + enabled: true + s3AccessKey: "accesskey" + s3SecretKey: "" + asserts: + - failedTemplate: + errorMessage: "backup.s3SecretKey is required when backup or bootstrap is enabled" diff --git a/packages/apps/mongodb/tests/credentials_test.yaml b/packages/apps/mongodb/tests/credentials_test.yaml new file mode 100644 index 00000000..b06924ef --- /dev/null +++ b/packages/apps/mongodb/tests/credentials_test.yaml @@ -0,0 +1,132 @@ +suite: credentials tests + +templates: + - templates/credentials.yaml + +tests: + # Basic rendering + - it: always renders a Secret + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - hasDocuments: + count: 1 + - isKind: + of: Secret + - equal: + path: metadata.name + value: test-mongodb-credentials + - equal: + path: type + value: Opaque + + # Username is always databaseAdmin + - it: sets username to databaseAdmin + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: stringData.username + value: databaseAdmin + + # Port is always 27017 + - it: sets port to 27017 + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: stringData.port + value: "27017" + + # Host for replica set mode + - it: uses rs0 service for replica set mode + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + sharding: false + asserts: + - equal: + path: stringData.host + value: test-mongodb-rs0.tenant-test.svc.cozy.local + + # Host for sharded mode + - it: uses mongos service for sharded mode + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + sharding: true + asserts: + - equal: + path: stringData.host + value: test-mongodb-mongos.tenant-test.svc.cozy.local + + # Custom cluster domain + - it: uses custom cluster domain + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: custom.domain + sharding: false + asserts: + - equal: + path: stringData.host + value: test-mongodb-rs0.tenant-test.svc.custom.domain + + # Default cluster domain when not set + - it: defaults to cozy.local when cluster domain not set + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: {} + sharding: false + asserts: + - equal: + path: stringData.host + value: test-mongodb-rs0.tenant-test.svc.cozy.local + + # Password empty without operator secret (lookup returns nil in tests) + - it: has empty password on first install + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: stringData.password + value: "" + + # URI empty without password + - it: has empty uri when password not available + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: stringData.uri + value: "" diff --git a/packages/apps/mongodb/tests/dashboard-resourcemap_test.yaml b/packages/apps/mongodb/tests/dashboard-resourcemap_test.yaml new file mode 100644 index 00000000..8cc1a0a7 --- /dev/null +++ b/packages/apps/mongodb/tests/dashboard-resourcemap_test.yaml @@ -0,0 +1,106 @@ +suite: dashboard resourcemap tests + +templates: + - templates/dashboard-resourcemap.yaml + +tests: + # Always renders Role and RoleBinding + - it: renders Role and RoleBinding + release: + name: test-mongodb + namespace: tenant-test + asserts: + - hasDocuments: + count: 2 + - isKind: + of: Role + documentIndex: 0 + - isKind: + of: RoleBinding + documentIndex: 1 + + # Role naming + - it: uses correct Role name + release: + name: mydb + namespace: tenant-test + asserts: + - equal: + path: metadata.name + value: mydb-dashboard-resources + documentIndex: 0 + + # RoleBinding naming + - it: uses correct RoleBinding name + release: + name: mydb + namespace: tenant-test + asserts: + - equal: + path: metadata.name + value: mydb-dashboard-resources + documentIndex: 1 + + # Role grants access to services + - it: grants access to MongoDB services + release: + name: test-mongodb + namespace: tenant-test + asserts: + - contains: + path: rules[0].resourceNames + content: test-mongodb-rs0 + documentIndex: 0 + - contains: + path: rules[0].resourceNames + content: test-mongodb-mongos + documentIndex: 0 + - contains: + path: rules[0].resourceNames + content: test-mongodb-external + documentIndex: 0 + + # Role grants access to credentials secret + - it: grants access to credentials secret + release: + name: test-mongodb + namespace: tenant-test + asserts: + - contains: + path: rules[1].resourceNames + content: test-mongodb-credentials + documentIndex: 0 + + # Role grants access to workloadmonitor + - it: grants access to WorkloadMonitor + release: + name: test-mongodb + namespace: tenant-test + asserts: + - contains: + path: rules[2].resourceNames + content: test-mongodb + documentIndex: 0 + - equal: + path: rules[2].apiGroups[0] + value: cozystack.io + documentIndex: 0 + + # RoleBinding references correct Role + - it: RoleBinding references correct Role + release: + name: test-mongodb + namespace: tenant-test + asserts: + - equal: + path: roleRef.kind + value: Role + documentIndex: 1 + - equal: + path: roleRef.name + value: test-mongodb-dashboard-resources + documentIndex: 1 + - equal: + path: roleRef.apiGroup + value: rbac.authorization.k8s.io + documentIndex: 1 diff --git a/packages/apps/mongodb/tests/external-svc_test.yaml b/packages/apps/mongodb/tests/external-svc_test.yaml new file mode 100644 index 00000000..ed3bf597 --- /dev/null +++ b/packages/apps/mongodb/tests/external-svc_test.yaml @@ -0,0 +1,154 @@ +suite: external service tests + +templates: + - templates/external-svc.yaml + +tests: + ################### + # Rendering # + ################### + + - it: does not render when external is false + release: + name: test-mongodb + namespace: tenant-test + set: + external: false + asserts: + - hasDocuments: + count: 0 + + - it: renders LoadBalancer service when external is true + release: + name: test-mongodb + namespace: tenant-test + set: + external: true + asserts: + - hasDocuments: + count: 1 + - isKind: + of: Service + + ################### + # Service config # + ################### + + - it: uses correct service name + release: + name: mydb + namespace: tenant-test + set: + external: true + asserts: + - equal: + path: metadata.name + value: mydb-external + + - it: sets LoadBalancer type + release: + name: test-mongodb + namespace: tenant-test + set: + external: true + asserts: + - equal: + path: spec.type + value: LoadBalancer + + - it: sets externalTrafficPolicy to Local + release: + name: test-mongodb + namespace: tenant-test + set: + external: true + asserts: + - equal: + path: spec.externalTrafficPolicy + value: Local + + - it: exposes MongoDB port 27017 + release: + name: test-mongodb + namespace: tenant-test + set: + external: true + asserts: + - equal: + path: spec.ports[0].name + value: mongodb + - equal: + path: spec.ports[0].port + value: 27017 + + ########################### + # Common selector labels # + ########################### + + - it: sets app.kubernetes.io/name selector + release: + name: test-mongodb + namespace: tenant-test + set: + external: true + asserts: + - equal: + path: spec.selector["app.kubernetes.io/name"] + value: percona-server-mongodb + + - it: sets app.kubernetes.io/instance selector + release: + name: mydb + namespace: tenant-test + set: + external: true + asserts: + - equal: + path: spec.selector["app.kubernetes.io/instance"] + value: mydb + + ########################### + # Replica set mode # + ########################### + + - it: selects mongod for replica set mode + release: + name: test-mongodb + namespace: tenant-test + set: + external: true + sharding: false + asserts: + - equal: + path: spec.selector["app.kubernetes.io/component"] + value: mongod + - equal: + path: spec.selector["app.kubernetes.io/replset"] + value: rs0 + + ########################### + # Sharded mode # + ########################### + + - it: selects mongos for sharded mode + release: + name: test-mongodb + namespace: tenant-test + set: + external: true + sharding: true + asserts: + - equal: + path: spec.selector["app.kubernetes.io/component"] + value: mongos + + - it: does not set replset selector for sharded mode + release: + name: test-mongodb + namespace: tenant-test + set: + external: true + sharding: true + asserts: + - notExists: + path: spec.selector["app.kubernetes.io/replset"] diff --git a/packages/apps/mongodb/tests/mongodb_test.yaml b/packages/apps/mongodb/tests/mongodb_test.yaml new file mode 100644 index 00000000..db46fe79 --- /dev/null +++ b/packages/apps/mongodb/tests/mongodb_test.yaml @@ -0,0 +1,703 @@ +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: {} + asserts: + - notExists: + path: spec.users + documentIndex: 0 + + - it: configures users when defined + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + users: + appuser: + db: appdb + roles: + - name: readWrite + db: appdb + asserts: + - exists: + path: spec.users + documentIndex: 0 + - equal: + path: spec.users[0].name + value: appuser + documentIndex: 0 + - equal: + path: spec.users[0].db + value: appdb + 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: configures user roles + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + users: + admin: + db: admin + roles: + - name: clusterAdmin + db: admin + - name: userAdminAnyDatabase + db: admin + asserts: + - equal: + path: spec.users[0].roles[0].name + value: clusterAdmin + documentIndex: 0 + - equal: + path: spec.users[0].roles[0].db + value: admin + documentIndex: 0 + - equal: + path: spec.users[0].roles[1].name + value: userAdminAnyDatabase + documentIndex: 0 + + - it: fails when user has empty roles + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + users: + myuser: + db: mydb + roles: [] + asserts: + - failedTemplate: + errorMessage: "users.myuser.roles is required and cannot be empty" + + ########################### + # Backup configuration # + ########################### + + - it: disables backup when not enabled + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + backup: + enabled: false + asserts: + - equal: + path: spec.backup.enabled + value: false + documentIndex: 0 + - notExists: + path: spec.backup.storages + documentIndex: 0 + + - it: configures backup when enabled + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + backup: + enabled: true + schedule: "0 3 * * *" + retentionPolicy: 14d + destinationPath: "s3://mybucket/backups/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - equal: + path: spec.backup.enabled + value: true + documentIndex: 0 + - equal: + path: spec.backup.storages.s3-storage.type + value: s3 + documentIndex: 0 + + - it: parses bucket from destinationPath + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + backup: + enabled: true + destinationPath: "s3://my-backup-bucket/mongodb/prod/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - equal: + path: spec.backup.storages.s3-storage.s3.bucket + value: my-backup-bucket + documentIndex: 0 + + - it: parses prefix from destinationPath + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + backup: + enabled: true + destinationPath: "s3://bucket/path/to/backups/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - equal: + path: spec.backup.storages.s3-storage.s3.prefix + value: path/to/backups/ + documentIndex: 0 + + - it: sets backup retention from retentionPolicy + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + backup: + enabled: true + retentionPolicy: 30d + destinationPath: "s3://bucket/path/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - equal: + path: spec.backup.tasks[0].keep + value: 30 + documentIndex: 0 + + - it: sets backup schedule + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + backup: + enabled: true + schedule: "0 4 * * *" + retentionPolicy: 7d + destinationPath: "s3://bucket/path/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - equal: + path: spec.backup.tasks[0].schedule + value: "0 4 * * *" + documentIndex: 0 + + - it: enables PITR when backup enabled + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + backup: + enabled: true + destinationPath: "s3://bucket/path/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - equal: + path: spec.backup.pitr.enabled + value: true + documentIndex: 0 + + - it: references s3-creds secret for backup + release: + name: mydb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + backup: + enabled: true + destinationPath: "s3://bucket/path/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - equal: + path: spec.backup.storages.s3-storage.s3.credentialsSecret + value: mydb-s3-creds + documentIndex: 0 + + ########################### + # WorkloadMonitor # + ########################### + + - it: creates WorkloadMonitor with correct metadata + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: metadata.name + value: test-mongodb + documentIndex: 1 + - equal: + path: spec.kind + value: mongodb + documentIndex: 1 + - equal: + path: spec.type + value: mongodb + documentIndex: 1 + + - it: sets replicas from values in non-sharded mode + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + sharding: false + replicas: 5 + asserts: + - equal: + path: spec.replicas + value: 5 + documentIndex: 1 + + - it: calculates total replicas in sharded mode + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + sharding: true + shardingConfig: + configServers: 3 + configServerSize: 3Gi + mongos: 2 + shards: + - name: rs0 + replicas: 3 + size: 10Gi + - name: rs1 + replicas: 5 + size: 10Gi + - name: rs2 + replicas: 2 + size: 10Gi + asserts: + - equal: + path: spec.replicas + value: 10 + documentIndex: 1 + + - it: sets minReplicas to 1 + release: + name: test-mongodb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: spec.minReplicas + value: 1 + documentIndex: 1 + + - it: sets correct selector labels + release: + name: mydb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: spec.selector["app.kubernetes.io/name"] + value: percona-server-mongodb + documentIndex: 1 + - equal: + path: spec.selector["app.kubernetes.io/instance"] + value: mydb + documentIndex: 1 + - equal: + path: spec.selector["app.kubernetes.io/component"] + value: mongod + documentIndex: 1 + diff --git a/packages/apps/mongodb/tests/restore_test.yaml b/packages/apps/mongodb/tests/restore_test.yaml new file mode 100644 index 00000000..e591587b --- /dev/null +++ b/packages/apps/mongodb/tests/restore_test.yaml @@ -0,0 +1,349 @@ +suite: restore tests + +templates: + - templates/restore.yaml + +tests: + ##################### + # Rendering # + ##################### + + - it: does not render when bootstrap is disabled + release: + name: test-mongodb + namespace: tenant-test + set: + bootstrap: + enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: renders PerconaServerMongoDBRestore CR when enabled + release: + name: test-mongodb + namespace: tenant-test + set: + bootstrap: + enabled: true + backupName: "my-backup-2025-01-07" + backup: + destinationPath: "s3://bucket/backups/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - hasDocuments: + count: 1 + - isKind: + of: PerconaServerMongoDBRestore + + ##################### + # Validation # + ##################### + + - it: fails when backupName is missing + release: + name: test-mongodb + namespace: tenant-test + set: + bootstrap: + enabled: true + backupName: "" + backup: + destinationPath: "s3://bucket/path/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - failedTemplate: + errorMessage: "bootstrap.backupName is required when bootstrap.enabled is true" + + - it: fails when destinationPath is missing + release: + name: test-mongodb + namespace: tenant-test + set: + bootstrap: + enabled: true + backupName: "my-backup" + backup: + destinationPath: "" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - failedTemplate: + errorMessage: "backup.destinationPath is required when bootstrap.enabled is true" + + - it: fails when endpointURL is missing + release: + name: test-mongodb + namespace: tenant-test + set: + bootstrap: + enabled: true + backupName: "my-backup" + backup: + destinationPath: "s3://bucket/path/" + endpointURL: "" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - failedTemplate: + errorMessage: "backup.endpointURL is required when bootstrap.enabled is true" + + ##################### + # CR metadata # + ##################### + + - it: uses correct restore CR name + release: + name: mydb + namespace: tenant-test + set: + bootstrap: + enabled: true + backupName: "backup-2025" + backup: + destinationPath: "s3://bucket/backups/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - equal: + path: metadata.name + value: mydb-restore + + - it: references correct cluster name + release: + name: test-mongodb + namespace: tenant-test + set: + bootstrap: + enabled: true + backupName: "backup-2025" + backup: + destinationPath: "s3://bucket/backups/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - equal: + path: spec.clusterName + value: test-mongodb + + ##################### + # Backup source # + ##################### + + - it: sets backupSource type to logical + release: + name: test-mongodb + namespace: tenant-test + set: + bootstrap: + enabled: true + backupName: "backup-2025" + backup: + destinationPath: "s3://bucket/backups/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - equal: + path: spec.backupSource.type + value: logical + + - it: constructs destination from destinationPath and backupName + release: + name: test-mongodb + namespace: tenant-test + set: + bootstrap: + enabled: true + backupName: "daily-backup-2025-01-07" + backup: + destinationPath: "s3://mybucket/mongodb/prod/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - equal: + path: spec.backupSource.destination + value: s3://mybucket/mongodb/prod/daily-backup-2025-01-07 + + - it: trims trailing slash from destinationPath + release: + name: test-mongodb + namespace: tenant-test + set: + bootstrap: + enabled: true + backupName: "backup" + backup: + destinationPath: "s3://bucket/path/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - equal: + path: spec.backupSource.destination + value: s3://bucket/path/backup + + ##################### + # S3 configuration # + ##################### + + - it: references s3-creds secret + release: + name: mydb + namespace: tenant-test + set: + bootstrap: + enabled: true + backupName: "backup" + backup: + destinationPath: "s3://bucket/path/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - equal: + path: spec.backupSource.s3.credentialsSecret + value: mydb-s3-creds + + - it: sets S3 endpoint URL + release: + name: test-mongodb + namespace: tenant-test + set: + bootstrap: + enabled: true + backupName: "backup" + backup: + destinationPath: "s3://bucket/path/" + endpointURL: "https://s3.amazonaws.com" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - equal: + path: spec.backupSource.s3.endpointUrl + value: "https://s3.amazonaws.com" + + - it: disables insecureSkipTLSVerify + release: + name: test-mongodb + namespace: tenant-test + set: + bootstrap: + enabled: true + backupName: "backup" + backup: + destinationPath: "s3://bucket/path/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - equal: + path: spec.backupSource.s3.insecureSkipTLSVerify + value: false + + - it: enables forcePathStyle + release: + name: test-mongodb + namespace: tenant-test + set: + bootstrap: + enabled: true + backupName: "backup" + backup: + destinationPath: "s3://bucket/path/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - equal: + path: spec.backupSource.s3.forcePathStyle + value: true + + ##################### + # PITR # + ##################### + + - it: does not set pitr when recoveryTime not specified + release: + name: test-mongodb + namespace: tenant-test + set: + bootstrap: + enabled: true + backupName: "backup" + backup: + destinationPath: "s3://bucket/path/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - notExists: + path: spec.pitr + + - it: configures PITR when recoveryTime is set + release: + name: test-mongodb + namespace: tenant-test + set: + bootstrap: + enabled: true + backupName: "my-backup" + recoveryTime: "2025-01-07 14:30:00" + backup: + destinationPath: "s3://bucket/backups/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "secret" + asserts: + - equal: + path: spec.pitr.type + value: date + - equal: + path: spec.pitr.date + value: "2025-01-07 14:30:00" + + ##################### + # S3 credentials # + ##################### + + - it: fails when s3AccessKey is missing + release: + name: test-mongodb + namespace: tenant-test + set: + bootstrap: + enabled: true + backupName: "backup" + backup: + destinationPath: "s3://bucket/path/" + endpointURL: "http://minio:9000" + s3AccessKey: "" + s3SecretKey: "secret" + asserts: + - failedTemplate: + errorMessage: "backup.s3AccessKey is required when bootstrap.enabled is true" + + - it: fails when s3SecretKey is missing + release: + name: test-mongodb + namespace: tenant-test + set: + bootstrap: + enabled: true + backupName: "backup" + backup: + destinationPath: "s3://bucket/path/" + endpointURL: "http://minio:9000" + s3AccessKey: "access" + s3SecretKey: "" + asserts: + - failedTemplate: + errorMessage: "backup.s3SecretKey is required when bootstrap.enabled is true" diff --git a/packages/apps/mongodb/tests/user-secrets_test.yaml b/packages/apps/mongodb/tests/user-secrets_test.yaml new file mode 100644 index 00000000..b16e4243 --- /dev/null +++ b/packages/apps/mongodb/tests/user-secrets_test.yaml @@ -0,0 +1,98 @@ +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: + db: mydb + roles: + - name: readWrite + db: mydb + 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: + db: db1 + roles: + - name: readWrite + db: db1 + user2: + db: db2 + roles: + - name: dbAdmin + db: db2 + 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" + db: mydb + roles: + - name: readWrite + db: mydb + 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: + db: admin + roles: + - name: clusterAdmin + db: admin + asserts: + - equal: + path: metadata.name + value: prod-db-user-admin diff --git a/packages/apps/mongodb/values.schema.json b/packages/apps/mongodb/values.schema.json new file mode 100644 index 00000000..74ffec7c --- /dev/null +++ b/packages/apps/mongodb/values.schema.json @@ -0,0 +1,309 @@ +{ + "title": "Chart Values", + "type": "object", + "properties": { + "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": "" + } + } + }, + "external": { + "description": "Enable external access from outside the cluster.", + "type": "boolean", + "default": false + }, + "images": { + "description": "Container images used by the operator.", + "type": "object", + "default": {}, + "required": [ + "backup", + "pmm" + ], + "properties": { + "backup": { + "description": "Percona Backup for MongoDB image.", + "type": "string", + "default": "percona/percona-backup-mongodb:2.11.0" + }, + "pmm": { + "description": "PMM client image for monitoring.", + "type": "string", + "default": "percona/pmm-client:2.44.1" + } + } + }, + "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" + ] + }, + "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 + } + } + } + } + } + }, + "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": "Custom MongoDB users configuration map.", + "type": "object", + "default": {}, + "additionalProperties": { + "type": "object", + "required": [ + "db" + ], + "properties": { + "db": { + "description": "Database to authenticate against.", + "type": "string" + }, + "password": { + "description": "Password for the user (auto-generated if omitted).", + "type": "string" + }, + "roles": { + "description": "List of MongoDB roles with database scope.", + "type": "array", + "items": { + "type": "object", + "required": [ + "db", + "name" + ], + "properties": { + "db": { + "description": "Database the role applies to.", + "type": "string" + }, + "name": { + "description": "Role name (e.g., readWrite, dbAdmin, clusterAdmin).", + "type": "string" + } + } + } + } + } + } + }, + "version": { + "description": "MongoDB major version to deploy.", + "type": "string", + "default": "v8", + "enum": [ + "v8", + "v7", + "v6" + ] + } + } +} \ No newline at end of file diff --git a/packages/apps/mongodb/values.yaml b/packages/apps/mongodb/values.yaml new file mode 100644 index 00000000..ea3a18dd --- /dev/null +++ b/packages/apps/mongodb/values.yaml @@ -0,0 +1,147 @@ +## +## @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 Image configuration +## + +## @typedef {struct} Images - Container image configuration. +## @field {string} pmm - PMM client image for monitoring. +## @field {string} backup - Percona Backup for MongoDB image. + +## @param {Images} images - Container images used by the operator. +images: + pmm: "percona/pmm-client:2.44.1" + backup: "percona/percona-backup-mongodb:2.11.0" + +## +## @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} Role - MongoDB role configuration. +## @field {string} name - Role name (e.g., readWrite, dbAdmin, clusterAdmin). +## @field {string} db - Database the role applies to. + +## @typedef {struct} User - User configuration. +## @field {string} [password] - Password for the user (auto-generated if omitted). +## @field {string} db - Database to authenticate against. +## @field {[]Role} roles - List of MongoDB roles with database scope. + +## @param {map[string]User} users - Custom MongoDB users configuration map. +users: {} +## Example: +## users: +## myuser: +## db: mydb +## roles: +## - name: readWrite +## db: mydb +## - name: dbAdmin +## db: mydb + +## +## @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/core/platform/bundles/paas-full.yaml b/packages/core/platform/bundles/paas-full.yaml index b83dec08..44a247f4 100644 --- a/packages/core/platform/bundles/paas-full.yaml +++ b/packages/core/platform/bundles/paas-full.yaml @@ -208,6 +208,12 @@ releases: namespace: cozy-system dependsOn: [cozystack-resource-definition-crd] +- name: mongodb-rd + releaseName: mongodb-rd + chart: mongodb-rd + namespace: cozy-system + dependsOn: [cozystack-resource-definition-crd] + - name: seaweedfs-rd releaseName: seaweedfs-rd chart: seaweedfs-rd @@ -411,6 +417,12 @@ releases: namespace: cozy-redis-operator dependsOn: [cilium,kubeovn,multus] +- name: mongodb-operator + releaseName: mongodb-operator + chart: cozy-mongodb-operator + namespace: cozy-mongodb-operator + dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] + - name: piraeus-operator releaseName: piraeus-operator chart: cozy-piraeus-operator diff --git a/packages/core/platform/sources/mongodb-application.yaml b/packages/core/platform/sources/mongodb-application.yaml new file mode 100644 index 00000000..b6106fe1 --- /dev/null +++ b/packages/core/platform/sources/mongodb-application.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.mongodb-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: mongodb + path: apps/mongodb + libraries: ["cozy-lib"] + - name: mongodb-rd + path: system/mongodb-rd + install: + namespace: cozy-system + releaseName: mongodb-rd diff --git a/packages/core/platform/sources/mongodb-operator.yaml b/packages/core/platform/sources/mongodb-operator.yaml new file mode 100644 index 00000000..e3d6fe9e --- /dev/null +++ b/packages/core/platform/sources/mongodb-operator.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.mongodb-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.prometheus-operator-crds + - cozystack.cert-manager + components: + - name: mongodb-operator + path: system/mongodb-operator + install: + namespace: cozy-mongodb-operator + releaseName: mongodb-operator diff --git a/packages/system/mongodb-operator/.helmignore b/packages/system/mongodb-operator/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/packages/system/mongodb-operator/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/packages/system/mongodb-operator/Chart.yaml b/packages/system/mongodb-operator/Chart.yaml new file mode 100644 index 00000000..6dc477a8 --- /dev/null +++ b/packages/system/mongodb-operator/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-mongodb-operator +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/mongodb-operator/Makefile b/packages/system/mongodb-operator/Makefile new file mode 100644 index 00000000..797ae6db --- /dev/null +++ b/packages/system/mongodb-operator/Makefile @@ -0,0 +1,11 @@ +export NAME=mongodb-operator +export NAMESPACE=cozy-$(NAME) + +include ../../../scripts/package.mk + +update: + rm -rf charts + helm repo add percona https://percona.github.io/percona-helm-charts + helm repo update percona + helm pull percona/psmdb-operator --untar --untardir charts + rm -rf charts/psmdb-operator/charts diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/.helmignore b/packages/system/mongodb-operator/charts/psmdb-operator/.helmignore new file mode 100644 index 00000000..50af0317 --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/Chart.yaml b/packages/system/mongodb-operator/charts/psmdb-operator/Chart.yaml new file mode 100644 index 00000000..4c268c13 --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v2 +appVersion: 1.21.1 +description: A Helm chart for deploying the Percona Operator for MongoDB +home: https://docs.percona.com/percona-operator-for-mongodb/ +maintainers: +- email: natalia.marukovich@percona.com + name: nmarukovich +- email: julio.pasinatto@percona.com + name: jvpasinatto +- email: eleonora.zinchenko@percona.com + name: eleo007 +name: psmdb-operator +version: 1.21.2 diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/LICENSE.txt b/packages/system/mongodb-operator/charts/psmdb-operator/LICENSE.txt new file mode 100644 index 00000000..6a31453a --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/LICENSE.txt @@ -0,0 +1,13 @@ +Copyright 2019 Paul Czarkowski + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/README.md b/packages/system/mongodb-operator/charts/psmdb-operator/README.md new file mode 100644 index 00000000..18292d17 --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/README.md @@ -0,0 +1,77 @@ +# Percona Operator for MongoDB + +Percona Operator for MongoDB allows users to deploy and manage Percona Server for MongoDB Clusters on Kubernetes. +Useful links: +- [Operator Github repository](https://github.com/percona/percona-server-mongodb-operator) +- [Operator Documentation](https://www.percona.com/doc/kubernetes-operator-for-psmongodb/index.html) + +## Pre-requisites +* Kubernetes 1.30+ +* Helm v3 + +# Installation + +This chart will deploy the Operator Pod for the further Percona Server for MongoDB creation in Kubernetes. + +## Installing the chart + +To install the chart with the `psmdb` release name using a dedicated namespace (recommended): + +```sh +helm repo add percona https://percona.github.io/percona-helm-charts/ +helm install my-operator percona/psmdb-operator --version 1.21.2 --namespace my-namespace +``` + +The chart can be customized using the following configurable parameters: + +| Parameter | Description | Default | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------ | ----------------------------------------- | +| `image.repository` | PSMDB Operator Container image name | `percona/percona-server-mongodb-operator` | +| `image.tag` | PSMDB Operator Container image tag | `1.21.1` | +| `image.pullPolicy` | PSMDB Operator Container pull policy | `Always` | +| `image.pullSecrets` | PSMDB Operator Pod pull secret | `[]` | +| `replicaCount` | PSMDB Operator Pod quantity | `1` | +| `tolerations` | List of node taints to tolerate | `[]` | +| `annotations` | PSMDB Operator Deployment annotations | `{}` | +| `podAnnotations` | PSMDB Operator Pod annotations | `{}` | +| `labels` | PSMDB Operator Deployment labels | `{}` | +| `podLabels` | PSMDB Operator Pod labels | `{}` | +| `resources` | Resource requests and limits | `{}` | +| `nodeSelector` | Labels for Pod assignment | `{}` | +| `podAnnotations` | Annotations for pod | `{}` | +| `podSecurityContext` | Pod Security Context | `{}` | +| `watchNamespace` | Set when a different from default namespace is needed to watch (comma separated if multiple needed) | `""` | +| `createNamespace` | Set if you want to create watched namespaces with helm | `false` | +| `rbac.create` | If false RBAC will not be created. RBAC resources will need to be created manually | `true` | +| `securityContext` | Container Security Context | `{}` | +| `serviceAccount.create` | If false the ServiceAccounts will not be created. The ServiceAccounts must be created manually | `true` | +| `serviceAccount.annotations` | PSMDB Operator ServiceAccount annotations | `{}` | +| `logStructured` | Force PSMDB operator to print JSON-wrapped log messages | `false` | +| `logLevel` | PSMDB Operator logging level | `INFO` | +| `disableTelemetry` | Disable sending PSMDB Operator telemetry data to Percona | `false` | +| `maxConcurrentReconciles` | Number of concurrent workers that can reconcile resources in Percona Server for MongoDB clusters in parallel | `1` | + +Specify parameters using `--set key=value[,key=value]` argument to `helm install` + +Alternatively a YAML file that specifies the values for the parameters can be provided like this: + +```sh +helm install psmdb-operator -f values.yaml percona/psmdb-operator +``` + +## Deploy the database + +To deploy Percona Server for MongoDB run the following command: + +```sh +helm install my-db percona/psmdb-db +``` + +See more about Percona Server for MongoDB deployment in its chart [here](https://github.com/percona/percona-helm-charts/tree/main/charts/psmdb-db) or in the [Helm chart installation guide](https://www.percona.com/doc/kubernetes-operator-for-psmongodb/helm.html). + +# Need help? + +**Commercial Support** | **Community Support** | +:-: | :-: | +|
Enterprise-grade assistance for your mission-critical database deployments in containers and Kubernetes. Get expert guidance for complex tasks like multi-cloud replication, database migration and building platforms.

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

| +| **[Get Percona Support](https://hubs.ly/Q02ZTH8Q0)** | **[Visit our Forum](https://forums.percona.com/)** | diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/crds/crd.yaml b/packages/system/mongodb-operator/charts/psmdb-operator/crds/crd.yaml new file mode 100644 index 00000000..47d11591 --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/crds/crd.yaml @@ -0,0 +1,25729 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/component: crd + app.kubernetes.io/name: percona-server-mongodb + app.kubernetes.io/part-of: percona-server-mongodb-operator + app.kubernetes.io/version: v1.21.1 + name: perconaservermongodbbackups.psmdb.percona.com +spec: + group: psmdb.percona.com + names: + kind: PerconaServerMongoDBBackup + listKind: PerconaServerMongoDBBackupList + plural: perconaservermongodbbackups + shortNames: + - psmdb-backup + singular: perconaservermongodbbackup + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Cluster name + jsonPath: .spec.clusterName + name: Cluster + type: string + - description: Storage name + jsonPath: .spec.storageName + name: Storage + type: string + - description: Backup destination + jsonPath: .status.destination + name: Destination + type: string + - description: Backup type + jsonPath: .status.type + name: Type + type: string + - description: Backup size + jsonPath: .status.size + name: Size + type: string + - description: Job status + jsonPath: .status.state + name: Status + type: string + - description: Completed time + jsonPath: .status.completed + name: Completed + type: date + - description: Created time + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + clusterName: + type: string + compressionLevel: + type: integer + compressionType: + type: string + startingDeadlineSeconds: + format: int64 + type: integer + storageName: + type: string + type: + enum: + - logical + - physical + - incremental + - incremental-base + type: string + type: object + status: + properties: + azure: + properties: + container: + type: string + credentialsSecret: + type: string + endpointUrl: + type: string + prefix: + type: string + required: + - credentialsSecret + type: object + completed: + format: date-time + type: string + destination: + type: string + error: + type: string + filesystem: + properties: + path: + type: string + required: + - path + type: object + gcs: + properties: + bucket: + type: string + chunkSize: + type: integer + credentialsSecret: + type: string + prefix: + type: string + retryer: + properties: + backoffInitial: + format: int64 + type: integer + backoffMax: + format: int64 + type: integer + backoffMultiplier: + type: number + required: + - backoffInitial + - backoffMax + - backoffMultiplier + type: object + required: + - bucket + - credentialsSecret + type: object + lastTransition: + format: date-time + type: string + lastWriteAt: + format: date-time + type: string + latestRestorableTime: + format: date-time + type: string + pbmName: + type: string + pbmPod: + type: string + pbmPods: + additionalProperties: + type: string + type: object + replsetNames: + items: + type: string + type: array + s3: + properties: + bucket: + type: string + credentialsSecret: + type: string + debugLogLevels: + type: string + endpointUrl: + type: string + forcePathStyle: + type: boolean + insecureSkipTLSVerify: + type: boolean + maxUploadParts: + format: int32 + type: integer + prefix: + type: string + region: + type: string + retryer: + properties: + maxRetryDelay: + type: string + minRetryDelay: + type: string + numMaxRetries: + type: integer + type: object + serverSideEncryption: + properties: + kmsKeyID: + type: string + sseAlgorithm: + type: string + sseCustomerAlgorithm: + type: string + sseCustomerKey: + type: string + type: object + storageClass: + type: string + uploadPartSize: + type: integer + required: + - bucket + type: object + size: + type: string + start: + format: date-time + type: string + state: + type: string + storageName: + type: string + type: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/component: crd + app.kubernetes.io/name: percona-server-mongodb + app.kubernetes.io/part-of: percona-server-mongodb-operator + app.kubernetes.io/version: v1.21.1 + name: perconaservermongodbrestores.psmdb.percona.com +spec: + group: psmdb.percona.com + names: + kind: PerconaServerMongoDBRestore + listKind: PerconaServerMongoDBRestoreList + plural: perconaservermongodbrestores + shortNames: + - psmdb-restore + singular: perconaservermongodbrestore + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Cluster name + jsonPath: .spec.clusterName + name: Cluster + type: string + - description: Job status + jsonPath: .status.state + name: Status + type: string + - description: Created time + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + backupName: + type: string + backupSource: + properties: + azure: + properties: + container: + type: string + credentialsSecret: + type: string + endpointUrl: + type: string + prefix: + type: string + required: + - credentialsSecret + type: object + completed: + format: date-time + type: string + destination: + type: string + error: + type: string + filesystem: + properties: + path: + type: string + required: + - path + type: object + gcs: + properties: + bucket: + type: string + chunkSize: + type: integer + credentialsSecret: + type: string + prefix: + type: string + retryer: + properties: + backoffInitial: + format: int64 + type: integer + backoffMax: + format: int64 + type: integer + backoffMultiplier: + type: number + required: + - backoffInitial + - backoffMax + - backoffMultiplier + type: object + required: + - bucket + - credentialsSecret + type: object + lastTransition: + format: date-time + type: string + lastWriteAt: + format: date-time + type: string + latestRestorableTime: + format: date-time + type: string + pbmName: + type: string + pbmPod: + type: string + pbmPods: + additionalProperties: + type: string + type: object + replsetNames: + items: + type: string + type: array + s3: + properties: + bucket: + type: string + credentialsSecret: + type: string + debugLogLevels: + type: string + endpointUrl: + type: string + forcePathStyle: + type: boolean + insecureSkipTLSVerify: + type: boolean + maxUploadParts: + format: int32 + type: integer + prefix: + type: string + region: + type: string + retryer: + properties: + maxRetryDelay: + type: string + minRetryDelay: + type: string + numMaxRetries: + type: integer + type: object + serverSideEncryption: + properties: + kmsKeyID: + type: string + sseAlgorithm: + type: string + sseCustomerAlgorithm: + type: string + sseCustomerKey: + type: string + type: object + storageClass: + type: string + uploadPartSize: + type: integer + required: + - bucket + type: object + size: + type: string + start: + format: date-time + type: string + state: + type: string + storageName: + type: string + type: + type: string + type: object + clusterName: + type: string + pitr: + properties: + date: + type: string + type: + type: string + type: object + x-kubernetes-validations: + - message: 'Time should be in format YYYY-MM-DD HH:MM:SS with valid + ranges (MM: 01-12, DD: 01-31, HH: 00-23, MM/SS: 00-59)' + rule: self.type != 'date' || (has(self.date) && self.date.matches('^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]) + ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$')) + - message: Date should not be used when 'latest' type is used + rule: self.type != 'latest' || !has(self.date) + replset: + type: string + selective: + properties: + namespaces: + items: + type: string + type: array + withUsersAndRoles: + type: boolean + type: object + storageName: + type: string + type: object + status: + properties: + completed: + format: date-time + type: string + error: + type: string + lastTransition: + format: date-time + type: string + pbmName: + type: string + pitrTarget: + type: string + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/component: crd + app.kubernetes.io/name: percona-server-mongodb + app.kubernetes.io/part-of: percona-server-mongodb-operator + app.kubernetes.io/version: v1.21.1 + name: perconaservermongodbs.psmdb.percona.com +spec: + group: psmdb.percona.com + names: + kind: PerconaServerMongoDB + listKind: PerconaServerMongoDBList + plural: perconaservermongodbs + shortNames: + - psmdb + singular: perconaservermongodb + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-2-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-2-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-3-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-3-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-4-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-4-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-5-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-5-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-6-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-6-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-7-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-7-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-8-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-8-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-9-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-9-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-10-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-10-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-11-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-11-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-12-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-12-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + allowUnsafeConfigurations: + type: boolean + backup: + properties: + annotations: + additionalProperties: + type: string + type: object + configuration: + properties: + backupOptions: + properties: + numParallelCollections: + type: integer + oplogSpanMin: + type: number + priority: + additionalProperties: + type: number + type: object + timeouts: + properties: + startingStatus: + format: int32 + type: integer + type: object + required: + - oplogSpanMin + type: object + restoreOptions: + properties: + batchSize: + type: integer + downloadChunkMb: + type: integer + maxDownloadBufferMb: + type: integer + mongodLocation: + type: string + mongodLocationMap: + additionalProperties: + type: string + type: object + numDownloadWorkers: + type: integer + numInsertionWorkers: + type: integer + numParallelCollections: + type: integer + type: object + type: object + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + enabled: + type: boolean + image: + type: string + labels: + additionalProperties: + type: string + type: object + pitr: + properties: + compressionLevel: + type: integer + compressionType: + type: string + enabled: + type: boolean + oplogOnly: + type: boolean + oplogSpanMin: + type: number + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + startingDeadlineSeconds: + format: int64 + type: integer + storages: + additionalProperties: + properties: + azure: + properties: + container: + type: string + credentialsSecret: + type: string + endpointUrl: + type: string + prefix: + type: string + required: + - credentialsSecret + type: object + filesystem: + properties: + path: + type: string + required: + - path + type: object + gcs: + properties: + bucket: + type: string + chunkSize: + type: integer + credentialsSecret: + type: string + prefix: + type: string + retryer: + properties: + backoffInitial: + format: int64 + type: integer + backoffMax: + format: int64 + type: integer + backoffMultiplier: + type: number + required: + - backoffInitial + - backoffMax + - backoffMultiplier + type: object + required: + - bucket + - credentialsSecret + type: object + main: + type: boolean + s3: + properties: + bucket: + type: string + credentialsSecret: + type: string + debugLogLevels: + type: string + endpointUrl: + type: string + forcePathStyle: + type: boolean + insecureSkipTLSVerify: + type: boolean + maxUploadParts: + format: int32 + type: integer + prefix: + type: string + region: + type: string + retryer: + properties: + maxRetryDelay: + type: string + minRetryDelay: + type: string + numMaxRetries: + type: integer + type: object + serverSideEncryption: + properties: + kmsKeyID: + type: string + sseAlgorithm: + type: string + sseCustomerAlgorithm: + type: string + sseCustomerKey: + type: string + type: object + storageClass: + type: string + uploadPartSize: + type: integer + required: + - bucket + type: object + type: + type: string + required: + - type + type: object + type: object + tasks: + items: + properties: + compressionLevel: + type: integer + compressionType: + type: string + enabled: + type: boolean + keep: + type: integer + name: + type: string + retention: + properties: + count: + minimum: 0 + type: integer + deleteFromStorage: + default: true + type: boolean + type: + enum: + - count + type: string + required: + - deleteFromStorage + - type + type: object + schedule: + type: string + storageName: + type: string + type: + enum: + - logical + - physical + - incremental + - incremental-base + type: string + required: + - enabled + - name + type: object + type: array + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + required: + - enabled + - image + type: object + clusterServiceDNSMode: + type: string + clusterServiceDNSSuffix: + type: string + crVersion: + type: string + enableExternalVolumeAutoscaling: + type: boolean + enableVolumeExpansion: + type: boolean + ignoreAnnotations: + items: + type: string + type: array + ignoreLabels: + items: + type: string + type: array + image: + type: string + imagePullPolicy: + type: string + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + initImage: + type: string + logcollector: + properties: + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + enabled: + type: boolean + image: + type: string + imagePullPolicy: + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + type: object + multiCluster: + properties: + DNSSuffix: + type: string + enabled: + type: boolean + required: + - enabled + type: object + pause: + type: boolean + platform: + type: string + pmm: + properties: + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + customClusterName: + type: string + enabled: + type: boolean + image: + type: string + mongodParams: + type: string + mongosParams: + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + serverHost: + type: string + required: + - image + type: object + replsets: + items: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + arbiter: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + enabled: + type: boolean + labels: + additionalProperties: + type: string + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + priorityClassName: + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + required: + - enabled + - size + type: object + clusterRole: + type: string + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + expose: + properties: + annotations: + additionalProperties: + type: string + type: object + enabled: + type: boolean + exposeType: + type: string + externalTrafficPolicy: + type: string + internalTrafficPolicy: + type: string + labels: + additionalProperties: + type: string + type: object + loadBalancerClass: + type: string + loadBalancerSourceRanges: + items: + type: string + type: array + serviceAnnotations: + additionalProperties: + type: string + type: object + serviceLabels: + additionalProperties: + type: string + type: object + type: + type: string + required: + - enabled + type: object + externalNodes: + items: + properties: + horizons: + additionalProperties: + type: string + type: object + host: + type: string + port: + type: integer + priority: + type: integer + tags: + additionalProperties: + type: string + type: object + votes: + type: integer + required: + - host + - priority + - votes + type: object + type: array + hidden: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + enabled: + type: boolean + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + persistentVolumeClaim: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + annotations: + additionalProperties: + type: string + type: object + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + labels: + additionalProperties: + type: string + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + required: + - enabled + - size + type: object + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + nodeSelector: + additionalProperties: + type: string + type: object + nonvoting: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + enabled: + type: boolean + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + persistentVolumeClaim: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + annotations: + additionalProperties: + type: string + type: object + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + labels: + additionalProperties: + type: string + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + required: + - enabled + - size + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + primaryPreferTagSelector: + additionalProperties: + type: string + type: object + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + replsetOverrides: + additionalProperties: + properties: + horizons: + additionalProperties: + type: string + type: object + host: + type: string + priority: + type: integer + tags: + additionalProperties: + type: string + type: object + type: object + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + splitHorizons: + additionalProperties: + additionalProperties: + type: string + type: object + type: object + storage: + properties: + directoryPerDB: + type: boolean + engine: + type: string + inMemory: + properties: + engineConfig: + properties: + inMemorySizeRatio: + type: number + type: object + type: object + mmapv1: + properties: + nsSize: + type: integer + smallfiles: + type: boolean + type: object + syncPeriodSecs: + type: integer + wiredTiger: + properties: + collectionConfig: + properties: + blockCompressor: + type: string + type: object + engineConfig: + properties: + cacheSizeRatio: + type: number + directoryForIndexes: + type: boolean + journalCompressor: + type: string + type: object + indexConfig: + properties: + prefixCompression: + type: boolean + type: object + type: object + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + persistentVolumeClaim: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + annotations: + additionalProperties: + type: string + type: object + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + labels: + additionalProperties: + type: string + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + required: + - size + type: object + type: array + roles: + items: + properties: + authenticationRestrictions: + items: + properties: + clientSource: + items: + type: string + type: array + serverAddress: + items: + type: string + type: array + type: object + type: array + db: + type: string + privileges: + items: + properties: + actions: + items: + type: string + type: array + resource: + properties: + cluster: + type: boolean + collection: + type: string + db: + type: string + type: object + required: + - actions + type: object + type: array + role: + type: string + roles: + items: + properties: + db: + type: string + role: + type: string + required: + - db + - role + type: object + type: array + required: + - db + - privileges + - role + type: object + type: array + schedulerName: + type: string + secrets: + properties: + encryptionKey: + type: string + keyFile: + type: string + ldapSecret: + type: string + sse: + type: string + ssl: + type: string + sslInternal: + type: string + users: + type: string + vault: + type: string + type: object + sharding: + properties: + balancer: + properties: + enabled: + type: boolean + type: object + configsvrReplSet: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + arbiter: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + enabled: + type: boolean + labels: + additionalProperties: + type: string + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + priorityClassName: + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + required: + - enabled + - size + type: object + clusterRole: + type: string + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + expose: + properties: + annotations: + additionalProperties: + type: string + type: object + enabled: + type: boolean + exposeType: + type: string + externalTrafficPolicy: + type: string + internalTrafficPolicy: + type: string + labels: + additionalProperties: + type: string + type: object + loadBalancerClass: + type: string + loadBalancerSourceRanges: + items: + type: string + type: array + serviceAnnotations: + additionalProperties: + type: string + type: object + serviceLabels: + additionalProperties: + type: string + type: object + type: + type: string + required: + - enabled + type: object + externalNodes: + items: + properties: + horizons: + additionalProperties: + type: string + type: object + host: + type: string + port: + type: integer + priority: + type: integer + tags: + additionalProperties: + type: string + type: object + votes: + type: integer + required: + - host + - priority + - votes + type: object + type: array + hidden: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + enabled: + type: boolean + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + persistentVolumeClaim: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + annotations: + additionalProperties: + type: string + type: object + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + labels: + additionalProperties: + type: string + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + required: + - enabled + - size + type: object + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + nodeSelector: + additionalProperties: + type: string + type: object + nonvoting: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + enabled: + type: boolean + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + persistentVolumeClaim: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + annotations: + additionalProperties: + type: string + type: object + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + labels: + additionalProperties: + type: string + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + required: + - enabled + - size + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + primaryPreferTagSelector: + additionalProperties: + type: string + type: object + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + replsetOverrides: + additionalProperties: + properties: + horizons: + additionalProperties: + type: string + type: object + host: + type: string + priority: + type: integer + tags: + additionalProperties: + type: string + type: object + type: object + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + splitHorizons: + additionalProperties: + additionalProperties: + type: string + type: object + type: object + storage: + properties: + directoryPerDB: + type: boolean + engine: + type: string + inMemory: + properties: + engineConfig: + properties: + inMemorySizeRatio: + type: number + type: object + type: object + mmapv1: + properties: + nsSize: + type: integer + smallfiles: + type: boolean + type: object + syncPeriodSecs: + type: integer + wiredTiger: + properties: + collectionConfig: + properties: + blockCompressor: + type: string + type: object + engineConfig: + properties: + cacheSizeRatio: + type: number + directoryForIndexes: + type: boolean + journalCompressor: + type: string + type: object + indexConfig: + properties: + prefixCompression: + type: boolean + type: object + type: object + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + persistentVolumeClaim: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + annotations: + additionalProperties: + type: string + type: object + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + labels: + additionalProperties: + type: string + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + required: + - size + type: object + enabled: + type: boolean + mongos: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + expose: + properties: + annotations: + additionalProperties: + type: string + type: object + exposeType: + type: string + externalTrafficPolicy: + type: string + internalTrafficPolicy: + type: string + labels: + additionalProperties: + type: string + type: object + loadBalancerClass: + type: string + loadBalancerSourceRanges: + items: + type: string + type: array + nodePort: + format: int32 + type: integer + serviceAnnotations: + additionalProperties: + type: string + type: object + serviceLabels: + additionalProperties: + type: string + type: object + servicePerPod: + type: boolean + type: + type: string + type: object + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostPort: + format: int32 + type: integer + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + port: + format: int32 + type: integer + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + setParameter: + properties: + cursorTimeoutMillis: + type: integer + type: object + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + type: object + required: + - enabled + type: object + tls: + properties: + allowInvalidCertificates: + type: boolean + certValidityDuration: + type: string + issuerConf: + properties: + group: + type: string + kind: + type: string + name: + type: string + required: + - name + type: object + mode: + type: string + type: object + unmanaged: + type: boolean + unsafeFlags: + properties: + backupIfUnhealthy: + type: boolean + mongosSize: + type: boolean + replsetSize: + type: boolean + terminationGracePeriod: + type: boolean + tls: + type: boolean + type: object + updateStrategy: + type: string + upgradeOptions: + properties: + apply: + type: string + schedule: + type: string + setFCV: + type: boolean + versionServiceEndpoint: + type: string + type: object + users: + items: + properties: + db: + type: string + name: + type: string + passwordSecretRef: + properties: + key: + type: string + name: + type: string + required: + - name + type: object + roles: + items: + properties: + db: + type: string + name: + type: string + required: + - db + - name + type: object + type: array + required: + - name + - roles + type: object + type: array + required: + - image + type: object + status: + properties: + backupConfigHash: + type: string + backupImage: + type: string + backupVersion: + type: string + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + host: + type: string + message: + type: string + mongoImage: + type: string + mongoVersion: + type: string + mongos: + properties: + message: + type: string + ready: + type: integer + size: + type: integer + status: + type: string + required: + - ready + - size + type: object + observedGeneration: + format: int64 + type: integer + pmmStatus: + type: string + pmmVersion: + type: string + ready: + format: int32 + type: integer + replsets: + additionalProperties: + properties: + added_as_shard: + type: boolean + clusterRole: + type: string + initialized: + type: boolean + members: + additionalProperties: + properties: + name: + type: string + state: + type: integer + stateStr: + type: string + type: object + type: object + message: + type: string + ready: + format: int32 + type: integer + size: + format: int32 + type: integer + status: + type: string + required: + - ready + - size + type: object + type: object + size: + format: int32 + type: integer + state: + type: string + required: + - ready + - size + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/templates/NOTES.txt b/packages/system/mongodb-operator/charts/psmdb-operator/templates/NOTES.txt new file mode 100644 index 00000000..9276ae03 --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/templates/NOTES.txt @@ -0,0 +1,40 @@ +1. Percona Operator for MongoDB is deployed. + See if the operator Pod is running: + + kubectl get pods -l app.kubernetes.io/name=psmdb-operator --namespace {{ .Release.Namespace }} + + Check the operator logs if the Pod is not starting: + + export POD=$(kubectl get pods -l app.kubernetes.io/name=psmdb-operator --namespace {{ .Release.Namespace }} --output name) + kubectl logs $POD --namespace={{ .Release.Namespace }} + +2. Deploy the database cluster from psmdb-db chart: + + helm install my-db percona/psmdb-db --namespace={{ .Release.Namespace }} + +{{- if .Release.IsUpgrade }} + {{- $ctx := dict "upgradeCrd" false }} + {{- $crdNames := list "perconaservermongodbbackups.psmdb.percona.com" "perconaservermongodbrestores.psmdb.percona.com " "perconaservermongodbs.psmdb.percona.com" }} + {{- range $name := $crdNames }} + {{- $crd := lookup "apiextensions.k8s.io/v1" "CustomResourceDefinition" "" $name }} + {{- if $crd }} + {{- $crdLabels := (($crd).metadata).labels | default dict }} + {{- $crdVersion := index $crdLabels "app.kubernetes.io/version" }} + {{- if or (not $crdVersion) (semverCompare (printf "< %s" $.Chart.AppVersion) (trimPrefix "v" $crdVersion)) }} + {{- $_ := set $ctx "upgradeCrd" true }} + {{- end }} + {{- end }} + {{- end }} + {{- if $ctx.upgradeCrd }} + +** WARNING ** During Helm upgrade CRDs are not automatically upgraded. + +Consider upgrading to the latest version of the CRDs using the command below: + + kubectl apply --server-side --force-conflicts -f https://raw.githubusercontent.com/percona/percona-server-mongodb-operator/v{{ .Chart.AppVersion }}/deploy/crd.yaml + +Ensure all deprecated fields are reviewed as part of the upgrade process, especially when running multiple PSMDB Operator versions in the same cluster. Deprecated fields may be removed or unsupported in newer CRD versions. + {{- end }} +{{- end }} + +Read more in our documentation: https://docs.percona.com/percona-operator-for-mongodb/ diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/templates/_helpers.tpl b/packages/system/mongodb-operator/charts/psmdb-operator/templates/_helpers.tpl new file mode 100644 index 00000000..1bf81ed1 --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/templates/_helpers.tpl @@ -0,0 +1,45 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "psmdb-operator.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "psmdb-operator.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "psmdb-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "psmdb-operator.labels" -}} +app.kubernetes.io/name: {{ include "psmdb-operator.name" . }} +helm.sh/chart: {{ include "psmdb-operator.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/templates/deployment.yaml b/packages/system/mongodb-operator/charts/psmdb-operator/templates/deployment.yaml new file mode 100644 index 00000000..14e2eb89 --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/templates/deployment.yaml @@ -0,0 +1,112 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "psmdb-operator.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "psmdb-operator.labels" . | nindent 4 }} + {{- with .Values.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: {{ include "psmdb-operator.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + app.kubernetes.io/name: {{ include "psmdb-operator.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ include "psmdb-operator.fullname" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - containerPort: 8080 + protocol: TCP + name: metrics + - containerPort: 8081 + protocol: TCP + name: health + command: + - percona-server-mongodb-operator + {{- if .Values.securityContext.readOnlyRootFilesystem }} + volumeMounts: + - name: tmpdir + mountPath: /tmp + {{- end }} + env: + - name: LOG_STRUCTURED + value: "{{ .Values.logStructured }}" + - name: LOG_LEVEL + value: "{{ .Values.logLevel }}" + - name: WATCH_NAMESPACE + {{- if .Values.watchAllNamespaces }} + value: "" + {{- else }} + value: "{{ default .Release.Namespace .Values.watchNamespace }}" + {{- end }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: OPERATOR_NAME + value: {{ default "percona-server-mongodb-operator" .Values.operatorName }} + - name: RESYNC_PERIOD + value: "{{ .Values.env.resyncPeriod }}" + - name: DISABLE_TELEMETRY + value: "{{ .Values.disableTelemetry }}" + {{- if .Values.maxConcurrentReconciles }} + - name: MAX_CONCURRENT_RECONCILES + value: "{{ .Values.maxConcurrentReconciles }}" + {{- end }} + livenessProbe: + httpGet: + path: /healthz + port: health + readinessProbe: + httpGet: + path: /healthz + port: health + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.securityContext.readOnlyRootFilesystem }} + volumes: + - name: tmpdir + emptyDir: {} + {{- end }} diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/templates/namespace.yaml b/packages/system/mongodb-operator/charts/psmdb-operator/templates/namespace.yaml new file mode 100644 index 00000000..cfc96d4d --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/templates/namespace.yaml @@ -0,0 +1,11 @@ +{{ if and .Values.watchNamespace .Values.createNamespace }} +{{ range ( split "," .Values.watchNamespace ) }} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ trim . }} + annotations: + helm.sh/resource-policy: keep +--- +{{ end }} +{{ end }} diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/templates/role-binding.yaml b/packages/system/mongodb-operator/charts/psmdb-operator/templates/role-binding.yaml new file mode 100644 index 00000000..a815869d --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/templates/role-binding.yaml @@ -0,0 +1,41 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "psmdb-operator.fullname" . }} + namespace: {{ .Release.Namespace }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +--- +{{- end }} +{{- if .Values.rbac.create }} +{{- if or .Values.watchNamespace .Values.watchAllNamespaces }} +kind: ClusterRoleBinding +{{- else }} +kind: RoleBinding +{{- end }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: service-account-{{ include "psmdb-operator.fullname" . }} +{{- if not (or .Values.watchNamespace .Values.watchAllNamespaces) }} + namespace: {{ .Release.Namespace }} +{{- end }} + labels: +{{ include "psmdb-operator.labels" . | indent 4 }} +subjects: +- kind: ServiceAccount + name: {{ include "psmdb-operator.fullname" . }} + {{- if or .Values.watchNamespace .Values.watchAllNamespaces }} + namespace: {{ .Release.Namespace }} + {{- end }} +roleRef: + {{- if or .Values.watchNamespace .Values.watchAllNamespaces }} + kind: ClusterRole + {{- else }} + kind: Role + {{- end }} + name: {{ include "psmdb-operator.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/templates/role.yaml b/packages/system/mongodb-operator/charts/psmdb-operator/templates/role.yaml new file mode 100644 index 00000000..4d65e6a7 --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/templates/role.yaml @@ -0,0 +1,167 @@ +{{- if .Values.rbac.create }} +{{- if or .Values.watchNamespace .Values.watchAllNamespaces }} +kind: ClusterRole +{{- else }} +kind: Role +{{- end }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "psmdb-operator.fullname" . }} +{{- if not (or .Values.watchNamespace .Values.watchAllNamespaces) }} + namespace: {{ .Release.Namespace }} +{{- end }} + labels: +{{ include "psmdb-operator.labels" . | indent 4 }} +rules: + - apiGroups: + - psmdb.percona.com + resources: + - perconaservermongodbs + - perconaservermongodbs/status + - perconaservermongodbs/finalizers + - perconaservermongodbbackups + - perconaservermongodbbackups/status + - perconaservermongodbbackups/finalizers + - perconaservermongodbrestores + - perconaservermongodbrestores/status + - perconaservermongodbrestores/finalizers + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +{{- if or .Values.watchNamespace .Values.watchAllNamespaces }} + - apiGroups: + - admissionregistration.k8s.io + resources: + - validatingwebhookconfigurations + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - list + - watch +{{- end }} + - apiGroups: + - "" + resources: + - pods + - pods/exec + - services + - persistentvolumeclaims + - secrets + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - apps + resources: + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - batch + resources: + - cronjobs + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - events.k8s.io + - "" + resources: + - events + verbs: + - get + - list + - watch + - create + - patch + - apiGroups: + - certmanager.k8s.io + - cert-manager.io + resources: + - issuers + - certificates + - certificaterequests + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - deletecollection + - apiGroups: + - net.gke.io + - multicluster.x-k8s.io + resources: + - serviceexports + - serviceimports + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - deletecollection +{{- end }} diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/values.yaml b/packages/system/mongodb-operator/charts/psmdb-operator/values.yaml new file mode 100644 index 00000000..cc5ece0b --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/values.yaml @@ -0,0 +1,103 @@ +# Default values for psmdb-operator. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: percona/percona-server-mongodb-operator + tag: 1.21.1 + pullPolicy: IfNotPresent + +# disableTelemetry: according to +# https://docs.percona.com/percona-operator-for-mongodb/telemetry.html +# this is how you can disable telemetry collection +# default is false which means telemetry will be collected +disableTelemetry: false + +# set if you want to specify a namespace to watch +# defaults to `.Release.namespace` if left blank +# multiple namespaces can be specified and separated by comma +# watchNamespace: +# set if you want that watched namespaces are created by helm +# createNamespace: false + +# set if operator should be deployed in cluster wide mode. defaults to false +watchAllNamespaces: false + +# rbac: settings for deployer RBAC creation +rbac: + # rbac.create: if false RBAC resources should be in place + create: true + +# serviceAccount: settings for Service Accounts used by the deployer +serviceAccount: + # serviceAccount.create: Whether to create the Service Accounts or not + create: true + # annotations to add to the service account + annotations: {} + +# annotations to add to the operator deployment +annotations: {} + +# labels to add to the operator deployment +labels: {} + +# annotations to add to the operator pod +podAnnotations: {} + # prometheus.io/scrape: "true" + # prometheus.io/port: "8080" + +# labels to the operator pod +podLabels: {} + +podSecurityContext: {} + # runAsNonRoot: true + # runAsUser: 2 + # runAsGroup: 2 + # fsGroup: 2 + # fsGroupChangePolicy: "OnRootMismatch" + +securityContext: {} + # allowPrivilegeEscalation: false + # capabilities: + # drop: + # - ALL + # seccompProfile: + # type: RuntimeDefault + +# set if you want to use a different operator name +# defaults to `percona-server-mongodb-operator` +# operatorName: + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +env: + resyncPeriod: 5s + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +logStructured: false +logLevel: "INFO" + +# maxConcurrentReconciles controls the number of concurrent workers +# that can reconcile resources in Percona Server for MongoDB clusters in parallel. +maxConcurrentReconciles: "1" diff --git a/packages/system/mongodb-operator/values.yaml b/packages/system/mongodb-operator/values.yaml new file mode 100644 index 00000000..b51a4e1d --- /dev/null +++ b/packages/system/mongodb-operator/values.yaml @@ -0,0 +1,2 @@ +psmdb-operator: + watchAllNamespaces: true diff --git a/packages/system/mongodb-rd/Chart.yaml b/packages/system/mongodb-rd/Chart.yaml new file mode 100644 index 00000000..41aafc6d --- /dev/null +++ b/packages/system/mongodb-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: mongodb-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/mongodb-rd/Makefile b/packages/system/mongodb-rd/Makefile new file mode 100644 index 00000000..eb609997 --- /dev/null +++ b/packages/system/mongodb-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=mongodb-rd +export NAMESPACE=cozy-system + +include ../../../scripts/package.mk diff --git a/packages/system/mongodb-rd/cozyrds/mongodb.yaml b/packages/system/mongodb-rd/cozyrds/mongodb.yaml new file mode 100644 index 00000000..a8058432 --- /dev/null +++ b/packages/system/mongodb-rd/cozyrds/mongodb.yaml @@ -0,0 +1,42 @@ +apiVersion: cozystack.io/v1alpha1 +kind: CozystackResourceDefinition +metadata: + name: mongodb +spec: + application: + kind: MongoDB + singular: mongodb + plural: mongodbs + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"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":""}}},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"images":{"description":"Container images used by the operator.","type":"object","default":{},"required":["backup","pmm"],"properties":{"backup":{"description":"Percona Backup for MongoDB image.","type":"string","default":"percona/percona-backup-mongodb:2.11.0"},"pmm":{"description":"PMM client image for monitoring.","type":"string","default":"percona/pmm-client:2.44.1"}}},"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"]},"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}}}}}},"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":"Custom MongoDB users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","required":["db"],"properties":{"db":{"description":"Database to authenticate against.","type":"string"},"password":{"description":"Password for the user (auto-generated if omitted).","type":"string"},"roles":{"description":"List of MongoDB roles with database scope.","type":"array","items":{"type":"object","required":["db","name"],"properties":{"db":{"description":"Database the role applies to.","type":"string"},"name":{"description":"Role name (e.g., readWrite, dbAdmin, clusterAdmin).","type":"string"}}}}}}},"version":{"description":"MongoDB major version to deploy.","type":"string","default":"v8","enum":["v8","v7","v6"]}}} + release: + prefix: mongodb- + labels: + cozystack.io/ui: "true" + chart: + name: mongodb + sourceRef: + kind: HelmRepository + name: cozystack-apps + namespace: cozy-public + dashboard: + category: PaaS + singular: MongoDB + plural: MongoDB Instances + description: Managed MongoDB service + tags: + - database + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl9tb25nb2RiKSIvPgo8cGF0aCBkPSJNNzIgMjRDNzIgMjQgNzIgMjQgNzIgMjRDNzIgMjQgNTggNDAgNTggNjJDNTggODQgNzIgMTIwIDcyIDEyMEM3MiAxMjAgODYgODQgODYgNjJDODYgNDAgNzIgMjQgNzIgMjRaIiBmaWxsPSIjMDBFRDY0Ii8+CjxwYXRoIGQ9Ik03MiAxMjBDNzIgMTIwIDg2IDg0IDg2IDYyQzg2IDQwIDcyIDI0IDcyIDI0IiBzdHJva2U9IiMwMDY4NEEiIHN0cm9rZS13aWR0aD0iNCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+CjxwYXRoIGQ9Ik03MiAyNEM3MiAyNCA1OCA0MCA1OCA2MkM1OCA4NCA3MiAxMjAgNzIgMTIwIiBzdHJva2U9IiMwMDFFMkIiIHN0cm9rZS13aWR0aD0iNCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+CjxyZWN0IHg9IjY5IiB5PSIxMDgiIHdpZHRoPSI2IiBoZWlnaHQ9IjE2IiByeD0iMiIgZmlsbD0iIzAwNjg0QSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyX21vbmdvZGIiIHgxPSIxNDAiIHkxPSIxMzAuNSIgeDI9IjQiIHkyPSI5LjQ5OTk5IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiMwMDFFMkIiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDIzNDMwIi8+CjwvbGluZWFyR3JhZGllbnQ+CjwvZGVmcz4KPC9zdmc+Cg== + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "version"], ["spec", "images"], ["spec", "images", "pmm"], ["spec", "images", "backup"], ["spec", "sharding"], ["spec", "shardingConfig"], ["spec", "shardingConfig", "configServers"], ["spec", "shardingConfig", "configServerSize"], ["spec", "shardingConfig", "mongos"], ["spec", "shardingConfig", "shards"], ["spec", "users"], ["spec", "backup"], ["spec", "backup", "enabled"], ["spec", "backup", "schedule"], ["spec", "backup", "retentionPolicy"], ["spec", "backup", "destinationPath"], ["spec", "backup", "endpointURL"], ["spec", "backup", "s3AccessKey"], ["spec", "backup", "s3SecretKey"], ["spec", "bootstrap"], ["spec", "bootstrap", "enabled"], ["spec", "bootstrap", "recoveryTime"], ["spec", "bootstrap", "backupName"]] + secrets: + exclude: [] + include: + - resourceNames: + - mongodb-{{ .name }}-credentials + services: + exclude: [] + include: + - resourceNames: + - mongodb-{{ .name }}-rs0 + - mongodb-{{ .name }}-mongos + - mongodb-{{ .name }}-external diff --git a/packages/system/mongodb-rd/templates/cozyrd.yaml b/packages/system/mongodb-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/mongodb-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/mongodb-rd/values.yaml b/packages/system/mongodb-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/mongodb-rd/values.yaml @@ -0,0 +1 @@ +{} From d33a2357ed496ddbc137301cd0e63206ab1185fb Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Sun, 18 Jan 2026 21:52:44 +0100 Subject: [PATCH 72/78] fix(kubernetes): increase default apiServer resourcesPreset to large Change the default resourcesPreset for kube-apiserver from "medium" to "large" to prevent OOM kills during normal operation. The "medium" preset provides insufficient memory for clusters with moderate workloads. Co-Authored-By: Claude Signed-off-by: Andrei Kvapil (cherry picked from commit 62568930405b2a0c53ae9831a6ec098bea739336) --- packages/apps/kubernetes/README.md | 50 +++++++++---------- packages/apps/kubernetes/values.schema.json | 2 +- packages/apps/kubernetes/values.yaml | 4 +- .../kubernetes-rd/cozyrds/kubernetes.yaml | 2 +- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/packages/apps/kubernetes/README.md b/packages/apps/kubernetes/README.md index 8bff49aa..b2fe102f 100644 --- a/packages/apps/kubernetes/README.md +++ b/packages/apps/kubernetes/README.md @@ -145,31 +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` | `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` | +| 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` | ## Parameter examples and reference diff --git a/packages/apps/kubernetes/values.schema.json b/packages/apps/kubernetes/values.schema.json index 9ec0c416..69b5145d 100644 --- a/packages/apps/kubernetes/values.schema.json +++ b/packages/apps/kubernetes/values.schema.json @@ -287,7 +287,7 @@ "resourcesPreset": { "description": "Preset if `resources` omitted.", "type": "string", - "default": "medium", + "default": "large", "enum": [ "nano", "micro", diff --git a/packages/apps/kubernetes/values.yaml b/packages/apps/kubernetes/values.yaml index 567d2e02..ba7d3f6d 100644 --- a/packages/apps/kubernetes/values.yaml +++ b/packages/apps/kubernetes/values.yaml @@ -153,7 +153,7 @@ addons: ## @typedef {struct} APIServer - API Server configuration. ## @field {Resources} resources - CPU and memory resources for API Server. -## @field {ResourcesPreset} resourcesPreset="medium" - Preset if `resources` omitted. +## @field {ResourcesPreset} resourcesPreset="large" - Preset if `resources` omitted. ## @typedef {struct} ControllerManager - Controller Manager configuration. ## @field {Resources} resources - CPU and memory resources for Controller Manager. @@ -182,7 +182,7 @@ controlPlane: replicas: 2 apiServer: resources: {} - resourcesPreset: "medium" + resourcesPreset: "large" controllerManager: resources: {} resourcesPreset: "micro" diff --git a/packages/system/kubernetes-rd/cozyrds/kubernetes.yaml b/packages/system/kubernetes-rd/cozyrds/kubernetes.yaml index 05ed110f..8bfce1e1 100644 --- a/packages/system/kubernetes-rd/cozyrds/kubernetes.yaml +++ b/packages/system/kubernetes-rd/cozyrds/kubernetes.yaml @@ -8,7 +8,7 @@ spec: singular: kubernetes plural: kuberneteses openAPISchema: |- - {"title":"Chart Values","type":"object","properties":{"addons":{"description":"Cluster addons configuration.","type":"object","default":{},"required":["certManager","cilium","coredns","fluxcd","gatewayAPI","gpuOperator","ingressNginx","monitoringAgents","velero","verticalPodAutoscaler"],"properties":{"certManager":{"description":"Cert-manager addon.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable cert-manager.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"cilium":{"description":"Cilium CNI plugin.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"coredns":{"description":"CoreDNS addon.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"fluxcd":{"description":"FluxCD GitOps operator.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable FluxCD.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"gatewayAPI":{"description":"Gateway API addon.","type":"object","default":{},"required":["enabled"],"properties":{"enabled":{"description":"Enable Gateway API.","type":"boolean","default":false}}},"gpuOperator":{"description":"NVIDIA GPU Operator.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable GPU Operator.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"ingressNginx":{"description":"Ingress-NGINX controller.","type":"object","default":{},"required":["enabled","exposeMethod","valuesOverride"],"properties":{"enabled":{"description":"Enable the controller (requires nodes labeled `ingress-nginx`).","type":"boolean","default":false},"exposeMethod":{"description":"Method to expose the controller. Allowed values: `Proxied`, `LoadBalancer`.","type":"string","default":"Proxied"},"hosts":{"description":"Domains routed to this tenant cluster when `exposeMethod` is `Proxied`.","type":"array","default":[],"items":{"type":"string"}},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"monitoringAgents":{"description":"Monitoring agents.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable monitoring agents.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"velero":{"description":"Velero backup/restore addon.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable Velero.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"verticalPodAutoscaler":{"description":"Vertical Pod Autoscaler.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}}}},"controlPlane":{"description":"Kubernetes control-plane configuration.","type":"object","default":{},"required":["apiServer","controllerManager","konnectivity","replicas","scheduler"],"properties":{"apiServer":{"description":"API Server configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for API Server.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"medium","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"controllerManager":{"description":"Controller Manager configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Controller Manager.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"konnectivity":{"description":"Konnectivity configuration.","type":"object","default":{},"required":["server"],"properties":{"server":{"description":"Konnectivity Server configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Konnectivity.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}}}},"replicas":{"description":"Number of control-plane replicas.","type":"integer","default":2},"scheduler":{"description":"Scheduler configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Scheduler.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}}}},"host":{"description":"External hostname for Kubernetes cluster. Defaults to `.` if empty.","type":"string","default":""},"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"}}}}},"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"]}}} + {"title":"Chart Values","type":"object","properties":{"addons":{"description":"Cluster addons configuration.","type":"object","default":{},"required":["certManager","cilium","coredns","fluxcd","gatewayAPI","gpuOperator","ingressNginx","monitoringAgents","velero","verticalPodAutoscaler"],"properties":{"certManager":{"description":"Cert-manager addon.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable cert-manager.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"cilium":{"description":"Cilium CNI plugin.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"coredns":{"description":"CoreDNS addon.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"fluxcd":{"description":"FluxCD GitOps operator.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable FluxCD.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"gatewayAPI":{"description":"Gateway API addon.","type":"object","default":{},"required":["enabled"],"properties":{"enabled":{"description":"Enable Gateway API.","type":"boolean","default":false}}},"gpuOperator":{"description":"NVIDIA GPU Operator.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable GPU Operator.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"ingressNginx":{"description":"Ingress-NGINX controller.","type":"object","default":{},"required":["enabled","exposeMethod","valuesOverride"],"properties":{"enabled":{"description":"Enable the controller (requires nodes labeled `ingress-nginx`).","type":"boolean","default":false},"exposeMethod":{"description":"Method to expose the controller. Allowed values: `Proxied`, `LoadBalancer`.","type":"string","default":"Proxied"},"hosts":{"description":"Domains routed to this tenant cluster when `exposeMethod` is `Proxied`.","type":"array","default":[],"items":{"type":"string"}},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"monitoringAgents":{"description":"Monitoring agents.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable monitoring agents.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"velero":{"description":"Velero backup/restore addon.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable Velero.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"verticalPodAutoscaler":{"description":"Vertical Pod Autoscaler.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}}}},"controlPlane":{"description":"Kubernetes control-plane configuration.","type":"object","default":{},"required":["apiServer","controllerManager","konnectivity","replicas","scheduler"],"properties":{"apiServer":{"description":"API Server configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for API Server.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"large","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"controllerManager":{"description":"Controller Manager configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Controller Manager.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"konnectivity":{"description":"Konnectivity configuration.","type":"object","default":{},"required":["server"],"properties":{"server":{"description":"Konnectivity Server configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Konnectivity.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}}}},"replicas":{"description":"Number of control-plane replicas.","type":"integer","default":2},"scheduler":{"description":"Scheduler configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Scheduler.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}}}},"host":{"description":"External hostname for Kubernetes cluster. Defaults to `.` if empty.","type":"string","default":""},"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"}}}}},"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"]}}} release: prefix: kubernetes- labels: From 125a57eb978d93dc5b705e01d29dedb05fd5fcc1 Mon Sep 17 00:00:00 2001 From: Andrei Kvapil Date: Sun, 18 Jan 2026 23:12:09 +0100 Subject: [PATCH 73/78] fix(kubernetes): increase kube-apiserver startup probe threshold Increase startupProbe.failureThreshold from 3 to 30 for kube-apiserver container. The default 30 seconds (3 failures * 10s period) is often insufficient for apiserver to complete RBAC bootstrap, especially under load or with slower etcd connections. This change gives kube-apiserver up to 300 seconds to initialize, preventing unnecessary CrashLoopBackOff cycles. Co-Authored-By: Claude Signed-off-by: Andrei Kvapil (cherry picked from commit 8261ea4fcf7b306293fc73efddcc9f508a853a20) --- .../increase-startup-probe-threshold.diff | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 packages/system/kamaji/images/kamaji/patches/increase-startup-probe-threshold.diff diff --git a/packages/system/kamaji/images/kamaji/patches/increase-startup-probe-threshold.diff b/packages/system/kamaji/images/kamaji/patches/increase-startup-probe-threshold.diff new file mode 100644 index 00000000..1938c9f6 --- /dev/null +++ b/packages/system/kamaji/images/kamaji/patches/increase-startup-probe-threshold.diff @@ -0,0 +1,31 @@ +diff --git a/internal/builders/controlplane/deployment.go b/internal/builders/controlplane/deployment.go +index e7f0b88..d67a851 100644 +--- a/internal/builders/controlplane/deployment.go ++++ b/internal/builders/controlplane/deployment.go +@@ -376,7 +376,7 @@ func (d Deployment) buildScheduler(podSpec *corev1.PodSpec, tenantControlPlane k + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, +- FailureThreshold: 3, ++ FailureThreshold: 30, + } + + switch { +@@ -469,7 +469,7 @@ func (d Deployment) buildControllerManager(podSpec *corev1.PodSpec, tenantContro + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, +- FailureThreshold: 3, ++ FailureThreshold: 30, + } + switch { + case tenantControlPlane.Spec.ControlPlane.Deployment.Resources == nil: +@@ -600,7 +600,7 @@ func (d Deployment) buildKubeAPIServer(podSpec *corev1.PodSpec, tenantControlPla + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, +- FailureThreshold: 3, ++ FailureThreshold: 30, + } + podSpec.Containers[index].ImagePullPolicy = corev1.PullAlways + // Volume mounts From 838d1abff699fb66ebc5bc24db2bda480275f86b Mon Sep 17 00:00:00 2001 From: IvanHunters Date: Tue, 20 Jan 2026 00:49:12 +0300 Subject: [PATCH 74/78] [fix] Fix view of loadbalancer ip in services window Signed-off-by: IvanHunters (cherry picked from commit 5c7c3359b3cefb5c0d708481c0308879f5cded90) --- internal/controller/dashboard/static_refactored.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/controller/dashboard/static_refactored.go b/internal/controller/dashboard/static_refactored.go index 619d36f5..36b61c04 100644 --- a/internal/controller/dashboard/static_refactored.go +++ b/internal/controller/dashboard/static_refactored.go @@ -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", ".spec.loadBalancerIP"), + createStringColumn("LoadbalancerIP", ".status.loadBalancer.ingress[0].ip"), createTimestampColumn("Created", ".metadata.creationTimestamp"), }), From 31422aba384cfd32c9851d743e05585134fd44d1 Mon Sep 17 00:00:00 2001 From: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> Date: Tue, 20 Jan 2026 01:21:24 +0000 Subject: [PATCH 75/78] Prepare release v0.41.0 Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> --- packages/core/installer/values.yaml | 2 +- packages/core/platform/values.yaml | 2 +- packages/core/testing/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- packages/extra/seaweedfs/images/objectstorage-sidecar.tag | 2 +- packages/system/bucket/images/s3manager.tag | 2 +- packages/system/cozystack-api/values.yaml | 2 +- packages/system/cozystack-controller/values.yaml | 4 ++-- packages/system/dashboard/templates/configmap.yaml | 2 +- packages/system/dashboard/values.yaml | 6 +++--- packages/system/kamaji/values.yaml | 4 ++-- packages/system/kubeovn-plunger/values.yaml | 2 +- packages/system/kubeovn-webhook/values.yaml | 2 +- packages/system/lineage-controller-webhook/values.yaml | 2 +- packages/system/linstor/values.yaml | 2 +- packages/system/objectstorage-controller/values.yaml | 2 +- packages/system/seaweedfs/values.yaml | 2 +- 17 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index f821a5c6..b7ba6565 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.40.3@sha256:4581c0a80fd31db2988411d96afc77afd315726348468e495c9f5c21b2b2a664 + image: ghcr.io/cozystack/cozystack/installer:v0.41.0@sha256:bb8de10621d16f6a6591397a25505d1df62b77d4fae9d0a384265e6edfb2b188 diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index 8c96c8e7..4c228e44 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -1,2 +1,2 @@ assets: - image: ghcr.io/cozystack/cozystack/cozystack-assets:v0.40.3@sha256:48e63ec92d473038e29ea2375f57a449ed9b9295aced53ae27d3944507c076c4 + image: ghcr.io/cozystack/cozystack/cozystack-assets:v0.41.0@sha256:800d4684d3aaef0a61b383a911acf7446ba0fd0860309fc91aa8fdc0e9491b07 diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index f08ce71d..36e8b9fb 100644 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.40.3@sha256:fde7616aacaf5939388bbe74eb6d946147ce855b9cceb47092f620b75ba2c98a + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.41.0@sha256:fde7616aacaf5939388bbe74eb6d946147ce855b9cceb47092f620b75ba2c98a diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index 755826a3..b014e133 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.40.3@sha256:d9674696eb6c59e4564127bb919582ea66bf5b267504ce11ef4f9431db3a247f +ghcr.io/cozystack/cozystack/matchbox:v0.41.0@sha256:40c0ae90d2d2eb15d195cb0fd15b172112690a3279b96af2210c4eda3f66fda3 diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag index 371b1575..7b87d542 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:v0.40.3@sha256:d342ac197b97b81ec42712ecd9d762c6c7710a401736e9d09c64a5b8d59774cc +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.41.0@sha256:87bc334ebbf94ea4096eb9bac52345573a41441c8d2f82cc5f304c2300bc4510 diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index 88b26eac..9e1e5bcc 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:79463ccddbbd2a4048863944a858b2aced3f6e1c2d77f7ef4fa57e30624f6e35 +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:985c8c5a7b6218230e4e590120ea74abd36e34d7f1ad2c46b6a4a32f4fbd657b diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index bcde28c5..2ef3e7bb 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,5 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.40.3@sha256:1b5109bc4149178084941cf1cb505110c581c9326dbb1ef94ffdcdb026dff0e8 + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.41.0@sha256:5aef475a81d765b343b92d08190f831739568c43658360791ed21e0ef3ecb9b2 localK8sAPIEndpoint: enabled: true replicas: 2 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index 187f00ef..3f639ffc 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,6 +1,6 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.40.3@sha256:2b4ad67116c03cd001c495001f9032e6d944199f14a2d80a24d697e2293650c3 + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.41.0@sha256:5cea23058c5d0f5370c57c901cefd9638ce31bfb995a3d7d07ca137b3768dffb debug: false disableTelemetry: false - cozystackVersion: "v0.40.3" + cozystackVersion: "v0.41.0" cozystackAPIKind: "DaemonSet" diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index cf5f9a57..e840b55a 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,6 +1,6 @@ {{- $brandingConfig := .Values._cluster.branding | default dict }} -{{- $tenantText := "v0.40.3" }} +{{- $tenantText := "v0.41.0" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} {{- $logoText := "" }} diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index 85613440..b0e123d7 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v0.40.3@sha256:9666e61fdf7d4ddfeb9084f49ee9c1297b67a4159c475fe62680a0d84ea4050c + image: ghcr.io/cozystack/cozystack/openapi-ui:v0.41.0@sha256:913ec92b8f9c5e2952264f718d92625ce5281c9714b281e3e8c0437af0d97385 openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.40.3@sha256:c905f98598526820bd71e3997fdc62868b9c3d7a4e9700b01d73b017b0953257 + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.41.0@sha256:fda379dce49c2cd8cb8d7d2a1d8ec6f7bedb3419c058c4355ecdece1c1e937f4 tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:v0.40.3@sha256:73887f80d96e7e3c16f1cebab521b05b4308bf4662ccc6724e6a8a9745ed8254 + image: ghcr.io/cozystack/cozystack/token-proxy:v0.41.0@sha256:73887f80d96e7e3c16f1cebab521b05b4308bf4662ccc6724e6a8a9745ed8254 diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index 911fa3d6..47e85a1c 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.40.3@sha256:777f1df253dc97da7f42019857e7a893c34bd98da1cf36e38533adbdf601acf7 + tag: v0.41.0@sha256:d5f2fa2972ba33cd2ccb855256e4bda4734d7e250638811b77f2e0dc72ad6b19 repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: @@ -13,4 +13,4 @@ kamaji: cpu: 100m memory: 100Mi extraArgs: - - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.40.3@sha256:777f1df253dc97da7f42019857e7a893c34bd98da1cf36e38533adbdf601acf7 + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.41.0@sha256:d5f2fa2972ba33cd2ccb855256e4bda4734d7e250638811b77f2e0dc72ad6b19 diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml index 219bb243..70ef984a 100644 --- a/packages/system/kubeovn-plunger/values.yaml +++ b/packages/system/kubeovn-plunger/values.yaml @@ -1,4 +1,4 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.40.3@sha256:864a75eb6fb07eedef3b9ff94e6bb6b02e94fe73c1e03bf360bc785fbfbc1170 +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.41.0@sha256:9d02fbe27c227152261f2cefa2da86d2b671cb1433a0868ddd42ad20da793633 ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index af6649e7..8758a16a 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.40.3@sha256:e18f9fd679e38f65362a8d0042f25468272f6d081136ad47027168d8e7e07a4a +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.41.0@sha256:e18f9fd679e38f65362a8d0042f25468272f6d081136ad47027168d8e7e07a4a diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index 68c78ad9..d4db1b7d 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,5 +1,5 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.40.3@sha256:3556a8ca2ee280dff3991519a5f536ec6ea0a4e5f9be0572f23adb8f59466e56 + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.41.0@sha256:c89f47352f0606dd475fe90e19fe2c6e13580af5c9af3f01f356efb4f5c7375e debug: false localK8sAPIEndpoint: enabled: true diff --git a/packages/system/linstor/values.yaml b/packages/system/linstor/values.yaml index 2287181b..4716bc38 100644 --- a/packages/system/linstor/values.yaml +++ b/packages/system/linstor/values.yaml @@ -10,4 +10,4 @@ linstor: linstorCSI: image: repository: ghcr.io/cozystack/cozystack/linstor-csi - tag: v1.10.5@sha256:68465f120cfeec3d7ccbb389dd9bdbf7df1675da3ab9ba91c3feff21a799bc36 + tag: v1.10.5@sha256:353a8bea0b41f832975132da3569da7d4fce85980474edce41a2a37097c7c3a9 diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml index 365e7b2c..8f4f711d 100644 --- a/packages/system/objectstorage-controller/values.yaml +++ b/packages/system/objectstorage-controller/values.yaml @@ -1,3 +1,3 @@ objectstorage: controller: - image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.40.3@sha256:76756860145d49abe1585c8ca600267a07fcdbb0b359bc9c127baf9efb8e006b" + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.41.0@sha256:5697f8aae011bd3a7bfde8256850921b84d170f794b26f7eebabaada499b954e" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index 4885e44f..0845c867 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -177,7 +177,7 @@ seaweedfs: bucketClassName: "seaweedfs" region: "" sidecar: - image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.40.3@sha256:d342ac197b97b81ec42712ecd9d762c6c7710a401736e9d09c64a5b8d59774cc" + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.41.0@sha256:87bc334ebbf94ea4096eb9bac52345573a41441c8d2f82cc5f304c2300bc4510" certificates: commonName: "SeaweedFS CA" ipAddresses: [] From 73cd3edbb70cd8acf992ae83a65ad23712c2f86f Mon Sep 17 00:00:00 2001 From: Kirill Ilin Date: Wed, 21 Jan 2026 16:49:13 +0500 Subject: [PATCH 76/78] [kubernetes] Add enum validation for IngressNginx exposeMethod Signed-off-by: Kirill Ilin (cherry picked from commit 0b95a72fa332164038bb2ad2afaa9a87b2494a3c) --- packages/apps/kubernetes/values.schema.json | 6 +++++- packages/apps/kubernetes/values.yaml | 6 +++++- packages/system/kubernetes-rd/cozyrds/kubernetes.yaml | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/apps/kubernetes/values.schema.json b/packages/apps/kubernetes/values.schema.json index 69b5145d..1f6c9361 100644 --- a/packages/apps/kubernetes/values.schema.json +++ b/packages/apps/kubernetes/values.schema.json @@ -150,7 +150,11 @@ "exposeMethod": { "description": "Method to expose the controller. Allowed values: `Proxied`, `LoadBalancer`.", "type": "string", - "default": "Proxied" + "default": "Proxied", + "enum": [ + "Proxied", + "LoadBalancer" + ] }, "hosts": { "description": "Domains routed to this tenant cluster when `exposeMethod` is `Proxied`.", diff --git a/packages/apps/kubernetes/values.yaml b/packages/apps/kubernetes/values.yaml index ba7d3f6d..7f15752f 100644 --- a/packages/apps/kubernetes/values.yaml +++ b/packages/apps/kubernetes/values.yaml @@ -76,9 +76,13 @@ 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 {string} exposeMethod - Method to expose the controller. Allowed values: `Proxied`, `LoadBalancer`. +## @field {IngressNginxExposeMethod} exposeMethod - Method to expose the controller. Allowed values: `Proxied`, `LoadBalancer`. ## @field {[]string} hosts - Domains routed to this tenant cluster when `exposeMethod` is `Proxied`. ## @field {object} valuesOverride - Custom Helm values overrides. diff --git a/packages/system/kubernetes-rd/cozyrds/kubernetes.yaml b/packages/system/kubernetes-rd/cozyrds/kubernetes.yaml index 8bfce1e1..25b4975d 100644 --- a/packages/system/kubernetes-rd/cozyrds/kubernetes.yaml +++ b/packages/system/kubernetes-rd/cozyrds/kubernetes.yaml @@ -8,7 +8,7 @@ spec: singular: kubernetes plural: kuberneteses openAPISchema: |- - {"title":"Chart Values","type":"object","properties":{"addons":{"description":"Cluster addons configuration.","type":"object","default":{},"required":["certManager","cilium","coredns","fluxcd","gatewayAPI","gpuOperator","ingressNginx","monitoringAgents","velero","verticalPodAutoscaler"],"properties":{"certManager":{"description":"Cert-manager addon.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable cert-manager.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"cilium":{"description":"Cilium CNI plugin.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"coredns":{"description":"CoreDNS addon.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"fluxcd":{"description":"FluxCD GitOps operator.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable FluxCD.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"gatewayAPI":{"description":"Gateway API addon.","type":"object","default":{},"required":["enabled"],"properties":{"enabled":{"description":"Enable Gateway API.","type":"boolean","default":false}}},"gpuOperator":{"description":"NVIDIA GPU Operator.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable GPU Operator.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"ingressNginx":{"description":"Ingress-NGINX controller.","type":"object","default":{},"required":["enabled","exposeMethod","valuesOverride"],"properties":{"enabled":{"description":"Enable the controller (requires nodes labeled `ingress-nginx`).","type":"boolean","default":false},"exposeMethod":{"description":"Method to expose the controller. Allowed values: `Proxied`, `LoadBalancer`.","type":"string","default":"Proxied"},"hosts":{"description":"Domains routed to this tenant cluster when `exposeMethod` is `Proxied`.","type":"array","default":[],"items":{"type":"string"}},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"monitoringAgents":{"description":"Monitoring agents.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable monitoring agents.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"velero":{"description":"Velero backup/restore addon.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable Velero.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"verticalPodAutoscaler":{"description":"Vertical Pod Autoscaler.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}}}},"controlPlane":{"description":"Kubernetes control-plane configuration.","type":"object","default":{},"required":["apiServer","controllerManager","konnectivity","replicas","scheduler"],"properties":{"apiServer":{"description":"API Server configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for API Server.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"large","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"controllerManager":{"description":"Controller Manager configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Controller Manager.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"konnectivity":{"description":"Konnectivity configuration.","type":"object","default":{},"required":["server"],"properties":{"server":{"description":"Konnectivity Server configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Konnectivity.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}}}},"replicas":{"description":"Number of control-plane replicas.","type":"integer","default":2},"scheduler":{"description":"Scheduler configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Scheduler.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}}}},"host":{"description":"External hostname for Kubernetes cluster. Defaults to `.` if empty.","type":"string","default":""},"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"}}}}},"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"]}}} + {"title":"Chart Values","type":"object","properties":{"addons":{"description":"Cluster addons configuration.","type":"object","default":{},"required":["certManager","cilium","coredns","fluxcd","gatewayAPI","gpuOperator","ingressNginx","monitoringAgents","velero","verticalPodAutoscaler"],"properties":{"certManager":{"description":"Cert-manager addon.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable cert-manager.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"cilium":{"description":"Cilium CNI plugin.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"coredns":{"description":"CoreDNS addon.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"fluxcd":{"description":"FluxCD GitOps operator.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable FluxCD.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"gatewayAPI":{"description":"Gateway API addon.","type":"object","default":{},"required":["enabled"],"properties":{"enabled":{"description":"Enable Gateway API.","type":"boolean","default":false}}},"gpuOperator":{"description":"NVIDIA GPU Operator.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable GPU Operator.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"ingressNginx":{"description":"Ingress-NGINX controller.","type":"object","default":{},"required":["enabled","exposeMethod","valuesOverride"],"properties":{"enabled":{"description":"Enable the controller (requires nodes labeled `ingress-nginx`).","type":"boolean","default":false},"exposeMethod":{"description":"Method to expose the controller. Allowed values: `Proxied`, `LoadBalancer`.","type":"string","default":"Proxied","enum":["Proxied","LoadBalancer"]},"hosts":{"description":"Domains routed to this tenant cluster when `exposeMethod` is `Proxied`.","type":"array","default":[],"items":{"type":"string"}},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"monitoringAgents":{"description":"Monitoring agents.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable monitoring agents.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"velero":{"description":"Velero backup/restore addon.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable Velero.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"verticalPodAutoscaler":{"description":"Vertical Pod Autoscaler.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}}}},"controlPlane":{"description":"Kubernetes control-plane configuration.","type":"object","default":{},"required":["apiServer","controllerManager","konnectivity","replicas","scheduler"],"properties":{"apiServer":{"description":"API Server configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for API Server.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"large","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"controllerManager":{"description":"Controller Manager configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Controller Manager.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"konnectivity":{"description":"Konnectivity configuration.","type":"object","default":{},"required":["server"],"properties":{"server":{"description":"Konnectivity Server configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Konnectivity.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}}}},"replicas":{"description":"Number of control-plane replicas.","type":"integer","default":2},"scheduler":{"description":"Scheduler configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Scheduler.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}}}},"host":{"description":"External hostname for Kubernetes cluster. Defaults to `.` if empty.","type":"string","default":""},"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"}}}}},"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"]}}} release: prefix: kubernetes- labels: From 6d3f5bbc60f5f58a4249872f5ab17c10e3e85134 Mon Sep 17 00:00:00 2001 From: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> Date: Thu, 22 Jan 2026 01:34:35 +0000 Subject: [PATCH 77/78] Prepare release v0.41.1 Signed-off-by: cozystack-bot <217169706+cozystack-bot@users.noreply.github.com> --- packages/apps/kubernetes/images/kubevirt-csi-driver.tag | 2 +- packages/core/installer/values.yaml | 2 +- packages/core/platform/values.yaml | 2 +- packages/core/testing/values.yaml | 2 +- packages/extra/bootbox/images/matchbox.tag | 2 +- packages/extra/seaweedfs/images/objectstorage-sidecar.tag | 2 +- packages/system/bucket/images/s3manager.tag | 2 +- packages/system/cozystack-api/values.yaml | 2 +- packages/system/cozystack-controller/values.yaml | 4 ++-- packages/system/dashboard/templates/configmap.yaml | 2 +- packages/system/dashboard/values.yaml | 6 +++--- packages/system/kamaji/values.yaml | 4 ++-- packages/system/kubeovn-plunger/values.yaml | 2 +- packages/system/kubeovn-webhook/values.yaml | 2 +- packages/system/kubevirt-csi-node/values.yaml | 2 +- packages/system/lineage-controller-webhook/values.yaml | 2 +- packages/system/objectstorage-controller/values.yaml | 2 +- packages/system/seaweedfs/values.yaml | 2 +- 18 files changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag index ea6c26b9..420fbc66 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:15b94dca216b73336e7f39f4ea1b76b7656890d6be8a8cf0d9a786b4006781f9 +ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:31aee6f63c25a443974b56011d2907cedfeba245aa7caf732d7fc437b2b3ed50 diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index b7ba6565..bdc5c381 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,2 @@ cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.41.0@sha256:bb8de10621d16f6a6591397a25505d1df62b77d4fae9d0a384265e6edfb2b188 + image: ghcr.io/cozystack/cozystack/installer:v0.41.1@sha256:2cea46ebf0c4049ac25cde663d38cab72a51eabdcc82889f0aa8f5d102891cb4 diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index 4c228e44..681e9b8b 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -1,2 +1,2 @@ assets: - image: ghcr.io/cozystack/cozystack/cozystack-assets:v0.41.0@sha256:800d4684d3aaef0a61b383a911acf7446ba0fd0860309fc91aa8fdc0e9491b07 + image: ghcr.io/cozystack/cozystack/cozystack-assets:v0.41.1@sha256:9e50ccc6835fa678c9c5985df3291495f4fa117c29f187d95cb57dfd656e7665 diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml index 36e8b9fb..5deac036 100644 --- a/packages/core/testing/values.yaml +++ b/packages/core/testing/values.yaml @@ -1,2 +1,2 @@ e2e: - image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.41.0@sha256:fde7616aacaf5939388bbe74eb6d946147ce855b9cceb47092f620b75ba2c98a + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.41.1@sha256:fde7616aacaf5939388bbe74eb6d946147ce855b9cceb47092f620b75ba2c98a diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index b014e133..7e5aa5fc 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.41.0@sha256:40c0ae90d2d2eb15d195cb0fd15b172112690a3279b96af2210c4eda3f66fda3 +ghcr.io/cozystack/cozystack/matchbox:v0.41.1@sha256:956ed15f5aa4206c5c74539337d918aa2e0401d1b59f14a693eb91e538834e69 diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag index 7b87d542..d300568e 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:v0.41.0@sha256:87bc334ebbf94ea4096eb9bac52345573a41441c8d2f82cc5f304c2300bc4510 +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.41.1@sha256:2761cafa5dbd9f15659affd9da413c9795a5fbc6b6165c530316f2ef0ccc2ce2 diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index 9e1e5bcc..b8d64513 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:985c8c5a7b6218230e4e590120ea74abd36e34d7f1ad2c46b6a4a32f4fbd657b +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:f21f693514f2a4624c46716d4b7a3cef7d775b9eab7474a49e6b151c5fe2905a diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 2ef3e7bb..f691d377 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,5 +1,5 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.41.0@sha256:5aef475a81d765b343b92d08190f831739568c43658360791ed21e0ef3ecb9b2 + image: ghcr.io/cozystack/cozystack/cozystack-api:v0.41.1@sha256:5aef475a81d765b343b92d08190f831739568c43658360791ed21e0ef3ecb9b2 localK8sAPIEndpoint: enabled: true replicas: 2 diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index 3f639ffc..71c04498 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,6 +1,6 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.41.0@sha256:5cea23058c5d0f5370c57c901cefd9638ce31bfb995a3d7d07ca137b3768dffb + image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.41.1@sha256:b9d067bea8bac4e99648ddc377a0a84f3215335f2693b2c948fa80a83539bec9 debug: false disableTelemetry: false - cozystackVersion: "v0.41.0" + cozystackVersion: "v0.41.1" cozystackAPIKind: "DaemonSet" diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml index e840b55a..5b77ea45 100644 --- a/packages/system/dashboard/templates/configmap.yaml +++ b/packages/system/dashboard/templates/configmap.yaml @@ -1,6 +1,6 @@ {{- $brandingConfig := .Values._cluster.branding | default dict }} -{{- $tenantText := "v0.41.0" }} +{{- $tenantText := "v0.41.1" }} {{- $footerText := "Cozystack" }} {{- $titleText := "Cozystack Dashboard" }} {{- $logoText := "" }} diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index b0e123d7..3bb5a3a3 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,6 +1,6 @@ openapiUI: - image: ghcr.io/cozystack/cozystack/openapi-ui:v0.41.0@sha256:913ec92b8f9c5e2952264f718d92625ce5281c9714b281e3e8c0437af0d97385 + image: ghcr.io/cozystack/cozystack/openapi-ui:v0.41.1@sha256:f93072db03c3b2f22b77bc80970f8c9b3eee25e23abb67de9d5ce9b4c9d3ce51 openapiUIK8sBff: - image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.41.0@sha256:fda379dce49c2cd8cb8d7d2a1d8ec6f7bedb3419c058c4355ecdece1c1e937f4 + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v0.41.1@sha256:d33583995dc81a47c1dcbe45dbd866fa9097f88f4b6eb78b408dca432f15bd38 tokenProxy: - image: ghcr.io/cozystack/cozystack/token-proxy:v0.41.0@sha256:73887f80d96e7e3c16f1cebab521b05b4308bf4662ccc6724e6a8a9745ed8254 + image: ghcr.io/cozystack/cozystack/token-proxy:v0.41.1@sha256:73887f80d96e7e3c16f1cebab521b05b4308bf4662ccc6724e6a8a9745ed8254 diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index 47e85a1c..e2ab2d15 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,7 +3,7 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.41.0@sha256:d5f2fa2972ba33cd2ccb855256e4bda4734d7e250638811b77f2e0dc72ad6b19 + tag: v0.41.1@sha256:d5f2fa2972ba33cd2ccb855256e4bda4734d7e250638811b77f2e0dc72ad6b19 repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: @@ -13,4 +13,4 @@ kamaji: cpu: 100m memory: 100Mi extraArgs: - - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.41.0@sha256:d5f2fa2972ba33cd2ccb855256e4bda4734d7e250638811b77f2e0dc72ad6b19 + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v0.41.1@sha256:d5f2fa2972ba33cd2ccb855256e4bda4734d7e250638811b77f2e0dc72ad6b19 diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml index 70ef984a..0831dcba 100644 --- a/packages/system/kubeovn-plunger/values.yaml +++ b/packages/system/kubeovn-plunger/values.yaml @@ -1,4 +1,4 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.41.0@sha256:9d02fbe27c227152261f2cefa2da86d2b671cb1433a0868ddd42ad20da793633 +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v0.41.1@sha256:f2b42d0d5853a6171e558244445141dbbeeb98399874b5ed82186e50ff267c4c ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index 8758a16a..0a7008e9 100644 --- a/packages/system/kubeovn-webhook/values.yaml +++ b/packages/system/kubeovn-webhook/values.yaml @@ -1,3 +1,3 @@ portSecurity: true routes: "" -image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.41.0@sha256:e18f9fd679e38f65362a8d0042f25468272f6d081136ad47027168d8e7e07a4a +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v0.41.1@sha256:e6334c29d3aaf0dea766c88e3e05b53ad623d1bb497b3c836e6f76adade45b29 diff --git a/packages/system/kubevirt-csi-node/values.yaml b/packages/system/kubevirt-csi-node/values.yaml index 5644e6d8..1fb152da 100644 --- a/packages/system/kubevirt-csi-node/values.yaml +++ b/packages/system/kubevirt-csi-node/values.yaml @@ -1,3 +1,3 @@ storageClass: replicated csiDriver: - image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:15b94dca216b73336e7f39f4ea1b76b7656890d6be8a8cf0d9a786b4006781f9 + image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:31aee6f63c25a443974b56011d2907cedfeba245aa7caf732d7fc437b2b3ed50 diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml index d4db1b7d..1e398d85 100644 --- a/packages/system/lineage-controller-webhook/values.yaml +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -1,5 +1,5 @@ lineageControllerWebhook: - image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.41.0@sha256:c89f47352f0606dd475fe90e19fe2c6e13580af5c9af3f01f356efb4f5c7375e + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v0.41.1@sha256:641d9a72b64ab68dd6f5b91de213e38f5587302cde3860c9395d3eff420f3924 debug: false localK8sAPIEndpoint: enabled: true diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml index 8f4f711d..8043ab58 100644 --- a/packages/system/objectstorage-controller/values.yaml +++ b/packages/system/objectstorage-controller/values.yaml @@ -1,3 +1,3 @@ objectstorage: controller: - image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.41.0@sha256:5697f8aae011bd3a7bfde8256850921b84d170f794b26f7eebabaada499b954e" + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v0.41.1@sha256:2614b05e63804f1f2ee74958342877acf17abc43f29ad022a6c4d40084266cd3" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index 0845c867..a91cbc88 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -177,7 +177,7 @@ seaweedfs: bucketClassName: "seaweedfs" region: "" sidecar: - image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.41.0@sha256:87bc334ebbf94ea4096eb9bac52345573a41441c8d2f82cc5f304c2300bc4510" + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v0.41.1@sha256:2761cafa5dbd9f15659affd9da413c9795a5fbc6b6165c530316f2ef0ccc2ce2" certificates: commonName: "SeaweedFS CA" ipAddresses: [] From d28ea7d5c592cb0079712e501a8288bbf5ceb064 Mon Sep 17 00:00:00 2001 From: nbykov0 <166552198+nbykov0@users.noreply.github.com> Date: Fri, 23 Jan 2026 01:20:16 +0300 Subject: [PATCH 78/78] [keycloak] fix strings with single quotes Signed-off-by: nbykov0 <166552198+nbykov0@users.noreply.github.com> --- packages/core/platform/templates/apps.yaml | 5 ++++- .../system/keycloak-configure/templates/configure-kk.yaml | 7 +++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/core/platform/templates/apps.yaml b/packages/core/platform/templates/apps.yaml index b42aad87..8a99b894 100644 --- a/packages/core/platform/templates/apps.yaml +++ b/packages/core/platform/templates/apps.yaml @@ -61,7 +61,10 @@ stringData: {{- $clusterConfig | toYaml | nindent 6 }} {{- with $cozystackBranding.data }} branding: - {{- . | toYaml | nindent 8 }} + # to keep strings with single quotes + {{- range $k, $v := . }} + {{ $k }}: {{ $v | quote }} + {{- end }} {{- end }} {{- with $cozystackScheduling.data }} scheduling: diff --git a/packages/system/keycloak-configure/templates/configure-kk.yaml b/packages/system/keycloak-configure/templates/configure-kk.yaml index cc15b161..49895214 100644 --- a/packages/system/keycloak-configure/templates/configure-kk.yaml +++ b/packages/system/keycloak-configure/templates/configure-kk.yaml @@ -6,10 +6,13 @@ {{- $existingAuthConfig := lookup "v1" "Secret" "cozy-dashboard" "kubeapps-auth-config" }} {{- $brandingConfig := .Values._cluster.branding | default dict }} +# to keep strings with single quotes {{ $branding := "" }} {{- if $brandingConfig }} - {{- $branding = $brandingConfig.branding }} -{{- end }} + {{- if hasKey $brandingConfig "branding" -}} + {{- $branding = $brandingConfig.branding | quote -}} + {{- end -}} +{{- end -}} ---