Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
1285746
chore: add chart conventions, lint script, and helm lint CI [#53]
KrutikaPhirangi Sep 2, 2026
b732a55
feat: add oan-common library chart and oan-template scaffold [#53]
KrutikaPhirangi Sep 2, 2026
f1038d3
feat: add postgresql-cnpg and postgresql-migration charts [#53]
KrutikaPhirangi Sep 2, 2026
363003b
feat: add keycloak chart with sunbird-rc realm import [#53]
KrutikaPhirangi Sep 2, 2026
02c3c65
feat: add registry and discovery service charts [#53]
KrutikaPhirangi Sep 2, 2026
2460c06
docs: list the seven charts and their install order in README [#53]
KrutikaPhirangi Sep 2, 2026
1eb98da
feat: point the discovery chart at the published image [#53]
KrutikaPhirangi Sep 4, 2026
7465939
chore: add chart conventions, lint script, and helm lint CI [#53]
KrutikaPhirangi Sep 2, 2026
8212a5c
feat: add oan-common library chart and oan-template scaffold [#53]
KrutikaPhirangi Sep 2, 2026
863386e
feat: add postgresql-cnpg and postgresql-migration charts [#53]
KrutikaPhirangi Sep 2, 2026
e7dd191
feat: add keycloak chart with sunbird-rc realm import [#53]
KrutikaPhirangi Sep 2, 2026
a67a110
feat: add registry and discovery service charts [#53]
KrutikaPhirangi Sep 2, 2026
b353a75
docs: list the seven charts and their install order in README [#53]
KrutikaPhirangi Sep 2, 2026
5ff2aab
feat: point the discovery chart at the published image [#53]
KrutikaPhirangi Sep 4, 2026
52a4ee4
Merge branch 'feat/53-chart-scaffold-common-library' of https://githu…
KrutikaPhirangi Sep 7, 2026
00292a2
feat: add network-adapter chart [#2]
KrutikaPhirangi Sep 8, 2026
94dd66d
chore: default the discovery image tag to latest [#3]
KrutikaPhirangi Sep 8, 2026
84f429d
Merge branch 'feat/4-docker-compose' into feat/53-chart-scaffold-comm…
KrutikaPhirangi Sep 8, 2026
f4fcf23
feat: generalise the adapter chart to all three roles [#2]
KrutikaPhirangi Sep 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/helm-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: helm-lint

on:
pull_request:
paths:
- 'charts/**'
- 'scripts/lint-charts.sh'
- '.github/workflows/helm-lint.yml'
push:
branches:
- main
- development
paths:
- 'charts/**'
- 'scripts/lint-charts.sh'
- '.github/workflows/helm-lint.yml'

jobs:
lint:
name: lint and render charts
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Helm
uses: azure/setup-helm@v4
with:
version: v3.16.4

- name: Lint and render all charts
run: ./scripts/lint-charts.sh
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@

# macOS
.DS_Store

# Helm dependency artifacts (regenerated by `helm dependency update`)
charts/**/charts/
charts/**/Chart.lock
*.tgz

# Rendered output
rendered/

# Editor/IDE
.vscode/
.idea/
*.swp


# Local scratch: a standalone registry someone ran by hand, with a real .env in
# it. Not part of this repo, and its .env holds live credentials -- it was
# committed once by a `git add -A` and must not be again.
registry/

123 changes: 123 additions & 0 deletions CONVENTIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# Chart conventions

Rules every chart in this repository follows. They exist so that a service chart
is predictable to read, safe to upgrade, and traceable back to the change that
produced it.

## Naming

| Thing | Rule | Example |
|---|---|---|
| Chart directory and `name` | `oan-<service>`, kebab-case, matching the service's repo/deployment name | `oan-registry-service` |
| Library chart | `oan-common` — the only library chart; every service chart depends on it | `oan-common` |
| Reference chart | `oan-template` — copied to start a new chart, never deployed as-is | `oan-template` |
| A deployed component | Named after the **role it plays in OAN**, no `oan-` prefix — the prefix is for the shared library and the starter chart | `registry`, `keycloak` |
| Two charts for the same role | Add the distinguishing implementation as a suffix, only when there is something to distinguish | `postgresql-cnpg` |
| Release name | The service name without the `oan-` prefix, so resources read `registry-service-...` not `oan-registry-service-oan-registry-service` | `helm install registry-service charts/oan-registry-service` |
| Template helpers | Chart-local helpers are namespaced by chart name: `<chart>.<helper>` | `oan-registry-service.fullname` |
| Value keys | camelCase, matching Kubernetes field names where one exists | `podSecurityContext`, `envFromSecrets` |
| Env var keys in `envConfig` | SCREAMING_SNAKE_CASE | `LOG_LEVEL` |
| Custom labels/annotations | Prefixed with a domain we own | `oan.in/environment: dev` |

Component charts are named after the role the component plays in OAN, not after
the software that happens to implement it: `registry` and `keycloak`, not
`registry-sunbird-rc` or `keycloak-sunbird-rc`. The implementation is an
implementation detail, and one that can change without the role changing.

Add an implementation suffix only when it actually distinguishes something —
`postgresql-cnpg` carries `-cnpg` because a plain `postgresql` chart could
reasonably mean several different operators, and which one is in use changes how
the chart is configured and operated.

The `oan-` prefix is reserved for the shared library (`oan-common`) and the
starter chart (`oan-template`). Every chart, prefixed or not, depends on
`oan-common` and carries the standard OAN labels, including
`app.kubernetes.io/part-of: oan`.

Chart directory name, `name` in `Chart.yaml`, and the prefix of the chart-local
helpers must all agree. A mismatch is the most common cause of a chart that
lints clean but renders the wrong resource names.

## Versioning

Two independent version fields, both required in every `Chart.yaml`:

- **`version`** — the version of the *chart*, following
[Semantic Versioning](https://semver.org/). Bumped on every chart change,
even a comment-only one.
- **`appVersion`** — the version of the *application image* the chart deploys by
default, quoted. It is the fallback for `image.tag`, so it must be a real,
pullable tag. Bumping it is a chart change, and so requires a `version` bump
too.

`version` bump rules:

| Change | Bump |
|---|---|
| New value key with a backward-compatible default; new optional resource | MINOR |
| Bug fix in a template; doc/comment change; `appVersion` bump | PATCH |
| Removing or renaming a value key or helper; changing a default that alters live behaviour; changing an immutable field such as a selector label | MAJOR |

For `oan-common` specifically: consumers pin `version: "0.1.x"`, so helper
additions ship as PATCH/MINOR and MAJOR is reserved for renaming or changing the
behaviour of an existing helper. A MAJOR bump of `oan-common` means every
consuming chart's pin has to be updated deliberately.

Pre-1.0.0 charts are still in flux; once a chart is deployed to production it
goes to `1.0.0` and the rules above are binding.

## Changelog

Every chart keeps a `CHANGELOG.md` in
[Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format. A chart change
is not complete without both the `version` bump and the matching changelog
entry. This is what makes "which chart version introduced this?" answerable.

## Required in every service chart

The deployment epic requires these on every component, and `oan-common`
enforces the first two at render time rather than leaving them to review:

1. **Resource requests and limits** — `oan-common.resources` fails the render
when `.Values.resources` is empty. This applies to data stores too, where the
requests land on the operator-managed pods.
2. **Liveness and readiness probes** — enabled by default in `oan-template`.
`oan-common.probeSpec` fails the render when an enabled probe declares no
handler, or declares more than one (which the API server would otherwise
reject at apply time, long after the render looked fine).
3. **A ServiceAccount per service** — never the namespace `default`. Attach IRSA
role ARNs via `serviceAccount.annotations`.
4. **Standard labels** — from `oan-common.labels`, giving every resource
`app.kubernetes.io/*` plus `app.kubernetes.io/part-of: oan`.

## Secrets

No secret value is ever committed to this repository — not in `values.yaml`, not
in a per-environment values file.

- **No chart in this repository renders a Secret.** Charts only *reference*
Secrets by name, so the question of how secret material gets into the cluster
is answered once, outside the charts, rather than differently per chart.
- `envFromSecrets` lists names of Secrets whose keys become environment
variables. `secretEnv` maps one Secret key to one variable name, for when the
producing key and the expected variable differ.
- `envConfig` is for non-secret configuration only. It lands in a ConfigMap.

## Validation

`./scripts/lint-charts.sh` runs `helm lint --strict` on every chart and
`helm template` on every application chart. CI runs the same script on pull
requests and on pushes to `main` and `development`, so a chart that fails
locally fails the same way in CI.

Because service charts depend on `oan-common` through
`file://../oan-common`, and the packaged dependency is not committed, an edit to
`oan-common` is only visible to a consuming chart after
`helm dependency update charts/<chart>` (or a run of the lint script).

## Traceability

Chart work follows the repository's git conventions: branch
`feat/<issue>-<slug>`, commits carrying `[#<issue>]`, PR body closing the issue.
The chart's changelog entry and the issue number are the two ends of the same
thread.
148 changes: 147 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,148 @@
# helmcharts
Helm charts for deploying and managing platform services

Helm charts for deploying and managing OpenAgriNet (OAN) platform services.

## Charts

| Chart | Type | Purpose |
|---|---|---|
| [`oan-common`](charts/oan-common) | library | Shared template helpers — names, labels, image refs, probes, resources, service account, env config, dependency waits. Renders nothing; never installed directly. |
| [`oan-template`](charts/oan-template) | application | Complete, working starter chart built on `oan-common`. Copy it to bootstrap a service chart. |
| [`postgresql-cnpg`](charts/postgresql-cnpg) | application | CloudNativePG-managed PostgreSQL cluster. One release per database. Requires the CNPG operator. |
| [`postgresql-migration`](charts/postgresql-migration) | application | Flyway migrations as a Job. Creates the per-service databases and applies versioned SQL. |
| [`keycloak`](charts/keycloak) | application | Auth for the registry, on the Sunbird RC Keycloak image. Imports the realm the registry expects. |
| [`registry`](charts/registry) | application | The OAN participant registry, on Sunbird RC core. Needs `postgresql-cnpg` and `keycloak`. |
| [`discovery`](charts/discovery) | application | The OAN Beckn discover-and-publish service. Needs `postgresql-cnpg` **with pgvector**. |
| [`adapter-service`](charts/adapter-service) | application | The OAN Beckn adapters. One chart, installed once per `role` — `provider`, `network` or `experience`. Needs `registry`. |

## How they fit together

```
charts/
├── oan-common/ # library chart — shared helpers
├── oan-template/ # starter chart — copy this to build a service chart
├── postgresql-cnpg/ # data store
├── postgresql-migration/# schema migrations (Flyway Job)
├── keycloak/ # auth for the registry
├── registry/ # the participant registry
├── discovery/ # the Beckn discover-and-publish service
└── adapter-service/ # the Beckn adapters — one release per role
```

Every chart depends on `oan-common` via `file://../oan-common`.

## The registry stack

Three charts, deployed in this order — the ordering is not optional:

```bash
# 1. Database cluster. Creates BOTH databases: `registry` via bootstrap.initdb
# and `keycloak` via a CNPG Database object, each owned by its own role.
helm install registry-db charts/postgresql-cnpg -n oan-registry -f charts/postgresql-cnpg/examples/registry-db.dev.yaml
# 2. Keycloak — imports the sunbird-rc realm it ships with, on first start
helm install keycloak charts/keycloak -n oan-registry -f charts/keycloak/examples/keycloak.dev.yaml
# MANUAL STEP: regenerate the admin-api client secret in the Keycloak console —
# the realm export ships it masked, so the registry cannot authenticate without this.
# 3. Registry
helm install registry charts/registry -n oan-registry -f charts/registry/examples/registry.dev.yaml
```

`postgresql-migration` is deliberately not in that list: both databases come from
the cluster chart, and Sunbird RC and Keycloak each manage their own schema, so
there is nothing for Flyway to apply yet. It joins the flow when OAN adds schemas
of its own.

Their configuration is ported from the verified `registry/docker-compose.yml`
stack at exact environment-variable parity (32 for the registry, 10 for
Keycloak), so a cluster deploy reproduces what was tested locally. Each chart's
README documents where it deliberately deviates and why. Full walkthrough:
[`charts/registry/README.md`](charts/registry/README.md).

## The discovery service

Two charts, and one prerequisite that is easy to miss:

```bash
# 1. Its own database — pgvector on PostgreSQL 16, with the `vector` extension
# created at bootstrap. Both are required: no stock CNPG operand image has
# pgvector, and `vector` is not a trusted extension, so the owner the service
# connects as cannot create it itself.
helm install discovery-db charts/postgresql-cnpg -n oan-discovery -f charts/postgresql-cnpg/examples/discovery-db.dev.yaml
# 2. The service
helm install discovery charts/discovery -n oan-discovery -f charts/discovery/examples/discovery.dev.yaml
```

It shares no database and no Keycloak with the registry stack, so the two are
independent installs. Full walkthrough, including how the DSN and the Beckn
specification are supplied:
[`charts/discovery/README.md`](charts/discovery/README.md).

Service charts depend on `oan-common` and call its helpers through thin
chart-local wrappers. That keeps naming, labelling, probe, resource, and secret
conventions identical across every OAN chart, and means a convention change is
one edit in the library rather than one edit per chart.

## Quick start

Build a service chart from the template:

```bash
# 1. Copy the starter chart
cp -r charts/oan-template charts/oan-my-service

# 2. In charts/oan-my-service/Chart.yaml set name: oan-my-service
# and appVersion to the image tag you deploy by default.
# Keep the oan-common dependency.

# 3. Rename the chart-local helpers to your service name. Change only the left
# side of each define in templates/_helpers.tpl (oan-template.* ->
# oan-my-service.*); the oan-common.* include inside the body stays. This
# renames the defines and the include calls together:
grep -rl 'oan-template\.' charts/oan-my-service | xargs sed -i '' 's/oan-template\./oan-my-service./g'
# (sed -i '' is the macOS form; on Linux use sed -i)

# 4. Set image, ports, probe paths, resources and envConfig in
# charts/oan-my-service/values.yaml

# 5. Validate
./scripts/lint-charts.sh
helm template oan-my-service charts/oan-my-service
```

See [`charts/oan-common/README.md`](charts/oan-common/README.md) for the full
helper reference and
[`charts/oan-template/README.md`](charts/oan-template/README.md) for the
step-by-step adaptation guide.

## Validation

```bash
./scripts/lint-charts.sh
```

Runs `helm lint --strict` on every chart and `helm template` on every
application chart. CI runs the identical script
([`.github/workflows/helm-lint.yml`](.github/workflows/helm-lint.yml)) on pull
requests and on pushes to `main` and `development`.

Because charts depend on `oan-common` through `file://../oan-common` and the
packaged dependency is not committed, an edit to `oan-common` only reaches a
consuming chart after `helm dependency update charts/<chart>` — or a run of the
lint script, which does it for you.

## Conventions

Chart naming, `version`/`appVersion` rules, changelog requirements, what every
service chart must declare, and how secrets are handled are documented in
[`CONVENTIONS.md`](CONVENTIONS.md).

Two of those rules are enforced at render time rather than at review time: a
chart with empty `resources` fails to render, and so does an enabled probe with
no handler or with more than one.

## Secrets

No secret value belongs in this repository, and **no chart here renders a
Secret**. Charts reference Secrets by name; creating them is deliberately left
outside the charts, so that decision is made once rather than per chart. See
[`CONVENTIONS.md`](CONVENTIONS.md#secrets).
51 changes: 51 additions & 0 deletions charts/adapter-service/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Changelog

All notable changes to this chart are documented here.

The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this chart adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Changed

- Renamed from `network-adapter` to `adapter-service`, and generalised from one
adapter to all three (#2). provider, network and experience run the same image and
the same config format, so `role` now selects what differed between them
rather than each needing its own chart.
- `role` is required and validated against `provider|network|experience`. It has no
default: a default would hand one adapter another one's handler role and step
list, which renders, starts, reports Ready and then mis-handles every request.
- `handler.role` and `handler.steps` derive from `role` and are overridable.
`experience` gets `bap` and `[addRoute, sign]` — it sits inside the trust boundary
and takes unsigned requests, so it has no signature to validate. The other
two get `bpp` and `[validateSign, addRoute, sign]`.
- `discovery.url` replaced by `routing.rules`, a list. `provider` fans out to
several upstreams; a single target could not express that.
- Config placeholders renamed `__NETWORK_*` to `__ADAPTER_*`, and the routing
file to `routing-<role>.yaml`.
- `appName` and `otel.serviceName` default to `<role>-adapter` and
`oan-<role>-adapter`, matching the compose stack's service and OTEL names.
- `http.timeout` is now a value rather than hardcoded.

### Added

- `examples/{provider,network,experience}.yaml` — one values file per role.
- `ci/otel-ingress-values.yaml` now renders the `experience` role, so the role
branches that `ci/lint-values.yaml` (network) does not reach are covered.
- NOTES print the role, resolved step list and routing targets, and warn that
an Ingress on the `experience` role exposes an unauthenticated entry point.

## [0.1.0] - 2026-09-04

### Added

- Initial chart, modelled on the `network-adapter` service in
`docker-deployment/docker-compose.yml` (#2).
- Config rendered from a ConfigMap of placeholders plus an identity Secret,
substituted by an init container into an `emptyDir` — so the keypair is
never written to a ConfigMap and never appears in a process environment.
- Render-time failures for the five values whose absence would otherwise
produce a pod that runs, reports Ready, and does not work.
- Optional HPA, PodDisruptionBudget, Ingress and upstream readiness gates, all
off by default.
Loading
Loading