Skip to content

Add Elasticsearch managed service with ECK operator - #1899

Closed
Matthieu ROBIN (matthieu-robin) wants to merge 4 commits into
cozystack:mainfrom
matthieu-robin:elasticsearch
Closed

Matthieu ROBIN (matthieu-robin) wants to merge 4 commits into
cozystack:mainfrom
matthieu-robin:elasticsearch

Conversation

@matthieu-robin

@matthieu-robin Matthieu ROBIN (matthieu-robin) commented Jan 21, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

This PR adds a managed Elasticsearch service following the existing MongoDB pattern:

  • elasticsearch-operator: ECK operator v3.2.0 with sysctl DaemonSet for vm.max_map_count
  • elasticsearch-rd: ApplicationDefinition for Cozystack dashboard integration
  • elasticsearch (apps): Application chart with full feature set

Features

  • Multi-version support (v9, v8, v7)
  • Optional Kibana deployment with resource presets
  • Custom users with auto-generated passwords
  • Topology spread policy (soft/hard) for pod distribution across nodes/zones
  • Automatic "replicated" storage class for single replica deployments
  • External access via LoadBalancer
  • TLS enabled by default
  • Node roles configuration (master, data, ingest, ml)

Testing

  • 45 Helm unit tests covering all templates
  • Tested on 3-node Cozystack cluster with Elasticsearch v9.0.0

Test plan

  • Deploy elasticsearch-operator
  • Deploy elasticsearch-rd
  • Create Elasticsearch instance via Cozystack API
  • Verify cluster health (green)
  • Test Kibana deployment
  • Test custom users
  • Test external access

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Managed Elasticsearch service: multi-version support (v7/v8/v9), configurable replicas, storage, resource presets, topology policy, optional Kibana, external access, per-user credentials, generated credentials Secret, and WorkloadMonitor.
    • ECK operator charts: packaging, RBAC, webhook, metrics/Prometheus integration, managed namespaces, and a sysctl DaemonSet for kernel tuning.
  • Documentation

    • New detailed README and chart reference.
  • Tests

    • Rendering and validation test suites for Elasticsearch, Kibana, and user secrets.

✏️ Tip: You can customize this high-level summary in your review settings.

@dosubot dosubot Bot added size/XXL This PR changes 1000+ lines, ignoring generated files kind/feature Categorizes issue or PR as related to a new feature labels Jan 21, 2026
@coderabbitai

coderabbitai Bot commented Jan 21, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Added Helm charts and templates to provision a managed Elasticsearch application and the ECK operator, including chart metadata, values/schema, CR templates (Elasticsearch, Kibana), RBAC, networking, monitoring, credential secrets, tests, and an ApplicationDefinition for system integration.

Changes

