Skip to content

feat: combine mail-plane charts into one umbrella Helm chart at helm/ - #36

Merged
maneesha-xyz merged 2 commits into
mainfrom
feat/umbrella-helm-chart
Aug 8, 2026
Merged

maneesha-xyz merged 2 commits into
mainfrom
feat/umbrella-helm-chart

Conversation

@Aravinda-HWK

Copy link
Copy Markdown
Contributor

What

Combines the four mail-plane charts into a single umbrella Helm chart at helm/, so the whole outbound-mail stack installs as one release instead of four:

helm upgrade --install pingmailer ./helm -n <namespace> -f my-values.yaml
helm/
├── Chart.yaml            # umbrella, declares the 4 subcharts
├── values.yaml           # defaults + the values you must fill in
├── values.example.yaml   # a complete install to copy from
├── README.md             # deployment guide
├── templates/NOTES.txt
└── charts/{api-server, opendkim-server, raven-sasl-server, smtp-server}/

Each service stays a self-contained subchart and can still be installed on its own. Every subchart is gated by <name>.enabled, so the stack can be rolled out piecemeal.

Why the subcharts were renamed

Subchart name: fields now match their directories (silver-api-serverapi-server, etc.) so umbrella values keys read naturally (smtp-server.domain rather than silver-smtp.domain).

This is safe: every subchart pins fullnameOverride, so no Service DNS name changes. Postfix's inet:opendkim-server:8891 and inet:raven-sasl:12345 wiring is untouched.

Also in this PR

hostAliases added to the api-server subchart. Callers pass smtp_host in the /notify body and the api-server verifies the SMTP TLS certificate against that name. The Service name smtp-server is not on the mail certificate, and the public mail hostname isn't reachable from inside the cluster (no hairpin). Mapping the cert-matching name to the SMTP ClusterIP fixes both. This previously existed only as a live oc patch and was silently lost on every redeploy — every send failed while /notify still returned 202.

helm/README.md — prerequisites, required values, DNS records, installing a subset, exposing SMTP, upgrade/rollback, troubleshooting, plus:

  • an OpenShift section: Route vs Ingress, restricted-v2 UID assignment, ResourceQuota requirements, NodePort for SMTP
  • an end-to-end in-cluster mail test procedure

Environment-specific references generalised across chart comments — no cluster, namespace, domain, or address from any particular deployment remains.

certbot-server intentionally stays under mail-infra/helm/ — certificate issuance has its own lifecycle and is a prerequisite, not a component of this chart.

Notable gotchas documented

  • raven-sasl-server pins UID 1001, which restricted-v2 rejects at ReplicaSet level, so you get no pod and no pod events. Note that podSecurityContext: {} does not clear it — Helm merges empty maps into the subchart's populated map, so each key must be nulled individually.
  • The api-server 0.1.0 tag exits demanding CERT_FILE/KEY_FILE; 0.1.1 is arm64-only. image.tag: "" resolves to appVersion (0.1.0), which is not what you want.
  • POST /notify returns 202 Email queued successfully even when the SMTP send later fails — never treat it as proof of delivery.
  • hostAliases pins a ClusterIP, so it needs refreshing if the smtp-server Service is recreated.

Verification

  • helm lint passes on the umbrella and on all four subcharts standalone
  • umbrella renders 19 resources with the example values
  • --set <name>.enabled=false correctly drops a subchart
  • required-value guards survived the move (bare render fails with a readable domain is required)
  • full uninstall → reinstall cycle on OpenShift: all four components came up on the first install, and mail was delivered end-to-end (XOAUTH2 auth via raven → Postfix submission → relayed out, status=sent, 250 2.0.0 OK)

Note for reviewers

Deployment-specific values are not committed. .gitignore gained my-values.yaml / my-*-values.yaml for local values files, which carry the OAuth client ID and sender allowlist.

