diff --git a/.github/actions/check-typos/action.yaml b/.github/actions/check-typos/action.yaml new file mode 100644 index 0000000..9663c10 --- /dev/null +++ b/.github/actions/check-typos/action.yaml @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2025 Yale University +# SPDX-License-Identifier: Apache-2.0 + +name: check-typos +description: Helper for running Typos +inputs: + files: + description: Files to check + required: false + default: '' +runs: + using: composite + steps: + - name: Install and run Typos + uses: crate-ci/typos@v1.29.7 + with: + config: ./configs/typos.toml + files: ${{ inputs.files }} diff --git a/.github/actions/setup-committed/action.yaml b/.github/actions/setup-committed/action.yaml new file mode 100644 index 0000000..ecae960 --- /dev/null +++ b/.github/actions/setup-committed/action.yaml @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2025 Yale University +# SPDX-License-Identifier: Apache-2.0 + +name: setup-committed +description: Helper for installing Committed +runs: + using: composite + steps: + - name: Install Committed + uses: jaxxstorm/action-install-gh-release@v2.1.0 + with: + repo: crate-ci/committed + tag: v1.1.7 diff --git a/.github/actions/setup-helm/action.yaml b/.github/actions/setup-helm/action.yaml new file mode 100644 index 0000000..d959686 --- /dev/null +++ b/.github/actions/setup-helm/action.yaml @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: 2025 Yale University +# SPDX-License-Identifier: Apache-2.0 + +name: setup-helm +description: Helper for installing Helm +runs: + using: composite + steps: + - name: Install Helm + uses: azure/setup-helm@v4 + with: + version: v3.17.0 diff --git a/.github/actions/setup-just/action.yaml b/.github/actions/setup-just/action.yaml new file mode 100644 index 0000000..b185b5e --- /dev/null +++ b/.github/actions/setup-just/action.yaml @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: 2025 Yale University +# SPDX-License-Identifier: Apache-2.0 + +name: setup-just +description: Helper for installing Just +runs: + using: composite + steps: + - name: Install Just + uses: taiki-e/install-action@v2 + with: + tool: just@1.40.0 diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml new file mode 100644 index 0000000..e2af4e3 --- /dev/null +++ b/.github/workflows/checks.yaml @@ -0,0 +1,133 @@ +# SPDX-FileCopyrightText: 2025 Yale University +# SPDX-License-Identifier: Apache-2.0 + +# Reusable workflow for running various checks on Helm charts + +name: checks +on: + workflow_call: + inputs: + enable-change-detection: + description: Enable change detection + default: false + type: boolean + chart: + description: Limit checks to a specific chart + default: '' + type: string + outputs: + charts: + description: List of validated charts + value: ${{ jobs.helm-linter.outputs.charts }} + +permissions: + contents: read + +env: + CLICOLOR: 1 + +jobs: + helm-linter: + runs-on: ubuntu-latest + outputs: + charts: ${{ steps.ct-log-parser.outputs.charts }} + env: + CHART_TESTING_LOG: chart-testing.log + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + # Fetch whole history required for change detection (if enabled) + fetch-depth: ${{ (inputs.enable-change-detection) && '0' || '1' }} + - name: Install Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + check-latest: true + - &install-just-step + name: Install Just + uses: ./.github/actions/setup-just + - &install-helm-step + name: Install Helm + uses: ./.github/actions/setup-helm + - &install-ct-step + name: Install chart-testing + uses: helm/chart-testing-action@v2.7.0 + - &add-chart-repos-step + name: Add external chart repositories + run: just add-chart-repos + - name: Run chart linters and validators + run: | + set -o pipefail + if ${{ inputs.enable-change-detection }}; then + # Enable change detection if requested + set -- "--target-branch" "main" + elif test -n "${{ inputs.chart }}"; then + # Process only the specified chart + set -- "--charts" "./charts/${{ inputs.chart }}" + else + # Process all charts + set -- "--all" + fi + ct lint --config ./configs/chart-testing.yaml "$@" \ + | tee "${{ env.CHART_TESTING_LOG }}" + - id: ct-log-parser + name: Parse chart-testing logs + uses: eaasi/chart-list-action@v0.3 + with: + ct-log-file: ${{ env.CHART_TESTING_LOG }} + + helm-tester: + runs-on: ubuntu-latest + needs: + - helm-linter + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - *install-just-step + - name: Install Minikube + uses: medyagh/setup-minikube@v0.0.20 + with: + start: false + - name: Start Minikube cluster + run: just cluster-start + - *install-helm-step + - *add-chart-repos-step + - name: Build chart dependencies + run: just build-chart-deps + - name: Install charts + run: just deploy-all + - name: Test charts + run: just test-all + + spell-checker: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Run spell checker + uses: ./.github/actions/check-typos + + changelog-checker: + runs-on: ubuntu-latest + needs: + - helm-linter + - spell-checker + if: ${{ needs.helm-linter.outputs.charts != '[]' }} + strategy: + matrix: + chart: ${{ fromJSON(needs.helm-linter.outputs.charts) }} + env: + CHANGELOG_FILE: ${{ matrix.chart.path }}/CHANGELOG.md + steps: + - name: Checkout chart's changelog + uses: actions/checkout@v4 + with: + sparse-checkout: ${{ env.CHANGELOG_FILE }} + - name: Check chart's changelog + uses: eaasi/release-notes-action@v0.6 + with: + changelog-file: ${{ env.CHANGELOG_FILE }} + release-version: ${{ matrix.chart.name }}-${{ matrix.chart.version }} + # Ignore missing changelogs for default chart version + continue-on-error: ${{ matrix.chart.version == '0.1.0' }} diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..5eb189c --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: 2025 Yale University +# SPDX-License-Identifier: Apache-2.0 + +# Workflow for running various CI checks + +name: continuous-integration +on: + push: + branches: + - main + pull_request: + branches: + - '**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + +permissions: + contents: read + +jobs: + checks: + uses: ./.github/workflows/checks.yaml + with: + enable-change-detection: ${{ github.ref != 'refs/heads/main' }} diff --git a/.github/workflows/commit-style.yaml b/.github/workflows/commit-style.yaml new file mode 100644 index 0000000..4b19e96 --- /dev/null +++ b/.github/workflows/commit-style.yaml @@ -0,0 +1,44 @@ +# SPDX-FileCopyrightText: 2025 Yale University +# SPDX-License-Identifier: Apache-2.0 + +# Workflow for enforcing commit style conventions + +name: commit-style +on: + push: + branches: + - main + pull_request: + branches: + - '**' + +permissions: + contents: read + +env: + CLICOLOR: 1 + +jobs: + commit-linter: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + # Fetch full history for merge-base detection! + fetch-depth: 0 + - id: commit-range + name: Determine commit range + uses: eaasi/commit-range-action@v0.5 + - name: Install commit style linter + uses: ./.github/actions/setup-committed + - name: Run commit style linter + run: | + range="${{ steps.commit-range.outputs.commit-range }}" + echo "Linting commits:" + git log --color=always --graph --oneline "${range:?}" || true + echo "" + committed -vv --color=always \ + --config ./configs/committed.toml \ + "${range}" + echo "DONE: Commits follow the required style conventions." diff --git a/.github/workflows/pr-naming.yaml b/.github/workflows/pr-naming.yaml new file mode 100644 index 0000000..c26aa56 --- /dev/null +++ b/.github/workflows/pr-naming.yaml @@ -0,0 +1,86 @@ +# SPDX-FileCopyrightText: 2025 Yale University +# SPDX-License-Identifier: Apache-2.0 + +# Workflow for enforcing PR naming conventions + +name: pr-naming +on: + pull_request: + types: + - opened + - edited + - reopened + +permissions: + contents: none + +env: + COMMIT_MESSAGE_FILE: ./commit-message.txt + CLICOLOR: 1 + +jobs: + commit-message: + runs-on: ubuntu-latest + outputs: + content: ${{ steps.message-constructor.outputs.content }} + steps: + - id: message-constructor + name: Construct commit message + env: + PR_TITLE: ${{ github.event.pull_request.title }} + PR_BODY: | + ${{ github.event.pull_request.body }} + run: | + print-commit-message() { + echo "${PR_TITLE:?}" + if test -n "${PR_BODY}"; then + echo "" + echo "${PR_BODY}" + fi + } + # Output commit message + { + echo "content<> "${GITHUB_OUTPUT}" + + commit-linter: + runs-on: ubuntu-latest + needs: + - commit-message + steps: + - &checkout-repository-step + name: Checkout repository + uses: actions/checkout@v4 + with: + sparse-checkout: | + .github/actions + configs + - &prepare-commit-message-step + name: Prepare commit message + run: | + echo -n '${{ needs.commit-message.outputs.content }}' > "${{ env.COMMIT_MESSAGE_FILE }}" + - name: Install commit style linter + uses: ./.github/actions/setup-committed + - name: Run commit style linter + run: | + echo "Linting commit message:" + cat "${{ env.COMMIT_MESSAGE_FILE }}" | sed 's/^/> /' + echo "" + committed -vv --color=always \ + --config ./configs/committed.toml \ + --commit-file "${{ env.COMMIT_MESSAGE_FILE }}" + echo "DONE: PR follows the required naming conventions." + + spell-checker: + runs-on: ubuntu-latest + needs: + - commit-message + steps: + - *checkout-repository-step + - *prepare-commit-message-step + - name: Run spell checker + uses: ./.github/actions/check-typos + with: + files: ${{ env.COMMIT_MESSAGE_FILE }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..b37e40e --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,134 @@ +# SPDX-FileCopyrightText: 2025 Yale University +# SPDX-License-Identifier: Apache-2.0 + +# Workflow for packaging and releasing Helm charts + +name: release +on: + push: + tags: + - '**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + +permissions: + contents: read + +env: + CLICOLOR: 1 + +jobs: + tag-parser: + runs-on: ubuntu-latest + outputs: + chart: ${{ steps.refname-parsing.outputs.chart }} + version: ${{ steps.refname-parsing.outputs.version }} + steps: + - id: refname-parsing + name: Parse pushed ref name + run: | + # Parse ref names of the form - + echo "Parsing ref name '${GITHUB_REF_NAME:?}'..." + refname="$(echo "${GITHUB_REF_NAME}" | sed -E 's/^(.+)-([0-9]+.*)$/\1:\2/')" + lookup() { cut -d ':' -f "${1:?}"; } + chart="$(echo "${refname:?}" | lookup 1)" + version="$(echo "${refname}" | lookup 2)" + echo "chart=${chart:?}" >> "${GITHUB_OUTPUT}" + echo "version=${version:?}" >> "${GITHUB_OUTPUT}" + echo "Parsed values:" + echo " chart = ${chart}" + echo " version = ${version}" + + chart-checks: + needs: + - tag-parser + uses: ./.github/workflows/checks.yaml + with: + chart: ${{ needs.tag-parser.outputs.chart }} + enable-change-detection: false + + chart-info: + runs-on: ubuntu-latest + needs: + - chart-checks + - tag-parser + outputs: + name: ${{ matrix.chart.name }} + version: ${{ matrix.chart.version}} + refname: ${{ matrix.chart.name }}-${{ matrix.chart.version }} + path: ${{ matrix.chart.path }} + strategy: + fail-fast: true + matrix: + chart: ${{ fromJSON(needs.chart-checks.outputs.charts) }} + steps: + - name: Find expected chart + run: | + test "${{ matrix.chart.name }}" = "${{ needs.tag-parser.outputs.chart }}" + + version-check: + runs-on: ubuntu-latest + needs: + - chart-info + - tag-parser + steps: + - name: Check chart version + run: | + curver="${{ needs.chart-info.outputs.version }}" + tagver="${{ needs.tag-parser.outputs.version }}" + if test "${curver:?}" != "${tagver:?}"; then + echo "::error::Chart version '${curver}' does not match tag version '${tagver}'!" + exit 1 + fi + + chart-releaser: + runs-on: ubuntu-latest + permissions: + contents: write + needs: + - chart-info + - chart-checks + - version-check + env: + CHART_RELEASER_CONFIG: ./configs/chart-releaser.yaml + RELEASE_NOTES_FILE_NAME: RELEASE.md + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Update Git configuration + run: | + git config user.name "${{ github.event.pusher.name }}" + git config user.email "${{ github.event.pusher.email }}" + - name: Install Just + uses: ./.github/actions/setup-just + - name: Install Helm + uses: ./.github/actions/setup-helm + - name: Install chart-releaser + uses: helm/chart-releaser-action@v1.7.0 + with: + install_only: true + - name: Add external chart repositories + run: just add-chart-repos + - name: Extract chart's release notes + uses: eaasi/release-notes-action@v0.6 + with: + changelog-file: ${{ needs.chart-info.outputs.path }}/CHANGELOG.md + release-notes-file: ${{ needs.chart-info.outputs.path }}/${{ env.RELEASE_NOTES_FILE_NAME }} + release-version: '${{ needs.chart-info.outputs.refname }}' + - name: Package requested chart + run: | + cr package "${{ needs.chart-info.outputs.path }}" \ + --config "${{ env.CHART_RELEASER_CONFIG }}" + - name: Upload chart package + run: | + cr upload --config "${{ env.CHART_RELEASER_CONFIG }}" \ + --token "${{ secrets.GITHUB_TOKEN }}" \ + --commit "${{ github.sha }}" \ + --release-notes-file "${{ env.RELEASE_NOTES_FILE_NAME }}" \ + --skip-existing + - name: Update chart repository index + run: | + cr index --config "${{ env.CHART_RELEASER_CONFIG }}" \ + --token "${{ secrets.GITHUB_TOKEN }}" \ + --push diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..03bd412 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.env diff --git a/Justfile b/Justfile new file mode 100644 index 0000000..1e48c01 --- /dev/null +++ b/Justfile @@ -0,0 +1,139 @@ +chart_dir := "./charts" +config_dir := "./configs" + +# Name of the Minikube cluster +cluster := "eaasi" + +# Name of the cluster namespace +namespace := "eaasi" + +# Defaults for database-cluster +database_cluster_name := "database-cluster" +database_cluster_ns := "database" + +### HELPERS ################################################################### + +# Run spell checker +spellcheck: + typos --config "{{ config_dir }}/typos.toml" + +# Run chart linter +lint chart="*": + helm lint "{{ chart_dir / chart }}" + +# Run chart validator +validate chart="*": + docker run -t --rm --network="host" \ + --workdir="/data" \ + --volume="$PWD:/data" \ + --volume="$(helm env HELM_CACHE_HOME):/root/.cache/helm:ro" \ + --volume="$(helm env HELM_CONFIG_HOME):/root/.config/helm:ro" \ + "quay.io/helmpack/chart-testing:v3.7.1" \ + ct lint --config "{{ config_dir }}/chart-testing.yaml" \ + --helm-dependency-extra-args "--skip-refresh" \ + {{ if chart == "*" { "--all" } else { '--charts "' + (chart_dir / chart) + '"' } }} + +# Update chart's changelog +update-changelog chart version="" dir=(chart_dir / chart): + #!/usr/bin/env -S sh -eu -o allexport + test -f cliff.env && . ./cliff.env + export cliff_commit_scope="{{ chart }}" + git cliff --unreleased \ + {{ if version == "" { "--bump" } else { "--tag " + chart + "-" + version } }} \ + --tag-pattern "{{ chart }}-.+" \ + --prepend "{{ dir }}/CHANGELOG.md" + +### HELM ###################################################################### + +# Add external chart repositories +add-chart-repos: + helm repo add "cnpg" "https://cloudnative-pg.github.io/charts" + +# Build dependencies for all charts +build-chart-deps: + #!/usr/bin/env -S sh -eu + charts=$(ls "{{ chart_dir }}/") + for chart in $charts; do + just dep-build "$chart" + done + +# Build Helm chart's dependencies from its lock file +dep-build chart *args="--skip-refresh": + helm dependency build "{{ chart_dir / chart }}" {{ args }} + +# Update Helm chart's on-disk dependencies +dep-update chart *args="--skip-refresh": + helm dependency update "{{ chart_dir / chart }}" {{ args }} + +# Install a Helm chart +install chart name=chart ns=namespace *args: + helm install "{{ name }}" "{{ chart_dir / chart }}" \ + --namespace "{{ ns }}" --create-namespace {{ args }} + +# Uninstall a Helm chart release +uninstall release ns=namespace *args: + helm uninstall "{{ release }}" --namespace "{{ ns }}" {{ args }} + +# Upgrade a Helm chart release +upgrade chart release=chart ns=namespace *args: + helm upgrade "{{ release }}" "{{ chart_dir / chart }}" \ + --namespace "{{ ns }}" --create-namespace --install {{ args }} + +# Render a Helm chart +render chart name=chart ns=namespace *args: + helm template "{{ name }}" "{{ chart_dir / chart }}" \ + --namespace "{{ ns }}" {{ args }} | less + +# Test a Helm chart release +test release ns=namespace *args: + helm test "{{ release }}" --namespace "{{ ns }}" {{ args }} + +### MINIKUBE ################################################################## + +# Start a Minikube cluster +cluster-start name=cluster ns=namespace *args: + minikube start --profile "{{ name }}" \ + --namespace "{{ ns }}" \ + --cpus "no-limit" \ + --memory "no-limit" \ + --force-systemd=true \ + {{ args }} + +# Stop a Minikube cluster +cluster-stop name=cluster: + minikube stop --profile "{{ name }}" + +# Pause a Minikube cluster +cluster-pause name=cluster: + minikube pause --profile "{{ name }}" --all-namespaces + +# Unpause a Minikube cluster +cluster-unpause name=cluster: + minikube unpause --profile "{{ name }}" --all-namespaces + +# Delete a Minikube cluster +cluster-delete name=cluster: + minikube delete --profile "{{ name }}" + +### EAASI ##################################################################### + +# Deploy the database-operator +deploy-database-operator name="database-operator" ns="cnpg-system" *args="--wait": \ + (upgrade "database" name ns "-f" (chart_dir / "database/configs/operator.yaml") args) + +# Deploy the database-cluster +deploy-database-cluster name=database_cluster_name ns=database_cluster_ns *args="--wait": \ + (upgrade "database" name ns args) + +# Deploy all components +deploy-all: \ + (deploy-database-operator) \ + (deploy-database-cluster) \ + +# Test the database-cluster +test-database-cluster name=database_cluster_name ns=database_cluster_ns *args: \ + (test name ns args) + +# Test all components +test-all: \ + (test-database-cluster) \ diff --git a/README.md b/README.md index b248514..e1259c5 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,14 @@ using the [Helm](https://helm.sh) package manager. ## Helm Repository Add this Helm repository using: + ```console $ helm repo add eaasi https://eaasi.github.io/helm-charts $ helm repo update ``` List the available charts by running: + ```console $ helm search repo eaasi ``` @@ -19,6 +21,110 @@ $ helm search repo eaasi ## Charts For more details, see the documentation for each chart: +- [database](./charts/database/README.md) + +## Development + +Multiple [Just](https://github.com/casey/just) recipes are provided in order to simplify local chart development. +For an overview of all available recipes and their parameters, take a look at the provided [Justfile](./Justfile) or simply run: + +```console +$ just --list +``` + +### Chart Helpers + +All source files can be checked for typos with: + +```console +$ just spellcheck +``` + +A chart linter can be run against a specific chart or all charts with: + +```console +$ just lint # omit name to lint all charts! +``` + +An extended validation can be performed on a specific chart or all charts with: + +```console +$ just validate # omit name to validate all charts! +``` + +All chart's templates can be rendered (without installing) with: + +```console +$ just render # +``` + +A specific chart can be installed or upgraded with: + +```console +$ just install # +$ just upgrade # +``` + +A previously installed release can be removed with: + +```console +$ just uninstall # +``` + +The dependencies of a chart can be managed with: + +```console +$ just dep-build # rebuild deps from Chart.lock file +$ just dep-update # update deps to mirror Chart.yaml +``` + +### Minikube Management + +A local [Minikube](https://minikube.sigs.k8s.io) cluster can be created with: + +```console +$ just cluster-start +``` + +A running Minikube cluster can be paused and resumed later with: + +```console +$ just cluster-pause +$ just cluster-unpause +``` + +When a local Minikube cluster is not needed anymore, it can be stopped or deleted with: + +```console +$ just cluster-stop +$ just cluster-delete +``` + +### Deployment + +Before deploying anything, the chart repositories for all dependencies must be added with: + +```console +$ just add-chart-repos +``` + +Next, rebuild all required chart dependencies with: + +```console +$ just build-chart-deps +``` + +The [database](./charts/database) operator can be deployed with: + +```console +$ just deploy-database-operator # +``` + +Then, a [database](./charts/database) cluster can be deployed with: + +```console +$ just deploy-database-cluster # +``` ## License diff --git a/charts/database/.helmignore b/charts/database/.helmignore new file mode 100644 index 0000000..6e75903 --- /dev/null +++ b/charts/database/.helmignore @@ -0,0 +1,26 @@ +# Patterns to ignore when building packages. + +CHANGELOG.md +.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/database/CHANGELOG.md b/charts/database/CHANGELOG.md new file mode 100644 index 0000000..2e1a615 --- /dev/null +++ b/charts/database/CHANGELOG.md @@ -0,0 +1,35 @@ +# Changelog + +## database-0.5.0 - *2025-03-21* + +### Features + +- Add initial database-operator config - ([`7e74059`](https://github.com/eaasi/helm-charts/commit/7e74059495b1f8372a18fde15a12fd717dd3180f)) +- Add initial database-cluster config - ([`4b69330`](https://github.com/eaasi/helm-charts/commit/4b693307d23e6d1809c96be67e3128ff8560e1e5)) +- Configure cluster's pod affinity - ([`4c246f2`](https://github.com/eaasi/helm-charts/commit/4c246f29808bc4d80966c4c793905fd1e0f2d1b7)) +- Add connection pooler for the primary instance - ([`dfb97d0`](https://github.com/eaasi/helm-charts/commit/dfb97d0909c2d57a715f9dd57a8c21b4b593c834)) + +### Testing + +- Add ping-test for configured connection poolers - ([`7e3c434`](https://github.com/eaasi/helm-charts/commit/7e3c434bdb769dc151719aabf0f750a918dd4043)) + +### Continuous Integration + +- Add helper for deploying database-operators - ([`4195122`](https://github.com/eaasi/helm-charts/commit/419512222f7fb7e6472a1e240b66c5da9379f843)) +- Add helper for deploying database-clusters - ([`6a2195b`](https://github.com/eaasi/helm-charts/commit/6a2195b2b779ec28b941c4dec82320646776a351)) + +### Documentation + +- Add initial README - ([`5e58495`](https://github.com/eaasi/helm-charts/commit/5e5849556726fb1a8155ed7088d384b5d2b323d7)) +- Describe a basic deployment procedure - ([`ad61b1b`](https://github.com/eaasi/helm-charts/commit/ad61b1bfdcd0dde0268a56e610ce329a2cae1553)) +- Describe available configuration parameters - ([`ed9d7db`](https://github.com/eaasi/helm-charts/commit/ed9d7dbb2b290ff0ca774db869ffa157ac83df3d)) +- Describe how a development database can be deployed - ([`3005ccb`](https://github.com/eaasi/helm-charts/commit/3005ccb54c62f5a9642be7ba35ee661e815f59df)) + +### Miscellaneous + +- Add initial `.helmignore` - ([`dda6abc`](https://github.com/eaasi/helm-charts/commit/dda6abc21b2734b0a0a52287e950afab05da90e7)) +- Add initial chart metadata - ([`1025303`](https://github.com/eaasi/helm-charts/commit/1025303121eb060421e299eda1267b2771bc0cf2)) +- Add external chart repository `cnpg` - ([`44fac8b`](https://github.com/eaasi/helm-charts/commit/44fac8b7aea39c68eb7b017f1eef5c23c8c521a4)) +- Add dependency `@cnpg/cloudnative-pg` v0.23.2 - ([`e473c61`](https://github.com/eaasi/helm-charts/commit/e473c61512bdaf0f82f7cfbcba66ca87314812f4)) +- Add dependency `@cnpg/cluster` v0.2.1 - ([`6833b2b`](https://github.com/eaasi/helm-charts/commit/6833b2b88b02177037b2a5972fb93592a1b5723e)) +- Fail early when operator and cluster are enabled - ([`d5de591`](https://github.com/eaasi/helm-charts/commit/d5de591555c44f77c43c23eb2a1e39b9f531a0ff)) diff --git a/charts/database/Chart.lock b/charts/database/Chart.lock new file mode 100644 index 0000000..d0413a0 --- /dev/null +++ b/charts/database/Chart.lock @@ -0,0 +1,9 @@ +dependencies: +- name: cloudnative-pg + repository: https://cloudnative-pg.github.io/charts + version: 0.23.2 +- name: cluster + repository: https://cloudnative-pg.github.io/charts + version: 0.2.1 +digest: sha256:a08a4edc8fc4f25677834d9157b702c8eeb5c33ace93f60fd5f450f5ce393d76 +generated: "2025-03-20T17:10:37.269076118+01:00" diff --git a/charts/database/Chart.yaml b/charts/database/Chart.yaml new file mode 100644 index 0000000..37206a2 --- /dev/null +++ b/charts/database/Chart.yaml @@ -0,0 +1,20 @@ +# SPDX-FileCopyrightText: 2025 Yale University +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: v2 +name: database +version: "0.5.0" +description: EAASI Database Helm Chart +type: application +sources: + - https://github.com/eaasi/helm-charts +dependencies: + - repository: "@cnpg" + name: cloudnative-pg + version: "0.23.2" + alias: operator + condition: operator.enabled + - repository: "@cnpg" + name: cluster + version: "0.2.1" + condition: cluster.enabled diff --git a/charts/database/README.md b/charts/database/README.md new file mode 100644 index 0000000..c36ae5b --- /dev/null +++ b/charts/database/README.md @@ -0,0 +1,41 @@ +# EAASI Database Helm Chart + +This Helm chart deploys the EAASI Database on [Kubernetes](https://kubernetes.io/) using the [Helm](https://helm.sh) package manager. + +## Getting Started + +This chart depends on the [operator](https://github.com/cloudnative-pg/charts/tree/main/charts/cloudnative-pg) and the [cluster](https://github.com/cloudnative-pg/charts/tree/main/charts/cluster) charts from the [CloudNativePG](https://github.com/cloudnative-pg) project. + +### Adding the Repositories + +```console +$ helm repo add cnpg "https://cloudnative-pg.github.io/charts" +$ helm repo add eaasi "https://eaasi.github.io/helm-charts" +``` + +### Installing the Operator + +First, the *CNPG operator* must be installed, since it provides several CRDs required for setting up new database *clusters*. +Skip this step if the operator is already installed in your K8s cluster: + +```console +$ helm install database-operator eaasi/database \ + --namespace cnpg-system --create-namespace \ + -f ./configs/operator.yaml +``` + +### Creating a Cluster + +A new *CNPG cluster* can be created with the following command: + +```console +$ helm install database-cluster eaasi/database \ + --namespace database --create-namespace +``` + +## Configuration + +A minimal configuration for an operator and a cluster is provided in the default [values.yaml](./values.yaml) file. +For further details on all available parameters, please refer to the configuration files of the upstream [operator](https://github.com/cloudnative-pg/charts/tree/main/charts/cloudnative-pg) and [cluster](https://github.com/cloudnative-pg/charts/tree/main/charts/cluster) charts. + +The extensive documentation for the CloudNativePG project can be found [here](https://cloudnative-pg.io/documentation/current/). diff --git a/charts/database/configs/operator.yaml b/charts/database/configs/operator.yaml new file mode 100644 index 0000000..6ba6cd7 --- /dev/null +++ b/charts/database/configs/operator.yaml @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: 2025 Yale University +# SPDX-License-Identifier: Apache-2.0 + +# Override values for installing the operator + +operator: + # Enable the operator + enabled: true + +cluster: + # Disable the cluster + enabled: false diff --git a/charts/database/templates/assertions.yaml b/charts/database/templates/assertions.yaml new file mode 100644 index 0000000..549ea95 --- /dev/null +++ b/charts/database/templates/assertions.yaml @@ -0,0 +1,6 @@ +# SPDX-FileCopyrightText: 2025 Yale University +# SPDX-License-Identifier: Apache-2.0 + +{{- if and .Values.operator.enabled .Values.cluster.enabled -}} +{{- fail "Either the operator or the cluster should be enabled, not both!" -}} +{{- end -}} diff --git a/charts/database/templates/tests/pooler-ping.yaml b/charts/database/templates/tests/pooler-ping.yaml new file mode 100644 index 0000000..4285955 --- /dev/null +++ b/charts/database/templates/tests/pooler-ping.yaml @@ -0,0 +1,69 @@ +# SPDX-FileCopyrightText: 2025 Yale University +# SPDX-License-Identifier: Apache-2.0 + +{{ if .Values.cluster.enabled -}} +{{ $context := dict "Values" .Values.cluster "Release" .Release -}} +{{ $fullname := include "cluster.fullname" $context -}} +{{ $namespace := include "cluster.namespace" $context -}} +{{ $secname := printf "%s-app" $fullname -}} +{{ range $index, $pooler := .Values.cluster.poolers -}} +{{ $svcname := printf "%s-pooler-%s" $fullname $pooler.name -}} +{{ $jobname := printf "%s-ping-test" $svcname -}} +{{/* +Simple database ping test for a configured CNPG Pooler, adapted from: +https://github.com/cloudnative-pg/charts/blob/cluster-v0.2.1/charts/cluster/templates/tests/ping.yaml +*/ -}} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ $jobname }} + namespace: {{ $namespace }} + labels: + app.kubernetes.io/component: database-ping-test + annotations: + "helm.sh/hook": test + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +spec: + template: + metadata: + name: {{ $jobname }} + namespace: {{ $namespace }} + labels: + app.kubernetes.io/component: database-ping-test + spec: + restartPolicy: Never + containers: + - name: alpine + image: alpine:3.21 + env: + - name: PGUSER + valueFrom: + secretKeyRef: + name: {{ $secname }} + key: username + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: {{ $secname }} + key: password + - name: PGDBNAME + valueFrom: + secretKeyRef: + name: {{ $secname }} + key: dbname + optional: true + command: + - "/bin/sh" + args: + - "-e" + - "-u" + - "-c" + - | + apk add postgresql-client + psql --no-password \ + -h "{{ $svcname }}.{{ $namespace }}.svc.cluster.local" \ + -p 5432 \ + -d "${PGDBNAME:-$PGUSER}" \ + -c "SELECT 1" +{{ end -}} +{{ end -}} diff --git a/charts/database/values.yaml b/charts/database/values.yaml new file mode 100644 index 0000000..206b9c0 --- /dev/null +++ b/charts/database/values.yaml @@ -0,0 +1,58 @@ +# SPDX-FileCopyrightText: 2025 Yale University +# SPDX-License-Identifier: Apache-2.0 + +# Default values for the EAASI Database + +# Configuration for the CNPG operator: +# https://github.com/cloudnative-pg/charts/tree/main/charts/cloudnative-pg +operator: + # -- Should the operator be enabled? + enabled: false + # -- Override operator name + fullnameOverride: cnpg-operator + # -- Override subchart name + # NOTE: The original chart name must be used here for now, because + # the upstream chart hard-codes it in multiple templates! + nameOverride: cloudnative-pg + # -- Number of replicas + replicaCount: 1 + +# Configuration for the CNPG cluster: +# https://github.com/cloudnative-pg/charts/tree/main/charts/cluster +cluster: + # -- Should the cluster be enabled? + enabled: true + # -- Override cluster name + fullnameOverride: eaasi + # -- Override subchart name + nameOverride: database-cluster + # -- Cluster mode of operation + mode: standalone + # -- Type of the CNPG database + type: postgresql + # -- Version of the CNPG database + version: + postgresql: "17.4" + # -- CNPG cluster config + cluster: + # -- Number of instances + instances: 1 + # -- Affinity rules for Pods + affinity: + enablePodAntiAffinity: true + podAntiAffinityType: preferred + topologyKey: kubernetes.io/hostname + # -- Database storage config + storage: + size: 1Gi + # -- PgBouncer poolers + poolers: + - name: rw + type: rw + instances: 1 + poolMode: transaction + parameters: + max_client_conn: "250" + default_pool_size: "20" + reserve_pool_size: "5" + min_pool_size: "5" diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 0000000..d6579b8 --- /dev/null +++ b/cliff.toml @@ -0,0 +1,78 @@ +# git-cliff configuration (https://github.com/orhun/git-cliff) + +[changelog] +trim = false + +header = """ +# Changelog +""" + +body = """ +## {{ version }} - *{{ timestamp | date(format="%Y-%m-%d") }}* +{% set scope = get_env(name="cliff_commit_scope") -%} +{% set commits = commits | filter(attribute="scope", value=scope) -%} +{% for group, commits in commits | group_by(attribute="group") %} +### {{ group | split(pat=":") | last | trim }} + +{% for commit in commits -%} +{% set message = commit.message | upper_first -%} +{% if commit.breaking -%} +{% set message = "(**!**) " ~ message -%} +{% endif -%} +{% set short_sha = commit.id | truncate(length=7, end="") -%} +{% set commit_url = "/commit/" ~ commit.id -%} +{% set ref = "[`" ~ short_sha ~ "`](" ~ commit_url ~ ")" -%} +{% if commit.remote.username -%} +{% set ref = ref ~ " by @" ~ commit.remote.username -%} +{% endif -%} +{% if commit.remote.pr_number -%} +{% set pr_num = commit.remote.pr_number -%} +{% set pr_url = "/pull/" ~ pr_num -%} +{% set ref = ref ~ " in [#" ~ pr_num ~ "](" ~ pr_url ~ ")" -%} +{% endif -%} +- {{ message }} - ({{ ref }}) +{% set include_commit_body = get_env(name="cliff_include_commit_body", default="false") -%} +{% set include_commit_body = include_commit_body == "true" -%} +{% if include_commit_body and commit.body %} + {{ commit.body | indent(prefix=" ") }} + +{% endif -%} +{% endfor -%} +{% endfor -%} +{% if previous.version -%} +{% set diff_url = "/compare/" ~ previous.version ~ ".." ~ version %} +The more detailed changelog for `{{ version }}` can be found [here]({{ diff_url }}). +{% endif -%} +""" + +postprocessors = [ + # Replace repository placeholder with the real URL + { pattern = "", replace = "https://github.com/eaasi/helm-charts" }, +] + +[git] +conventional_commits = true +filter_unconventional = true +filter_commits = false +split_commits = false +sort_commits = "oldest" +topo_order = false + +commit_preprocessors = [ + # Replace issue references with their remote link template + { pattern = '([\(\s]+)#([0-9]+)', replace = "${1}[#${2}](/issues/${2})"}, +] + +commit_parsers = [ + { message = "^feat", group = "1: Features" }, + { message = "^fix", group = "2: Bug Fixes" }, + { message = "^refactor", group = "3: Refactoring" }, + { message = "^test", group = "4: Testing" }, + { message = "^ci", group = "5: Continuous Integration" }, + { message = "^docs", group = "6: Documentation" }, + { message = ".*", group = "7: Miscellaneous" }, +] + +[remote.github] +owner = "eaasi" +repo = "helm-charts" diff --git a/configs/chart-releaser.yaml b/configs/chart-releaser.yaml new file mode 100644 index 0000000..a16b9b4 --- /dev/null +++ b/configs/chart-releaser.yaml @@ -0,0 +1,5 @@ +# chart-releaser configuration (https://github.com/helm/chart-releaser) + +pages-branch: pages +skip-existing: true +make-release-latest: false diff --git a/configs/chart-testing.yaml b/configs/chart-testing.yaml new file mode 100644 index 0000000..d3f98d0 --- /dev/null +++ b/configs/chart-testing.yaml @@ -0,0 +1,7 @@ +# chart-testing configuration (https://github.com/helm/chart-testing) + +check-version-increment: false +validate-maintainers: false +remote: origin +chart-dirs: + - charts diff --git a/configs/committed.toml b/configs/committed.toml new file mode 100644 index 0000000..ba8dcaf --- /dev/null +++ b/configs/committed.toml @@ -0,0 +1,31 @@ +# committed configuration (https://github.com/crate-ci/committed) + +line_length = 0 +subject_length = 0 +subject_capitalized = false +subject_not_punctuated = true +imperative_subject = true +merge_commit = true +no_fixup = true +no_wip = true + +style = "conventional" + +# allowed commit types +allowed_types = [ + "build", + "chore", + "ci", + "docs", + "feat", + "fix", + "refactor", + "revert", + "style", + "test", +] + +# allowed commit scopes +allowed_scopes = [ + "database", +] diff --git a/configs/typos.toml b/configs/typos.toml new file mode 100644 index 0000000..c727fa6 --- /dev/null +++ b/configs/typos.toml @@ -0,0 +1,15 @@ +# typos configuration (https://github.com/crate-ci/typos) + +[default] +extend-ignore-re = [ + # ignore lines with trailing "spellchecker:disable-line" + "(?Rm)^.*(#|//)\\s*spellchecker:disable-line$", + # ignore blocks with "spellchecker:" + "(?s)(#|//)\\s*spellchecker:off.*?\\n\\s*(#|//)\\s*spellchecker:on", + # ignore false positives triggered by "ba" surrounded by numbers + "[0-9]+ba", + "ba[0-9]+", +] + +[default.extend-words] +eaasi = "eaasi"