Cohort / File(s) Summary
Elasticsearch app chart
packages/apps/elasticsearch/Chart.yaml, packages/apps/elasticsearch/.helmignore, packages/apps/elasticsearch/Makefile, packages/apps/elasticsearch/README.md, packages/apps/elasticsearch/values.yaml, packages/apps/elasticsearch/values.schema.json
New Helm chart metadata, packaging ignores, Makefile, README, default values and JSON Schema for chart validation.
Elasticsearch templates & helpers
packages/apps/elasticsearch/templates/elasticsearch.yaml, packages/apps/elasticsearch/templates/kibana.yaml, packages/apps/elasticsearch/templates/credentials.yaml, packages/apps/elasticsearch/templates/users.yaml, packages/apps/elasticsearch/templates/dashboard-resourcemap.yaml, packages/apps/elasticsearch/templates/external-svc.yaml, packages/apps/elasticsearch/templates/_versions.tpl
Helm templates for Elasticsearch CR, optional Kibana CR, credentials aggregation and per-user Secrets, dashboard Role/RoleBinding, external Services, and version mapping with runtime validation.
Version files & libs
packages/apps/elasticsearch/files/versions.yaml, packages/apps/elasticsearch/charts/cozy-lib
Added version-to-image mapping and local reference to cozy-lib chart.
Chart tests
packages/apps/elasticsearch/tests/elasticsearch_test.yaml, packages/apps/elasticsearch/tests/kibana_test.yaml, packages/apps/elasticsearch/tests/users_test.yaml
Comprehensive unit tests validating template rendering across versions, topology, storage, TLS, users, and Kibana.
ECK operator chart (system)
packages/system/elasticsearch-operator/Chart.yaml, packages/system/elasticsearch-operator/.helmignore, packages/system/elasticsearch-operator/Makefile, packages/system/elasticsearch-operator/values.yaml
New operator chart metadata, packaging ignores, Makefile to fetch upstream ECK chart, and top-level values entries for enabling/installing the operator.
ECK subchart & CRDs
packages/system/elasticsearch-operator/charts/eck-operator/Chart.yaml, packages/system/elasticsearch-operator/charts/eck-operator/LICENSE, packages/system/elasticsearch-operator/charts/eck-operator/README.md, packages/system/elasticsearch-operator/charts/eck-operator/charts/eck-operator-crds/*
Embedded eck-operator and CRDs charts with metadata, license, READMEs, CRD helpers, and packaging files.
ECK helpers & RBAC
packages/system/elasticsearch-operator/charts/eck-operator/templates/_helpers.tpl, .../templates/cluster-roles.yaml, .../templates/role-bindings.yaml, .../templates/service-account.yaml
Extensive helper templates and RBAC rendering for cluster-scoped vs namespace-scoped modes, Role/ClusterRole and RoleBinding/ClusterRoleBinding generation, and service account wiring.
Operator runtime & monitoring
.../charts/eck-operator/templates/statefulset.yaml, .../charts/eck-operator/templates/configmap.yaml, .../templates/pdb.yaml, .../templates/podMonitor.yaml, .../templates/service-monitor.yaml, .../templates/metrics-service.yaml
Operator StatefulSet, generated eck.yaml ConfigMap, runtime validations, PDB, PodMonitor and ServiceMonitor templates, and conditional metrics/service resources.
Networking & multi-tenancy
.../charts/eck-operator/templates/operator-network-policy.yaml, managed-ns-network-policy.yaml, managed-namespaces.yaml, validate-chart.yaml, webhook.yaml, templates/NOTES.txt
NetworkPolicy templates for tenant isolation, chart-level validation rules, webhook ValidatingWebhookConfiguration and associated Service/Secret, and NOTES.
Sysctl DaemonSet
packages/system/elasticsearch-operator/templates/sysctl-daemonset.yaml
DaemonSet to set vm.max_map_count across nodes.
ApplicationDefinition / RD
packages/system/elasticsearch-rd/cozyrds/elasticsearch.yaml, packages/system/elasticsearch-rd/Chart.yaml, packages/system/elasticsearch-rd/Makefile, packages/system/elasticsearch-rd/templates/cozyrd.yaml, packages/system/elasticsearch-rd/values.yaml
ApplicationDefinition and release descriptor registering Elasticsearch with schema, dashboard metadata, secrets/services mapping, and loader template.
Packaging ignores for subcharts
multiple .helmignore under packages/system/elasticsearch-operator/charts/...
Added .helmignore files across operator subcharts to exclude VCS, backup, and IDE files from packaging.

Sequence Diagram(s)

sequenceDiagram
    participant Admin as Admin
    participant Helm as Helm
    participant K8s as Kubernetes
    participant Operator as ECK Operator
    participant ES as Elasticsearch

    Admin->>Helm: install charts (eck-operator, elasticsearch)
    Helm->>K8s: create RBAC, ConfigMap, StatefulSet, Webhook, NetworkPolicies
    K8s->>Operator: operator Pod starts and watches CRs
    Helm->>K8s: create Elasticsearch CR (and Kibana CR if enabled)
    K8s->>Operator: Operator reconciles Elasticsearch CR
    Operator->>K8s: create Pods / StatefulSets / PVCs for ES
    K8s->>ES: start Pods and attach storage
    ES-->>Operator: update status
    Operator->>K8s: populate credentials Secret
    K8s-->>Admin: Services/Ingress expose ES/Kibana
Loading
sequenceDiagram
    participant Values as values.yaml
    participant Templates as Helm templates
    participant K8s as Kubernetes
    participant Secret as Secret

    Values->>Templates: provide users map
    Templates->>Templates: iterate users -> resolve password source
    alt password provided
        Templates->>Secret: create Secret with provided password
    else
        Templates->>Secret: create Secret with generated 16-char password
    end
    Templates->>K8s: emit Secrets and fileRealm Secret
    K8s-->>Operator: Secrets available for operator consumption
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~70 minutes

Poem

🐇 I hopped through charts with tidy paws,

RBAC and secrets in neat little claws.
Operators wake, clusters hum and grow,
Kibana paints dashboards with a gentle glow.
A rabbit's blessing for deploys that flow.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly and clearly summarizes the main change: adding a managed Elasticsearch service with the ECK operator, which aligns with the primary objective of the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello Matthieu ROBIN (@matthieu-robin), I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request delivers a fully managed Elasticsearch service, integrating it deeply within the Cozystack ecosystem. By utilizing the ECK operator, it provides a feature-rich and resilient Elasticsearch offering, complete with flexible deployment options, security configurations, and dashboard integration. This addition significantly expands the platform's data storage and analytics capabilities for users.

Highlights

  • Managed Elasticsearch Service: Introduces a new managed Elasticsearch service, leveraging the Elastic Cloud on Kubernetes (ECK) operator for robust cluster management and self-healing capabilities.
  • Comprehensive Feature Set: The service supports multiple Elasticsearch versions (v9, v8, v7), optional Kibana deployment, custom user management with auto-generated passwords, configurable topology spread policies for high availability, automatic 'replicated' storage class for single-replica deployments, external access via LoadBalancer, and TLS encryption by default.
  • Cozystack Integration: Includes an ApplicationDefinition for seamless integration with the Cozystack dashboard, allowing users to deploy and manage Elasticsearch instances through the Cozystack API.
  • System Prerequisites Handled: Automatically configures the vm.max_map_count kernel parameter on all cluster nodes via a DaemonSet, addressing a common Elasticsearch prerequisite.
  • Extensive Testing: The implementation is backed by 45 Helm unit tests covering all templates and has been tested on a 3-node Cozystack cluster with Elasticsearch v9.0.0.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment Gemini (@gemini-code-assist) Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on Gemini (@gemini-code-assist) comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This is an excellent and comprehensive pull request that adds a managed Elasticsearch service, following the established patterns in the repository. The new application chart is well-structured, includes extensive features like multi-version support, Kibana integration, and custom user management, and is accompanied by thorough documentation and unit tests. The code is clean and maintainable. I've identified a few minor areas for improvement to enhance consistency and adhere to best practices, but overall, this is a fantastic contribution.

@@ -0,0 +1,89 @@
{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The variable $clusterDomain is defined on this line but is not used anywhere within this template file. To improve code clarity and maintainability, it's best to remove unused variable definitions.

spec:
containers:
- name: kibana
resources: {{- include "cozy-lib.resources.defaultingSanitize" (list (.Values.kibana.resourcesPreset | default "small") .Values.kibana.resources $) | nindent 12 }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The default resource preset for Kibana is set to small in this template, which is inconsistent with the medium default specified in values.yaml and values.schema.json. The README also recommends medium as the minimum preset for Kibana. To ensure consistency and prevent under-provisioning Kibana by default, please update the default value here to medium.

          resources: {{- include "cozy-lib.resources.defaultingSanitize" (list (.Values.kibana.resourcesPreset | default "medium") .Values.kibana.resources $) | nindent 12 }}

readOnly: false
containers:
- name: pause
image: gcr.io/google_containers/pause:3.9

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The pause container image is being pulled from gcr.io, which is a deprecated registry. To ensure future compatibility and avoid potential image pull failures, please update this to use the current official Kubernetes registry, registry.k8s.io.

          image: registry.k8s.io/pause:3.9

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 17

🤖 Fix all issues with AI agents
In `@packages/apps/elasticsearch/files/versions.yaml`:
- Around line 1-5: The versions.yaml entry for "v7" is out of date (shows
7.17.27) and should be refreshed by running the generator rather than editing
the file; run the hack/update-versions.sh script to fetch the latest container
tags and regenerate packages/apps/elasticsearch/files/versions.yaml so the "v7"
mapping becomes 7.17.28 (or the newest available), then commit the regenerated
file instead of making manual edits.

In `@packages/apps/elasticsearch/README.md`:
- Line 11: Update the README text that currently reads "Github:
<https://github.com/elastic/cloud-on-k8s>" to use the correct branding "GitHub";
locate the string in the README (packages/apps/elasticsearch/README.md) and
replace "Github" with "GitHub" so the link label matches official
capitalization.

In `@packages/apps/elasticsearch/templates/kibana.yaml`:
- Line 19: The template is defaulting Kibana resources to "small" which
contradicts the README requirement for a minimum "medium"; update the fallback
in the resources line that references .Values.kibana.resourcesPreset (currently
default "small") to default to "medium" so the call to include
"cozy-lib.resources.defaultingSanitize" uses "medium" as the preset when
.Values.kibana.resourcesPreset is unset.

In `@packages/apps/elasticsearch/values.schema.json`:
- Around line 10-24: The JSON schema for the "images" object declares
"required": ["elasticsearch"] but its "default" is an empty object, causing
validation failure; fix by either removing the "required" array from the
"images" schema or by changing the "default" value to include the
"elasticsearch" property (e.g., set default to an object containing the
"elasticsearch" string currently used as the property's default). Update the
schema around the "images" object and "elasticsearch" property so the default
state satisfies the required constraints.

In `@packages/system/elasticsearch-operator/charts/eck-operator/Chart.yaml`:
- Around line 1-26: This Chart.yaml shows a vendored upstream chart (name:
eck-operator, version: 3.2.0) that must not be checked in directly; remove the
chart from the charts/ directory and instead add it as a dependency in your
umbrella Chart.yaml (add an entry with name: eck-operator, version: 3.2.0 and a
proper repository URL, include the eck-operator-crds dependency via condition:
installCRDs if needed), then run Helm dependency update to generate Chart.lock
and vendor the chart through Helm’s dependency mechanism; ensure you delete the
direct eck-operator chart files from the vendored charts folder so only the
umbrella Chart.yaml/Chart.lock manage this dependency.

In
`@packages/system/elasticsearch-operator/charts/eck-operator/profile-disable-automounting-api.yaml`:
- Around line 1-29: This profile file under the vendored chart must be moved out
of the vendored chart directory: remove the file containing
automountServiceAccountToken/serviceAccount/volumeMounts/volumes from the
eck-operator chart and instead place its content into the umbrella chart or the
package-level values directory, then wire it into the packaging flow so the
profile is applied at deployment time (do not modify vendored charts that are
re-created by make update); update the umbrella chart's values/overlays or the
package packaging configuration to reference these settings so
automountServiceAccountToken and the projected serviceAccountToken volume are
injected without editing the vendored chart.

In
`@packages/system/elasticsearch-operator/charts/eck-operator/profile-restricted.yaml`:
- Around line 1-12: This file modifies vendored chart values (managedNamespaces,
createClusterScopedResources, config.validateStorageClass, installCRDs,
webhook.enabled); revert these direct edits in the vendored chart and instead
implement the same changes via the umbrella chart or overlay values (or vendor a
forked chart) so the upstream chart under packages/system remains untouched—move
the customized keys (managedNamespaces, createClusterScopedResources,
validateStorageClass, installCRDs, webhook.enabled) into the umbrella/overlay
values.yaml or create a forked chart and update the umbrella to reference it.

In `@packages/system/elasticsearch-operator/charts/eck-operator/README.md`:
- Around line 14-20: Replace the two bare URLs in README.md with markdown links:
change the plain
https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s_supported_versions.html
and https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-install-helm.html
to inline markdown link syntax (e.g., [Supported Kubernetes versions](<url>) and
[Installation guide for Helm](<url>)) so the file no longer contains bare URLs
and passes MD034; update the lines near the "Supported Kubernetes versions" and
"Usage" sections where those URLs appear.

In
`@packages/system/elasticsearch-operator/charts/eck-operator/templates/cluster-roles.yaml`:
- Around line 4-98: This change edits a vendored Helm template
(cluster-roles.yaml) to add/adjust ClusterRole rules—do not modify vendored
charts directly; instead revert edits in the template and move your RBAC changes
into the wrapper/umbrella chart using supported vendoring mechanisms: supply
overrides via values (e.g., add rules through a values.yaml key consumed by the
chart), apply a post-render patch to inject or patch ClusterRole resources, or
submit the changes upstream and re-vendor; target the same logical objects
referenced here (ClusterRole names from include "eck-operator.fullname" and
include "eck-operator.name"-view/-edit and the templates
"eck-operator.rbacRules"/"eck-operator.clusterWideRbacRules") so the
wrapper/post-render applies the equivalent rule additions without editing the
vendored templates.

In
`@packages/system/elasticsearch-operator/charts/eck-operator/templates/managed-ns-network-policy.yaml`:
- Around line 41-46: This vendored Helm chart must not be edited directly; do
not change the namespaceSelector -> matchLabels -> name label in
managed-ns-network-policy.yaml. Instead, create a Kustomize overlay or a patch
that replaces the NetworkPolicy rule (targeting the
namespaceSelector.matchLabels entry that currently uses "name") with the
standard label key ("kubernetes.io/metadata.name") or remove/override the
namespaceSelector entirely, and/or open an upstream issue against Elastic ECK
v3.2.0 asking them to use "kubernetes.io/metadata.name"; reference the manifest
block containing namespaceSelector, matchLabels, and the include
"eck-operator.selectorLabels" to locate the rule to patch.

In
`@packages/system/elasticsearch-operator/charts/eck-operator/templates/NOTES.txt`:
- Around line 1-2: The NOTES.txt uses sts/{{ .Release.Name }} which may not
match the actual StatefulSet name; update the kubectl logs example in
packages/system/elasticsearch-operator/charts/eck-operator/templates/NOTES.txt
to reference the correct template variable by using {{ include
"eck-operator.fullname" . }} (keep the existing {{ .Release.Namespace }}), i.e.
change the resource reference from sts/{{ .Release.Name }} to sts/{{ include
"eck-operator.fullname" . }} so the command targets the real StatefulSet name.

In
`@packages/system/elasticsearch-operator/charts/eck-operator/templates/role-bindings.yaml`:
- Around line 17-18: The Helm helper invocation uses the template action
incorrectly; replace uses of template "eck-operator.rbacRules" piped into
toYaml|indent with include "eck-operator.rbacRules" (which returns a string you
can pipe to toYaml and indent), and remove toYaml if the rbacRules helper
already emits valid YAML; apply this fix for the rbacRules invocation(s) in the
role bindings template so the helper output is captured via include and
correctly indented.
- Around line 46-47: Replace the use of the Helm template function with include
for rendering the rbac rules: change the rules block that calls {{ template
"eck-operator.rbacRules" $ | toYaml | indent 2 }} to use include instead (i.e.,
call "eck-operator.rbacRules" via include) so the helper is evaluated correctly;
update the invocation where "eck-operator.rbacRules" is referenced in the
role-bindings template accordingly.

In `@packages/system/elasticsearch-operator/charts/eck-operator/values.yaml`:
- Around line 81-86: Fix the typo in the podDisruptionBudget comment: change
"maxium" to "maximum" in the comment that describes podDisruptionBudget (the
block with keys podDisruptionBudget, enabled, minAvailable, maxUnavailable) so
the documentation reads "maximum available pods" instead of "maxium".
- Around line 321-324: Update the incorrect comment above the serviceMonitor key
so it references the correct config path; change "Only used when
config.enableSecureMetrics is true" to "Only used when
config.metrics.secureMode.enabled is true" (the comment immediately preceding
serviceMonitor in the values.yaml) to accurately reflect the configuration flag.

In `@packages/system/elasticsearch-operator/templates/sysctl-daemonset.yaml`:
- Around line 20-21: Remove the unnecessary hostPID and hostNetwork entries from
the DaemonSet spec in sysctl-daemonset.yaml: the privileged container already
has access required to write /proc/sys/vm/max_map_count, so delete the hostPID:
true and hostNetwork: true keys to reduce privilege surface; ensure the
DaemonSet still sets securityContext.privileged as intended and that the
container runs the sysctl command for vm.max_map_count without referencing host
PID or network namespaces.

In `@packages/system/elasticsearch-rd/cozyrds/elasticsearch.yaml`:
- Line 11: The openAPISchema's images.elasticsearch default is misleading
because image selection is driven by version (see version and versionMap logic);
update the images.elasticsearch property in elasticsearch.yaml by removing the
default value (or set it to an empty string) and adjust its description to state
that image is auto-selected based on the chart `version`/`versionMap` so users
aren't confused; target the images.elasticsearch schema entry in the file when
making this change.
♻️ Duplicate comments (1)
packages/system/elasticsearch-operator/charts/eck-operator/profile-global.yaml (1)

1-6: Same vendored-chart modification concern as above.

This profile will be overwritten by make update and should live outside the vendored chart.

🧹 Nitpick comments (9)
packages/system/elasticsearch-operator/templates/sysctl-daemonset.yaml (1)

22-39: Consider adding resource limits to the initContainer.

The initContainer lacks resource requests/limits. While it runs briefly, adding limits ensures consistent behavior and prevents resource starvation in edge cases.

♻️ Proposed addition
           command:
             - sh
             - -c
             - |
               sysctl -w vm.max_map_count=262144
               # Keep the value persistent by writing to sysctl.conf if writable
               if [ -w /host-etc/sysctl.conf ]; then
                 grep -q "vm.max_map_count" /host-etc/sysctl.conf || echo "vm.max_map_count=262144" >> /host-etc/sysctl.conf
               fi
+          resources:
+            requests:
+              cpu: 1m
+              memory: 1Mi
+            limits:
+              cpu: 50m
+              memory: 16Mi
           volumeMounts:
packages/system/elasticsearch-operator/Chart.yaml (1)

1-3: Consider adding metadata fields for better chart documentation.

The Chart.yaml is missing several recommended metadata fields that would improve discoverability and maintainability, especially since this chart will be exposed in the Cozystack dashboard:

  • description: Brief explanation of what the chart deploys
  • type: Should be application for deployable charts
  • appVersion: The ECK operator version (3.2.0) being deployed
📝 Proposed metadata additions
 apiVersion: v2
 name: cozy-elasticsearch-operator
 version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process
+description: Elastic Cloud on Kubernetes (ECK) operator for managing Elasticsearch clusters
+type: application
+appVersion: "3.2.0"
packages/system/elasticsearch-rd/cozyrds/elasticsearch.yaml (1)

10-11: Consider formatting the openAPISchema as multi-line YAML for maintainability.

The single-line JSON blob is difficult to read and maintain. Consider using YAML's literal block scalar with proper indentation, or keeping the JSON but formatting it across multiple lines. This would make future schema modifications less error-prone.

packages/apps/elasticsearch/README.md (1)

119-128: Resource presets table could include "medium" and "small" entries.

The README mentions medium preset for Kibana (line 122) but the table only shows large, xlarge, and 2xlarge. Consider adding the smaller presets for completeness.

packages/apps/elasticsearch/templates/kibana.yaml (1)

2-2: Unused variable $clusterDomain.

The variable is defined but never referenced in this template. Either remove it or use it (e.g., for DNS configuration).

Proposed fix if not needed
 {{- if .Values.kibana.enabled }}
-{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }}
 ---
packages/apps/elasticsearch/templates/elasticsearch.yaml (1)

1-1: Unused variable $clusterDomain.

Same as in kibana.yaml - this variable is defined but not used in the template.

Proposed fix if not needed
-{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }}
 {{- $topologyMode := .Values.topologySpreadPolicy | default "soft" }}
packages/apps/elasticsearch/tests/kibana_test.yaml (1)

53-85: Consider adding v7 version test for consistency.

The Elasticsearch test suite includes a v7 version test (7.17.27), but Kibana tests only cover v9 and v8. For consistency and complete coverage, consider adding a test case for v7:

  - it: uses same version as Elasticsearch (v7)
    release:
      name: test-es
      namespace: tenant-test
    set:
      _cluster:
        cluster-domain: cozy.local
      version: v7
      kibana:
        enabled: true
    asserts:
      - equal:
          path: spec.version
          value: "7.17.27"
packages/system/elasticsearch-operator/Makefile (1)

1-10: Consider adding minimal phony targets if checkmake is enforced.

Static analysis flags missing all, clean, and test phony targets. If checkmake is part of CI, add stubs or adjust the rule to avoid pipeline noise.

♻️ Optional Makefile stub targets
+.PHONY: all clean test update
+
+all:
+	`@true`
+
+clean:
+	`@true`
+
+test:
+	`@true`
packages/system/elasticsearch-operator/charts/eck-operator/templates/webhook.yaml (1)

283-292: Inconsistent indentation style in webhook rules.

The rules for mapsservers (lines 284-292) and some other resources use 4-space indentation under rules:, while earlier webhook definitions use 2-space indentation. This inconsistency doesn't affect functionality but reduces readability.

For consistency, consider aligning all rules sections to use the same indentation style (2 spaces as used in lines 35-44).

Comment thread packages/apps/elasticsearch/README.md Resolved
Comment on lines +81 to +86
# podDisruptionBudget configures the minimum or the maxium available pods for voluntary disruptions,
# set to either an integer (e.g. 1) or a percentage value (e.g. 25%).
podDisruptionBudget:
enabled: false
minAvailable: 1
# maxUnavailable: 3

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Typo: "maxium" should be "maximum".

Proposed fix
-# podDisruptionBudget configures the minimum or the maxium available pods for voluntary disruptions,
+# podDisruptionBudget configures the minimum or the maximum available pods for voluntary disruptions,
🤖 Prompt for AI Agents
In `@packages/system/elasticsearch-operator/charts/eck-operator/values.yaml`
around lines 81 - 86, Fix the typo in the podDisruptionBudget comment: change
"maxium" to "maximum" in the comment that describes podDisruptionBudget (the
block with keys podDisruptionBudget, enabled, minAvailable, maxUnavailable) so
the documentation reads "maximum available pods" instead of "maxium".

Comment on lines +321 to +324
# Prometheus ServiceMonitor configuration
# Only used when config.enableSecureMetrics is true
# Reference: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#servicemonitor
serviceMonitor:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Comment references incorrect value path.

The comment says "Only used when config.enableSecureMetrics is true" but the actual configuration path is config.metrics.secureMode.enabled.

Proposed fix
 # Prometheus ServiceMonitor configuration
-# Only used when config.enableSecureMetrics is true
+# Only used when config.metrics.secureMode.enabled is true
 # Reference: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#servicemonitor
🤖 Prompt for AI Agents
In `@packages/system/elasticsearch-operator/charts/eck-operator/values.yaml`
around lines 321 - 324, Update the incorrect comment above the serviceMonitor
key so it references the correct config path; change "Only used when
config.enableSecureMetrics is true" to "Only used when
config.metrics.secureMode.enabled is true" (the comment immediately preceding
serviceMonitor in the values.yaml) to accurately reflect the configuration flag.

singular: elasticsearch
plural: elasticsearches
openAPISchema: |-
{"title":"Chart Values","type":"object","properties":{"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":["elasticsearch"],"properties":{"elasticsearch":{"description":"Elasticsearch image.","type":"string","default":"docker.elastic.co/elasticsearch/elasticsearch:8.17.0"}}},"nodeRoles":{"description":"Node roles configuration.","type":"object","default":{},"properties":{"master":{"description":"Enable master role.","type":"boolean","default":true},"data":{"description":"Enable data role.","type":"boolean","default":true},"ingest":{"description":"Enable ingest role.","type":"boolean","default":true},"ml":{"description":"Enable machine learning role.","type":"boolean","default":false}}},"replicas":{"description":"Number of Elasticsearch nodes in the cluster.","type":"integer","default":3},"resources":{"description":"Explicit CPU and memory configuration for each Elasticsearch node. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each node.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each node.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted. Elasticsearch requires minimum 2Gi memory.","type":"string","default":"large","enum":["large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"topologySpreadPolicy":{"description":"Pod distribution policy across nodes and zones. 'soft' allows scheduling even if spread cannot be achieved, 'hard' prevents scheduling if pods cannot be evenly distributed.","type":"string","default":"soft","enum":["soft","hard"]},"users":{"description":"Custom Elasticsearch users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"password":{"description":"Password for the user (auto-generated if omitted).","type":"string"},"roles":{"description":"List of Elasticsearch roles.","type":"array","items":{"type":"string"}}}}},"version":{"description":"Elasticsearch major version to deploy.","type":"string","default":"v9","enum":["v9","v8","v7"]},"kibana":{"description":"Kibana deployment configuration.","type":"object","default":{},"properties":{"enabled":{"description":"Enable Kibana deployment.","type":"boolean","default":false},"replicas":{"description":"Number of Kibana replicas.","type":"integer","default":1},"resources":{"description":"Explicit CPU and memory configuration for Kibana.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to Kibana.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-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 Kibana.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset for Kibana. Minimum 1Gi memory recommended.","type":"string","default":"medium","enum":["small","medium","large","xlarge","2xlarge"]}}}}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the file and its contents
fd -t f 'elasticsearch.yaml' packages/system --exec head -20 {} \;

Repository: cozystack/cozystack

Length of output: 4729


🏁 Script executed:

#!/bin/bash
# Get the full context of line 11 in the mentioned file
fd -t f 'elasticsearch.yaml' packages/system/elasticsearch-rd --exec cat -n {} \;

Repository: cozystack/cozystack

Length of output: 7461


🏁 Script executed:

#!/bin/bash
# Explore the directory structure
ls -la packages/system/elasticsearch-rd/ 2>/dev/null || echo "Directory not found"
ls -la packages/apps/elasticsearch/ 2>/dev/null || echo "apps/elasticsearch not found"

Repository: cozystack/cozystack

Length of output: 1255


🏁 Script executed:

#!/bin/bash
# Check values.yaml in the app chart
fd -t f 'values.yaml' packages/apps/elasticsearch --exec head -100 {} \;

Repository: cozystack/cozystack

Length of output: 3059


🏁 Script executed:

#!/bin/bash
# Check templates in the app chart to see how version and images are used
fd -t f '*.yaml' 'packages/apps/elasticsearch/templates' --exec cat -n {} \;

Repository: cozystack/cozystack

Length of output: 348


🏁 Script executed:

#!/bin/bash
# Also check for any helper templates or includes that might handle version logic
find packages/apps/elasticsearch -name '*.tpl' -o -name 'helpers.tpl' | xargs cat -n 2>/dev/null || echo "No helper templates found"

Repository: cozystack/cozystack

Length of output: 572


🏁 Script executed:

#!/bin/bash
# Check if there's a values.schema.json that might shed light on the mapping
cat packages/apps/elasticsearch/values.schema.json | head -200

Repository: cozystack/cozystack

Length of output: 6194


🏁 Script executed:

#!/bin/bash
# Check the versions mapping file that drives version-to-image selection
cat packages/apps/elasticsearch/files/versions.yaml

Repository: cozystack/cozystack

Length of output: 235


🏁 Script executed:

#!/bin/bash
# Also check if there are templates that use the version mapping
fd --glob 'templates/*.yaml' packages/apps/elasticsearch --exec grep -l "versionMap\|version\|images.elasticsearch" {} \;

Repository: cozystack/cozystack

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Get one of the main templates to see how versionMap is used
fd --glob 'templates/*.yaml' packages/apps/elasticsearch -x head -100 {} \;

Repository: cozystack/cozystack

Length of output: 45


🏁 Script executed:

#!/bin/bash
# List all template files in the app chart
fd --glob 'templates/*' packages/apps/elasticsearch --type f

Repository: cozystack/cozystack

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check the main Elasticsearch template to see how it uses images and versions
find packages/apps/elasticsearch/templates -type f -exec cat -n {} \;

Repository: cozystack/cozystack

Length of output: 10311


🏁 Script executed:

#!/bin/bash
# Check if images.elasticsearch value is actually used in any templates
rg 'images\.elasticsearch|\.Values\.images' packages/apps/elasticsearch/

Repository: cozystack/cozystack

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check the Chart.yaml to understand the app chart structure
cat packages/apps/elasticsearch/Chart.yaml

Repository: cozystack/cozystack

Length of output: 308


🏁 Script executed:

#!/bin/bash
# Verify that images.elasticsearch value is never actually used in templates or by ECK
rg 'images' packages/apps/elasticsearch/templates/ 2>/dev/null || echo "No matches found"
rg 'Values\.images\|\.images\.' packages/apps/elasticsearch/ 2>/dev/null || echo "No matches found"

Repository: cozystack/cozystack

Length of output: 96


🏁 Script executed:

#!/bin/bash
# Double-check all files in the app chart for any reference to images configuration
find packages/apps/elasticsearch -type f \( -name '*.yaml' -o -name '*.tpl' -o -name '*.yml' \) -exec grep -l 'images' {} \;

Repository: cozystack/cozystack

Length of output: 102


🏁 Script executed:

#!/bin/bash
# Confirm the images.elasticsearch value is defined but completely unused
cat packages/apps/elasticsearch/values.yaml | grep -A 5 "images:"

Repository: cozystack/cozystack

Length of output: 186


🏁 Script executed:

#!/bin/bash
# Check the README or documentation for the app chart to see if images.elasticsearch is mentioned as usable
cat packages/apps/elasticsearch/README.md | head -150

Repository: cozystack/cozystack

Length of output: 4305


🏁 Script executed:

#!/bin/bash
# Verify ECK operator behavior - check if ECK automatically selects images based on version
# Search for any comments or docs about version-to-image mapping in the codebase
rg -A 3 -B 3 'version.*image|image.*version' packages/apps/elasticsearch/ --type yaml

Repository: cozystack/cozystack

Length of output: 411


Remove or update the images.elasticsearch schema default to prevent user confusion.

The openAPISchema has version defaulting to "v9" but images.elasticsearch defaulting to "docker.elastic.co/elasticsearch/elasticsearch:8.17.0" (v8.17.0). Since the application uses ECK's automatic version-based image selection (via the versionMap helper), the images.elasticsearch parameter is never actually used. The misleading schema default should either be removed entirely or updated to reflect that image selection is version-driven.

🤖 Prompt for AI Agents
In `@packages/system/elasticsearch-rd/cozyrds/elasticsearch.yaml` at line 11, The
openAPISchema's images.elasticsearch default is misleading because image
selection is driven by version (see version and versionMap logic); update the
images.elasticsearch property in elasticsearch.yaml by removing the default
value (or set it to an empty string) and adjust its description to state that
image is auto-selected based on the chart `version`/`versionMap` so users aren't
confused; target the images.elasticsearch schema entry in the file when making
this change.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In
`@packages/system/elasticsearch-operator/charts/eck-operator/templates/podMonitor.yaml`:
- Around line 1-42: This change edits a vendored upstream Helm template
(podMonitor.yaml) — revert the direct edits in this file and instead apply the
fix via the upstream chart or an overlay/values override; specifically remove
modifications around the checks and PodMonitor resource in podMonitor.yaml and
implement the desired configuration by updating the vendored chart upstream or
adding a values override (or kustomize/Helm overlay) that sets
.Values.podMonitor.enabled, .Values.config.metrics.secureMode.enabled, and the
metrics port (template "eck-operator.metrics.port") as needed; ensure any
behavioral changes are made outside the vendored templates and reference the
same symbols (.Values.podMonitor.enabled,
.Values.config.metrics.secureMode.enabled, include "eck-operator.metrics.port",
include "eck-operator.fullname") when applying overrides.

In `@packages/system/elasticsearch-operator/charts/eck-operator/values.yaml`:
- Around line 1-377: The vendored chart was directly modified by setting
nameOverride and fullnameOverride; remove or revert those two entries in the
vendored values (leave them empty as upstream expects) and instead add the
overrides to the parent package values under the eck-operator key: add
eck-operator:nameOverride, eck-operator:fullnameOverride and include the shared
entries managedNamespaces, installCRDs, and createClusterScopedResources (i.e.,
set eck-operator.managedNamespaces, eck-operator.installCRDs,
eck-operator.createClusterScopedResources alongside the two name overrides) so
chart customizations are applied via the parent values override mechanism rather
than editing the vendored chart.

In `@packages/system/elasticsearch-operator/templates/sysctl-daemonset.yaml`:
- Around line 28-33: The current persistence logic in the sysctl snippet (in the
sysctl-daemonset.yaml template) only appends to /host-etc/sysctl.conf when
vm.max_map_count is absent, which leaves existing differing entries unchanged;
change the template to create/ensure a dedicated drop-in file under
/host-etc/sysctl.d (e.g., /host-etc/sysctl.d/99-elasticsearch.conf) and
write/overwrite the single line "vm.max_map_count=262144" there (while still
running sysctl -w at runtime), ensuring the directory exists and the file is
written atomically so existing conflicting entries are replaced and
systemd/sysctl semantics are followed.
🧹 Nitpick comments (7)
packages/system/elasticsearch-operator/templates/sysctl-daemonset.yaml (1)

21-25: Consider adding resource limits to the initContainer.

The sysctl initContainer lacks resource requests/limits. While it runs briefly, adding minimal limits ensures consistent resource governance.

♻️ Proposed addition
         - name: sysctl
           image: busybox:1.36
           securityContext:
             privileged: true
+          resources:
+            requests:
+              cpu: 1m
+              memory: 1Mi
+            limits:
+              cpu: 10m
+              memory: 10Mi
           command:
packages/system/elasticsearch-operator/charts/eck-operator/templates/statefulset.yaml (1)

80-85: Consider quoting tracing config values to handle non-string types.

If .Values.tracing.config contains numeric or boolean values, they may not render correctly without explicit quoting.

♻️ Proposed fix
             {{- if .Values.tracing.enabled -}}
             {{- range $name, $value :=  .Values.tracing.config }}
             - name: {{ $name }}
-              value: {{ $value }}
+              value: {{ $value | quote }}
             {{- end }}
             {{- end }}
packages/system/elasticsearch-operator/charts/eck-operator/templates/metrics-service.yaml (1)

6-11: Consider using the standard labels helper for consistency.

Other templates in this chart use {{- include "eck-operator.labels" . | nindent 4 }} for labels. This template manually constructs similar labels, which could lead to drift if the helper is updated.

♻️ Proposed fix
 metadata:
   labels:
-    app.kubernetes.io/name: {{ include "eck-operator.name" . }}-metrics-service
-    app.kubernetes.io/instance: {{ .Release.Name }}
-    app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
-    helm.sh/chart: {{ include "eck-operator.chart" . }}
-    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    {{- include "eck-operator.labels" . | nindent 4 }}
   name: "{{ include "eck-operator.fullname" . }}-metrics"
packages/apps/elasticsearch/README.md (1)

63-63: Clarify the replicated StorageClass requirement.

If a cluster doesn’t have a replicated StorageClass, single‑replica installs will fail to provision PVCs. Consider calling out the requirement or advising storageClass override.

✏️ Suggested doc tweak
-Note: Single-replica deployments automatically use `replicated` storage class for data resilience.
+Note: Single-replica deployments automatically use `replicated` storage class for data resilience. Ensure this StorageClass exists in the cluster, or set `storageClass` explicitly.
packages/apps/elasticsearch/templates/elasticsearch.yaml (1)

23-36: Guard against an empty node.roles configuration.

If all roles are set to false, the cluster will render with no roles and become non-functional. Consider a template/schema guard that requires at least one role.

♻️ Proposed guard
       config:
+        {{- if not (or .Values.nodeRoles.master .Values.nodeRoles.data .Values.nodeRoles.ingest .Values.nodeRoles.ml) }}
+        {{- fail "At least one node role must be enabled." }}
+        {{- end }}
         node.roles:
           {{- if .Values.nodeRoles.master }}
           - master
packages/apps/elasticsearch/tests/kibana_test.yaml (1)

53-85: Consider adding test coverage for v7 version mapping.

Tests cover v9 and v8 version mappings but the PR adds multi-version support including v7 (mapping to 7.17.28). Consider adding a test case for completeness.

📝 Suggested test case
  - it: uses same version as Elasticsearch (v7)
    release:
      name: test-es
      namespace: tenant-test
    set:
      _cluster:
        cluster-domain: cozy.local
      version: v7
      kibana:
        enabled: true
    asserts:
      - equal:
          path: spec.version
          value: "7.17.28"
packages/system/elasticsearch-operator/charts/eck-operator/templates/service-monitor.yaml (1)

6-6: Complex ternary expression could be simplified.

The namespace selection logic is hard to parse. Consider using a cleaner conditional:

♻️ Suggested simplification
-  namespace: {{ ternary .Values.serviceMonitor.namespace .Release.Namespace (not (and (.Values.serviceMonitor) (empty .Values.serviceMonitor.namespace))) }}
+  namespace: {{ .Values.serviceMonitor.namespace | default .Release.Namespace }}

The default function handles empty/nil values cleanly and is more readable.

Comment on lines +1 to +42
{{- $metricsPort := int (include "eck-operator.metrics.port" .)}}
{{- if and .Values.config.metrics.secureMode.enabled (eq $metricsPort 0) }}
{{- fail "config.metrics.port must be greater than 0 when config.metrics.secureMode.enabled is true" }}
{{- end }}
{{- if and .Values.podMonitor.enabled (gt $metricsPort 0) }}
{{- if and .Values.podMonitor.enabled .Values.config.metrics.secureMode.enabled }}
{{- fail "podMonitor and config.metrics.secureMode are mutually exclusive" }}
{{- end }}
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: {{ include "eck-operator.fullname" . }}
namespace: {{ ternary .Values.podMonitor.namespace .Release.Namespace (not (and (.Values.podMonitor) (empty .Values.podMonitor.namespace))) }}
labels: {{- include "eck-operator.labels" . | nindent 4 }}
{{- with .Values.podMonitor.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.podMonitor.annotations }}
annotations: {{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.podMonitor.podTargetLabels }}
podTargetLabels: {{- toYaml . | nindent 4 }}
{{- end }}
podMetricsEndpoints:
- port: metrics
path: /metrics
{{- with .Values.podMonitor.interval }}
interval: {{ . }}
{{- end }}
{{- with .Values.podMonitor.scrapeTimeout }}
scrapeTimeout: {{ . }}
{{- end }}
{{- with .Values.podMonitor.podMetricsEndpointConfig }}
{{- toYaml . | nindent 6 }}
{{- end }}
namespaceSelector:
matchNames:
- {{ .Release.Namespace }}
selector:
matchLabels: {{- include "eck-operator.selectorLabels" . | nindent 6 }}
{{- end }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid direct edits inside vendored chart templates.

This file lives under charts/eck-operator/templates, which is a vendored upstream chart; repo guidance prefers updating the vendored chart (or applying overlays) rather than direct template edits. As per coding guidelines: Do NOT directly edit upstream Helm charts in vendored charts directory; use proper chart vendoring mechanisms.

🧰 Tools
🪛 YAMLlint (1.38.0)

[error] 1-1: syntax error: expected the node content, but found '-'

(syntax)

🤖 Prompt for AI Agents
In
`@packages/system/elasticsearch-operator/charts/eck-operator/templates/podMonitor.yaml`
around lines 1 - 42, This change edits a vendored upstream Helm template
(podMonitor.yaml) — revert the direct edits in this file and instead apply the
fix via the upstream chart or an overlay/values override; specifically remove
modifications around the checks and PodMonitor resource in podMonitor.yaml and
implement the desired configuration by updating the vendored chart upstream or
adding a values override (or kustomize/Helm overlay) that sets
.Values.podMonitor.enabled, .Values.config.metrics.secureMode.enabled, and the
metrics port (template "eck-operator.metrics.port") as needed; ensure any
behavioral changes are made outside the vendored templates and reference the
same symbols (.Values.podMonitor.enabled,
.Values.config.metrics.secureMode.enabled, include "eck-operator.metrics.port",
include "eck-operator.fullname") when applying overrides.

Comment on lines +1 to +377
# nameOverride is the short name for the deployment. Leave empty to let Helm generate a name using chart values.
nameOverride: "elastic-operator"

# fullnameOverride is the full name for the deployment. Leave empty to let Helm generate a name using chart values.
fullnameOverride: "elastic-operator"

# managedNamespaces is the set of namespaces that the operator manages. Leave empty to manage all namespaces.
managedNamespaces: []

# installCRDs determines whether Custom Resource Definitions (CRD) are installed by the chart.
# Note that CRDs are global resources and require cluster admin privileges to install.
# If you are sharing a cluster with other users who may want to install ECK on their own namespaces, setting this to true can have unintended consequences.
# 1. Upgrades will overwrite the global CRDs and could disrupt the other users of ECK who may be running a different version.
# 2. Uninstalling the chart will delete the CRDs and potentially cause Elastic resources deployed by other users to be removed as well.
installCRDs: true

# replicaCount is the number of operator pods to run.
replicaCount: 1

image:
# repository is the container image prefixed by the registry name.
repository: docker.elastic.co/eck/eck-operator
# pullPolicy is the container image pull policy.
pullPolicy: IfNotPresent
# tag is the container image tag. If not defined, defaults to chart appVersion.
tag: null
# fips specifies whether the operator will use a FIPS compliant container image for its own StatefulSet image.
# This setting does not apply to Elastic Stack applications images.
# Can be combined with config.ubiOnly.
fips: false

# priorityClassName defines the PriorityClass to be used by the operator pods.
priorityClassName: ""

# imagePullSecrets defines the secrets to use when pulling the operator container image.
imagePullSecrets: []

# resources define the container resource limits for the operator.
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 100m
memory: 150Mi

# statefulsetAnnotations define the annotations that should be added to the operator StatefulSet.
statefulsetAnnotations: {}

# statefulsetLabels define additional labels that should be added to the operator StatefulSet.
statefulsetLabels: {}

# podAnnotations define the annotations that should be added to the operator pod.
podAnnotations: {}

## podLabels define additional labels that should be added to the operator pod.
podLabels: {}

# podSecurityContext defines the pod security context for the operator pod.
podSecurityContext:
runAsNonRoot: true

# securityContext defines the security context of the operator container.
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true

# nodeSelector defines the node selector for the operator pod.
nodeSelector: {}

# tolerations defines the node tolerations for the operator pod.
tolerations: []

# affinity defines the node affinity rules for the operator pod.
affinity: {}

# podDisruptionBudget configures the minimum or the maxium available pods for voluntary disruptions,
# set to either an integer (e.g. 1) or a percentage value (e.g. 25%).
podDisruptionBudget:
enabled: false
minAvailable: 1
# maxUnavailable: 3

# additional environment variables for the operator container.
env: []

# additional volume mounts for the operator container.
volumeMounts: []

# additional volumes to add to the operator pod.
volumes: []

# createClusterScopedResources determines whether cluster-scoped resources (ClusterRoles, ClusterRoleBindings) should be created.
createClusterScopedResources: true

# Automount API credentials for the Service Account into the pod.
automountServiceAccountToken: true

serviceAccount:
# create specifies whether a service account should be created for the operator.
create: true
# Specifies whether a service account should automount API credentials.
automountServiceAccountToken: true
# annotations to add to the service account
annotations: {}
# name of the service account to use. If not set and create is true, a name is generated using the fullname template.
name: ""

tracing:
# enabled specifies whether APM tracing is enabled for the operator.
enabled: false
# config is a map of APM Server configuration variables that should be set in the environment.
config:
ELASTIC_APM_SERVER_URL: http://localhost:8200
ELASTIC_APM_SERVER_TIMEOUT: 30s

refs:
# enforceRBAC specifies whether RBAC should be enforced for cross-namespace associations between resources.
enforceRBAC: false

webhook:
# enabled determines whether the webhook is installed.
enabled: true
# caBundle is the PEM-encoded CA trust bundle for the webhook certificate. Only required if manageCerts is false and certManagerCert is null.
caBundle: Cg==
# certManagerCert is the name of the cert-manager certificate to use with the webhook.
certManagerCert: null
# certsDir is the directory to mount the certificates.
certsDir: "/tmp/k8s-webhook-server/serving-certs"
# failurePolicy of the webhook.
failurePolicy: Ignore
# manageCerts determines whether the operator manages the webhook certificates automatically.
manageCerts: true
# namespaceSelector corresponds to the namespaceSelector property of the webhook.
# Setting this restricts the webhook to act only on objects submitted to namespaces that match the selector.
namespaceSelector: {}
# objectSelector corresponds to the objectSelector property of the webhook.
# Setting this restricts the webhook to act only on objects that match the selector.
objectSelector: {}
# port is the port that the validating webhook binds to.
port: 9443
# secret specifies the Kubernetes secret to be mounted into the path designated by the certsDir value to be used for webhook certificates.
certsSecret: ""

# hostNetwork allows a Pod to use the Node network namespace.
# This is required to allow for communication with the kube API when using some alternate CNIs in conjunction with webhook enabled.
# If hostNetwork is enabled, dnsPolicy defaults to ClusterFirstWithHostNet unless explicitly set.
# CAUTION: Proceed at your own risk. This setting has security concerns such as allowing malicious users to access workloads running on the host.
hostNetwork: false

# dnsPolicy defines the DNS policy for the operator pod.
# Check https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy for more details.
dnsPolicy: ""

# dnsConfig defines the DNS configuration for the operator pod.
# Check https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config for more details.
# dnsConfig:
# nameservers:
# - 169.254.20.10
# searches:
# - svc.cluster.local
# options:
# - name: ndots
# value: "2"
dnsConfig: {}

softMultiTenancy:
# enabled determines whether the operator is installed with soft multi-tenancy extensions.
# This requires network policies to be enabled on the Kubernetes cluster.
enabled: false

# kubeAPIServerIP is required when softMultiTenancy is enabled.
kubeAPIServerIP: null

telemetry:
# disabled determines whether the operator periodically updates ECK telemetry data for Kibana to consume.
disabled: false
# distributionChannel denotes which distribution channel was used to install the operator.
distributionChannel: "helm"

# config values for the operator.
config:
# logVerbosity defines the logging level. Valid values are as follows:
# -2: Errors only
# -1: Errors and warnings
# 0: Errors, warnings, and information
# number greater than 0: Errors, warnings, information, and debug details.
logVerbosity: "0"

# (Deprecated: use metrics.port: will be removed in v2.14.0) metricsPort defines the port to expose operator metrics. Set to 0 to disable metrics reporting.
metricsPort: 0

metrics:
# port defines the port to expose operator metrics. Set to 0 to disable metrics reporting.
port: "0"
# secureMode contains the options for enabling and configuring RBAC and TLS/HTTPs for the metrics endpoint.
secureMode:
# secureMode.enabled specifies whether to enable RBAC and TLS/HTTPs for the metrics endpoint.
# * This option makes most sense when using a ServiceMonitor to scrape the metrics and is therefore mutually exclusive with the podMonitor.enabled option.
# * This option also requires using cluster scoped resources (ClusterRole, ClusterRoleBinding) to
# grant access to the /metrics endpoint. (createClusterScopedResources: true is required)
#
enabled: false
tls:
# certificateSecret is the name of the tls secret containing the custom TLS certificate and key for the secure metrics endpoint.
#
# * This is an optional setting and is only required if you are using a custom TLS certificate. A self-signed certificate will be generated by default.
# * TLS secret key must be named tls.crt.
# * TLS key's secret key must be named tls.key.
# * It is assumed to be in the same namespace as the ServiceMonitor.
#
# example: kubectl create secret tls eck-metrics-tls-certificate -n elastic-system \
# --cert=/path/to/tls.crt --key=/path/to/tls.key
certificateSecret: ""

# containerRegistry to use for pulling Elasticsearch and other application container images.
containerRegistry: docker.elastic.co

# containerRepository to use for pulling Elasticsearch and other application container images.
# containerRepository: ""

# containerSuffix suffix to be appended to container images by default. Cannot be combined with -ubiOnly flag
# containerSuffix: ""

# maxConcurrentReconciles is the number of concurrent reconciliation operations to perform per controller.
maxConcurrentReconciles: "3"

# caValidity defines the validity period of the CA certificates generated by the operator.
caValidity: 8760h

# caRotateBefore defines when to rotate a CA certificate that is due to expire.
caRotateBefore: 24h

# caDir defines the directory containing a CA certificate (tls.crt) and its associated private key (tls.key) to be used for all managed resources.
# Setting this makes caRotateBefore and caValidity values ineffective.
caDir: ""

# certificatesValidity defines the validity period of certificates generated by the operator.
certificatesValidity: 8760h

# certificatesRotateBefore defines when to rotate a certificate that is due to expire.
certificatesRotateBefore: 24h

# disableConfigWatch specifies whether the operator watches the configuration file for changes.
disableConfigWatch: false

# exposedNodeLabels is an array of regular expressions of node labels which are allowed to be copied as annotations on Elasticsearch Pods.
exposedNodeLabels:
["topology.kubernetes.io/.*", "failure-domain.beta.kubernetes.io/.*"]

# ipFamily specifies the IP family to use. Possible values: IPv4, IPv6 and "" (auto-detect)
ipFamily: ""

# setDefaultSecurityContext determines whether a default security context is set on application containers created by the operator.
# *note* that the default option now is "auto-detect" to attempt to set this properly automatically when both running
# in an openshift cluster, and a standard kubernetes cluster. Valid values are as follows:
# "auto-detect" : auto detect
# "true" : set pod security context when creating resources.
# "false" : do not set pod security context when creating resources.
setDefaultSecurityContext: "auto-detect"

# kubeClientTimeout sets the request timeout for Kubernetes API calls made by the operator.
kubeClientTimeout: 60s

# elasticsearchClientTimeout sets the request timeout for Elasticsearch API calls made by the operator.
elasticsearchClientTimeout: 180s

# policies contains policies for the operator, currently only password generation policies are supported.
policies: {}
# passwords:
# length: 24

# validateStorageClass specifies whether storage classes volume expansion support should be verified.
# Can be disabled if cluster-wide storage class RBAC access is not available.
validateStorageClass: true

# enableLeaderElection specifies whether leader election should be enabled
enableLeaderElection: true

# Interval between observations of Elasticsearch health, non-positive values disable asynchronous observation.
elasticsearchObservationInterval: 10s

# ubiOnly specifies whether the operator will use only UBI container images to deploy Elastic Stack applications as well as for its own StatefulSet image. UBI images are only available from 7.10.0 onward.
# Cannot be combined with the containerSuffix value.
ubiOnly: false

# Prometheus PodMonitor configuration
# Reference: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#podmonitor
podMonitor:
# enabled determines whether a podMonitor should deployed to scrape the eck metrics.
# This requires the prometheus operator and the config.metrics.port not to be 0
enabled: false

# labels adds additional labels to the podMonitor
labels: {}

# annotations adds additional annotations to the podMonitor
annotations: {}

# namespace determines in which namespace the podMonitor will be deployed.
# If not set the podMonitor will be created in the namespace where the Helm release is installed into
# namespace: monitoring

# interval specifies the interval at which metrics should be scraped
interval: 5m

# scrapeTimeout specifies the timeout after which the scrape is ended
scrapeTimeout: 30s

# podTargetLabels transfers labels on the Kubernetes Pod onto the target.
podTargetLabels: []

# podMetricsEndpointConfig allows to add an extended configuration to the podMonitor
podMetricsEndpointConfig: {}
# honorTimestamps: true

# Prometheus ServiceMonitor configuration
# Only used when config.enableSecureMetrics is true
# Reference: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#servicemonitor
serviceMonitor:
# This option requires the following settings within Prometheus to function:
# 1. RBAC settings for the Prometheus instance to access the metrics endpoint.
#
# - nonResourceURLs:
# - /metrics
# verbs:
# - get
#
# 2. If using the Prometheus Operator and your Prometheus instance is not in the same namespace as the operator you will need
# the Prometheus Operator configured with the following Helm values:
#
# prometheus:
# prometheusSpec:
# serviceMonitorNamespaceSelector: {}
# serviceMonitorSelectorNilUsesHelmValues: false
#
# allows to disable the serviceMonitor, enabled by default for backwards compatibility
enabled: true
# namespace determines in which namespace the serviceMonitor will be deployed.
# If not set the serviceMonitor will be created in the namespace where the Helm release is installed into
# namespace: monitoring
# caSecret is the name of the secret containing the custom CA certificate used to generate the custom TLS certificate for the secure metrics endpoint.
#
# * This *must* be the name of the secret containing the CA certificate used to sign the custom TLS certificate for the metrics endpoint.
# * This secret *must* be in the same namespace as the Prometheus instance that will scrape the metrics.
# * If using the Prometheus operator this secret must be within the `spec.secrets` field of the `Prometheus` custom resource such that it is mounted into the Prometheus pod at `caMountDirectory`, which defaults to /etc/prometheus/secrets/{secret-name}.
# * This is an optional setting and is only required if you are using a custom TLS certificate.
# * Key must be named ca.crt.
#
# example: kubectl create secret generic eck-metrics-tls-ca -n monitoring \
# --from-file=ca.crt=/path/to/ca.pem
caSecret: ""
# caMountDirectory is the directory at which the CA certificate is mounted within the Prometheus pod.
#
# * You should only need to adjust this if you are *not* using the Prometheus operator.
caMountDirectory: "/etc/prometheus/secrets/"
# insecureSkipVerify specifies whether to skip verification of the TLS certificate for the secure metrics endpoint.
#
# * If this setting is set to false, then the following settings are required:
# - certificateSecret
# - caSecret
insecureSkipVerify: true

# Globals meant for internal use only
global:
# manifestGen specifies whether the chart is running under manifest generator.
# This is used for tasks specific to generating the all-in-one.yaml file.
manifestGen: false
# createOperatorNamespace defines whether the operator namespace manifest should be generated when in manifestGen mode.
# Usually we do want that to happen (e.g. all-in-one.yaml) but, sometimes we don't (e.g. E2E tests).
createOperatorNamespace: true
# kubeVersion is the effective Kubernetes version we target when generating the all-in-one.yaml.
kubeVersion: 1.21.0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# 1. Check the directory structure of elasticsearch-operator package
echo "=== Directory structure of elasticsearch-operator package ==="
find packages/system/elasticsearch-operator -type f -name "*.yaml" | head -20

echo ""
echo "=== Check if parent values.yaml exists ==="
cat packages/system/elasticsearch-operator/values.yaml 2>/dev/null || echo "No parent values.yaml found"

echo ""
echo "=== Check Chart.yaml in both locations ==="
echo "--- Parent Chart.yaml ---"
cat packages/system/elasticsearch-operator/Chart.yaml 2>/dev/null | head -20

echo ""
echo "--- Vendored Chart.yaml ---"
cat packages/system/elasticsearch-operator/charts/eck-operator/Chart.yaml 2>/dev/null | head -20

Repository: cozystack/cozystack

Length of output: 2682


🏁 Script executed:

#!/bin/bash

# 2. Check for vendoring documentation (Chart.lock, go.mod, etc.)
echo "=== Check for vendoring indicators ==="
ls -la packages/system/elasticsearch-operator/ | grep -E "(Chart\.lock|requirements|go\.mod|\.gitignore)" || echo "No explicit vendoring files found"

echo ""
echo "=== Check if this follows umbrella chart pattern ==="
echo "Looking at parent Chart.yaml dependencies:"
cat packages/system/elasticsearch-operator/Chart.yaml 2>/dev/null | grep -A 20 "dependencies:" || echo "No dependencies found"

echo ""
echo "=== Compare with other vendored charts ==="
echo "Looking at hetzner-robotlb package structure:"
ls -la packages/system/hetzner-robotlb/charts/ 2>/dev/null | head -10

Repository: cozystack/cozystack

Length of output: 509


🏁 Script executed:

#!/bin/bash

# 3. Check how values are being overridden
echo "=== Compare original ECK upstream with this version ==="
echo "First 30 lines of vendored eck-operator values.yaml:"
head -30 packages/system/elasticsearch-operator/charts/eck-operator/values.yaml

echo ""
echo "=== Check if nameOverride is commonly set in upstream ECK ==="
rg "nameOverride|fullnameOverride" packages/system/elasticsearch-operator/ --type yaml

Repository: cozystack/cozystack

Length of output: 2476


🏁 Script executed:

#!/bin/bash

# 4. Check other packages to see vendoring patterns
echo "=== Check how other system packages handle vendored charts ==="
for chart_dir in $(find packages/system -type d -name "charts" | head -3); do
  echo "=== $chart_dir ==="
  # Check if parent has values that override vendored chart
  parent_dir=$(dirname "$chart_dir")
  if [ -f "$parent_dir/values.yaml" ]; then
    echo "Parent values.yaml found, first 20 lines:"
    head -20 "$parent_dir/values.yaml"
  else
    echo "No parent values.yaml"
  fi
  echo ""
done

Repository: cozystack/cozystack

Length of output: 668


This vendored chart has direct modifications that should be applied through the parent values override mechanism.

The nameOverride and fullnameOverride values on lines 2 and 5 are directly edited in the vendored chart file. Per the coding guidelines and the pattern used in other system packages (e.g., capi-operator, cert-manager-crds), these should be overridden via the parent values.yaml file instead. Move these settings from the vendored chart to the parent packages/system/elasticsearch-operator/values.yaml using the eck-operator: key prefix:

eck-operator:
  managedNamespaces: []
  installCRDs: true
  createClusterScopedResources: true
  nameOverride: "elastic-operator"
  fullnameOverride: "elastic-operator"

Then revert the vendored chart values to their original upstream state or leave them empty as the comments suggest.

🤖 Prompt for AI Agents
In `@packages/system/elasticsearch-operator/charts/eck-operator/values.yaml`
around lines 1 - 377, The vendored chart was directly modified by setting
nameOverride and fullnameOverride; remove or revert those two entries in the
vendored values (leave them empty as upstream expects) and instead add the
overrides to the parent package values under the eck-operator key: add
eck-operator:nameOverride, eck-operator:fullnameOverride and include the shared
entries managedNamespaces, installCRDs, and createClusterScopedResources (i.e.,
set eck-operator.managedNamespaces, eck-operator.installCRDs,
eck-operator.createClusterScopedResources alongside the two name overrides) so
chart customizations are applied via the parent values override mechanism rather
than editing the vendored chart.

Comment on lines +28 to +33
- |
sysctl -w vm.max_map_count=262144
# Keep the value persistent by writing to sysctl.conf if writable
if [ -w /host-etc/sysctl.conf ]; then
grep -q "vm.max_map_count" /host-etc/sysctl.conf || echo "vm.max_map_count=262144" >> /host-etc/sysctl.conf
fi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Persistence logic won't update existing entries with different values.

If /host-etc/sysctl.conf already contains vm.max_map_count with a different value (e.g., from a previous configuration), the grep -q will match and skip the append, leaving the old value persisted while the runtime value is 262144.

🔧 Proposed fix to handle existing entries
              sysctl -w vm.max_map_count=262144
-              # Keep the value persistent by writing to sysctl.conf if writable
-              if [ -w /host-etc/sysctl.conf ]; then
-                grep -q "vm.max_map_count" /host-etc/sysctl.conf || echo "vm.max_map_count=262144" >> /host-etc/sysctl.conf
+              # Keep the value persistent by writing to sysctl.d if directory exists
+              if [ -d /host-etc/sysctl.d ]; then
+                echo "vm.max_map_count=262144" > /host-etc/sysctl.d/99-elasticsearch.conf
               fi

Using a dedicated drop-in file in sysctl.d/ avoids conflicts with existing entries and follows best practices for sysctl configuration management.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- |
sysctl -w vm.max_map_count=262144
# Keep the value persistent by writing to sysctl.conf if writable
if [ -w /host-etc/sysctl.conf ]; then
grep -q "vm.max_map_count" /host-etc/sysctl.conf || echo "vm.max_map_count=262144" >> /host-etc/sysctl.conf
fi
- |
sysctl -w vm.max_map_count=262144
# Keep the value persistent by writing to sysctl.d if directory exists
if [ -d /host-etc/sysctl.d ]; then
echo "vm.max_map_count=262144" > /host-etc/sysctl.d/99-elasticsearch.conf
fi
🤖 Prompt for AI Agents
In `@packages/system/elasticsearch-operator/templates/sysctl-daemonset.yaml`
around lines 28 - 33, The current persistence logic in the sysctl snippet (in
the sysctl-daemonset.yaml template) only appends to /host-etc/sysctl.conf when
vm.max_map_count is absent, which leaves existing differing entries unchanged;
change the template to create/ensure a dedicated drop-in file under
/host-etc/sysctl.d (e.g., /host-etc/sysctl.d/99-elasticsearch.conf) and
write/overwrite the single line "vm.max_map_count=262144" there (while still
running sysctl -w at runtime), ensuring the directory exists and the file is
written atomically so existing conflicting entries are replaced and
systemd/sysctl semantics are followed.

Matthieu and others added 3 commits January 28, 2026 18:05
This adds a managed Elasticsearch service following the existing MongoDB pattern:

- packages/system/elasticsearch-operator: ECK operator v3.2.0 with sysctl DaemonSet
- packages/system/elasticsearch-rd: ApplicationDefinition for Cozystack dashboard
- packages/apps/elasticsearch: Application chart with Kibana support

Features:
- Multi-version support (v9, v8, v7)
- Optional Kibana deployment
- Custom users with auto-generated passwords
- Topology spread policy (soft/hard) for pod distribution
- Automatic "replicated" storage class for single replica
- External access via LoadBalancer
- Comprehensive Helm unit tests (45 tests)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: Matthieu <[email protected]>
- Replace template with include in role-bindings.yaml for proper helper evaluation
- Remove unnecessary hostPID and hostNetwork from sysctl DaemonSet
- Update pause image to registry.k8s.io/pause:3.9
- Change Kibana default resourcesPreset from small to medium
- Remove required constraint for images object in schema
- Fix GitHub capitalization in README
- Remove unused $clusterDomain variables from templates
- Update Elasticsearch v7 version to 7.17.28
- Remove vendored profile-*.yaml files from eck-operator chart

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: Matthieu <[email protected]>
Run 'make generate' to synchronize generated files with source values.yaml.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: Matthieu <[email protected]>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In
`@packages/system/elasticsearch-operator/charts/eck-operator/templates/configmap.yaml`:
- Around line 1-88: This change edits a vendored Helm chart template (the
ConfigMap creating eck.yaml via the template include "eck-operator.fullname")
which must not be modified directly; revert this file and instead implement the
required changes by updating the vendored chart properly or applying a
values/overlay-based customization (e.g., set the relevant keys in values.yaml
such as config.metrics.secureMode, config.metrics.port,
config.policies.passwords.length, config.* entries referenced in eck.yaml, or
add a kustomize/Helm overlay/patch to adjust the template behavior), ensuring
the validation logic that references metrics-port and password-length (the fail
checks around metrics.secureMode and password length) is preserved in the
upstream chart update rather than edited inline here.

In
`@packages/system/elasticsearch-operator/charts/eck-operator/templates/operator-network-policy.yaml`:
- Around line 1-59: This custom Helm template operator-network-policy.yaml (it
uses .Values.softMultiTenancy.enabled, .Values.kubeAPIServerIP, includes like
"eck-operator.fullname" and "eck-operator.metrics.port") must be removed from
the vendored eck-operator chart and relocated into the parent/umbrella chart's
templates directory so custom network policies are managed at the top level;
move the file accordingly, update any Chart.yaml/values wiring if necessary, and
regenerate dependencies/templates by running the project's update task (make
update).

In
`@packages/system/elasticsearch-operator/charts/eck-operator/templates/role-bindings.yaml`:
- Around line 1-98: The template under charts/eck-operator was edited directly;
revert changes to the vendored template and instead implement the desired
behavior by updating the vendored chart upstream or via an overlay/values-driven
customization (e.g., set .Values.createClusterScopedResources,
.Values.managedNamespaces, or .Values.config.metrics.secureMode.enabled) or by
supplying a kustomize/Helm patch; do not modify the template file
directly—restore the original role-bindings.yaml and apply configuration changes
through the chart vendoring/update process or an external overlay so that
references like $fullName, $svcAccount, $enableSecureMetrics,
.Values.createClusterScopedResources and .Values.managedNamespaces remain
untouched in the vendored template.

In
`@packages/system/elasticsearch-operator/charts/eck-operator/templates/webhook.yaml`:
- Around line 1-473: This change directly modifies the vendored Helm chart
template (charts/eck-operator/templates/webhook.yaml) which is prohibited;
revert any edits to webhook.yaml and instead apply the intended modifications by
updating the vendored chart upstream or by layering an overlay/patch (e.g.,
update the vendored chart version, run the chart vendoring process, or add a
Kustomize/Helm post-render or values-driven patch) so the webhook resources
(ValidatingWebhookConfiguration, Service, Secret and templates using include
"eck-operator.webhookName" and include "eck-operator.webhookServiceName") are
changed via the proper vendoring mechanism rather than direct edits.
🧹 Nitpick comments (6)
packages/system/elasticsearch-operator/templates/sysctl-daemonset.yaml (2)

20-37: Add resource requests/limits to the initContainer.

The sysctl initContainer lacks resource constraints. While it runs briefly, defining requests/limits ensures consistent scheduling and prevents resource contention.

🔧 Proposed fix
         - name: sysctl
           image: busybox:1.36
           securityContext:
             privileged: true
+          resources:
+            requests:
+              cpu: 1m
+              memory: 1Mi
+            limits:
+              cpu: 10m
+              memory: 10Mi
           command:

38-47: Harden the pause container's securityContext.

While the initContainer requires privileged access for sysctl, the pause container does not. Adding explicit security constraints reduces the attack surface.

🔧 Proposed fix
       containers:
         - name: pause
           image: registry.k8s.io/pause:3.9
+          securityContext:
+            allowPrivilegeEscalation: false
+            readOnlyRootFilesystem: true
+            runAsNonRoot: true
+            runAsUser: 65534
           resources:
             requests:
packages/system/elasticsearch-operator/Makefile (1)

6-10: Consider adding a version pin for consistency with upstream, but follow the repository pattern.

While the vendored chart already specifies version 3.2.0, the helm pull command lacks a --version flag, which will fetch the latest chart rather than the pinned version. However, note that this repository's established pattern is to omit version constraints—only 2 of 40+ similar packages (cilium and kafka-operator) pin versions. Version pinning would improve reproducibility, but since it's not standard practice here, this is an optional improvement rather than a requirement.

packages/system/elasticsearch-operator/charts/eck-operator/templates/service-monitor.yaml (1)

6-6: Consider simplifying the namespace ternary logic.

The current expression is hard to parse:

ternary .Values.serviceMonitor.namespace .Release.Namespace (not (and (.Values.serviceMonitor) (empty .Values.serviceMonitor.namespace)))

This could be simplified for readability:

♻️ Suggested simplification
-  namespace: {{ ternary .Values.serviceMonitor.namespace .Release.Namespace (not (and (.Values.serviceMonitor) (empty .Values.serviceMonitor.namespace))) }}
+  namespace: {{ .Values.serviceMonitor.namespace | default .Release.Namespace }}

The default function achieves the same result more readably—use the configured namespace or fall back to the release namespace.

packages/apps/elasticsearch/templates/elasticsearch.yaml (2)

24-36: Consider handling the case where all node roles are disabled.

If all nodeRoles boolean values (master, data, ingest, ml) are false, the node.roles list will be empty. While Elasticsearch may handle this gracefully, it could lead to unexpected behavior where nodes don't participate in the cluster properly.

Option: Add validation or default roles

Consider adding a validation check in your values schema or defaulting to essential roles:

       config:
         node.roles:
+          {{- if and (not .Values.nodeRoles.master) (not .Values.nodeRoles.data) (not .Values.nodeRoles.ingest) (not .Values.nodeRoles.ml) }}
+          - master
+          - data
+          {{- else }}
           {{- if .Values.nodeRoles.master }}
           - master
           {{- end }}
           ...
+          {{- end }}

Alternatively, enforce at least one role via values.schema.json.


70-73: Consider simplifying the TLS configuration.

Using disabled: false is a double negative. While functionally correct, enabled: true (if supported by the ECK API) would be clearer.

Comment on lines +1 to +88
---
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "eck-operator.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "eck-operator.labels" . | nindent 4 }}
data:
eck.yaml: |-
{{- $metricsPort := int (include "eck-operator.metrics.port" .)}}
log-verbosity: {{ int .Values.config.logVerbosity }}
{{- if and .Values.config.metrics.secureMode.enabled (eq $metricsPort 0) }}
{{- fail "config.metrics.port must be greater than 0 when config.metrics.secureMode.enabled is true" }}
{{- end }}
metrics-port: {{ $metricsPort }}
metrics-secure: {{ .Values.config.metrics.secureMode.enabled }}
container-registry: {{ .Values.config.containerRegistry }}
{{- with .Values.config.containerSuffix }}
container-suffix: {{ . }}
{{- end }}
{{- with .Values.config.containerRepository }}
container-repository: {{ . }}
{{- end }}
max-concurrent-reconciles: {{ int .Values.config.maxConcurrentReconciles }}
{{- with .Values.config.passwordHashCacheSize }}
password-hash-cache-size: {{ int . }}
{{- end }}
ca-cert-validity: {{ .Values.config.caValidity }}
ca-cert-rotate-before: {{ .Values.config.caRotateBefore }}
{{- with .Values.config.caDir }}
ca-dir: {{ . }}
{{- end }}
cert-validity: {{ .Values.config.certificatesValidity }}
cert-rotate-before: {{ .Values.config.certificatesRotateBefore }}
disable-config-watch: {{ .Values.config.disableConfigWatch }}
{{- with .Values.config.exposedNodeLabels }}
exposed-node-labels: [{{ join "," . }}]
{{- end }}
{{- with .Values.config.ipFamily }}
ip-family: {{ . }}
{{- end }}
set-default-security-context: {{ .Values.config.setDefaultSecurityContext }}
kube-client-timeout: {{ .Values.config.kubeClientTimeout }}
{{- with .Values.config.kubeClientQPS }}
kube-client-qps: {{ int . }}
{{- end }}
elasticsearch-client-timeout: {{ .Values.config.elasticsearchClientTimeout }}
disable-telemetry: {{ .Values.telemetry.disabled }}
distribution-channel: {{ .Values.telemetry.distributionChannel }}
{{- with .Values.telemetry.interval }}
telemetry-interval: {{ . }}
{{- end }}
validate-storage-class: {{ .Values.config.validateStorageClass }}
{{- if .Values.tracing.enabled }}
enable-tracing: true
{{- end }}
{{- if .Values.refs.enforceRBAC }}
enforce-rbac-on-refs: true
{{- end }}
enable-webhook: {{ .Values.webhook.enabled }}
{{- if .Values.webhook.enabled }}
webhook-name: {{ include "eck-operator.webhookName" . }}
{{- if not .Values.webhook.manageCerts }}
manage-webhook-certs: false
webhook-cert-dir: {{ .Values.webhook.certsDir }}
{{- end }}
webhook-port: {{ .Values.webhook.port }}
{{- end }}
{{- with .Values.managedNamespaces }}
namespaces: [{{ join "," . }}]
{{- end }}
operator-namespace: {{ .Release.Namespace }}
enable-leader-election: {{ .Values.config.enableLeaderElection }}
elasticsearch-observation-interval: {{ .Values.config.elasticsearchObservationInterval }}
{{- if not .Values.config.containerSuffix }}
ubi-only: {{ .Values.config.ubiOnly }}
{{- end }}
{{- with .Values.webhook.certsSecret }}
webhook-secret: {{ . }}
{{- end }}
{{- $passwordLength := int (dig "policies" "passwords" "length" 0 .Values.config) }}
{{- with $passwordLength }}
{{- if or (lt $passwordLength 6) (gt $passwordLength 72) }}
{{- fail "config.policies.passwords.length must be >= 6 and <= 72" }}
{{- end }}
password-length: {{ $passwordLength }}
{{- end }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid direct edits in vendored chart templates.

This template lives under charts/eck-operator/, which is treated as a vendored upstream chart. Please apply changes via a vendored chart update or an overlay/values-driven customization instead of editing the template directly.
As per coding guidelines, Do NOT directly edit upstream Helm charts in vendored charts directory; use proper chart vendoring mechanisms.

🧰 Tools
🪛 YAMLlint (1.38.0)

[error] 8-8: syntax error: expected the node content, but found '-'

(syntax)

🤖 Prompt for AI Agents
In
`@packages/system/elasticsearch-operator/charts/eck-operator/templates/configmap.yaml`
around lines 1 - 88, This change edits a vendored Helm chart template (the
ConfigMap creating eck.yaml via the template include "eck-operator.fullname")
which must not be modified directly; revert this file and instead implement the
required changes by updating the vendored chart properly or applying a
values/overlay-based customization (e.g., set the relevant keys in values.yaml
such as config.metrics.secureMode, config.metrics.port,
config.policies.passwords.length, config.* entries referenced in eck.yaml, or
add a kustomize/Helm overlay/patch to adjust the template behavior), ensuring
the validation logic that references metrics-port and password-length (the fail
checks around metrics.secureMode and password length) is preserved in the
upstream chart update rather than edited inline here.

Comment on lines +1 to +59
{{- if .Values.softMultiTenancy.enabled -}}
{{- $kubeAPIServerIP := (required "kubeAPIServerIP is required" .Values.kubeAPIServerIP) -}}
{{- $metricsPort := int (include "eck-operator.metrics.port" .)}}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: {{ include "eck-operator.fullname" . }}
namespace: {{ .Release.Namespace}}
labels:
{{- include "eck-operator.labels" . | nindent 4 }}
spec:
podSelector:
matchLabels:
{{- include "eck-operator.selectorLabels" . | nindent 6 }}
egress:
# DNS
- ports:
- port: 53
protocol: UDP
to: []
# API server
- ports:
- port: 443
to:
- ipBlock:
cidr: "{{ $kubeAPIServerIP }}/32"
# Elasticsearch
- ports:
- port: 9200
to:
- namespaceSelector:
matchExpressions:
- key: "eck.k8s.elastic.co/tenant"
operator: In
values:
{{- range .Values.managedNamespaces }}
- {{ . }}
{{- end }}
podSelector:
matchLabels:
common.k8s.elastic.co/type: "elasticsearch"
{{- if or .Values.webhook.enabled (gt $metricsPort 0) }}
ingress:
{{- if .Values.webhook.enabled }}
- ports:
- port: {{ .Values.webhook.port }}
from:
- ipBlock:
cidr: "{{ $kubeAPIServerIP }}/32"
{{- end }}
{{- if gt $metricsPort 0 }}
# Metrics
- ports:
- port: {{ $metricsPort }}
from: []
{{- end }}
{{- end }}
{{- end -}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Check if the file exists
find . -path "*/elasticsearch-operator/charts/eck-operator/templates/operator-network-policy.yaml" -type f