Move api-server, opendkim-server, raven-sasl-server and smtp-server out of
mail-infra/helm/ and into a single umbrella chart at the repo root, so the
whole outbound-mail stack installs as one release:

    helm upgrade --install pingmailer ./helm -n <ns> -f my-values.yaml

Each service stays a self-contained subchart under helm/charts/ and can still
be installed on its own. Every subchart is gated by an `<name>.enabled` flag
so the stack can be rolled out piecemeal.

Subchart `name:` fields were renamed to match their directories
(silver-api-server -> api-server, etc.) so the umbrella values keys read
naturally. This is safe because every subchart pins fullnameOverride, so no
Service DNS name changes and Postfix's inet:opendkim-server:8891 /
inet:raven-sasl:12345 wiring is untouched.

Also:

- Add `hostAliases` to the api-server subchart. Callers pass `smtp_host` in the
  /notify body and the api-server verifies the SMTP TLS certificate against
  that name; the Service name `smtp-server` is not on the mail cert, and the
  public mail hostname is unreachable from inside the cluster. Mapping the
  cert-matching name to the SMTP ClusterIP fixes both. This previously existed
  only as a live `oc patch` and was lost on every redeploy.

- Add helm/README.md: a full deployment guide covering prerequisites, required
  values, DNS records, installing a subset, exposing SMTP, upgrades and
  rollbacks, plus an OpenShift section (Route vs Ingress, restricted-v2 UID
  assignment, ResourceQuota requirements, NodePort for SMTP) and an
  end-to-end in-cluster mail test procedure.

- Generalise environment-specific references in chart comments so nothing
  points at a particular cluster, namespace, domain or address.

certbot-server intentionally stays under mail-infra/helm/ — certificate
issuance has a separate lifecycle and is a prerequisite, not a component.

Verified: `helm lint` passes, the umbrella renders 19 resources, all four
subcharts still lint standalone, and a full uninstall/reinstall cycle on
OpenShift brought all four components up and delivered mail end-to-end
(XOAUTH2 auth via raven -> Postfix submission -> relayed out, status=sent).
@Aravinda-HWK Aravinda-HWK self-assigned this Aug 7, 2026
Adds two workflows, both driven by publishing a GitHub Release (plus
workflow_dispatch for manual runs and a no-push dry run on PRs).

docker-release.yaml — builds the three images this repo owns and pushes each
to GHCR tagged with both `latest` and the release version:

  - pingmailer-api-server  (static Go binary, built for amd64, arm64,
                            arm/v7, ppc64le and s390x)
  - silver-dkim            (amd64, arm64)
  - silver-smtp            (amd64, arm64 — rebuilds Postfix from source, so
                            every extra platform is a full compile under QEMU)

silver-smtp also keeps its `rootless` tag moving, because that is what the
smtp-server subchart defaults to; without it a chart install would pin an
ageing image.

After pushing, the workflow inspects the manifest and fails if any requested
platform is missing. This guards a regression we actually hit: a tag was
published arm64-only and the cluster refused it with "no image found in image
index for architecture amd64" — better to fail at build time than at deploy.

`latest` moves only on a real release, never from a dispatch or a PR, so a
manual run cannot silently redirect consumers.

helm-release.yaml — lints the umbrella chart and every subchart standalone,
renders the example values, asserts the required-value guards still fire when
values are absent, then packages and pushes to
oci://ghcr.io/<owner>/charts/pingmailer.

The chart is versioned from the release tag via `helm package --version
--app-version`, so the chart, its appVersion and the image tags always agree
for a given release rather than drifting against Chart.yaml.

Also documents installing from the registry in helm/README.md.

raven-sasl is deliberately not built here — it lives in another repository and
is only consumed by this chart.

@maneesha-xyz maneesha-xyz 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.

LGTM.

@maneesha-xyz
maneesha-xyz merged commit 23aaa0d into main Aug 8, 2026
6 checks passed
@Aravinda-HWK
Aravinda-HWK deleted the feat/umbrella-helm-chart branch August 12, 2026 10:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants