Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
72 changes: 72 additions & 0 deletions .github/workflows/helm-chart.yml
Original file line number Diff line number Diff line change
@@ -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-<version>.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 .
2 changes: 2 additions & 0 deletions .yamllint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ ignore:
- '*.env'
- '*.txt'
- '*.sh'
# Helm templates are not valid YAML until rendered (Go templating).
- 'charts/**/templates/**'

rules:
line-length:
Expand Down
25 changes: 25 additions & 0 deletions charts/rhoso-apps/.helmignore
Original file line number Diff line number Diff line change
@@ -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/
25 changes: 25 additions & 0 deletions charts/rhoso-apps/Chart.yaml
Original file line number Diff line number Diff line change
@@ -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"
59 changes: 59 additions & 0 deletions charts/rhoso-apps/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{{/*
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 }}

{{/*
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 }}
21 changes: 21 additions & 0 deletions charts/rhoso-apps/templates/application.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{{- range $name, $app := .Values.applications }}
{{- if $app.enabled }}
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: {{ $name }}
namespace: {{ include "rhoso-apps.applicationNamespace" $ }}
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) }}
destination:
server: {{ include "rhoso-apps.destinationServer" $ }}
{{ include "rhoso-apps.syncPolicySpec" (dict "app" $app) }}
{{- end }}
{{- end }}
78 changes: 78 additions & 0 deletions charts/rhoso-apps/tests/application_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
# 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.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: examples/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: 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
98 changes: 98 additions & 0 deletions charts/rhoso-apps/values.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
{
"$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.<name>.",
"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
}
}
}
}
}
Loading
Loading