# List the elasticsearch-operator directory structure
ls -la packages/system/elasticsearch-operator/ 2>/dev/null || echo "Directory not found"

# Check if there's a Chart.yaml or vendor-related config
find packages/system/elasticsearch-operator -name "Chart.yaml" -o -name "Chart.lock" -o -name "go.sum" 2>/dev/null | head -20

Repository: cozystack/cozystack

Length of output: 930


🏁 Script executed:

# Check for helm dependency or chart vendoring patterns
if [ -f "packages/system/elasticsearch-operator/Chart.yaml" ]; then
  echo "=== Chart.yaml content ==="
  cat packages/system/elasticsearch-operator/Chart.yaml | head -50
fi

# Look for charts directory structure
find packages/system/elasticsearch-operator/charts -type f -name "Chart.yaml" 2>/dev/null | head -10

Repository: cozystack/cozystack

Length of output: 403


🏁 Script executed:

# Check if git tracks this as a submodule or vendored dependency
cd packages/system/elasticsearch-operator
git status 2>/dev/null | head -20
cd - > /dev/null

# Check .gitmodules
git config --file=.gitmodules --name-only --get-regexp path 2>/dev/null | grep eck-operator || echo "No git submodule found"

Repository: cozystack/cozystack

Length of output: 339


🏁 Script executed:

