diff --git a/.github/workflows/helm-chart.yml b/.github/workflows/helm-chart.yml new file mode 100644 index 0000000..42cae19 --- /dev/null +++ b/.github/workflows/helm-chart.yml @@ -0,0 +1,102 @@ +--- +# 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 + # Tool download integrity: linux amd64 only (matches ubuntu-latest). + # + # The SHA256 values below are committed so CI checks the *downloaded* file + # against a maintainer-approved hash (bump + review in git). This catches + # in-transit tampering, wrong file/download errors, and accidental URL + # mistakes; it does not replace "do we trust the upstream project?" (record + # a new hash when you accept a new release). + # + # Bumping kubeconform: + # 1. Set KUBECONFORM_VERSION to the new tag (e.g. v0.6.7). + # 2. Open that release, download CHECKSUMS; copy the sha256 for + # kubeconform-linux-amd64.tar.gz into KUBECONFORM_SHA256 (or run + # sha256sum on that file on a trusted host). + # + # helm-unittest: pinned by Git tag (no release tarball checksum). Bump + # HELM_UNITTEST_VERSION to a published tag, then + # helm plugin install https://github.com/helm-unittest/helm-unittest.git --version + # so CI always installs that ref (not floating main). + # + # Kubeconform: linux-amd64 only below; if the job is moved to arm64, add new + # KUBECONFORM_SHA256 (or a matrix). + env: + KUBECONFORM_VERSION: v0.6.7 + KUBECONFORM_SHA256: 95f14e87aa28c09d5941f11bd024c1d02fdc0303ccaa23f61cef67bc92619d73 + HELM_UNITTEST_VERSION: v0.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 + # Avoid job default charts/rhoso-apps cwd (plugin hooks can be cwd-sensitive). + working-directory: ${{ github.workspace }} + run: | + set -euo pipefail + helm plugin install https://github.com/helm-unittest/helm-unittest.git --version "${HELM_UNITTEST_VERSION}" + + - name: Install kubeconform + working-directory: ${{ github.workspace }} + run: | + set -euo pipefail + mkdir -p "${HOME}/.local/bin" + tgz="/tmp/kubeconform-linux-amd64.tar.gz" + curl -fsSL -o "${tgz}" \ + "https://github.com/yannh/kubeconform/releases/download/${KUBECONFORM_VERSION}/kubeconform-linux-amd64.tar.gz" + printf '%s %s\n' "${KUBECONFORM_SHA256}" "${tgz}" | sha256sum -c - + tar xzf "${tgz}" -C /tmp + mv /tmp/kubeconform "${HOME}/.local/bin/kubeconform" + echo "${HOME}/.local/bin" >> "${GITHUB_PATH}" + rm -f "${tgz}" + + - 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..814cf8a --- /dev/null +++ b/charts/rhoso-apps/Chart.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: v2 +name: rhoso-apps +description: Create and manage argocd applications to deploy RHOSO +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..66b646f --- /dev/null +++ b/charts/rhoso-apps/README.md @@ -0,0 +1,243 @@ +# 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. + +## Basic usage + +From the chart directory (for example `charts/rhoso-apps`), install with the bundled `values.yaml` and a release name of your choice: + +```bash +helm install deploy-rhoso . -f values.yaml +``` + +To render manifests without applying (for example to inspect or pipe to a file): + +```bash +helm template deploy-rhoso . -f values.yaml +``` + +Defaults for `applications` and global settings are defined in `values.yaml`. Use additional `-f` files to layer environment-specific overrides; see [Advanced usage and examples](#advanced-usage-and-examples). + +## 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. Optional; the chart default is `0` in the rendered manifest when unset. | +| `syncOptions` | list | Optional strings for `spec.syncPolicy.syncOptions` (for example `Prune=true`). Used when `syncPolicy` is not set, or is an empty map: if you set a **non-empty** `syncPolicy`, top-level `syncOptions` is **ignored** (put options under `syncPolicy.syncOptions` instead). | +| `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 | When non-empty, this map **is** `spec.syncPolicy` (including `automated` and nested `syncOptions`, etc.). Set `automated` (with optional `prune` / `selfHeal`) for [automatic sync](https://argo-cd.readthedocs.io/en/stable/user-guide/auto_sync/). In that case top-level `syncOptions` from this chart is ignored, including values inherited from `values.yaml` overlays. | + +### Adding a new application + +Copy a block under `applications`, choose a unique key, set `enabled: true`, and set `repoURL`, `path`, and `targetRevision` as needed. + +## Advanced usage and examples + +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). In the YAML snippets below, string values use double quotes; booleans and other non-string scalars are left unquoted. + +**Contents:** [Install with base + environment file](#install-with-base-environment-file) · [Scaling out on Day 2](#example-scaling-out-on-day-2-gitops-friendly) · [Override Git revision](#example-override-git-revision-for-all-apps-that-share-defaults) · [Change one application](#example-change-only-one-application) · [Automated sync](#example-automated-sync-for-one-application) · [Kustomize overrides](#example-kustomize-overrides-for-one-application) · [Chart-wide + per-app overlay](#example-chart-wide-per-app-in-one-overlay) + +### 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: scaling out on Day 2 (GitOps-friendly) + +Commit the scaled dataplane manifests under a dedicated directory in your app repo, then repoint the `openstack-dataplane` application to that path. The chart only changes the Argo CD `Application` source; Git remains the source of truth for the actual scale change. + +`values-scale-out.yaml`: + +```yaml +applications: + openstack-dataplane: + path: "environments/cluster01/scaling-2026-04-01" +``` + +```bash +helm upgrade deploy-rhoso . -f values.yaml -f values-prod.yaml -f values-scale-out.yaml +``` + +### 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: automated sync for one application + +The default `values.yaml` does not set `spec.syncPolicy.automated`; Argo CD stays on manual sync until you add it. Set `syncPolicy.automated` on an application to enable automatic sync, pruning, and self-heal. The chart sets `spec.syncPolicy` from the `syncPolicy` value when it is a non-empty map, and does **not** apply top-level `syncOptions` in that case—so chart defaults like `Prune=true` on that app are not merged in unless you add them under `syncPolicy.syncOptions` yourself. + +`values-automated-operator-deps.yaml`: + +```yaml +applications: + operator-dependencies: + syncPolicy: + automated: + prune: true + selfHeal: true +``` + +If you need `spec.syncPolicy.syncOptions` (for example `Prune=true`) while using `syncPolicy`, list them under `syncPolicy.syncOptions` rather than only at the top level. + +```bash +helm upgrade deploy-rhoso . -f values.yaml -f values-automated-operator-deps.yaml +``` + +### Example: Kustomize overrides for one application + +`values-dev-prefix.yaml`: + +```yaml +applications: + openstack-networks: + kustomize: + namePrefix: "dev-" +``` + +```bash +helm upgrade deploy-rhoso . -f values.yaml -f values-dev-prefix.yaml +``` + +### 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`. + +## Default applications (from `values.yaml`) + +These entries ship enabled by default; each has a `syncWave` that defines Argo CD apply order (lower waves first). + +Install and configure `vault-secrets-operator` or `external-secrets-operator` in `operator-dependencies`. The `openstack-secrets` +application is a later wave: manifests that create cluster secrets by syncing from the secure backend (for example +`VaultStaticSecret` or ExternalSecret resources), not deployment of the secrets operator itself. + +### `openstack-secrets` path + +The chart default uses a placeholder `path` (`TODO` in `values.yaml`) so the structure is visible. Before relying on this Application in a real cluster, set `path` to a directory in **your** Git repository that contains manifests which sync cluster secrets from your secure store (for example Vault StaticSecrets or ExternalSecrets). Until that path is valid, expect **only** the `openstack-secrets` Application to fail in Argo CD; other Applications from this chart are unchanged. You may set `enabled: false` under `applications.openstack-secrets` until the path is ready. + +| Application | Purpose (summary) | Default `syncWave` | +|-------------|---------------------|--------------------| +| `operator-dependencies` | MetalLB, nmstate, cert-manager; VSO or ESO install | `-20` | +| `openstack-operator` | OpenStack operator | `-20` | +| `openstack-operator-cr` | Main OpenStack custom resource | `-15` | +| `openstack-secrets` | Cluster secrets from secure backend (configure `path`) | `-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) + +```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)"] +``` + +## Lifecycle management + +### Upgrading and Day-2 operations + +When updating an existing deployment (for example changing `path` or `targetRevision` for a specific application), **re-pass every values file** used during the initial install so the release stays aligned with your Git source of truth. + +```bash +helm upgrade deploy-rhoso . \ + -f values.yaml \ + -f values-custom.yaml \ + -f values-upgrade-01.yaml +``` + +**`--reuse-values`:** Helm can merge new overrides with values stored in the cluster. Use that flag with care: it can leave **ghost values** (old settings you meant to remove) or miss new chart defaults after a chart version bump. + +**Argo CD sync notice:** This chart only updates Argo CD `Application` manifests. After `helm upgrade`, confirm in the Argo CD UI (or CLI) that child applications (for example `openstack-controlplane`) sync to the new `targetRevision` or `path`. + +## See also + +This README describes this Helm chart: values, rendered Argo CD `Application` manifests, and install or upgrade patterns. Broader operations—rollback strategy, disaster recovery, backup and restore, or adopting existing clusters in Argo CD—are out of scope here; use your platform, OpenShift GitOps, and product documentation for those topics. + +- [Argo CD Application specification](https://argo-cd.readthedocs.io/en/stable/operator-manual/application-specification/) +- [Red Hat OpenShift GitOps documentation](https://docs.redhat.com/en/documentation/red_hat_openshift_gitops/) +- [Working with Helm charts](https://docs.redhat.com/en/documentation/openshift_container_platform/4.18/html/building_applications/working-with-helm-charts) (OpenShift Container Platform 4.18) +- 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..6dd9b07 --- /dev/null +++ b/charts/rhoso-apps/templates/_helpers.tpl @@ -0,0 +1,98 @@ +{{/* +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 }} + +{{/* +argocd.argoproj.io/sync-wave annotation; omitted in values defaults to "0". +Pass dict with key "app" (per-application values map). +*/}} +{{- define "rhoso-apps.syncWave" -}} +{{- $app := .app -}} +{{- default "0" $app.syncWave | 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 }} + +{{/* +Build spec.syncPolicy; emit block or nothing. +If syncPolicy is a non-empty map, it is the sole source (top-level syncOptions is ignored). +If syncPolicy is absent or empty, top-level syncOptions is merged in as spec.syncPolicy.syncOptions. +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 not (empty $merged) }} + syncPolicy: +{{ toYaml $merged | indent 4 }} +{{- else if and $app.syncOptions (not (empty $app.syncOptions)) }} +{{- $only := dict "syncOptions" $app.syncOptions }} + syncPolicy: +{{ toYaml $only | 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..71ed96f --- /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: {{ include "rhoso-apps.syncWave" (dict "app" $app) }} +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..6a39dfb --- /dev/null +++ b/charts/rhoso-apps/tests/application_test.yaml @@ -0,0 +1,220 @@ +--- +# 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: uses syncPolicy and ignores top-level syncOptions when both are set + set: + applicationNamespace: openshift-gitops + destinationServer: https://kubernetes.default.svc + applications: + policy-merge-test: + enabled: true + repoURL: https://github.com/example/repo + path: "." + targetRevision: HEAD + syncWave: "0" + syncPolicy: + automated: + prune: true + syncOptions: + - FromNestedPolicy=true + syncOptions: + - FromTopLevel=true + documentSelector: + path: metadata.name + value: policy-merge-test + asserts: + - lengthEqual: + path: spec.syncPolicy.syncOptions + count: 1 + - equal: + path: spec.syncPolicy.syncOptions[0] + value: FromNestedPolicy=true + + - it: uses top-level syncOptions when syncPolicy is unset + set: + applicationNamespace: openshift-gitops + destinationServer: https://kubernetes.default.svc + applications: + syncopt-only: + enabled: true + repoURL: https://github.com/example/repo + path: "." + targetRevision: main + syncWave: "0" + syncOptions: + - OnlyFromTopLevel=true + documentSelector: + path: metadata.name + value: syncopt-only + asserts: + - equal: + path: spec.syncPolicy.syncOptions[0] + value: OnlyFromTopLevel=true + - notExists: + path: spec.syncPolicy.automated + + - it: defaults syncWave to 0 when omitted + set: + applicationNamespace: openshift-gitops + destinationServer: https://kubernetes.default.svc + applications: + no-wave: + enabled: true + repoURL: https://github.com/example/repo + path: "." + targetRevision: main + syncOptions: + - Prune=true + documentSelector: + path: metadata.name + value: no-wave + asserts: + - equal: + path: metadata.annotations["argocd.argoproj.io/sync-wave"] + value: "0" + + - 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..ef154eb --- /dev/null +++ b/charts/rhoso-apps/values.schema.json @@ -0,0 +1,118 @@ +{ + "$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", + "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. Omit to use default wave 0 in the rendered Application." + }, + "syncOptions": { + "type": "array", + "description": "Argo CD sync option strings. Used for spec.syncPolicy.syncOptions when syncPolicy is not set or is an empty object; ignored when syncPolicy is a non-empty object (use 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": "When non-empty, the map is rendered as spec.syncPolicy in full; top-level syncOptions is not merged in. For syncOptions only, omit syncPolicy or set it to {} and set top-level syncOptions.", + "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..f9a1739 --- /dev/null +++ b/charts/rhoso-apps/values.yaml @@ -0,0 +1,86 @@ +--- +# Parameter documentation: charts/rhoso-apps/README.md +applicationNamespace: openshift-gitops +destinationServer: https://kubernetes.default.svc +applications: + # Deploy and initialize MetalLB, nmstate, cert-manager; install and configure + # vault-secrets-operator or external-secrets-operator as needed. + # 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: "example/openstack-operator" + 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: "example/openstack-operator-cr" + repoURL: https://github.com/openstack-k8s-operators/gitops + syncOptions: + - Prune=true + syncWave: "-15" + targetRevision: v0.1.0 + # Create cluster secrets by syncing from the secure backend (placeholder path). + # Runs after operator-dependencies provides vault-secrets-operator or external-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: false + 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: "example/openstack-networks" + 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