From 63d2510bcca6dc178d96f95b71354029645dabfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Jeanneret?= Date: Thu, 2 Apr 2026 09:34:17 +0200 Subject: [PATCH 1/2] refactor(secrets): add kustomize components tree Move vault-secrets-operator and external-secrets-operator manifests under components/secrets/. Keep resources/ paths as thin wrappers. Pin Argo CD remote kustomize component URLs with ?ref=feature/rhoso-apps-helm-chart. Add ESO Application CRs and extend docs for remote consumption. AI-Assist: Cursor; model=Composer; mode=agent; origin=cursor Made-with: Cursor --- .../external-secrets-operator-redhat.yaml | 23 +++++++++++++++ applications/external-secrets-operator.yaml | 23 +++++++++++++++ applications/vault-secrets-operator.yaml | 4 +-- components/secrets/README.md | 28 +++++++++++++++++++ .../community/kustomization.yaml | 5 ++++ .../community/subscription.yaml | 0 .../redhat/kustomization.yaml | 14 ++++++++++ .../redhat/namespace.yaml | 0 .../redhat/operatorgroup.yaml | 0 .../redhat/patch-subscription-redhat.json | 0 .../vault-secrets-operator/kustomization.yaml | 5 ++++ .../vault-secrets-operator/subscription.yaml | 0 resources/external-secrets-operator/README.md | 17 +++++++++-- .../community/kustomization.yaml | 5 ---- .../kustomization.yaml | 4 +-- .../redhat/kustomization.yaml | 10 +------ resources/vault-secrets-operator/README.md | 10 +++++++ .../vault-secrets-operator/kustomization.yaml | 4 +-- 18 files changed, 129 insertions(+), 23 deletions(-) create mode 100644 applications/external-secrets-operator-redhat.yaml create mode 100644 applications/external-secrets-operator.yaml create mode 100644 components/secrets/README.md create mode 100644 components/secrets/external-secrets-operator/community/kustomization.yaml rename {resources => components/secrets}/external-secrets-operator/community/subscription.yaml (100%) create mode 100644 components/secrets/external-secrets-operator/redhat/kustomization.yaml rename {resources => components/secrets}/external-secrets-operator/redhat/namespace.yaml (100%) rename {resources => components/secrets}/external-secrets-operator/redhat/operatorgroup.yaml (100%) rename {resources => components/secrets}/external-secrets-operator/redhat/patch-subscription-redhat.json (100%) create mode 100644 components/secrets/vault-secrets-operator/kustomization.yaml rename {resources => components/secrets}/vault-secrets-operator/subscription.yaml (100%) delete mode 100644 resources/external-secrets-operator/community/kustomization.yaml diff --git a/applications/external-secrets-operator-redhat.yaml b/applications/external-secrets-operator-redhat.yaml new file mode 100644 index 0000000..0080c72 --- /dev/null +++ b/applications/external-secrets-operator-redhat.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/sync-wave: "-10" + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground + name: subscribe-external-secrets-operator-redhat + namespace: openshift-gitops +spec: + destination: + server: https://kubernetes.default.svc + project: default + source: + kustomize: + components: + - https://github.com/openstack-k8s-operators/gitops/components/argocd/annotations?ref=feature/rhoso-apps-helm-chart + path: resources/external-secrets-operator/redhat + repoURL: https://github.com/openstack-k8s-operators/gitops.git + targetRevision: feature/rhoso-apps-helm-chart + syncPolicy: + automated: {} diff --git a/applications/external-secrets-operator.yaml b/applications/external-secrets-operator.yaml new file mode 100644 index 0000000..32fd6e9 --- /dev/null +++ b/applications/external-secrets-operator.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/sync-wave: "-10" + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground + name: subscribe-external-secrets-operator + namespace: openshift-gitops +spec: + destination: + server: https://kubernetes.default.svc + project: default + source: + kustomize: + components: + - https://github.com/openstack-k8s-operators/gitops/components/argocd/annotations?ref=feature/rhoso-apps-helm-chart + path: resources/external-secrets-operator + repoURL: https://github.com/openstack-k8s-operators/gitops.git + targetRevision: feature/rhoso-apps-helm-chart + syncPolicy: + automated: {} diff --git a/applications/vault-secrets-operator.yaml b/applications/vault-secrets-operator.yaml index 44b695e..a0cb4e8 100644 --- a/applications/vault-secrets-operator.yaml +++ b/applications/vault-secrets-operator.yaml @@ -15,9 +15,9 @@ spec: source: kustomize: components: - - https://github.com/openstack-k8s-operators/gitops/components/argocd/annotations + - https://github.com/openstack-k8s-operators/gitops/components/argocd/annotations?ref=feature/rhoso-apps-helm-chart path: resources/vault-secrets-operator repoURL: https://github.com/openstack-k8s-operators/gitops.git - targetRevision: HEAD + targetRevision: feature/rhoso-apps-helm-chart syncPolicy: automated: {} diff --git a/components/secrets/README.md b/components/secrets/README.md new file mode 100644 index 0000000..ae622fe --- /dev/null +++ b/components/secrets/README.md @@ -0,0 +1,28 @@ +# Secrets operator components + +Kustomize `Component` and overlay bases for Vault Secrets Operator (VSO) and External Secrets Operator (ESO). The matching [`resources/`](../../resources/) paths are thin wrappers so you can install from this repo with `oc apply -k resources/...` or compose only the component from another repository. + +Pin a Git revision on remote URLs (replace `BRANCH` with your branch or tag): + +- VSO: `https://github.com/openstack-k8s-operators/gitops/components/secrets/vault-secrets-operator?ref=BRANCH` +- ESO (community catalog): `https://github.com/openstack-k8s-operators/gitops/components/secrets/external-secrets-operator/community?ref=BRANCH` +- ESO (Red Hat overlay): use as a **base** (not `kind: Component`): `https://github.com/openstack-k8s-operators/gitops/components/secrets/external-secrets-operator/redhat?ref=BRANCH` + +Example overlay `kustomization.yaml` (VSO): + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: [] +components: + - https://github.com/openstack-k8s-operators/gitops/components/secrets/vault-secrets-operator?ref=feature/rhoso-apps-helm-chart +``` + +Example including the Red Hat ESO overlay as a resource: + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - https://github.com/openstack-k8s-operators/gitops/components/secrets/external-secrets-operator/redhat?ref=feature/rhoso-apps-helm-chart +``` diff --git a/components/secrets/external-secrets-operator/community/kustomization.yaml b/components/secrets/external-secrets-operator/community/kustomization.yaml new file mode 100644 index 0000000..f9f33bb --- /dev/null +++ b/components/secrets/external-secrets-operator/community/kustomization.yaml @@ -0,0 +1,5 @@ +--- +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - subscription.yaml diff --git a/resources/external-secrets-operator/community/subscription.yaml b/components/secrets/external-secrets-operator/community/subscription.yaml similarity index 100% rename from resources/external-secrets-operator/community/subscription.yaml rename to components/secrets/external-secrets-operator/community/subscription.yaml diff --git a/components/secrets/external-secrets-operator/redhat/kustomization.yaml b/components/secrets/external-secrets-operator/redhat/kustomization.yaml new file mode 100644 index 0000000..901ccab --- /dev/null +++ b/components/secrets/external-secrets-operator/redhat/kustomization.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - namespace.yaml + - operatorgroup.yaml +components: + - ../community +patches: + - path: patch-subscription-redhat.json + target: + kind: Subscription + name: external-secrets-operator + namespace: openshift-operators diff --git a/resources/external-secrets-operator/redhat/namespace.yaml b/components/secrets/external-secrets-operator/redhat/namespace.yaml similarity index 100% rename from resources/external-secrets-operator/redhat/namespace.yaml rename to components/secrets/external-secrets-operator/redhat/namespace.yaml diff --git a/resources/external-secrets-operator/redhat/operatorgroup.yaml b/components/secrets/external-secrets-operator/redhat/operatorgroup.yaml similarity index 100% rename from resources/external-secrets-operator/redhat/operatorgroup.yaml rename to components/secrets/external-secrets-operator/redhat/operatorgroup.yaml diff --git a/resources/external-secrets-operator/redhat/patch-subscription-redhat.json b/components/secrets/external-secrets-operator/redhat/patch-subscription-redhat.json similarity index 100% rename from resources/external-secrets-operator/redhat/patch-subscription-redhat.json rename to components/secrets/external-secrets-operator/redhat/patch-subscription-redhat.json diff --git a/components/secrets/vault-secrets-operator/kustomization.yaml b/components/secrets/vault-secrets-operator/kustomization.yaml new file mode 100644 index 0000000..f9f33bb --- /dev/null +++ b/components/secrets/vault-secrets-operator/kustomization.yaml @@ -0,0 +1,5 @@ +--- +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - subscription.yaml diff --git a/resources/vault-secrets-operator/subscription.yaml b/components/secrets/vault-secrets-operator/subscription.yaml similarity index 100% rename from resources/vault-secrets-operator/subscription.yaml rename to components/secrets/vault-secrets-operator/subscription.yaml diff --git a/resources/external-secrets-operator/README.md b/resources/external-secrets-operator/README.md index c503bf4..8ce4367 100644 --- a/resources/external-secrets-operator/README.md +++ b/resources/external-secrets-operator/README.md @@ -4,8 +4,10 @@ Subscribe to External Secrets Operator on OpenShift via Operator Lifecycle Manag ## Layout -- **`community/`** — default install: a single `Subscription` in `openshift-operators` from the **community-operators** catalog (`spec.channel: stable`). This is split into a `community` kustomization so the **`redhat/`** overlay can include it without tripping kustomize path or cycle restrictions (you cannot reference a parent directory that contains the overlay, or files outside the overlay path, from `redhat/`). -- **`redhat/`** — overlay that includes `community`, adds Namespace `external-secrets-operator` and an `OperatorGroup`, and applies a **JSON6902** patch to the community `Subscription` so it targets the Red Hat catalog (`openshift-external-secrets-operator`, `redhat-operators`, `stable-v1`), including `metadata.name` / `metadata.namespace` and stripping `metadata.labels`. Strategic merge does not reliably change Subscription identity fields; use RFC6902 for those edits. +Manifests live under [`components/secrets/external-secrets-operator/`](../../components/secrets/external-secrets-operator/) in this repository. The `resources/` paths here are thin entrypoints for `oc apply -k` and Argo CD. + +- **`components/.../community/`** — default install: a single `Subscription` in `openshift-operators` from the **community-operators** catalog (`spec.channel: stable`). Implemented as a `kind: Component` so the **`redhat/`** overlay can compose it without kustomize path cycles. +- **`components/.../redhat/`** — overlay that includes `community` as a component, adds Namespace `external-secrets-operator` and an `OperatorGroup`, and applies a **JSON6902** patch to the community `Subscription` so it targets the Red Hat catalog (`openshift-external-secrets-operator`, `redhat-operators`, `stable-v1`), including `metadata.name` / `metadata.namespace` and stripping `metadata.labels`. Strategic merge does not reliably change Subscription identity fields; use RFC6902 for those edits. ## Choose one catalog @@ -32,7 +34,16 @@ Point `spec.source.path` at: - `resources/external-secrets-operator` for the default (community) manifest, or - `resources/external-secrets-operator/redhat` for the Red Hat operator. -You can mirror [applications/vault-secrets-operator.yaml](https://github.com/openstack-k8s-operators/gitops/blob/main/applications/vault-secrets-operator.yaml) (sync-wave, repo URL, kustomize components) and set `path` accordingly. +Use pinned revisions and mirror the pattern in [`applications/external-secrets-operator.yaml`](https://github.com/openstack-k8s-operators/gitops/blob/feature/rhoso-apps-helm-chart/applications/external-secrets-operator.yaml) or [`applications/external-secrets-operator-redhat.yaml`](https://github.com/openstack-k8s-operators/gitops/blob/feature/rhoso-apps-helm-chart/applications/external-secrets-operator-redhat.yaml) (sync-wave, repo URL, `targetRevision`, `kustomize.components` with `?ref=` on remote component URLs). + +## Consuming as a component (remote) + +From another repo, reference the same content as `components` or `resources` with a **pinned** `ref` (use your branch or tag instead of `feature/rhoso-apps-helm-chart` after merge): + +- Community (Component): `https://github.com/openstack-k8s-operators/gitops/components/secrets/external-secrets-operator/community?ref=feature/rhoso-apps-helm-chart` +- Red Hat (Kustomization base; include under `resources:`): `https://github.com/openstack-k8s-operators/gitops/components/secrets/external-secrets-operator/redhat?ref=feature/rhoso-apps-helm-chart` + +See also [`components/secrets/README.md`](../../components/secrets/README.md). ## Links diff --git a/resources/external-secrets-operator/community/kustomization.yaml b/resources/external-secrets-operator/community/kustomization.yaml deleted file mode 100644 index e3e73e6..0000000 --- a/resources/external-secrets-operator/community/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - subscription.yaml diff --git a/resources/external-secrets-operator/kustomization.yaml b/resources/external-secrets-operator/kustomization.yaml index 04caaf0..8b48a2a 100644 --- a/resources/external-secrets-operator/kustomization.yaml +++ b/resources/external-secrets-operator/kustomization.yaml @@ -1,5 +1,5 @@ --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization -resources: - - community +components: + - ../../components/secrets/external-secrets-operator/community diff --git a/resources/external-secrets-operator/redhat/kustomization.yaml b/resources/external-secrets-operator/redhat/kustomization.yaml index e03bbdf..56fc358 100644 --- a/resources/external-secrets-operator/redhat/kustomization.yaml +++ b/resources/external-secrets-operator/redhat/kustomization.yaml @@ -2,12 +2,4 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - - ../community - - namespace.yaml - - operatorgroup.yaml -patches: - - path: patch-subscription-redhat.json - target: - kind: Subscription - name: external-secrets-operator - namespace: openshift-operators + - ../../../components/secrets/external-secrets-operator/redhat diff --git a/resources/vault-secrets-operator/README.md b/resources/vault-secrets-operator/README.md index d5f7d22..e43854d 100644 --- a/resources/vault-secrets-operator/README.md +++ b/resources/vault-secrets-operator/README.md @@ -1,3 +1,13 @@ # Vault Secrets Operator Subscribe to the Vault Secrets Operator on OpenShift. + +The subscription manifest lives under [`components/secrets/vault-secrets-operator/`](../../components/secrets/vault-secrets-operator/) in this repository. This `resources/` directory is a thin wrapper for `oc apply -k` and Argo CD (`applications/vault-secrets-operator.yaml`). + +## Consuming as a component (remote) + +Pin a Git revision (replace `BRANCH` with your branch or tag): + +`https://github.com/openstack-k8s-operators/gitops/components/secrets/vault-secrets-operator?ref=BRANCH` + +See [`components/secrets/README.md`](../../components/secrets/README.md). diff --git a/resources/vault-secrets-operator/kustomization.yaml b/resources/vault-secrets-operator/kustomization.yaml index e3e73e6..11f0234 100644 --- a/resources/vault-secrets-operator/kustomization.yaml +++ b/resources/vault-secrets-operator/kustomization.yaml @@ -1,5 +1,5 @@ --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization -resources: - - subscription.yaml +components: + - ../../components/secrets/vault-secrets-operator From cc0e53ae07f5aecc11c7a60a0b1a1b6b23d67183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Jeanneret?= Date: Tue, 24 Mar 2026 13:25:35 +0100 Subject: [PATCH 2/2] feat(charts): add rhoso-apps helm chart and ci Add Helm chart for Argo CD Applications (templates, values, values.schema.json), and a path-filtered GitHub Actions workflow (lint, template, package) with a TODO for publishing release artifacts. Refs: https://redhat.atlassian.net/browse/OSPRH-27658 AI-Assist: Cursor; model=Composer-2; mode=agent; origin=cursor Made-with: Cursor --- .github/workflows/helm-chart.yml | 72 ++++++++ .yamllint.yml | 2 + charts/rhoso-apps/.helmignore | 25 +++ charts/rhoso-apps/Chart.yaml | 25 +++ charts/rhoso-apps/README.md | 157 ++++++++++++++++++ charts/rhoso-apps/templates/_helpers.tpl | 86 ++++++++++ charts/rhoso-apps/templates/application.yaml | 24 +++ charts/rhoso-apps/tests/application_test.yaml | 148 +++++++++++++++++ charts/rhoso-apps/values.schema.json | 119 +++++++++++++ charts/rhoso-apps/values.yaml | 84 ++++++++++ 10 files changed, 742 insertions(+) create mode 100644 .github/workflows/helm-chart.yml create mode 100644 charts/rhoso-apps/.helmignore create mode 100644 charts/rhoso-apps/Chart.yaml create mode 100644 charts/rhoso-apps/README.md create mode 100644 charts/rhoso-apps/templates/_helpers.tpl create mode 100644 charts/rhoso-apps/templates/application.yaml create mode 100644 charts/rhoso-apps/tests/application_test.yaml create mode 100644 charts/rhoso-apps/values.schema.json create mode 100644 charts/rhoso-apps/values.yaml diff --git a/.github/workflows/helm-chart.yml b/.github/workflows/helm-chart.yml new file mode 100644 index 0000000..73eb3ef --- /dev/null +++ b/.github/workflows/helm-chart.yml @@ -0,0 +1,72 @@ +--- +# Validate charts/rhoso-apps: lint (incl. values.schema.json), helm-unittest, +# kubeconform on rendered CRs, package. +# TODO: When release process is defined, persist and publish the chart artifact +# (rhoso-apps-.tgz from `helm package`)—e.g. GitHub Release asset, Helm +# HTTP repo, or OCI registry—for downloadable installs. +name: helm-chart +permissions: + contents: read +on: # yamllint disable-line rule:truthy + pull_request: + branches: + - main + paths: + - "charts/**" + - ".github/workflows/helm-chart.yml" + push: + branches: + - main + paths: + - "charts/**" + - ".github/workflows/helm-chart.yml" +jobs: + validate: + runs-on: ubuntu-latest + env: + # Pin tool versions (kubeconform: https://github.com/yannh/kubeconform/releases) + KUBECONFORM_VERSION: v0.6.7 + # helm-unittest plugin: https://github.com/helm-unittest/helm-unittest/releases + HELM_UNITTEST_VERSION: "0.7.0" + # Kubernetes OpenAPI for built-in kinds; Argo Application uses Datree CRDs-catalog. + KUBERNETES_SCHEMA_VERSION: "1.29.0" + defaults: + run: + working-directory: charts/rhoso-apps + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Helm + uses: azure/setup-helm@v4 + with: + version: v3.16.3 + + - name: Install helm-unittest plugin + run: helm plugin install https://github.com/helm-unittest/helm-unittest.git --version "${HELM_UNITTEST_VERSION}" + + - name: Install kubeconform + run: | + set -euo pipefail + mkdir -p "${HOME}/.local/bin" + curl -sSL "https://github.com/yannh/kubeconform/releases/download/${KUBECONFORM_VERSION}/kubeconform-linux-amd64.tar.gz" | tar xz -C /tmp + mv /tmp/kubeconform "${HOME}/.local/bin/kubeconform" + echo "${HOME}/.local/bin" >> "${GITHUB_PATH}" + + - name: Helm lint + run: helm lint . -f values.yaml + + - name: Helm unittest + run: helm unittest . + + - name: Helm template (kubeconform) + run: | + set -euo pipefail + helm template rhoso-apps-test . -f values.yaml | kubeconform -summary \ + -kubernetes-version "${KUBERNETES_SCHEMA_VERSION}" \ + -schema-location default \ + -schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json' + + # Produces rhoso-apps-*.tgz; publishing is TODO until release workflow exists (see file header). + - name: Helm package + run: helm package . diff --git a/.yamllint.yml b/.yamllint.yml index f783856..a89b1b2 100644 --- a/.yamllint.yml +++ b/.yamllint.yml @@ -5,6 +5,8 @@ ignore: - '*.env' - '*.txt' - '*.sh' + # Helm templates are not valid YAML until rendered (Go templating). + - 'charts/**/templates/**' rules: line-length: diff --git a/charts/rhoso-apps/.helmignore b/charts/rhoso-apps/.helmignore new file mode 100644 index 0000000..8709d2e --- /dev/null +++ b/charts/rhoso-apps/.helmignore @@ -0,0 +1,25 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ +# helm-unittest suites (not part of the packaged chart) +tests/ diff --git a/charts/rhoso-apps/Chart.yaml b/charts/rhoso-apps/Chart.yaml new file mode 100644 index 0000000..151d7df --- /dev/null +++ b/charts/rhoso-apps/Chart.yaml @@ -0,0 +1,25 @@ +--- +apiVersion: v2 +name: rhoso-apps +description: Create and manage argocd applications to deploy RHOSO + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "18.0.17" diff --git a/charts/rhoso-apps/README.md b/charts/rhoso-apps/README.md new file mode 100644 index 0000000..6ceb997 --- /dev/null +++ b/charts/rhoso-apps/README.md @@ -0,0 +1,157 @@ +# rhoso-apps Helm chart + +This chart renders Argo CD `Application` resources to deploy Red Hat OpenStack Services on OpenShift (RHOSO) and related manifests from Git. Chart-wide defaults apply to every rendered application; each entry under `applications` is optional and can be toggled or overridden independently. + +## Chart-wide values + +| Key | Type | Description | +|-----|------|-------------| +| `applicationNamespace` | string | Namespace for the Argo CD `Application` CRs (`metadata.namespace`). Default: `openshift-gitops`. | +| `destinationServer` | string | `spec.destination.server` for every application. Default: `https://kubernetes.default.svc`. | + +This chart does not set `spec.destination.namespace`; only `destination.server` is set (from `destinationServer`). + +## Per-application keys (`applications.`) + +Each `` is a unique key (DNS-1123). Set `enabled: true` to render that `Application`; set `enabled: false` to skip it. + +| Key | Type | Description | +|-----|------|-------------| +| `enabled` | bool | If `true`, render an `Application` CR; if `false`, skip. | +| `repoURL` | string | `spec.source.repoURL` (Git URL). | +| `path` | string | Directory in the repo; empty uses default `"."`. | +| `targetRevision` | string | Branch, tag, or commit; empty uses default `"HEAD"`. | +| `syncWave` | string | `argocd.argoproj.io/sync-wave` annotation. | +| `syncOptions` | list | Optional strings merged into `spec.syncPolicy.syncOptions` (for example `Prune=true`). | +| `kustomize` | map | Optional; passed to `spec.source.kustomize` (`namePrefix`, `patches`, `components`, etc.). See [Argo CD Kustomize](https://argo-cd.readthedocs.io/en/stable/user-guide/kustomize/). | +| `finalizers` | list | `metadata.finalizers` (Argo CD resources finalizer). Valid: `resources-finalizer.argocd.argoproj.io/background` or `.../foreground`. Omit to use chart default (background). | +| `project` | string | Argo CD `AppProject`; default `default` if unset. | +| `syncPolicy` | map | Merged with `syncOptions` into `spec.syncPolicy`. | + +### Adding a new application + +Copy a block under `applications`, choose a unique key, set `enabled: true`, and set `repoURL`, `path`, and `targetRevision` as needed. + +### Default applications (from `values.yaml`) + +These entries ship enabled by default; each has a `syncWave` that defines Argo CD apply order (lower waves first). + +| Application | Purpose (summary) | Default `syncWave` | +|-------------|---------------------|--------------------| +| `operator-dependencies` | MetalLB, nmstate, cert-manager | `-20` | +| `openstack-operator` | OpenStack operator | `-20` | +| `openstack-operator-cr` | Main OpenStack custom resource | `-15` | +| `openstack-secrets` | Vault secrets operator | `-10` | +| `openstack-networks` | Control plane and dataplane networks | `0` | +| `openstack-controlplane` | `OpenStackControlPlane` | `10` | +| `openstack-dataplane` | Data plane node set and deployment | `20` | + +## Default application ordering (sync waves) + +Replace the placeholder below with a diagram of the default sync-wave ordering for the applications listed in `values.yaml`. + +```mermaid +flowchart TD +A["operator-dependencies (-20)"] --> C["openstack-operator-cr (-15)"] +B["openstack-operator (-20)"] --> C["openstack-operator-cr (-15)"] +C --> D["openstack-secrets (-10)"] +D --> E["openstack-networks (0)"] +E --> F["openstack-controlplane (10)"] +F --> G["openstack-dataplane (20)"] +``` + +## Layered values and partial overrides + +Helm merges values files left to right: later files override earlier ones. Keep a **base** `values.yaml` (or your fork of the chart defaults) and add **environment** files that only change what differs (for example one Git revision, one path, or a single application). + +### Install with base + environment file + +```bash +helm install deploy-rhoso . \ + -f values.yaml \ + -f values-prod.yaml +``` + +Use any release name and paths; `values-prod.yaml` can be minimal. + +### Example: override Git revision for all apps that share defaults + +`values-revision.yaml`: + +```yaml +applications: + operator-dependencies: + targetRevision: main + openstack-operator: + targetRevision: main + openstack-operator-cr: + targetRevision: main + openstack-secrets: + targetRevision: main + openstack-networks: + targetRevision: main + openstack-controlplane: + targetRevision: main + openstack-dataplane: + targetRevision: main +``` + +```bash +helm template deploy-rhoso . -f values.yaml -f values-revision.yaml +``` + +### Example: change only one application + +Disable or repoint a single app without repeating the rest of `values.yaml`: + +`values-disable-dataplane.yaml`: + +```yaml +applications: + openstack-dataplane: + enabled: false +``` + +`values-custom-controlplane-path.yaml`: + +```yaml +applications: + openstack-controlplane: + path: environments/prod/controlplane + targetRevision: v1.2.3 +``` + +```bash +helm install deploy-rhoso . -f values.yaml -f values-custom-controlplane-path.yaml +``` + +### Example: Kustomize overrides for one application + +`values-dev-prefix.yaml`: + +```yaml +applications: + openstack-networks: + kustomize: + namePrefix: dev- +``` + +### Example: chart-wide + per-app in one overlay + +`values-staging.yaml`: + +```yaml +destinationServer: https://kubernetes.default.svc +applications: + openstack-operator: + targetRevision: staging + openstack-controlplane: + syncWave: "15" +``` + +Later keys win for the same path; unspecified keys under `applications.` keep values from `values.yaml`. + +## See also + +- [Argo CD Application specification](https://argo-cd.readthedocs.io/en/stable/operator-manual/application-specification/) +- Chart templates: `templates/application.yaml`, `templates/_helpers.tpl` diff --git a/charts/rhoso-apps/templates/_helpers.tpl b/charts/rhoso-apps/templates/_helpers.tpl new file mode 100644 index 0000000..44ea23c --- /dev/null +++ b/charts/rhoso-apps/templates/_helpers.tpl @@ -0,0 +1,86 @@ +{{/* +Namespace for Argo CD Application CRs (metadata.namespace). +Pass root context ($) from inside range. +*/}} +{{- define "rhoso-apps.applicationNamespace" -}} +{{- default "openshift-gitops" .Values.applicationNamespace | quote -}} +{{- end }} + +{{/* +Default Kubernetes API server URL for spec.destination.server. +Pass root context ($) from inside range. +*/}} +{{- define "rhoso-apps.destinationServer" -}} +{{- default "https://kubernetes.default.svc" .Values.destinationServer | quote -}} +{{- end }} + +{{/* +Argo CD AppProject name; empty string in values maps to "default". +Pass dict with key "app" (per-application values map). +*/}} +{{- define "rhoso-apps.argocdProject" -}} +{{- $app := .app -}} +{{- default "default" $app.project | quote -}} +{{- end }} + +{{/* +Repository path under spec.source.path. +*/}} +{{- define "rhoso-apps.sourcePath" -}} +{{- $app := .app -}} +{{- default "." $app.path | quote -}} +{{- end }} + +{{/* +Git revision, branch, or tag for spec.source.targetRevision. +*/}} +{{- define "rhoso-apps.targetRevision" -}} +{{- $app := .app -}} +{{- default "HEAD" $app.targetRevision | quote -}} +{{- end }} + +{{/* +Optional spec.source.kustomize (Argo CD Kustomize overrides). +Pass dict with key "app" (per-application values map). Omitted if unset, non-map, or empty map. +*/}} +{{- define "rhoso-apps.sourceKustomize" -}} +{{- $app := .app -}} +{{- $k := $app.kustomize | default dict }} +{{- if not (kindIs "map" $k) }} +{{- $k = dict }} +{{- end }} +{{- if not (empty $k) }} + kustomize: +{{ toYaml $k | nindent 6 }} +{{- end }} +{{- end }} + +{{/* +Merge syncPolicy map with optional syncOptions; emit spec.syncPolicy block or nothing. +Pass dict with key "app" (per-application values map). +*/}} +{{- define "rhoso-apps.syncPolicySpec" -}} +{{- $app := .app -}} +{{- $merged := $app.syncPolicy | default dict }} +{{- if not (kindIs "map" $merged) }} +{{- $merged = dict }} +{{- end }} +{{- if and $app.syncOptions (not (empty $app.syncOptions)) }} +{{- $merged = merge $merged (dict "syncOptions" $app.syncOptions) }} +{{- end }} +{{- if not (empty $merged) }} + syncPolicy: +{{ toYaml $merged | indent 4 }} +{{- end }} +{{- end }} + +{{/* +Argo CD Application metadata.finalizers (resources finalizer: background vs foreground). +Omitted finalizers default to background deletion. +Pass dict with key "app" (per-application values map). +*/}} +{{- define "rhoso-apps.applicationFinalizers" -}} +{{- $app := .app -}} +{{- $f := default (list "resources-finalizer.argocd.argoproj.io/background") $app.finalizers }} +{{- toYaml $f -}} +{{- end }} diff --git a/charts/rhoso-apps/templates/application.yaml b/charts/rhoso-apps/templates/application.yaml new file mode 100644 index 0000000..95ec21e --- /dev/null +++ b/charts/rhoso-apps/templates/application.yaml @@ -0,0 +1,24 @@ +{{- range $name, $app := .Values.applications }} +{{- if $app.enabled }} +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: {{ $name }} + namespace: {{ include "rhoso-apps.applicationNamespace" $ }} + finalizers: +{{- include "rhoso-apps.applicationFinalizers" (dict "app" $app) | nindent 4 }} + annotations: + argocd.argoproj.io/sync-wave: {{ $app.syncWave | quote }} +spec: + project: {{ include "rhoso-apps.argocdProject" (dict "app" $app) }} + source: + repoURL: {{ $app.repoURL | quote }} + path: {{ include "rhoso-apps.sourcePath" (dict "app" $app) }} + targetRevision: {{ include "rhoso-apps.targetRevision" (dict "app" $app) }} +{{ include "rhoso-apps.sourceKustomize" (dict "app" $app) }} + destination: + server: {{ include "rhoso-apps.destinationServer" $ }} +{{ include "rhoso-apps.syncPolicySpec" (dict "app" $app) }} +{{- end }} +{{- end }} diff --git a/charts/rhoso-apps/tests/application_test.yaml b/charts/rhoso-apps/tests/application_test.yaml new file mode 100644 index 0000000..e05ff40 --- /dev/null +++ b/charts/rhoso-apps/tests/application_test.yaml @@ -0,0 +1,148 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: rhoso-apps application template +templates: + - application.yaml +tests: + # Helm merges values; we cannot replace the whole applications map from tests. + # Assert on one real Application from values.yaml via documentSelector. + - it: renders openstack-controlplane Application from default values + values: + - ../values.yaml + documentSelector: + path: metadata.name + value: openstack-controlplane + asserts: + - isKind: + of: Application + - equal: + path: apiVersion + value: argoproj.io/v1alpha1 + - equal: + path: metadata.name + value: openstack-controlplane + - equal: + path: metadata.namespace + value: openshift-gitops + - equal: + path: metadata.finalizers[0] + value: resources-finalizer.argocd.argoproj.io/foreground + - equal: + path: metadata.annotations["argocd.argoproj.io/sync-wave"] + value: "10" + - equal: + path: spec.project + value: default + - equal: + path: spec.source.repoURL + value: https://github.com/openstack-k8s-operators/gitops + - equal: + path: spec.source.path + value: example/controlplane + - equal: + path: spec.source.targetRevision + value: v0.1.0 + - equal: + path: spec.destination.server + value: https://kubernetes.default.svc + - equal: + path: spec.syncPolicy.syncOptions[0] + value: Prune=true + + - it: renders operator-dependencies with default background finalizer + values: + - ../values.yaml + documentSelector: + path: metadata.name + value: operator-dependencies + asserts: + - equal: + path: metadata.finalizers[0] + value: resources-finalizer.argocd.argoproj.io/background + + - it: omits spec.source.kustomize when not set in values + values: + - ../values.yaml + documentSelector: + path: metadata.name + value: operator-dependencies + asserts: + - notExists: + path: spec.source.kustomize + + - it: renders spec.source.kustomize when applications entry sets kustomize + set: + applicationNamespace: openshift-gitops + destinationServer: https://kubernetes.default.svc + applications: + kustom-test: + enabled: true + repoURL: https://github.com/example/repo + path: examples/foo + targetRevision: main + syncWave: "0" + syncOptions: + - Prune=true + kustomize: + namePrefix: dev- + components: + - https://github.com/example/components/overlay + documentSelector: + path: metadata.name + value: kustom-test + asserts: + - equal: + path: spec.source.kustomize.namePrefix + value: dev- + - equal: + path: spec.source.kustomize.components[0] + value: https://github.com/example/components/overlay + + - it: fails values schema when repoURL is missing + set: + applicationNamespace: openshift-gitops + destinationServer: https://kubernetes.default.svc + applications: + bad: + enabled: true + path: "." + targetRevision: main + syncWave: "0" + syncOptions: [] + asserts: + - failedTemplate: + errorPattern: repoURL + + - it: fails values schema when destinationServer is not an https URI + set: + applicationNamespace: openshift-gitops + destinationServer: http://insecure.example + applications: + a: + enabled: true + repoURL: https://github.com/example/repo + path: "." + targetRevision: main + syncWave: "0" + syncOptions: [] + asserts: + - failedTemplate: + errorPattern: destinationServer + + - it: fails values schema when finalizer is not allowed + set: + applicationNamespace: openshift-gitops + destinationServer: https://kubernetes.default.svc + applications: + bad: + enabled: true + repoURL: https://github.com/example/repo + path: "." + targetRevision: main + syncWave: "0" + syncOptions: [] + finalizers: + - resources-finalizer.argocd.argoproj.io/invalid + asserts: + - failedTemplate: + errorPattern: finalizers diff --git a/charts/rhoso-apps/values.schema.json b/charts/rhoso-apps/values.schema.json new file mode 100644 index 0000000..56f8cb2 --- /dev/null +++ b/charts/rhoso-apps/values.schema.json @@ -0,0 +1,119 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://github.com/openstack-k8s-operators/gitops/charts/rhoso-apps/values.schema.json", + "title": "rhoso-apps Helm chart values", + "description": "Validated against templates/ and the documentation block in values.yaml.", + "type": "object", + "required": [ + "applicationNamespace", + "destinationServer", + "applications" + ], + "additionalProperties": false, + "properties": { + "applicationNamespace": { + "type": "string", + "minLength": 1, + "description": "Namespace for Argo CD Application CRs (metadata.namespace).", + "pattern": "^[a-z0-9]([-a-z0-9]*[a-z0-9])?$" + }, + "destinationServer": { + "type": "string", + "minLength": 1, + "description": "Kubernetes API server URL for spec.destination.server.", + "format": "uri", + "pattern": "^https://" + }, + "applications": { + "type": "object", + "minProperties": 1, + "description": "Map of Application name to Argo CD Application settings.", + "propertyNames": { + "description": "DNS-1123 label: lowercase alphanumeric and hyphens (e.g. openstack-operator-cr).", + "pattern": "^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?$" + }, + "additionalProperties": { + "$ref": "#/definitions/application" + } + } + }, + "definitions": { + "application": { + "type": "object", + "description": "Per-application values under applications..", + "required": [ + "enabled", + "repoURL", + "path", + "targetRevision", + "syncWave", + "syncOptions" + ], + "additionalProperties": false, + "properties": { + "enabled": { + "type": "boolean", + "description": "If true, render an Application CR." + }, + "repoURL": { + "type": "string", + "minLength": 1, + "description": "Git repository URL for spec.source.repoURL.", + "format": "uri", + "pattern": "^https://" + }, + "path": { + "type": "string", + "description": "Path inside the repo; empty string uses chart default '.'." + }, + "targetRevision": { + "type": "string", + "description": "Branch, tag, or commit; empty string uses chart default 'HEAD'." + }, + "syncWave": { + "type": "string", + "description": "Value for argocd.argoproj.io/sync-wave annotation." + }, + "syncOptions": { + "type": "array", + "description": "Argo CD sync option strings merged into spec.syncPolicy.syncOptions.", + "minItems": 0, + "items": { + "type": "string", + "minLength": 1 + } + }, + "project": { + "type": "string", + "description": "Optional Argo CD AppProject; default in chart is 'default' if omitted." + }, + "syncPolicy": { + "type": "object", + "description": "Optional map merged with syncOptions into spec.syncPolicy.", + "additionalProperties": true + }, + "kustomize": { + "type": "object", + "description": "Optional Argo CD spec.source.kustomize overrides (see Argo CD Kustomize user guide).", + "additionalProperties": true + }, + "finalizers": { + "type": "array", + "description": "Argo CD Application metadata.finalizers (resources finalizer). Omit to use chart default (background).", + "default": [ + "resources-finalizer.argocd.argoproj.io/background" + ], + "minItems": 1, + "maxItems": 1, + "items": { + "type": "string", + "enum": [ + "resources-finalizer.argocd.argoproj.io/background", + "resources-finalizer.argocd.argoproj.io/foreground" + ] + } + } + } + } + } +} diff --git a/charts/rhoso-apps/values.yaml b/charts/rhoso-apps/values.yaml new file mode 100644 index 0000000..30a7225 --- /dev/null +++ b/charts/rhoso-apps/values.yaml @@ -0,0 +1,84 @@ +--- +# Parameter documentation: charts/rhoso-apps/README.md +applicationNamespace: openshift-gitops +destinationServer: https://kubernetes.default.svc +applications: + # Deploy and initialize MetalLB, nmstate, cert-manager. + # This covers "Planning your deployment - chapter 3.1.3" + # https://docs.redhat.com/en/documentation/red_hat_openstack_services_on_openshift/18.0/html/planning_your_deployment/assembly_infrastructure-and-system-requirements#ref_RHOCP-software-requirements_planning + operator-dependencies: + enabled: true + path: "example/dependencies" + repoURL: https://github.com/openstack-k8s-operators/gitops + syncOptions: + - Prune=true + syncWave: "-20" + targetRevision: v0.1.0 + # Deploy openstack-operator. + # This covers "Deploying RHOSO - chapter 1" + # https://docs.redhat.com/en/documentation/red_hat_openstack_services_on_openshift/18.0/html/deploying_red_hat_openstack_services_on_openshift/assembly_installing-and-preparing-the-openstack-operator + openstack-operator: + enabled: true + path: "TODO" + repoURL: https://github.com/openstack-k8s-operators/gitops + syncOptions: + - Prune=true + syncWave: "-20" + targetRevision: v0.1.0 + # Create the main OpenStack Custom Resource. + # This covers "Deploying RHOSO - chapter 1" + # https://docs.redhat.com/en/documentation/red_hat_openstack_services_on_openshift/18.0/html/deploying_red_hat_openstack_services_on_openshift/assembly_installing-and-preparing-the-openstack-operator + openstack-operator-cr: + enabled: true + path: "TODO" + repoURL: https://github.com/openstack-k8s-operators/gitops + syncOptions: + - Prune=true + syncWave: "-15" + targetRevision: v0.1.0 + # Deploy and configure vault-secrets operator. + # This covers "Deploying RHOSO - chapter 2.3" + # https://docs.redhat.com/en/documentation/red_hat_openstack_services_on_openshift/18.0/html/deploying_red_hat_openstack_services_on_openshift/assembly_preparing-rhocp-for-rhoso#proc_providing-secure-access-to-the-RHOSO-services_preparing + openstack-secrets: + enabled: true + path: "TODO" + repoURL: https://github.com/openstack-k8s-operators/gitops + syncOptions: + - Prune=true + syncWave: "-10" + targetRevision: v0.1.0 + # Create underlying networks for controlplane and dataplane. + # Covers "Deploying RHOSO - chapter 3" + # https://docs.redhat.com/en/documentation/red_hat_openstack_services_on_openshift/18.0/html/deploying_red_hat_openstack_services_on_openshift/assembly_preparing-rhoso-networks_preparing + openstack-networks: + enabled: true + path: "TODO" + repoURL: https://github.com/openstack-k8s-operators/gitops + syncOptions: + - Prune=true + syncWave: "0" + targetRevision: v0.1.0 + # Deploy and configure OpenStackControlPlane resource. + # Covers "Deploying RHOSO - chapter 4" + # https://docs.redhat.com/en/documentation/red_hat_openstack_services_on_openshift/18.0/html/deploying_red_hat_openstack_services_on_openshift/assembly_creating-the-control-plane + openstack-controlplane: + enabled: true + path: "example/controlplane" + repoURL: https://github.com/openstack-k8s-operators/gitops + finalizers: + - resources-finalizer.argocd.argoproj.io/foreground + syncOptions: + - Prune=true + syncWave: "10" + targetRevision: v0.1.0 + # Deploy and configure OpenStackDataPlaneNodeSet and OpenStackDataPlaneDeployment resources. + # Covers "Deploying RHOSO - chapter 5" + # https://docs.redhat.com/en/documentation/red_hat_openstack_services_on_openshift/18.0/html/deploying_red_hat_openstack_services_on_openshift/assembly_creating-the-data-plane + openstack-dataplane: + enabled: true + path: "example/dataplane" + repoURL: https://github.com/openstack-k8s-operators/gitops + syncOptions: + - Prune=true + syncWave: "20" + targetRevision: v0.1.0