# Examine the Chart.lock to understand vendoring mechanism
cat packages/system/elasticsearch-operator/charts/eck-operator/Chart.lock 2>/dev/null | head -30

# Check the parent Chart.yaml dependencies
cat packages/system/elasticsearch-operator/Chart.yaml 2>/dev/null

Repository: cozystack/cozystack

Length of output: 408


🏁 Script executed:

# Check if this chart was vendored via Helm dependencies
cat packages/system/elasticsearch-operator/charts/eck-operator/Chart.yaml 2>/dev/null | head -20

Repository: cozystack/cozystack

Length of output: 480


🏁 Script executed:

# Look for any helm dependency or vendoring documentation
find packages/system/elasticsearch-operator -name "*.md" -o -name "Makefile" | xargs grep -l "helm.*dependency\|vendor\|fetch" 2>/dev/null || echo "No vendoring docs found"

# Check the Makefile for how charts are managed
cat packages/system/elasticsearch-operator/Makefile 2>/dev/null

Repository: cozystack/cozystack

Length of output: 340


🏁 Script executed:

# Verify the actual upstream ECK operator chart has this file at v3.2.0
curl -sL "https://raw.githubusercontent.com/elastic/cloud-on-k8s/3.2.0/deploy/eck-operator/templates/operator-network-policy.yaml" 2>/dev/null | head -20 || echo "Checking alternative path..."

