From b9442e8777d4c0283f165d4753d9cc8ce9b8e96b Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Fri, 14 Nov 2025 13:02:36 -0600 Subject: [PATCH 1/3] chore: don't ignore the charts directory --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index 66deb1b36..ffa55d630 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -# where helm charts will get downloaded by kustomize -/charts/ - # un-encrypted secrets /secret-*.yaml # sealed secrets From 71d9538e4ea35f5f1336defff222b6b3ec439004 Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Fri, 19 Dec 2025 11:46:02 -0600 Subject: [PATCH 2/3] chore: don't spellcheck helm chart versions as they are hex --- .typos.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.typos.toml b/.typos.toml index 589c1bd54..066bf1abf 100644 --- a/.typos.toml +++ b/.typos.toml @@ -19,6 +19,9 @@ extend-exclude = [ extend-ignore-identifiers-re = [ "ironic_retrive_*", ] +extend-ignore-re = [ + "chartVersion:.*", +] [default.extend-words] # Don't correct "HPE" From ff8a1a5b86141ed8c77b1fcade30bcb3bc1e9963 Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Tue, 18 Nov 2025 09:35:08 -0600 Subject: [PATCH 3/3] feat: Add an ArgoCD Application chart to replace AppSets The AppSets have proven to have quite a bit of limitations and attempts to make the kustomize interface take references like the helm interface can from different repos or branches has not merged upstream. It's harder to see what is being generated or rendered by the AppSet as well. ArgoCD's UI doesn't show AppSets or what they are doing but shows Applications in detail. So switch to utilizing Helm to generate the Applications. We have the added benefit that the Applications can be of different base templates in the same ArgoCD for targeting different clusters as well. With AppSets we have the same base template that is used for all the clusters so they need to stay relatively at the same version. --- .../workflows/argocd-understack-release.yaml | 85 +++++++++ .github/workflows/helm-chart-test.yaml | 71 ++++++++ charts/argocd-understack/.helmignore | 23 +++ charts/argocd-understack/Chart.yaml | 27 +++ charts/argocd-understack/ci/example.yaml | 2 + .../argocd-understack/templates/_helpers.tpl | 99 +++++++++++ .../application-openstack-helm.yaml.tpl | 49 ++++++ .../templates/application-openstack.yaml.tpl | 44 +++++ charts/argocd-understack/values.yaml | 161 ++++++++++++++++++ 9 files changed, 561 insertions(+) create mode 100644 .github/workflows/argocd-understack-release.yaml create mode 100644 .github/workflows/helm-chart-test.yaml create mode 100644 charts/argocd-understack/.helmignore create mode 100644 charts/argocd-understack/Chart.yaml create mode 100644 charts/argocd-understack/ci/example.yaml create mode 100644 charts/argocd-understack/templates/_helpers.tpl create mode 100644 charts/argocd-understack/templates/application-openstack-helm.yaml.tpl create mode 100644 charts/argocd-understack/templates/application-openstack.yaml.tpl create mode 100644 charts/argocd-understack/values.yaml diff --git a/.github/workflows/argocd-understack-release.yaml b/.github/workflows/argocd-understack-release.yaml new file mode 100644 index 000000000..4c6f91dfa --- /dev/null +++ b/.github/workflows/argocd-understack-release.yaml @@ -0,0 +1,85 @@ +--- +name: argocd-understack release + +on: + push: + tags: + - "argocd-understack-v*.*.*" + workflow_dispatch: + inputs: + chart_version: + description: "Chart version to release (e.g., 0.1.0)" + required: true + type: string + +permissions: + contents: read + packages: write + id-token: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Set up Helm + uses: azure/setup-helm@v4 + with: + version: v3.18.4 + + - name: Install Cosign + uses: sigstore/cosign-installer@v3 + + - name: Extract version from tag or input + id: version + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + VERSION="${{ inputs.chart_version }}" + else + VERSION=${GITHUB_REF#refs/tags/argocd-understack-v} + fi + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + + - name: Helm lint + run: | + helm lint charts/argocd-understack --strict + + - name: Package chart + run: | + VERSION="${{ steps.version.outputs.version }}" + helm package charts/argocd-understack --version "$VERSION" + + - name: Login to GitHub Container Registry + run: | + echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io -u ${{ github.actor }} --password-stdin + + - name: Push chart to GHCR + run: | + VERSION="${{ steps.version.outputs.version }}" + CHART_PACKAGE="argocd-understack-${VERSION}.tgz" + + if [[ ! -f "$CHART_PACKAGE" ]]; then + echo "::error::Chart package $CHART_PACKAGE not found" + ls -la *.tgz + exit 1 + fi + + helm push "$CHART_PACKAGE" oci://ghcr.io/${{ github.repository }} + + echo "::notice::Chart pushed to oci://ghcr.io/${{ github.repository }}/argocd-understack:${VERSION}" + + - name: Sign chart with Cosign + run: | + VERSION="${{ steps.version.outputs.version }}" + cosign sign --yes ghcr.io/${{ github.repository }}/argocd-understack:${VERSION} + + echo "::notice::Chart signed with keyless signature" + + - name: Logout from GHCR + if: always() + run: | + helm registry logout ghcr.io diff --git a/.github/workflows/helm-chart-test.yaml b/.github/workflows/helm-chart-test.yaml new file mode 100644 index 000000000..58fc41ce8 --- /dev/null +++ b/.github/workflows/helm-chart-test.yaml @@ -0,0 +1,71 @@ +--- +name: Helm Chart Testing + +on: + pull_request: + paths: + - "charts/**" + - ".github/workflows/helm-chart-test.yaml" + push: + branches: + - main + paths: + - "charts/**" + merge_group: + types: [checks_requested] + workflow_dispatch: + +jobs: + lint-test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Set up Helm + uses: azure/setup-helm@v4 + with: + version: v3.18.4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + check-latest: true + + - name: Set up chart-testing + uses: helm/chart-testing-action@v2 + + - name: Run chart-testing (list-changed) + id: list-changed + run: | + changed=$(ct list-changed --chart-dirs charts --target-branch ${{ github.event.repository.default_branch }}) + if [[ -n "$changed" ]]; then + echo "changed=true" >> "$GITHUB_OUTPUT" + + # Set individual output variables for each changed chart + for chart in $changed; do + chart_name=$(basename "$chart") + echo "$chart_name=true" >> "$GITHUB_OUTPUT" + echo "Changed: $chart_name" + done + fi + + - name: Run chart-testing (lint) + if: steps.list-changed.outputs.changed == 'true' + run: ct lint --chart-dirs charts --target-branch ${{ github.event.repository.default_branch }} + + - name: Create kind cluster + if: steps.list-changed.outputs.changed == 'true' + uses: helm/kind-action@v1 + + - name: Install ArgoCD + if: steps.list-changed.outputs.argocd-understack == 'true' + run: | + ./bootstrap/argocd.sh + + - name: install argocd-understack + if: steps.list-changed.outputs.argocd-understack == 'true' + run: helm install testsite charts/argocd-understack --namespace argocd --values charts/argocd-understack/ci/example.yaml diff --git a/charts/argocd-understack/.helmignore b/charts/argocd-understack/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/argocd-understack/.helmignore @@ -0,0 +1,23 @@ +# 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/ diff --git a/charts/argocd-understack/Chart.yaml b/charts/argocd-understack/Chart.yaml new file mode 100644 index 000000000..0599dd50a --- /dev/null +++ b/charts/argocd-understack/Chart.yaml @@ -0,0 +1,27 @@ +apiVersion: v2 +name: argocd-understack +description: ArgoCD Application definitions for UnderStack + +# 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: "1.16.0" + +maintainers: + - name: rackerlabs diff --git a/charts/argocd-understack/ci/example.yaml b/charts/argocd-understack/ci/example.yaml new file mode 100644 index 000000000..4b1367296 --- /dev/null +++ b/charts/argocd-understack/ci/example.yaml @@ -0,0 +1,2 @@ +--- +deploy_url: https://github.com/example/example diff --git a/charts/argocd-understack/templates/_helpers.tpl b/charts/argocd-understack/templates/_helpers.tpl new file mode 100644 index 000000000..220e7d194 --- /dev/null +++ b/charts/argocd-understack/templates/_helpers.tpl @@ -0,0 +1,99 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "understack.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "understack.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "understack.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "understack.labels" -}} +helm.sh/chart: {{ include "understack.chart" . }} +{{ include "understack.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "understack.selectorLabels" -}} +app.kubernetes.io/name: {{ include "understack.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "understack.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "understack.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Create a valid ArgoCD Application name +*/}} +{{- define "understack.argocdAppName" -}} +{{- $root := index . 0 }} +{{- $appName := index . 1 }} +{{- printf "%s-%s" $root.Release.Name $appName }} +{{- end }} + +{{/* +Get the UnderStack repository URL +*/}} +{{- define "understack.understack_url" -}} +{{- .Values.understack_url }} +{{- end }} + +{{/* +Get the UnderStack repository git reference +*/}} +{{- define "understack.understack_ref" -}} +{{- .Values.understack_ref }} +{{- end }} + +{{/* +Get the deployment repository URL +*/}} +{{- define "understack.deploy_url" -}} +{{- required "deploy_url is required. Please set it in your values file" .Values.deploy_url }} +{{- end }} + +{{/* +Get the deployment repository git reference +*/}} +{{- define "understack.deploy_ref" -}} +{{- .Values.deploy_ref }} +{{- end }} diff --git a/charts/argocd-understack/templates/application-openstack-helm.yaml.tpl b/charts/argocd-understack/templates/application-openstack-helm.yaml.tpl new file mode 100644 index 000000000..f8441c082 --- /dev/null +++ b/charts/argocd-understack/templates/application-openstack-helm.yaml.tpl @@ -0,0 +1,49 @@ +{{- range $appName, $app := .Values.site.openstack.apps }} +{{- if $app.enabled | default false }} +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: {{ printf "%s-%s" $.Release.Name $appName }} + {{/* + {{- with $app.wave }} + annotations: + argocd.argoproj.io/sync-wave: {{ quote . }} + {{- end }} + */}} +spec: + destination: + namespace: {{ $.Values.site.openstack.namespace }} + server: https://kubernetes.default.svc + project: understack + sources: + - repoURL: {{ $.Values.site.openstack.repoUrl }} + targetRevision: {{ $app.chartVersion }} + chart: {{ $appName }} + helm: + ignoreMissingValueFiles: true + releaseName: {{ $appName }} + valueFiles: + - $understack/components/images-openstack.yaml + - $understack/components/{{ $appName }}/values.yaml + - $deploy/{{ $.Release.Name }}/manifests/secret-openstack.yaml + - $deploy/{{ $.Release.Name }}/manifests/images-openstack.yaml + - $deploy/{{ $.Release.Name }}/helm-configs/{{ $appName }}.yaml + - path: components/{{ $appName }}/ + ref: understack + repoURL: {{ include "understack.understack_url" $ }} + targetRevision: {{ include "understack.understack_ref" $ }} + - path: {{ $.Release.Name }}/manifests/{{ $appName }} + ref: deploy + repoURL: {{ include "understack.deploy_url" $ }} + targetRevision: {{ include "understack.deploy_ref" $ }} + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - ServerSideApply=false + - RespectIgnoreDifferences=true + - ApplyOutOfSyncOnly=true +{{- end }} +{{- end }} diff --git a/charts/argocd-understack/templates/application-openstack.yaml.tpl b/charts/argocd-understack/templates/application-openstack.yaml.tpl new file mode 100644 index 000000000..fe6c0dc57 --- /dev/null +++ b/charts/argocd-understack/templates/application-openstack.yaml.tpl @@ -0,0 +1,44 @@ +{{- if .Values.site.openstack.enabled }} +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: {{ printf "%s-%s" $.Release.Name "openstack" }} + annotations: + argocd.argoproj.io/compare-options: ServerSideDiff=true,IncludeMutationWebhook=true + {{/* + {{- with $app.wave }} + argocd.argoproj.io/sync-wave: {{ quote . }} + {{- end }} + */}} +spec: + destination: + namespace: {{ .Values.site.openstack.namespace }} + server: https://kubernetes.default.svc + project: understack + sources: + - path: components/openstack + ref: understack + repoURL: {{ include "understack.understack_url" $ }} + targetRevision: {{ include "understack.understack_ref" $ }} + helm: + ignoreMissingValueFiles: true + valueFiles: + - $deploy/bravo-uc-iad3-dev/helm-configs/openstack.yaml + - path: {{ $.Release.Name }}/manifests/openstack + ref: deploy + repoURL: {{ include "understack.deploy_url" $ }} + targetRevision: {{ include "understack.deploy_ref" $ }} + syncPolicy: + automated: + prune: true + selfHeal: true + managedNamespaceMetadata: + annotations: + argocd.argoproj.io/sync-options: Delete=false + syncOptions: + - CreateNamespace=true + - ServerSideApply=true + - RespectIgnoreDifferences=true + - ApplyOutOfSyncOnly=true +{{- end }} diff --git a/charts/argocd-understack/values.yaml b/charts/argocd-understack/values.yaml new file mode 100644 index 000000000..5457dba98 --- /dev/null +++ b/charts/argocd-understack/values.yaml @@ -0,0 +1,161 @@ +# -- Defines the UnderStack repository URL +# [[ref]](https://rackerlabs.github.io/understack/deploy-guide/requirements/) +# @default -- https://github.com/rackerlabs/understack.git +understack_url: https://github.com/rackerlabs/understack.git + +# -- Defines the UnderStack repository git reference (commit/branch/tag) +# [[ref]](https://rackerlabs.github.io/understack/deploy-guide/requirements/) +# @default -- HEAD +understack_ref: HEAD + +# -- Defines the deployment repository URL +# [[ref]](https://rackerlabs.github.io/understack/deploy-guide/requirements/) +deploy_url: + +# -- Defines the deployment repository git reference (commit/branch/tag) +# [[ref]](https://rackerlabs.github.io/understack/deploy-guide/requirements/) +# @default -- HEAD +deploy_ref: HEAD + +# -- This block is for setting up the UnderStack site specific ArgoCD Applications +site: + # -- Enable/disable deploying the site specific applications + # @default -- true + enabled: true + + # -- OpenStack service applications configuration + openstack: + # -- Enable/disable deploying the base OpenStack configs + # @default -- true + enabled: true + + # -- OpenStack Helm chart repository URL + # @default -- https://tarballs.opendev.org/openstack/openstack-helm + repoUrl: https://tarballs.opendev.org/openstack/openstack-helm + + # -- Namespace to deploy OpenStack Helm into + # @default -- openstack + namespace: openstack + + # -- Dictionary of OpenStack applications to deploy + # @default -- See below for default apps + apps: + # -- Keystone (Identity Service) + keystone: + # -- Enable/disable deploying Keystone + # @default -- true + enabled: true + # -- Sync wave for deployment ordering (lower numbers deploy first) + # @default -- 1 + wave: 1 + # renovate: datasource=helm depName=keystone registryUrl=https://tarballs.opendev.org/openstack/openstack-helm + # -- Chart version for Keystone + chartVersion: 2025.2.6+9b270fe35 + + # -- Glance (Image Service) + glance: + # -- Enable/disable deploying Glance + # @default -- true + enabled: true + # -- Sync wave for deployment ordering + # @default -- 2 + wave: 2 + # renovate: datasource=helm depName=glance registryUrl=https://tarballs.opendev.org/openstack/openstack-helm + # -- Chart version for Glance + chartVersion: 2025.2.6+9b270fe35 + + # -- Cinder (Block Storage Service) + cinder: + # -- Enable/disable deploying Cinder + # @default -- true + enabled: true + # -- Sync wave for deployment ordering + # @default -- 2 + wave: 2 + # renovate: datasource=helm depName=cinder registryUrl=https://tarballs.opendev.org/openstack/openstack-helm + # -- Chart version for Cinder + chartVersion: 2025.1.3+abd55b4a7 + + # -- Ironic (Bare Metal Service) + ironic: + # -- Enable/disable deploying Ironic + # @default -- true + enabled: true + # -- Sync wave for deployment ordering + # @default -- 2 + wave: 2 + # renovate: datasource=helm depName=ironic registryUrl=https://tarballs.opendev.org/openstack/openstack-helm + # -- Chart version for Ironic + chartVersion: 2025.2.5+e61f0342c + + # -- Neutron (Networking Service) + neutron: + # -- Enable/disable deploying Neutron + # @default -- true + enabled: true + # -- Sync wave for deployment ordering + # @default -- 2 + wave: 2 + # renovate: datasource=helm depName=neutron registryUrl=https://tarballs.opendev.org/openstack/openstack-helm + # -- Chart version for Neutron + chartVersion: 2025.2.12+9cc7c1ea9 + + # -- Placement (Placement Service) + placement: + # -- Enable/disable deploying Placement + # @default -- true + enabled: true + # -- Sync wave for deployment ordering + # @default -- 2 + wave: 2 + # renovate: datasource=helm depName=placement registryUrl=https://tarballs.opendev.org/openstack/openstack-helm + # -- Chart version for Placement + chartVersion: 2025.2.4+9b270fe35 + + # -- Nova (Compute Service) + nova: + # -- Enable/disable deploying Nova + # @default -- true + enabled: true + # -- Sync wave for deployment ordering + # @default -- 3 + wave: 3 + # renovate: datasource=helm depName=nova registryUrl=https://tarballs.opendev.org/openstack/openstack-helm + # -- Chart version for Nova + chartVersion: 2025.1.19+12458c92d + + # -- Octavia (Load Balancer Service) + octavia: + # -- Enable/disable deploying Octavia + # @default -- true + enabled: true + # -- Sync wave for deployment ordering + # @default -- 3 + wave: 3 + # renovate: datasource=helm depName=octavia registryUrl=https://tarballs.opendev.org/openstack/openstack-helm + # -- Chart version for Octavia + chartVersion: 2025.2.7+9b270fe35 + + # -- Horizon (Dashboard) + horizon: + # -- Enable/disable deploying Horizon + # @default -- true + enabled: true + # -- Sync wave for deployment ordering + # @default -- 4 + wave: 4 + # renovate: datasource=helm depName=horizon registryUrl=https://tarballs.opendev.org/openstack/openstack-helm + # -- Chart version for Horizon + chartVersion: 2025.2.3+9b270fe35 + + # -- Skyline (Dashboard) + skyline: + # -- Enable/disable deploying Skyline + # @default -- true + enabled: true + # -- Sync wave for deployment ordering + # @default -- 4 + wave: 4 + # renovate: datasource=helm depName=horizon registryUrl=https://tarballs.opendev.org/openstack/openstack-helm + # -- Chart version for Skyline + chartVersion: 2025.2.3+b6bb28b51