Skip to content

Commit 77145ba

Browse files
feat: add elasticsearch-self-signed-upgrade scenario for 8.7->8.8 TLS upgrade testing (#5974)
1 parent 27f7478 commit 77145ba

14 files changed

Lines changed: 873 additions & 4 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ scripts/deploy-camunda/.env
4343
charts/camunda-platform*/test/e2e/package-lock.json
4444

4545
diagnostics/
46+
deployment-logs/
4647
STATE.md
4748

4849
**/.omc

AGENTS.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,52 @@ make tools.asdf-install
161161
- `8.7` and older use separate component template directories.
162162
- Never assume paths/components are identical across versions.
163163

164+
### Template Gating Patterns
165+
Many template blocks are gated behind value flags that create implicit coupling:
166+
167+
- **`global.elasticsearch.external`** gates ES auth env var injection in most components (8.7 and 8.8). A hard constraint in `constraints.tpl` blocks setting `external=true` when the bundled subchart is active (`elasticsearch.enabled=true`). To inject auth when using the bundled subchart, use component-level `env` overrides instead.
168+
- **`global.elasticsearch.tls.existingSecret`** triggers TLS truststore volume mounts and `JAVA_TOOL_OPTIONS` injection in most components. This is NOT behind the `external` gate — it works with the bundled subchart.
169+
- Template blocks often differ between versions (e.g., 8.7 Operate init container renders `operate.env` with `toYaml` but NOT `tpl`, so `{{ .Release.Name }}` in `valueFrom.secretKeyRef.name` is literal). Always read the specific version's template before writing env overrides.
170+
171+
### Helm Subchart Value Override Patterns
172+
Helm's values merge is a **deep merge for maps** but a **full replace for arrays**. This matters for subchart overrides:
173+
174+
```yaml
175+
# Parent chart values.yaml default:
176+
elasticsearch:
177+
master:
178+
extraEnvVars: # <-- array
179+
- name: SOME_VAR
180+
value: "default"
181+
182+
# Your overlay:
183+
elasticsearch:
184+
master:
185+
extraEnvVars: [] # Replaces the entire array — parent default is gone
186+
```
187+
188+
This is the correct way to neutralize a parent chart's default array value. Setting `extraEnvVars: []` removes the parent's entries entirely. Setting `extraEnvVars: [{name: SOME_VAR, value: "override"}]` replaces the array with your single entry.
189+
190+
**Contrast with deploy-camunda's merge:** The `deploy-camunda` CLI uses name-keyed deep merge for `env` arrays (matching on `name` field). But Helm itself does NOT — Helm replaces arrays wholesale. Know which merge strategy applies at each layer.
191+
192+
### Bitnami Subchart Env Var Chains
193+
Bitnami charts often set env vars from multiple sources in a fixed order within the statefulset template:
194+
195+
1. Security helper (from `security.*` values)
196+
2. `<role>.extraEnvVars` (e.g., `master.extraEnvVars`)
197+
3. Top-level `extraEnvVars`
198+
199+
When Kubernetes encounters duplicate env var names, **the last one wins**. If the parent chart's `values.yaml` defaults an `extraEnvVars` entry that conflicts with a security helper value, you must either override or clear the array. To diagnose:
200+
201+
```bash
202+
# Render and count occurrences of a suspicious env var:
203+
helm template integration charts/camunda-platform-8.X \
204+
-f <your-values.yaml> \
205+
--show-only charts/elasticsearch/templates/master/statefulset.yaml \
206+
| grep -c 'ELASTICSEARCH_ENABLE_REST_TLS'
207+
# Should be exactly 1. If >1, there's a duplicate.
208+
```
209+
164210
## Commit and Branch Conventions
165211
- Branches: `issueId-description` (example `123-adding-bpel-support`).
166212
- Commit/PR titles: Conventional Commits.
@@ -182,3 +228,50 @@ make tools.asdf-install
182228
4. Run single package/test first, then chart-scoped test run.
183229
5. Update golden files only for intentional rendering changes.
184230
6. Record discoveries and remaining work in `STATE.md`.
231+
232+
## Adding New Persistence Layers and Scenarios
233+
234+
### New Persistence Layer
235+
A persistence layer is a values file at `charts/<version>/test/integration/scenarios/chart-full-setup/values/persistence/<name>.yaml`. To add one:
236+
237+
1. Create the YAML file with the values needed for the data backend.
238+
2. Add the name to `validPersistence` in `scripts/camunda-core/pkg/scenarios/scenarios.go`.
239+
3. Update help text and shell completions in `scripts/deploy-camunda/cmd/prepare_values.go` and `scripts/deploy-camunda/cmd/root.go`.
240+
241+
### New CI Test Scenario
242+
Scenarios are defined in `charts/<version>/test/ci-test-config.yaml`. Each entry specifies identity, persistence, platforms, flows, and optional features. Example:
243+
244+
```yaml
245+
- name: elasticsearch-self-signed-upgrade
246+
enabled: false # set true when ready for CI
247+
identity: keycloak
248+
persistence: elasticsearch-self-signed
249+
platforms: [gke]
250+
flows: [upgrade-minor]
251+
features: [migrator] # includes values/features/migrator.yaml
252+
shortname: esss # 4-char, used in namespace generation
253+
```
254+
255+
The `features` array maps to `values/features/<name>.yaml`. The `migrator` feature enables identity and data migration jobs during upgrades — use it for any `upgrade-minor` scenario. Note: the automatic `needsMigrator()` function in `scenarios.go` only activates when `ChartVersion` starts with "13", but the matrix runner does not set `ChartVersion`, so always use `features: [migrator]` explicitly.
256+
257+
### Pre-Install Hooks (Scenario-Specific)
258+
When a scenario needs prerequisites in the namespace before `helm install` (e.g., TLS secrets), use a pre-install script:
259+
260+
1. Create `charts/<version>/test/integration/scenarios/pre-setup-scripts/pre-install-<scenario-name>.sh`.
261+
2. The script receives `NAMESPACE`, `RELEASE`, and `KUBE_CONTEXT` as environment variables.
262+
3. Discovery is automatic: `versionmatrix.HasPreInstallScript(repoRoot, appVersion, scenario)` checks for the file.
263+
4. The runner calls it after namespace creation but before `helm install`, in both single-step and two-step upgrade flows.
264+
265+
For reusable logic (e.g., cert generation), create a separate script and have the pre-install wrapper `exec` into it:
266+
```bash
267+
#!/usr/bin/env bash
268+
set -euo pipefail
269+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
270+
exec bash "$SCRIPT_DIR/create-elasticsearch-tls-secrets.sh"
271+
```
272+
273+
### Pre-Upgrade Scripts
274+
For cleanup needed between Step 1 (old version) and Step 2 (new version) of an upgrade flow, use `pre-upgrade-minor.sh` in the target version's `pre-setup-scripts/`. Common needs for 8.7→8.8:
275+
- Delete identity deployment (port naming conflict: 8.7 uses `containerPort: 8080`, 8.8 uses `8084`, both named `http` — Kubernetes strategic merge patch keeps both, causing a duplicate name error).
276+
- Delete stale 8.7 ingresses that route to non-existent services.
277+
- Delete PostgreSQL statefulsets (Bitnami version changes).
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# =============================================================================
2+
# Elasticsearch Backend with Self-Signed TLS
3+
# =============================================================================
4+
# Layer 3: Data backend - Elasticsearch (bundled, self-signed TLS)
5+
# Used with: --persistence elasticsearch-self-signed
6+
#
7+
# This layer enables the bundled Bitnami Elasticsearch subchart with X-Pack
8+
# security and TLS using pre-provisioned self-signed certificates.
9+
#
10+
# Prerequisites (must exist in the namespace before deployment):
11+
# - Secret "elasticsearch-tls-certs" with keys:
12+
# elasticsearch.keystore.jks, elasticsearch.truststore.jks
13+
# - Secret "elasticsearch-tls-passwords" with keys:
14+
# keystore-password, truststore-password
15+
# - Secret "elasticsearch-jks" with keys:
16+
# externaldb.jks (JKS truststore for Camunda components)
17+
# truststore-password
18+
# =============================================================================
19+
#
20+
# Auth notes:
21+
# The 8.7 templates only inject ES auth env vars when
22+
# global.elasticsearch.external=true. Since we use the bundled subchart we
23+
# cannot flip that flag (constraints.tpl blocks it), so we:
24+
# 1. Set a known elasticPassword on the subchart.
25+
# 2. Inject username + password via component-level env using plain values
26+
# (no secretKeyRef / template expressions), which avoids the missing
27+
# tpl() call in the operate init-container env rendering.
28+
#
29+
# Java 21 defaults keystore.type to pkcs12; our truststore is JKS format so we
30+
# must set -Djavax.net.ssl.trustStoreType=jks and provide the password.
31+
# The 8.7 templates prepend the trustStore path to javaOpts when
32+
# tls.existingSecret is set.
33+
# =============================================================================
34+
35+
global:
36+
elasticsearch:
37+
enabled: true
38+
url:
39+
protocol: https
40+
host: "{{ .Release.Name }}-elasticsearch"
41+
port: 9200
42+
auth:
43+
username: elastic
44+
existingSecret: "{{ .Release.Name }}-elasticsearch"
45+
existingSecretKey: elasticsearch-password
46+
tls:
47+
enabled: true
48+
existingSecret: elasticsearch-jks
49+
50+
operate:
51+
javaOpts: "-Djavax.net.ssl.trustStoreType=jks -Djavax.net.ssl.trustStorePassword=changeit"
52+
env:
53+
- name: CAMUNDA_OPERATE_ELASTICSEARCH_USERNAME
54+
value: elastic
55+
- name: CAMUNDA_OPERATE_ELASTICSEARCH_PASSWORD
56+
value: "camunda-ci-es-password"
57+
- name: CAMUNDA_OPERATE_ZEEBE_ELASTICSEARCH_USERNAME
58+
value: elastic
59+
- name: CAMUNDA_OPERATE_ZEEBE_ELASTICSEARCH_PASSWORD
60+
value: "camunda-ci-es-password"
61+
- name: CAMUNDA_DATABASE_USERNAME
62+
value: elastic
63+
- name: CAMUNDA_DATABASE_PASSWORD
64+
value: "camunda-ci-es-password"
65+
66+
optimize:
67+
javaOpts: "-Djavax.net.ssl.trustStoreType=jks -Djavax.net.ssl.trustStorePassword=changeit"
68+
env:
69+
- name: CAMUNDA_OPTIMIZE_ELASTICSEARCH_SECURITY_USERNAME
70+
value: elastic
71+
- name: CAMUNDA_OPTIMIZE_ELASTICSEARCH_SSL_ENABLED
72+
value: "true"
73+
- name: CAMUNDA_OPTIMIZE_ELASTICSEARCH_SECURITY_PASSWORD
74+
value: "camunda-ci-es-password"
75+
76+
tasklist:
77+
javaOpts: "-Djavax.net.ssl.trustStoreType=jks -Djavax.net.ssl.trustStorePassword=changeit"
78+
env:
79+
- name: CAMUNDA_TASKLIST_ELASTICSEARCH_USERNAME
80+
value: elastic
81+
- name: CAMUNDA_TASKLIST_ELASTICSEARCH_PASSWORD
82+
value: "camunda-ci-es-password"
83+
- name: CAMUNDA_TASKLIST_ZEEBE_ELASTICSEARCH_USERNAME
84+
value: elastic
85+
- name: CAMUNDA_TASKLIST_ZEEBE_ELASTICSEARCH_PASSWORD
86+
value: "camunda-ci-es-password"
87+
- name: CAMUNDA_DATABASE_USERNAME
88+
value: elastic
89+
- name: CAMUNDA_DATABASE_PASSWORD
90+
value: "camunda-ci-es-password"
91+
92+
zeebe:
93+
javaOpts: "-Djavax.net.ssl.trustStoreType=jks -Djavax.net.ssl.trustStorePassword=changeit"
94+
env:
95+
- name: ZEEBE_BROKER_EXPORTERS_ELASTICSEARCH_ARGS_AUTHENTICATION_USERNAME
96+
value: elastic
97+
- name: ZEEBE_BROKER_EXPORTERS_ELASTICSEARCH_ARGS_AUTHENTICATION_PASSWORD
98+
value: "camunda-ci-es-password"
99+
- name: CAMUNDA_DATABASE_USERNAME
100+
value: elastic
101+
- name: CAMUNDA_DATABASE_PASSWORD
102+
value: "camunda-ci-es-password"
103+
104+
zeebeGateway:
105+
env:
106+
- name: CAMUNDA_DATABASE_USERNAME
107+
value: elastic
108+
- name: CAMUNDA_DATABASE_PASSWORD
109+
value: "camunda-ci-es-password"
110+
111+
connectors:
112+
env:
113+
- name: JAVA_TOOL_OPTIONS
114+
value: "-Djavax.net.ssl.trustStore=/usr/local/connectors/certificates/externaldb.jks -Djavax.net.ssl.trustStoreType=jks -Djavax.net.ssl.trustStorePassword=changeit"
115+
116+
elasticsearch:
117+
enabled: true
118+
security:
119+
enabled: true
120+
elasticPassword: "camunda-ci-es-password"
121+
tls:
122+
restEncryption: true
123+
autoGenerated: false
124+
verificationMode: certificate
125+
master:
126+
existingSecret: elasticsearch-tls-certs
127+
passwordsSecret: elasticsearch-tls-passwords
128+
keystorePassword: ""
129+
truststorePassword: ""
130+
# The parent chart's values.yaml defaults master.extraEnvVars to
131+
# [{name: ELASTICSEARCH_ENABLE_REST_TLS, value: "false"}], which would
132+
# override the security helper's "true" (from restEncryption: true above).
133+
# Setting extraEnvVars to an empty array clears that default so only the
134+
# security helper's correct value remains — no duplicate env var.
135+
master:
136+
extraEnvVars: []

0 commit comments

Comments
 (0)