# Also check if the file exists in the vendored location with correct ownership
ls -l packages/system/elasticsearch-operator/charts/eck-operator/templates/operator-network-policy.yaml

Repository: cozystack/cozystack

Length of output: 223


🏁 Script executed:

# Check if this file exists elsewhere in the upstream ECK operator at v3.2.0
curl -sL "https://raw.githubusercontent.com/elastic/cloud-on-k8s/3.2.0/deploy/eck-operator/templates/" 2>/dev/null | grep -i "network\|policy" || echo "No network policy in standard templates"

# List all templates in the upstream at 3.2.0
curl -sL "https://api.github.com/repos/elastic/cloud-on-k8s/contents/deploy/eck-operator/templates?ref=3.2.0" 2>/dev/null | grep '"name"' | head -20

Repository: cozystack/cozystack

Length of output: 102


🏁 Script executed:

# Check if this is a locally added file in the cozystack repo (new file not from upstream)
git log --oneline -- packages/system/elasticsearch-operator/charts/eck-operator/templates/operator-network-policy.yaml 2>/dev/null | head -5

# Check the commit that added this file
git log --all --source --full-history -- packages/system/elasticsearch-operator/charts/eck-operator/templates/operator-network-policy.yaml 2>/dev/null | head -20

Repository: cozystack/cozystack

