From 02f25d5883efd53e0d8eafe808bfcf8113bcf8b9 Mon Sep 17 00:00:00 2001 From: MergeCheck Date: Thu, 2 Jul 2026 21:45:33 -0300 Subject: [PATCH 1/2] fix(answer): align template standards --- charts/answer/ci/external-db-values.yaml | 62 ++++++++++++++++++- charts/answer/ci/external-secrets.yaml | 76 ++++++++++++++++++++---- charts/answer/templates/NOTES.txt | 23 +++---- charts/answer/templates/_helpers.tpl | 18 ++++++ charts/answer/templates/validate.yaml | 2 + charts/answer/tests/validation_test.yaml | 48 +++++++++++++++ 6 files changed, 202 insertions(+), 27 deletions(-) create mode 100644 charts/answer/templates/validate.yaml create mode 100644 charts/answer/tests/validation_test.yaml diff --git a/charts/answer/ci/external-db-values.yaml b/charts/answer/ci/external-db-values.yaml index f19b92867..16831501d 100644 --- a/charts/answer/ci/external-db-values.yaml +++ b/charts/answer/ci/external-db-values.yaml @@ -1,9 +1,67 @@ # SPDX-License-Identifier: Apache-2.0 -# CI: External PostgreSQL database +# CI: external PostgreSQL database backed by a local disposable PostgreSQL pod database: external: vendor: postgres - host: postgresql.example.svc + host: postgresql + port: "5432" name: answer username: answer password: external-password + +extraManifests: + - apiVersion: v1 + kind: Service + metadata: + name: postgresql + labels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/component: external-db-ci + spec: + type: ClusterIP + ports: + - name: postgresql + port: 5432 + targetPort: postgresql + selector: + app.kubernetes.io/name: postgresql + app.kubernetes.io/component: external-db-ci + - apiVersion: apps/v1 + kind: Deployment + metadata: + name: postgresql + labels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/component: external-db-ci + spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/component: external-db-ci + template: + metadata: + labels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/component: external-db-ci + spec: + containers: + - name: postgresql + image: docker.io/library/postgres:18.4-alpine + imagePullPolicy: IfNotPresent + env: + - name: POSTGRES_DB + value: answer + - name: POSTGRES_USER + value: answer + - name: POSTGRES_PASSWORD + value: external-password + ports: + - name: postgresql + containerPort: 5432 + volumeMounts: + - name: data + mountPath: /var/lib/postgresql + volumes: + - name: data + emptyDir: {} diff --git a/charts/answer/ci/external-secrets.yaml b/charts/answer/ci/external-secrets.yaml index 05ab19578..5b07e2329 100644 --- a/charts/answer/ci/external-secrets.yaml +++ b/charts/answer/ci/external-secrets.yaml @@ -5,7 +5,8 @@ admin: database: external: vendor: postgres - host: postgresql.example.com + host: postgresql + port: "5432" name: answer username: answer existingSecret: answer-db @@ -17,30 +18,83 @@ backup: externalSecrets: enabled: true secretStoreRef: - name: vault - kind: SecretStore + name: helmforge-fake-store + kind: ClusterSecretStore admin: enabled: true data: - secretKey: admin-password remoteRef: - key: answer/admin - property: password + key: test/password database: enabled: true data: - secretKey: database-password remoteRef: - key: answer/database - property: password + key: test/password backup: enabled: true data: - secretKey: access-key remoteRef: - key: answer/s3 - property: accessKey + key: test/username - secretKey: secret-key remoteRef: - key: answer/s3 - property: secretKey + key: test/token + +extraManifests: + - apiVersion: v1 + kind: Service + metadata: + name: postgresql + labels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/component: external-db-ci + spec: + type: ClusterIP + ports: + - name: postgresql + port: 5432 + targetPort: postgresql + selector: + app.kubernetes.io/name: postgresql + app.kubernetes.io/component: external-db-ci + - apiVersion: apps/v1 + kind: Deployment + metadata: + name: postgresql + labels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/component: external-db-ci + spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/component: external-db-ci + template: + metadata: + labels: + app.kubernetes.io/name: postgresql + app.kubernetes.io/component: external-db-ci + spec: + containers: + - name: postgresql + image: docker.io/library/postgres:18.4-alpine + imagePullPolicy: IfNotPresent + env: + - name: POSTGRES_DB + value: answer + - name: POSTGRES_USER + value: answer + - name: POSTGRES_PASSWORD + value: helmforge-test-password + ports: + - name: postgresql + containerPort: 5432 + volumeMounts: + - name: data + mountPath: /var/lib/postgresql + volumes: + - name: data + emptyDir: {} diff --git a/charts/answer/templates/NOTES.txt b/charts/answer/templates/NOTES.txt index 7903f9e9f..e456aaf1c 100644 --- a/charts/answer/templates/NOTES.txt +++ b/charts/answer/templates/NOTES.txt @@ -1,9 +1,7 @@ {{/* SPDX-License-Identifier: Apache-2.0 */}} -============================================================================= -Apache Answer deployed successfully! -============================================================================= +Apache Answer deployed successfully. -SUMMARY: +1. Summary: Release: {{ .Release.Name }} Namespace: {{ .Release.Namespace }} Chart: {{ .Chart.Name }} {{ .Chart.Version }} @@ -13,7 +11,7 @@ SUMMARY: Persistence: {{ if .Values.persistence.enabled }}enabled ({{ .Values.persistence.size }}){{ else }}disabled{{ end }} ServiceAccount: {{ include "answer.serviceAccountName" . }} -ACCESS: +2. Access: {{- if .Values.ingress.enabled }} {{- range .Values.ingress.hosts }} Ingress: http{{ if $.Values.ingress.tls }}s{{ end }}://{{ .host }} @@ -30,7 +28,7 @@ ACCESS: http://127.0.0.1:9080 {{- end }} -ADMIN: +3. Credentials: Username: {{ .Values.admin.name }} Email: {{ .Values.admin.email }} {{- if .Values.admin.existingSecret }} @@ -42,7 +40,7 @@ ADMIN: kubectl get secret {{ include "answer.adminSecretName" . }} -n {{ .Release.Namespace }} -o jsonpath="{.data.{{ include "answer.adminSecretKey" . }}}" | base64 -d {{- end }} -DATABASE: +4. Configuration: {{- $dbMode := include "answer.databaseMode" . }} Mode: {{ $dbMode }} {{- if eq $dbMode "sqlite" }} @@ -56,7 +54,6 @@ DATABASE: Password secret: {{ include "answer.databaseSecretName" . }} / {{ include "answer.databaseSecretKey" . }} {{- end }} -ROUTING: Service: {{ include "answer.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.service.port }} Ingress enabled: {{ .Values.ingress.enabled }} Gateway API enabled: {{ .Values.gateway.enabled }} @@ -67,7 +64,6 @@ ROUTING: IP families: {{ join ", " . }} {{- end }} -OPTIONAL FEATURES: Backups: {{ .Values.backup.enabled }} External Secrets: {{ .Values.externalSecrets.enabled }} {{- if .Values.backup.enabled }} @@ -78,7 +74,7 @@ OPTIONAL FEATURES: SecretStore: {{ .Values.externalSecrets.secretStoreRef.name }} ({{ .Values.externalSecrets.secretStoreRef.kind }}) {{- end }} -VALIDATION: +5. Validation: Release status: helm status {{ .Release.Name }} -n {{ .Release.Namespace }} @@ -91,7 +87,7 @@ VALIDATION: Health check: kubectl run {{ include "answer.fullname" . }}-health-check -n {{ .Release.Namespace }} --rm -i --restart=Never --image=docker.io/library/busybox:1.37 -- wget -qO- http://{{ include "answer.fullname" . }}:{{ .Values.service.port }}/healthz -TROUBLESHOOTING: +6. Troubleshooting: Events: kubectl get events -n {{ .Release.Namespace }} --sort-by=.lastTimestamp @@ -101,16 +97,15 @@ TROUBLESHOOTING: Init container logs when using PostgreSQL, MySQL, or external DB: kubectl logs deploy/{{ include "answer.fullname" . }} -n {{ .Release.Namespace }} -c wait-for-db --tail=200 -NOTES: +7. Upgrade Notes: - Keep the admin password and database password stable across upgrades. - Use PostgreSQL, MySQL, or an external database for production concurrency. - Enable backups before changing storage, database mode, or chart major versions. - Set answer.siteUrl to the externally reachable URL for production installs. -DOCUMENTATION: +8. Resources: Chart: https://helmforge.dev/docs/charts/answer Apache Answer: https://answer.apache.org Source: https://github.com/helmforgedev/charts/tree/main/charts/answer -============================================================================= Happy Helmforging :) diff --git a/charts/answer/templates/_helpers.tpl b/charts/answer/templates/_helpers.tpl index 185aa4b52..b6fe57cc2 100644 --- a/charts/answer/templates/_helpers.tpl +++ b/charts/answer/templates/_helpers.tpl @@ -329,3 +329,21 @@ true database-password {{- end -}} {{- end -}} + +{{- define "answer.validate" -}} +{{- $databaseMode := include "answer.databaseMode" . -}} +{{- if .Values.backup.enabled -}} +{{- $_ := include "answer.backupEnabled" . -}} +{{- end -}} +{{- if and .Values.ingress.enabled (empty .Values.ingress.hosts) -}} +{{- fail "ingress.hosts must contain at least one host when ingress.enabled=true" -}} +{{- end -}} +{{- if .Values.podLabels -}} +{{- if hasKey .Values.podLabels "app.kubernetes.io/name" -}} +{{- fail "podLabels must not override the selector label app.kubernetes.io/name" -}} +{{- end -}} +{{- if hasKey .Values.podLabels "app.kubernetes.io/instance" -}} +{{- fail "podLabels must not override the selector label app.kubernetes.io/instance" -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/answer/templates/validate.yaml b/charts/answer/templates/validate.yaml new file mode 100644 index 000000000..7677bf233 --- /dev/null +++ b/charts/answer/templates/validate.yaml @@ -0,0 +1,2 @@ +{{/* SPDX-License-Identifier: Apache-2.0 */}} +{{- include "answer.validate" . -}} diff --git a/charts/answer/tests/validation_test.yaml b/charts/answer/tests/validation_test.yaml new file mode 100644 index 000000000..00ad14ec3 --- /dev/null +++ b/charts/answer/tests/validation_test.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: Apache-2.0 +suite: Validation +templates: + - templates/validate.yaml +release: + name: test + namespace: default +tests: + - it: should reject ambiguous database auto-selection + set: + database.external.host: db.example.com + postgresql.enabled: true + asserts: + - failedTemplate: + errorMessage: "answer database selection is ambiguous: configure only one of database.external.host, postgresql.enabled, or mysql.enabled" + + - it: should require backup S3 endpoint when backup is enabled + set: + backup.enabled: true + backup.s3.bucket: answer-backups + backup.s3.accessKey: access + backup.s3.secretKey: secret + asserts: + - failedTemplate: + errorMessage: "backup.s3.endpoint is required when backup.enabled is true" + + - it: should require at least one ingress host when ingress is enabled + set: + ingress.enabled: true + asserts: + - failedTemplate: + errorMessage: "ingress.hosts must contain at least one host when ingress.enabled=true" + + - it: should reject podLabels that override the name selector + set: + podLabels: + app.kubernetes.io/name: other + asserts: + - failedTemplate: + errorMessage: "podLabels must not override the selector label app.kubernetes.io/name" + + - it: should reject podLabels that override the instance selector + set: + podLabels: + app.kubernetes.io/instance: other + asserts: + - failedTemplate: + errorMessage: "podLabels must not override the selector label app.kubernetes.io/instance" From bcb614704b87f6ddfa97185ab76ae9a3d0892f09 Mon Sep 17 00:00:00 2001 From: MergeCheck Date: Sun, 5 Jul 2026 20:24:08 -0300 Subject: [PATCH 2/2] fix(answer): gate ci postgres readiness --- charts/answer/ci/external-db-values.yaml | 12 ++++++++++++ charts/answer/ci/external-secrets.yaml | 12 ++++++++++++ charts/answer/templates/_helpers.tpl | 4 +--- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/charts/answer/ci/external-db-values.yaml b/charts/answer/ci/external-db-values.yaml index 16831501d..9f6923707 100644 --- a/charts/answer/ci/external-db-values.yaml +++ b/charts/answer/ci/external-db-values.yaml @@ -59,6 +59,18 @@ extraManifests: ports: - name: postgresql containerPort: 5432 + readinessProbe: + exec: + command: + - pg_isready + - -U + - answer + - -d + - answer + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 12 volumeMounts: - name: data mountPath: /var/lib/postgresql diff --git a/charts/answer/ci/external-secrets.yaml b/charts/answer/ci/external-secrets.yaml index 5b07e2329..35ebfc0dd 100644 --- a/charts/answer/ci/external-secrets.yaml +++ b/charts/answer/ci/external-secrets.yaml @@ -92,6 +92,18 @@ extraManifests: ports: - name: postgresql containerPort: 5432 + readinessProbe: + exec: + command: + - pg_isready + - -U + - answer + - -d + - answer + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 12 volumeMounts: - name: data mountPath: /var/lib/postgresql diff --git a/charts/answer/templates/_helpers.tpl b/charts/answer/templates/_helpers.tpl index b6fe57cc2..93351102d 100644 --- a/charts/answer/templates/_helpers.tpl +++ b/charts/answer/templates/_helpers.tpl @@ -331,10 +331,8 @@ database-password {{- end -}} {{- define "answer.validate" -}} -{{- $databaseMode := include "answer.databaseMode" . -}} -{{- if .Values.backup.enabled -}} +{{- $_ := include "answer.databaseMode" . -}} {{- $_ := include "answer.backupEnabled" . -}} -{{- end -}} {{- if and .Values.ingress.enabled (empty .Values.ingress.hosts) -}} {{- fail "ingress.hosts must contain at least one host when ingress.enabled=true" -}} {{- end -}}