Length of output: 523


🏁 Script executed:

# Confirm this file is not from upstream - check other recent vendored files structure
ls packages/system/elasticsearch-operator/charts/eck-operator/templates/ | head -20

# Verify no other custom files were added to vendored templates
git status packages/system/elasticsearch-operator/charts/eck-operator/templates/ 2>/dev/null || echo "Checking git history..."

# Check if the parent chart templates directory has custom content
ls -la packages/system/elasticsearch-operator/templates/ 2>/dev/null

Repository: cozystack/cozystack

Length of output: 632


🏁 Script executed:

# Verify the intended approach - check if this should be in parent chart or overlay
cat packages/system/elasticsearch-operator/values.yaml 2>/dev/null

# Look for any overlay or patch mechanisms in the elasticsearch-operator
find packages/system/elasticsearch-operator -name "*patch*" -o -name "*overlay*" -o -name "kustomization.yaml" 2>/dev/null

Repository: cozystack/cozystack

Length of output: 157


Move this custom NetworkPolicy template to the parent chart templates directory.

This file does not exist in the upstream ECK operator (v3.2.0) and should not be added to the vendored charts/eck-operator/templates/ directory. Custom templates must be managed in packages/system/elasticsearch-operator/templates/ instead, following the umbrella chart pattern. The vendored chart should only contain upstream files pulled via Helm dependency mechanisms.

Move operator-network-policy.yaml to packages/system/elasticsearch-operator/templates/ and regenerate via make update.

🧰 Tools
🪛 YAMLlint (1.38.0)

[error] 1-1: syntax error: expected the node content, but found '-'

(syntax)

🤖 Prompt for AI Agents
In
`@packages/system/elasticsearch-operator/charts/eck-operator/templates/operator-network-policy.yaml`
around lines 1 - 59, This custom Helm template operator-network-policy.yaml (it
uses .Values.softMultiTenancy.enabled, .Values.kubeAPIServerIP, includes like
"eck-operator.fullname" and "eck-operator.metrics.port") must be removed from
the vendored eck-operator chart and relocated into the parent/umbrella chart's
templates directory so custom network policies are managed at the top level;
move the file accordingly, update any Chart.yaml/values wiring if necessary, and
regenerate dependencies/templates by running the project's update task (make
update).

Comment on lines +1 to +98
{{- $operatorNSIsManaged := has .Release.Namespace .Values.managedNamespaces -}}
{{- $fullName := include "eck-operator.fullname" . -}}
{{- $svcAccount := include "eck-operator.serviceAccountName" . }}
{{- $enableSecureMetrics := .Values.config.metrics.secureMode.enabled -}}

{{- if not .Values.createClusterScopedResources }}
{{- range .Values.managedNamespaces }}
{{- $namespace := . }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: "{{ $fullName }}"
namespace: {{ $namespace }}
labels:
{{- include "eck-operator.labels" $ | nindent 4 }}
rules:
{{- include "eck-operator.rbacRules" $ | toYaml | nindent 2 }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: "{{ $fullName }}"
namespace: {{ $namespace }}
labels:
{{- include "eck-operator.labels" $ | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: "{{ $fullName }}"
subjects:
- kind: ServiceAccount
name: {{ $svcAccount }}
namespace: {{ $.Release.Namespace }}
{{- end }} {{- /* end of range over managed namespaces */}}
{{- /* If createClusterScopedResources is false and operator namespace is not in the managed namespaces list, create additional role binding */}}
{{- if not $operatorNSIsManaged }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ $fullName }}
namespace: {{ $.Release.Namespace }}
labels:
{{- include "eck-operator.labels" $ | nindent 4 }}
rules:
{{- include "eck-operator.rbacRules" $ | toYaml | nindent 2 }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: "{{ $fullName }}"
namespace: {{ $.Release.Namespace }}
labels:
{{- include "eck-operator.labels" $ | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: "{{ $fullName }}"
subjects:
- kind: ServiceAccount
name: {{ $svcAccount }}
namespace: {{ $.Release.Namespace }}
{{- end }} {{- /* end of operator role binding if operator namespace is not managed */}}
{{- else }} {{- /* we can create cluster-scoped resources so just create a cluster role binding */}}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ $fullName }}
labels:
{{- include "eck-operator.labels" $ | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ $fullName }}
subjects:
- kind: ServiceAccount
name: {{ $svcAccount }}
namespace: {{ $.Release.Namespace }}
{{- if $enableSecureMetrics }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
{{- include "eck-operator.labels" $ | nindent 4 }}
name: "{{ include "eck-operator.fullname" . }}-metrics-auth-rolebinding"
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: "{{ include "eck-operator.fullname" . }}-metrics-auth-role"
subjects:
- kind: ServiceAccount
name: {{ $svcAccount }}
namespace: {{ $.Release.Namespace }}
{{- end }}
{{- end }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid direct edits in vendored chart templates.

This file is under charts/eck-operator/ (vendored upstream). Please apply changes via a vendored chart update or an overlay/values-driven customization instead of editing the template directly.
As per coding guidelines, Do NOT directly edit upstream Helm charts in vendored charts directory; use proper chart vendoring mechanisms.

🧰 Tools
🪛 YAMLlint (1.38.0)

[error] 1-1: syntax error: expected the node content, but found '-'

(syntax)

🤖 Prompt for AI Agents
In
`@packages/system/elasticsearch-operator/charts/eck-operator/templates/role-bindings.yaml`
around lines 1 - 98, The template under charts/eck-operator was edited directly;
revert changes to the vendored template and instead implement the desired
behavior by updating the vendored chart upstream or via an overlay/values-driven
customization (e.g., set .Values.createClusterScopedResources,
.Values.managedNamespaces, or .Values.config.metrics.secureMode.enabled) or by
supplying a kustomize/Helm patch; do not modify the template file
directly—restore the original role-bindings.yaml and apply configuration changes
through the chart vendoring/update process or an external overlay so that
references like $fullName, $svcAccount, $enableSecureMetrics,
.Values.createClusterScopedResources and .Values.managedNamespaces remain
untouched in the vendored template.

Comment on lines +1 to +473
{{- if .Values.webhook.enabled -}}
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: {{ include "eck-operator.webhookName" . }}
labels:
{{- include "eck-operator.labels" . | nindent 4 }}
{{- with .Values.webhook.certManagerCert }}
annotations:
cert-manager.io/inject-ca-from: "{{ $.Release.Namespace }}/{{ . }}"
{{- end }}
webhooks:
- clientConfig:
{{- if and (not .Values.webhook.manageCerts) (not .Values.webhook.certManagerCert) }}
caBundle: {{ .Values.webhook.caBundle }}
{{- end }}
service:
name: {{ include "eck-operator.webhookServiceName" . }}
namespace: {{ .Release.Namespace }}
path: /validate-agent-k8s-elastic-co-v1alpha1-agent
failurePolicy: {{ .Values.webhook.failurePolicy }}
{{- with .Values.webhook.namespaceSelector }}
namespaceSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.webhook.objectSelector }}
objectSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
name: elastic-agent-validation-v1alpha1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1]
sideEffects: None
rules:
- apiGroups:
- agent.k8s.elastic.co
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- agents
- clientConfig:
{{- if and (not .Values.webhook.manageCerts) (not .Values.webhook.certManagerCert) }}
caBundle: {{ .Values.webhook.caBundle }}
{{- end }}
service:
name: {{ include "eck-operator.webhookServiceName" . }}
namespace: {{ .Release.Namespace }}
path: /validate-apm-k8s-elastic-co-v1-apmserver
failurePolicy: {{ .Values.webhook.failurePolicy }}
{{- with .Values.webhook.namespaceSelector }}
namespaceSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.webhook.objectSelector }}
objectSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
name: elastic-apm-validation-v1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1]
sideEffects: None
rules:
- apiGroups:
- apm.k8s.elastic.co
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- apmservers
- clientConfig:
{{- if and (not .Values.webhook.manageCerts) (not .Values.webhook.certManagerCert) }}
caBundle: {{ .Values.webhook.caBundle }}
{{- end }}
service:
name: {{ include "eck-operator.webhookServiceName" . }}
namespace: {{ .Release.Namespace }}
path: /validate-apm-k8s-elastic-co-v1beta1-apmserver
failurePolicy: {{ .Values.webhook.failurePolicy }}
{{- with .Values.webhook.namespaceSelector }}
namespaceSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.webhook.objectSelector }}
objectSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
name: elastic-apm-validation-v1beta1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1]
sideEffects: None
rules:
- apiGroups:
- apm.k8s.elastic.co
apiVersions:
- v1beta1
operations:
- CREATE
- UPDATE
resources:
- apmservers
- clientConfig:
{{- if and (not .Values.webhook.manageCerts) (not .Values.webhook.certManagerCert) }}
caBundle: {{ .Values.webhook.caBundle }}
{{- end }}
service:
name: {{ include "eck-operator.webhookServiceName" . }}
namespace: {{ .Release.Namespace }}
path: /validate-beat-k8s-elastic-co-v1beta1-beat
failurePolicy: {{ .Values.webhook.failurePolicy }}
{{- with .Values.webhook.namespaceSelector }}
namespaceSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.webhook.objectSelector }}
objectSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
name: elastic-beat-validation-v1beta1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1]
sideEffects: None
rules:
- apiGroups:
- beat.k8s.elastic.co
apiVersions:
- v1beta1
operations:
- CREATE
- UPDATE
resources:
- beats
- clientConfig:
{{- if and (not .Values.webhook.manageCerts) (not .Values.webhook.certManagerCert) }}
caBundle: {{ .Values.webhook.caBundle }}
{{- end }}
service:
name: {{ include "eck-operator.webhookServiceName" . }}
namespace: {{ .Release.Namespace }}
path: /validate-enterprisesearch-k8s-elastic-co-v1-enterprisesearch
failurePolicy: {{ .Values.webhook.failurePolicy }}
{{- with .Values.webhook.namespaceSelector }}
namespaceSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.webhook.objectSelector }}
objectSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
name: elastic-ent-validation-v1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1]
sideEffects: None
rules:
- apiGroups:
- enterprisesearch.k8s.elastic.co
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- enterprisesearches
- clientConfig:
{{- if and (not .Values.webhook.manageCerts) (not .Values.webhook.certManagerCert) }}
caBundle: {{ .Values.webhook.caBundle }}
{{- end }}
service:
name: {{ include "eck-operator.webhookServiceName" . }}
namespace: {{ .Release.Namespace }}
path: /validate-enterprisesearch-k8s-elastic-co-v1beta1-enterprisesearch
failurePolicy: {{ .Values.webhook.failurePolicy }}
{{- with .Values.webhook.namespaceSelector }}
namespaceSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.webhook.objectSelector }}
objectSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
name: elastic-ent-validation-v1beta1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1]
sideEffects: None
rules:
- apiGroups:
- enterprisesearch.k8s.elastic.co
apiVersions:
- v1beta1
operations:
- CREATE
- UPDATE
resources:
- enterprisesearches
- clientConfig:
{{- if and (not .Values.webhook.manageCerts) (not .Values.webhook.certManagerCert) }}
caBundle: {{ .Values.webhook.caBundle }}
{{- end }}
service:
name: {{ include "eck-operator.webhookServiceName" . }}
namespace: {{ .Release.Namespace }}
path: /validate-elasticsearch-k8s-elastic-co-v1-elasticsearch
failurePolicy: {{ .Values.webhook.failurePolicy }}
{{- with .Values.webhook.namespaceSelector }}
namespaceSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.webhook.objectSelector }}
objectSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
name: elastic-es-validation-v1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1]
sideEffects: None
rules:
- apiGroups:
- elasticsearch.k8s.elastic.co
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- elasticsearches
- clientConfig:
{{- if and (not .Values.webhook.manageCerts) (not .Values.webhook.certManagerCert) }}
caBundle: {{ .Values.webhook.caBundle }}
{{- end }}
service:
name: {{ include "eck-operator.webhookServiceName" . }}
namespace: {{ .Release.Namespace }}
path: /validate-elasticsearch-k8s-elastic-co-v1beta1-elasticsearch
failurePolicy: {{ .Values.webhook.failurePolicy }}
{{- with .Values.webhook.namespaceSelector }}
namespaceSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.webhook.objectSelector }}
objectSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
name: elastic-es-validation-v1beta1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1]
sideEffects: None
rules:
- apiGroups:
- elasticsearch.k8s.elastic.co
apiVersions:
- v1beta1
operations:
- CREATE
- UPDATE
resources:
- elasticsearches
- clientConfig:
{{- if and (not .Values.webhook.manageCerts) (not .Values.webhook.certManagerCert) }}
caBundle: {{ .Values.webhook.caBundle }}
{{- end }}
service:
name: {{ include "eck-operator.webhookServiceName" . }}
namespace: {{ .Release.Namespace }}
path: /validate-ems-k8s-elastic-co-v1alpha1-mapsservers
failurePolicy: {{ .Values.webhook.failurePolicy }}
{{- with .Values.webhook.namespaceSelector }}
namespaceSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.webhook.objectSelector }}
objectSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
name: elastic-ems-validation-v1alpha1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1]
sideEffects: None
rules:
- apiGroups:
- maps.k8s.elastic.co
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- mapsservers
- clientConfig:
{{- if and (not .Values.webhook.manageCerts) (not .Values.webhook.certManagerCert) }}
caBundle: {{ .Values.webhook.caBundle }}
{{- end }}
service:
name: {{ include "eck-operator.webhookServiceName" . }}
namespace: {{ .Release.Namespace }}
path: /validate-kibana-k8s-elastic-co-v1-kibana
failurePolicy: {{ .Values.webhook.failurePolicy }}
{{- with .Values.webhook.namespaceSelector }}
namespaceSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.webhook.objectSelector }}
objectSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
name: elastic-kb-validation-v1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1]
sideEffects: None
rules:
- apiGroups:
- kibana.k8s.elastic.co
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- kibanas
- clientConfig:
{{- if and (not .Values.webhook.manageCerts) (not .Values.webhook.certManagerCert) }}
caBundle: {{ .Values.webhook.caBundle }}
{{- end }}
service:
name: {{ include "eck-operator.webhookServiceName" . }}
namespace: {{ .Release.Namespace }}
path: /validate-kibana-k8s-elastic-co-v1beta1-kibana
failurePolicy: {{ .Values.webhook.failurePolicy }}
{{- with .Values.webhook.namespaceSelector }}
namespaceSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.webhook.objectSelector }}
objectSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
name: elastic-kb-validation-v1beta1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1]
sideEffects: None
rules:
- apiGroups:
- kibana.k8s.elastic.co
apiVersions:
- v1beta1
operations:
- CREATE
- UPDATE
resources:
- kibanas
- clientConfig:
{{- if and (not .Values.webhook.manageCerts) (not .Values.webhook.certManagerCert) }}
caBundle: {{ .Values.webhook.caBundle }}
{{- end }}
service:
name: {{ include "eck-operator.webhookServiceName" . }}
namespace: {{ .Release.Namespace }}
path: /validate-autoscaling-k8s-elastic-co-v1alpha1-elasticsearchautoscaler
failurePolicy: {{ .Values.webhook.failurePolicy }}
{{- with .Values.webhook.namespaceSelector }}
namespaceSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.webhook.objectSelector }}
objectSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
name: elastic-esa-validation-v1alpha1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1]
sideEffects: None
rules:
- apiGroups:
- autoscaling.k8s.elastic.co
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- elasticsearchautoscalers
- clientConfig:
{{- if and (not .Values.webhook.manageCerts) (not .Values.webhook.certManagerCert) }}
caBundle: {{ .Values.webhook.caBundle }}
{{- end }}
service:
name: {{ include "eck-operator.webhookServiceName" . }}
namespace: {{ .Release.Namespace }}
path: /validate-scp-k8s-elastic-co-v1alpha1-stackconfigpolicies
failurePolicy: {{ .Values.webhook.failurePolicy }}
{{- with .Values.webhook.namespaceSelector }}
namespaceSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.webhook.objectSelector }}
objectSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
name: elastic-scp-validation-v1alpha1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1]
sideEffects: None
rules:
- apiGroups:
- stackconfigpolicy.k8s.elastic.co
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- stackconfigpolicies
- clientConfig:
{{- if and (not .Values.webhook.manageCerts) (not .Values.webhook.certManagerCert) }}
caBundle: {{ .Values.webhook.caBundle }}
{{- end }}
service:
name: {{ include "eck-operator.webhookServiceName" . }}
namespace: {{ .Release.Namespace }}
path: /validate-logstash-k8s-elastic-co-v1alpha1-logstash
failurePolicy: {{ .Values.webhook.failurePolicy }}
{{- with .Values.webhook.namespaceSelector }}
namespaceSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.webhook.objectSelector }}
objectSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
name: elastic-logstash-validation-v1alpha1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1]
sideEffects: None
rules:
- apiGroups:
- logstash.k8s.elastic.co
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- logstashes
---
apiVersion: v1
kind: Service
metadata:
name: {{ include "eck-operator.webhookServiceName" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "eck-operator.labels" . | nindent 4 }}
spec:
ports:
- name: https
port: 443
targetPort: {{ .Values.webhook.port }}
selector:
{{- include "eck-operator.selectorLabels" . | nindent 4 }}
{{- if .Values.webhook.manageCerts }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ include "eck-operator.webhookSecretName" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "eck-operator.labels" . | nindent 4 }}
{{- end }}
{{- end -}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid direct edits in vendored chart templates.

This file resides under charts/eck-operator/, which is treated as a vendored upstream chart. Please implement changes via a vendored chart update or overlays rather than editing the template directly.
As per coding guidelines, Do NOT directly edit upstream Helm charts in vendored charts directory; use proper chart vendoring mechanisms.

🧰 Tools
🪛 YAMLlint (1.38.0)

[error] 1-1: syntax error: expected the node content, but found '-'

(syntax)

🤖 Prompt for AI Agents
In
`@packages/system/elasticsearch-operator/charts/eck-operator/templates/webhook.yaml`
around lines 1 - 473, This change directly modifies the vendored Helm chart
template (charts/eck-operator/templates/webhook.yaml) which is prohibited;
revert any edits to webhook.yaml and instead apply the intended modifications by
updating the vendored chart upstream or by layering an overlay/patch (e.g.,
update the vendored chart version, run the chart vendoring process, or add a
Kustomize/Helm post-render or values-driven patch) so the webhook resources
(ValidatingWebhookConfiguration, Service, Secret and templates using include
"eck-operator.webhookName" and include "eck-operator.webhookServiceName") are
changed via the proper vendoring mechanism rather than direct edits.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In `@packages/apps/elasticsearch/README.md`:
- Line 122: Update the README sentence to include the missing article: change
"Kibana requires minimum `medium` preset (1Gi RAM)." to "Kibana requires a
minimum `medium` preset (1Gi RAM)." Alternatively you can rephrase to "The
minimum recommended preset for Kibana is `medium` (1Gi RAM)." Modify the line in
the README.md where that sentence appears.
- Line 125: The table header row "|--------|-----|--------|" has inconsistent
spacing around pipe characters; update the Markdown table to use
compact-table-spacing consistently by adding single spaces around each cell
separator (e.g., change to a form like "| -------- | ----- | -------- |") and
ensure all subsequent table rows use the same spacing style so markdownlint no
longer flags the spacing inconsistency.
- Line 170: Update the default Elasticsearch image in values.yaml to match the
v9 default referenced in the README and tests: replace the current
images.elasticsearch value (which points to
docker.elastic.co/elasticsearch/elasticsearch:8.17.0) with the v9 image tag
(e.g. docker.elastic.co/elasticsearch/elasticsearch:9.0.0) so
images.elasticsearch in values.yaml and the README are consistent with the v9
default.

In `@packages/system/elasticsearch-operator/templates/sysctl-daemonset.yaml`:
- Around line 32-36: The initContainer's shell command runs "sysctl -w
vm.max_map_count=262144" but does not fail the container when that command
fails; update the command block for the initContainer (the shell/command
sequence that contains the sysctl invocation) to fail fast on error by enabling
shell strict mode or explicitly checking the exit status—for example, prepend
"set -euo pipefail" (or "set -e") at the top of the here-doc or change the line
to "sysctl -w vm.max_map_count=262144 || { echo 'sysctl failed' >&2; exit 1; }"
so the initContainer exits non‑zero and Kubernetes will retry the pod.
- Around line 21-22: Replace hardcoded image tags with digest-pinned,
configurable values: update the container image entries (the "name: sysctl"
container image currently set to "busybox:1.36" and the other pause image at
lines noted) to use digest pins (e.g., busybox@sha256... and
registry.k8s.io/pause@sha256...) and expose them as Helm values in values.yaml
(e.g., sysctl.image and sysctl.pauseImage) so templates reference {{
.Values.sysctl.image }} and {{ .Values.sysctl.pauseImage }}; ensure default
values in values.yaml use the pinned digests (or upgraded versions) and keep the
template fallbacks if values are omitted.
🧹 Nitpick comments (2)
packages/apps/elasticsearch/tests/kibana_test.yaml (2)

175-187: Consider adding a test for TLS disabled scenario.

The current test validates that TLS with self-signed certificates is enabled by default (via disabled: false). For completeness, consider adding a test case that verifies behavior when TLS is explicitly disabled, if that's a supported configuration.


6-187: Consider adding tests for Kibana resource presets.

The PR objectives mention "Kibana deployment with resource presets" as a feature. If the Kibana CR template supports resource preset configuration (similar to Elasticsearch), consider adding test cases to validate that resource limits/requests are correctly applied to Kibana pods.

### Resource Requirements

Elasticsearch requires significant memory. The minimum recommended preset is `large` (2Gi RAM per node).
Kibana requires minimum `medium` preset (1Gi RAM).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix grammar: add article before "minimum".

The sentence is missing an article and reads awkwardly. It should be "Kibana requires a minimum medium preset" or "The minimum recommended preset for Kibana is medium".

📝 Proposed fix
-Kibana requires minimum `medium` preset (1Gi RAM).
+Kibana requires a minimum `medium` preset (1Gi RAM).
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Kibana requires minimum `medium` preset (1Gi RAM).
Kibana requires a minimum `medium` preset (1Gi RAM).
🧰 Tools
🪛 LanguageTool

[grammar] ~122-~122: Ensure spelling is correct
Context: ...ibana requires minimum medium preset (1Gi RAM). | Preset | CPU | Memory | |-----...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🤖 Prompt for AI Agents
In `@packages/apps/elasticsearch/README.md` at line 122, Update the README
sentence to include the missing article: change "Kibana requires minimum
`medium` preset (1Gi RAM)." to "Kibana requires a minimum `medium` preset (1Gi
RAM)." Alternatively you can rephrase to "The minimum recommended preset for
Kibana is `medium` (1Gi RAM)." Modify the line in the README.md where that
sentence appears.

Kibana requires minimum `medium` preset (1Gi RAM).

| Preset | CPU | Memory |
|--------|-----|--------|

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix table formatting spacing.

The table header is missing consistent spacing around pipe characters according to markdownlint rules for compact table style.

📋 Proposed fix
-| Preset | CPU | Memory |
+| Preset  | CPU | Memory |

Alternatively, ensure all pipes have consistent spacing on both sides throughout the table.

🧰 Tools
🪛 markdownlint-cli2 (0.20.0)

125-125: Table column style
Table pipe is missing space to the right for style "compact"

(MD060, table-column-style)


125-125: Table column style
Table pipe is missing space to the left for style "compact"

(MD060, table-column-style)


125-125: Table column style
Table pipe is missing space to the right for style "compact"

(MD060, table-column-style)


125-125: Table column style
Table pipe is missing space to the left for style "compact"

(MD060, table-column-style)


125-125: Table column style
Table pipe is missing space to the right for style "compact"

(MD060, table-column-style)


125-125: Table column style
Table pipe is missing space to the left for style "compact"

(MD060, table-column-style)

🤖 Prompt for AI Agents
In `@packages/apps/elasticsearch/README.md` at line 125, The table header row
"|--------|-----|--------|" has inconsistent spacing around pipe characters;
update the Markdown table to use compact-table-spacing consistently by adding
single spaces around each cell separator (e.g., change to a form like "|
-------- | ----- | -------- |") and ensure all subsequent table rows use the
same spacing style so markdownlint no longer flags the spacing inconsistency.

| Name | Description | Type | Value |
| ---------------------- | -------------------------------------- | -------- | ------------------------------------------------------ |
| `images` | Container images used by the operator. | `object` | `{}` |
| `images.elasticsearch` | Elasticsearch image. | `string` | `docker.elastic.co/elasticsearch/elasticsearch:8.17.0` |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify default Elasticsearch image version in values.yaml

# Check default images in values
rg -n 'elasticsearch.*image|docker.elastic.co/elasticsearch' packages/apps/elasticsearch/values.yaml -B2 -A2

# Check for version mapping logic
rg -n 'version.*v[789]|v[789].*image' packages/apps/elasticsearch/ -B2 -A2

Repository: cozystack/cozystack

Length of output: 6158


Fix image version mismatch in values.yaml and README.

The default image version docker.elastic.co/elasticsearch/elasticsearch:8.17.0 (v8) conflicts with the default version setting v9. According to the test cases, v9 should use image tag 9.0.0, not 8.17.0. Update images.elasticsearch in values.yaml to use the correct v9 image.

🤖 Prompt for AI Agents
In `@packages/apps/elasticsearch/README.md` at line 170, Update the default
Elasticsearch image in values.yaml to match the v9 default referenced in the
README and tests: replace the current images.elasticsearch value (which points
to docker.elastic.co/elasticsearch/elasticsearch:8.17.0) with the v9 image tag
(e.g. docker.elastic.co/elasticsearch/elasticsearch:9.0.0) so
images.elasticsearch in values.yaml and the README are consistent with the v9
default.

Comment on lines +21 to +22
- name: sysctl
image: busybox:1.36

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, verify the file exists and check its content
cd /tmp/repository 2>/dev/null || cd . 
ls -la packages/system/elasticsearch-operator/templates/sysctl-daemonset.yaml

Repository: cozystack/cozystack

Length of output: 182


🏁 Script executed:

# Read the file to see the current state around the mentioned lines
head -50 packages/system/elasticsearch-operator/templates/sysctl-daemonset.yaml | cat -n

Repository: cozystack/cozystack

Length of output: 1896


🏁 Script executed:

# Check if there's a values.yaml file for this chart
find packages/system/elasticsearch-operator -name "values*.yaml" -o -name "Chart.yaml" | head -20

Repository: cozystack/cozystack

Length of output: 495


🏁 Script executed:

# Look at the project structure to understand image management patterns
find packages/system -name "values*.yaml" | head -10

Repository: cozystack/cozystack

Length of output: 525


🏁 Script executed:

# Check the values.yaml to see how images are typically configured in this chart
cat -n packages/system/elasticsearch-operator/values.yaml

Repository: cozystack/cozystack

Length of output: 185


🏁 Script executed:

# Check if there are other examples of image pinning in the system charts
grep -r "image:" packages/system/*/values.yaml | head -20

Repository: cozystack/cozystack

Length of output: 2903


🌐 Web query:

busybox 1.36 docker image digest security advisories

💡 Result:

Docker image digests (BusyBox 1.36 / 1.36.1)

  • Docker Hub’s official busybox image lists tags 1.36 / stable and 1.36.1 (plus -glibc/-musl/-uclibc variants). It does not reliably expose full digests in the human HTML view. (hub.docker.com)
  • A third-party mirror site reports the following manifest digests (treat as unverified; confirm with docker buildx imagetools inspect busybox:1.36.1 or skopeo inspect docker://docker.io/library/busybox:1.36.1):
    • busybox:1.36 → busybox@sha256:303337d3d52898b33018796d760d3a01c2dcc87973dd66ec22fe78ae1e8429c9 (docker.aityp.com)
    • busybox:1.36.1 → busybox@sha256:7edf5efe6b86dbf01ccc3c76b32a37a8e23b84e6bad81ce8ae8c221fa456fda8 (docker.aityp.com)

Security advisories affecting BusyBox v1.36.1 (commonly relevant to busybox:1.36* images)

NVD lists multiple BusyBox 1.36.1 issues (notably around the awk applet):

Example downstream tracking/fix status (Ubuntu): CVE-2023-42364 and CVE-2023-42365 are marked fixed in newer Ubuntu busybox package builds (distro-package context, not the Docker Official Image build itself). (ubuntu.com)

Citations:


🌐 Web query:

registry.k8s.io/pause 3.9 image digest kubernetes

💡 Result:

For Kubernetes’ pause image registry.k8s.io/pause:3.9, the registry digest (manifest list / image index) is:

registry.k8s.io/pause@sha256:7031c1b283388d2c2e09b57badb803c05ebed362dc88d84b480cc47f72a21097 [1][2]


Pin BusyBox and Pause images by digest; consider moving to values.yaml for override capability.

The hardcoded images should include digest pins to reduce supply-chain drift. This aligns with the project's pattern in other system packages (e.g., backup-controller, cozystack-controller use digest pins in values.yaml).

  • busybox:1.36 has known security advisories (CVE-2023-42363, CVE-2023-42364, CVE-2023-42365, CVE-2023-42366) related to the awk applet; consider upgrading to busybox:1.36.1@sha256:7edf5efe6b86dbf01ccc3c76b32a37a8e23b84e6bad81ce8ae8c221fa456fda8 or newer.
  • Pin pause:3.9 to registry.k8s.io/pause@sha256:7031c1b283388d2c2e09b57badb803c05ebed362dc88d84b480cc47f72a21097.

Parameterizing these via values.yaml would also enable deployment-time overrides, improving flexibility.

Also applies to: 46-47

🤖 Prompt for AI Agents
In `@packages/system/elasticsearch-operator/templates/sysctl-daemonset.yaml`
around lines 21 - 22, Replace hardcoded image tags with digest-pinned,
configurable values: update the container image entries (the "name: sysctl"
container image currently set to "busybox:1.36" and the other pause image at
lines noted) to use digest pins (e.g., busybox@sha256... and
registry.k8s.io/pause@sha256...) and expose them as Helm values in values.yaml
(e.g., sysctl.image and sysctl.pauseImage) so templates reference {{
.Values.sysctl.image }} and {{ .Values.sysctl.pauseImage }}; ensure default
values in values.yaml use the pinned digests (or upgraded versions) and keep the
template fallbacks if values are omitted.

Comment on lines +32 to +36
command:
- sh
- -c
- |
sysctl -w vm.max_map_count=262144

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fail fast when sysctl fails.

If sysctl -w fails, the initContainer still exits 0 and the DaemonSet appears healthy even though the node isn’t configured. Add a fail-fast guard so the pod retries.

✅ Proposed fix
             - |
+              set -e
               sysctl -w vm.max_map_count=262144
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
command:
- sh
- -c
- |
sysctl -w vm.max_map_count=262144
command:
- sh
- -c
- |
set -e
sysctl -w vm.max_map_count=262144
🤖 Prompt for AI Agents
In `@packages/system/elasticsearch-operator/templates/sysctl-daemonset.yaml`
around lines 32 - 36, The initContainer's shell command runs "sysctl -w
vm.max_map_count=262144" but does not fail the container when that command
fails; update the command block for the initContainer (the shell/command
sequence that contains the sysctl invocation) to fail fast on error by enabling
shell strict mode or explicitly checking the exit status—for example, prepend
"set -euo pipefail" (or "set -e") at the top of the here-doc or change the line
to "sysctl -w vm.max_map_count=262144 || { echo 'sysctl failed' >&2; exit 1; }"
so the initContainer exits non‑zero and Kubernetes will retry the pod.

- Add resource limits to sysctl initContainer for better resource governance
- Add Kibana v7 version test for complete coverage
- Complete resource presets documentation (add small and medium presets)

All 46 Helm unit tests passing.

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
@kvaps

Copy link
Copy Markdown
Member

Hello Matthieu ROBIN (@matthieu-robin), thank you very much for your contribution! Unfortunately, there is a legal issue with implementing Elasticsearch in Cozystack.

Elasticsearch and the Elasticsearch Operator are licensed under the Elastic License 2.0, which restricts providing ELK as a Service. Additionally, CNCF does not allow us to use licenses that are not compatible with Apache 2.0.

Have you considered using OpenSearch instead?

@matthieu-robin

Copy link
Copy Markdown
Collaborator Author

Oups! Sorry about the licence... Can we make a "bring your own licence" model?

@kvaps

Copy link
Copy Markdown
Member

With the new Cozystack, we can ship this as an external module.
Alternatively, we can treat Cozystack as a distribution that provides a catalog of external software with independent licensing.

In any case, we cannot include any code that is incompatible with Apache-2.0 in this repository.

We faced a similar legal situation previously when providing a managed MongoDB application.
In practice, we use an unofficial MongoDB operator licensed under Apache-2.0 (Percona). However, MongoDB itself is licensed under SSPL, which requires that if you provide MongoDB as a Service, you must open-source the full system used to operate that service.

In that case, both conditions were satisfied:

  • Cozystack does not contain code under incompatible licenses (we include only Percona’s Apache-2.0 MongoDB operator)
  • If MongoDB is offered as a service, the platform’s source code must be open — and Cozystack is open-source

Therefore, we decided it was acceptable to merge that integration into the main tree.

For this PR, the situation is more complex because Elastic License 2.0 is not compatible with Apache-2.0:

  • The ELK operator and its manifests are licensed under Elastic License 2.0 and cannot be merged into the main Cozystack repository
  • Elastic License 2.0 explicitly prohibits providing Elasticsearch as a Service, unless explicit permission is obtained from Elastic

By contrast, OpenSearch is licensed under Apache-2.0 and does not have these restrictions.

I need to consult with the CNCF legal team to confirm the correct approach.
I have already opened a ticket in the CNCF Service Desk — it is still awaiting answer, I will update this request and let you know when I get the answer from CNCF legals.

I'm so sorry about that.

@YohanSciubukgian

Copy link
Copy Markdown

Andrei Kvapil (@kvaps) Would it be worth considering a dedicated repository such as cozystack-contrib or cozystack-community for all PaaS‑level third‑party integrations? Several CNCF projects follow this pattern, and it could offer a clean separation between the core platform and optional services. This would keep the main Cozystack repository focused on what the platform strictly requires and ensure that licensing remains fully aligned with your expectations, while still giving the community a place to maintain integrations like Elasticsearch, MongoDB, and other third‑party services with their various licensing models.

Would it make sense to also open a conversation with the Elastic team to get clearer guidance on how ELv2 applies in the context of a platform like Cozystack? With many companies moving toward hybrid or even fully on‑prem environments again, it could be in Elastic’s interest to clarify how community platforms such as CozyStack can integrate Elasticsearch in a compliant way. Their input might help define a path that works both for Cozystack and for organizations that already rely on Elasticsearch.

@kvaps

Andrei Kvapil (kvaps) commented Feb 23, 2026 •

Copy link
Copy Markdown
Member

YohanS (@YohanSciubukgian) Yes, this is exactly the direction we've been planning to take. In the v1.0.0 release we implemented a comprehensive plugin system with pluggable repositories. The system is similar to how APT repositories work in Ubuntu.

Right after the release, we had two things on our roadmap:

Looking further ahead, I hope that vendors like Elasticsearch will eventually provide official Cozystack packages within their own GitHub organizations — the same way they already ship Helm charts and Docker images for their software.

@github-actions github-actions Bot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress and removed do-not-merge labels Apr 27, 2026
@lexfrei

Copy link
Copy Markdown
Contributor

Closing on licensing grounds. Elasticsearch and the ECK operator are distributed under the Elastic License 2.0, which is not compatible with Apache-2.0, so they can't be included in this repository. The right home for this is an external module (external-apps) rather than core. For an in-tree, Apache-2.0 managed search service, packages/apps/opensearch already covers that need. I appreciate the amount of work that went into this — it's just better placed as an external app.

@kvaps

Copy link
Copy Markdown
Member

Matthieu ROBIN (@matthieu-robin) An update on the licensing side: we have asked CNCF for guidance on establishing a Debian-style "contrib" repository for exactly this kind of integration (ServiceDesk ticket CNCFSD-3698) — Apache-2.0 charts maintained under project governance, with restricted-license components such as the ECK operator fetched by the user's cluster from vendor sources at deploy time, nothing non-Apache stored or redistributed.

If CNCF confirms the pattern, your Elasticsearch integration would be its first candidate — with you as its maintainer, if the offer still stands. We will follow up here once we hear back.

@YohanSciubukgian

Copy link
Copy Markdown

It would be a great addition !
A broader -contrib scope could be so valuable.

Instead of limiting it to components with non‑Apache‑2.0 licenses, it might make sense to treat -contrib as the place for everything that is not part of CozyStack’s core vital services — even if CozyStack members currently maintains those projects.

This would include services such as PostgreSQL, OpenBao, Keycloak, OpenSearch, SeaweedFS, and generally anything CozyStack provides as-a-service today but that is not essential to the core CozyStack runtime itself. As CozyStack evolves, maintainers of the upstream projects may eventually take over again, or CozyStack’s own surface area may shift.

The CNCF Graduated project of OpenTelemetry provides an OpenTelemetry Collector & Collector Contrib model is a good example of this architecture:
you can build your own OpenTelemetry distribution with specific contrib components, to avoid shipping with everything by default, and manage a smaller security surface in a clean, modular way where each component as its own maturity (experimental, beta, etc), license and maintainers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress kind/feature Categorizes issue or PR as related to a new feature size/XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants