From e79b94255291dc75583db34c680883eae899f695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Wed, 14 Jan 2026 16:53:37 +0100 Subject: [PATCH 1/3] Prepare for OCI publishing of helm charts to docker hub --- .github/workflows/publish-helm-oci.yaml | 82 +++++++++++++++++++++++++ README.md | 6 +- hack/release/wizard/releaseWizard.yaml | 42 +++++++++++++ helm/solr-operator/README.md | 49 +++++++++++---- helm/solr/README.md | 12 +++- 5 files changed, 178 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/publish-helm-oci.yaml diff --git a/.github/workflows/publish-helm-oci.yaml b/.github/workflows/publish-helm-oci.yaml new file mode 100644 index 00000000..9eb6aa3c --- /dev/null +++ b/.github/workflows/publish-helm-oci.yaml @@ -0,0 +1,82 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: Publish Helm Charts to OCI Registry + +on: + workflow_dispatch: + inputs: + solr-operator-chart-url: + description: 'URL to solr-operator Helm chart tarball (e.g., https://dist.apache.org/repos/dist/release/solr/solr-operator/v0.10.0/helm-charts/solr-operator-0.10.0.tgz)' + required: true + type: string + solr-chart-url: + description: 'URL to solr Helm chart tarball (e.g., https://dist.apache.org/repos/dist/release/solr/solr-operator/v0.10.0/helm-charts/solr-0.10.0.tgz)' + required: true + type: string + +jobs: + publish-oci: + name: Publish Helm Charts to OCI Registry + runs-on: ubuntu-latest + steps: + - name: Install Helm + uses: azure/setup-helm@v4 + with: + version: 'latest' + + - name: Download Helm Charts + run: | + echo "Downloading solr-operator chart from: ${{ inputs.solr-operator-chart-url }}" + wget -O solr-operator.tgz "${{ inputs.solr-operator-chart-url }}" + + echo "Downloading solr chart from: ${{ inputs.solr-chart-url }}" + wget -O solr.tgz "${{ inputs.solr-chart-url }}" + + echo "Charts downloaded successfully" + ls -lh *.tgz + + - name: Login to Docker Hub + run: | + echo "Logging in to Docker Hub as ${{ secrets.DOCKERHUB_USER }}" + echo "${{ secrets.DOCKERHUB_TOKEN }}" | helm registry login docker.io -u "${{ secrets.DOCKERHUB_USER }}" --password-stdin + echo "Login successful" + + - name: Push solr-operator chart to OCI registry + run: | + echo "Pushing solr-operator chart to oci://docker.io/apache/solr-operator-chart" + helm push solr-operator.tgz oci://docker.io/apache/solr-operator-chart + echo "solr-operator chart pushed successfully" + + - name: Push solr chart to OCI registry + run: | + echo "Pushing solr chart to oci://docker.io/apache/solr-chart" + helm push solr.tgz oci://docker.io/apache/solr-chart + echo "solr chart pushed successfully" + + - name: Logout from Docker Hub + if: always() + run: | + helm registry logout docker.io + echo "Logged out from Docker Hub" + + - name: Summary + if: success() + run: | + echo "✅ Successfully published Helm charts to OCI registries:" + echo " - oci://docker.io/apache/solr-operator-chart" + echo " - oci://docker.io/apache/solr-chart" diff --git a/README.md b/README.md index d3a0f36e..5236850a 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,11 @@ Join us on the [#solr-operator](https://kubernetes.slack.com/messages/solr-opera Please visit the following pages for documentation on using and developing the Solr Operator: - [Local Tutorial](https://solr.apache.org/guide/operator/latest/getting-started/local-tutorial.html) -- [Helm Instructions via Artifact Hub](https://artifacthub.io/packages/helm/apache-solr/solr-operator) +- **Helm Chart Installation** + - The Helm charts are published as OCI artifacts (recommended): + - **Solr Operator**: `helm install solr-operator oci://ghcr.io/apache/solr-operator/helm/solr-operator --version ` + - **Solr Cloud**: `helm install solr oci://ghcr.io/apache/solr-operator/helm/solr --version ` + - Or via the deprecated HTTPS repository: [Helm Instructions via Artifact Hub](https://artifacthub.io/packages/helm/apache-solr/solr-operator) - The released helm charts and their instructions should be used for all safe and stable deployments. The charts found in `helm/` are not guaranteed to be compatible with the last stable release, and should only be used for development purposes. - [Running the Solr Operator](https://solr.apache.org/guide/operator/latest/getting-started/running-the-operator.html) diff --git a/hack/release/wizard/releaseWizard.yaml b/hack/release/wizard/releaseWizard.yaml index ee3b9eb7..30840e56 100644 --- a/hack/release/wizard/releaseWizard.yaml +++ b/hack/release/wizard/releaseWizard.yaml @@ -1120,6 +1120,45 @@ groups: cmd: ./hack/release/upload/upload_helm.sh -g "{{ gpg_key | default("", True) }}" -a "{{ gpg.apache_id | default("", True) }}" -c "{{ official_helm_charts_url }}" -r "{{ dist_release_url }}" logfile: upload_helm.log tee: true + - !Todo + id: publish_helm_charts_oci + title: Publish Helm charts to OCI registry (Docker Hub) + depends: publish_helm_charts + vars: + dist_release_url: https://dist.apache.org/repos/dist/release/solr/solr-operator/{{ release_version }} + solr_operator_chart_url: '{{ dist_release_url }}/helm-charts/solr-operator-{{ release_version[1:] }}.tgz' + solr_chart_url: '{{ dist_release_url }}/helm-charts/solr-{{ release_version[1:] }}.tgz' + workflow_url: https://github.com/apache/solr-operator/actions/workflows/publish-helm-oci.yaml + description: | + Publish the Helm charts to OCI registries on Docker Hub using the GitHub Actions workflow. + + This task publishes the voted Helm charts to OCI registries, making them available via: + - oci://docker.io/apache/solr-operator-chart + - oci://docker.io/apache/solr-chart + + Steps to publish: + 1. Navigate to the GitHub Actions workflow: + {{ workflow_url }} + + 2. Click the "Run workflow" button on the right side + + 3. Fill in the workflow inputs: + - solr-operator-chart-url: {{ solr_operator_chart_url }} + - solr-chart-url: {{ solr_chart_url }} + + 4. Click "Run workflow" to start the publishing job + + 5. Monitor the workflow execution for any errors + + 6. Verify successful completion by checking that both charts are accessible: + helm pull oci://docker.io/apache/solr-operator-chart --version {{ release_version[1:] }} + helm pull oci://docker.io/apache/solr-chart --version {{ release_version[1:] }} + + Note: The workflow uses repository secrets DOCKERHUB_USER and DOCKERHUB_TOKEN for authentication. + links: + - '{{ workflow_url }}' + - '{{ solr_operator_chart_url }}' + - '{{ solr_chart_url }}' - !Todo id: publish_crds title: Publish the staged CRDs @@ -1179,11 +1218,14 @@ groups: depends: - publish_docker_image - publish_helm_charts + - publish_helm_charts_oci description: | Check to make sure that ArtifactHub has successfully loaded the {{ release_version }} version of the Solr Operator and Solr Helm Charts. Mark this as complete when you have confirmed all aspects of the chart in artifactHub. The ChangeLog is very finicky, so make sure that it renders correctly. + + Also verify that the OCI registry information is correctly displayed on ArtifactHub. links: - https://artifacthub.io/packages/helm/apache-solr/solr-operator - https://artifacthub.io/packages/helm/apache-solr/solr diff --git a/helm/solr-operator/README.md b/helm/solr-operator/README.md index 79acc1a4..b632a185 100644 --- a/helm/solr-operator/README.md +++ b/helm/solr-operator/README.md @@ -31,19 +31,34 @@ If you do not wish to use the Zookeeper Operator, set: - `zookeeper-operator.use: false` -### Adding the Solr Operator Helm Chart Repository -You should only need to add the solr operator helm chart repository once, by running the following command: +### Installing the Chart + +The Solr Operator Helm chart can be installed using either the OCI registry (recommended) or the traditional HTTPS repository. + +#### Installation via OCI Registry (Recommended) + +The Helm chart is available directly from Docker Hub as an OCI artifact, which provides a more reliable distribution mechanism and doesn't require adding a repository. ```bash -helm repo add apache-solr https://solr.apache.org/charts +# Install CRDs first +kubectl create -f https://solr.apache.org/operator/downloads/crds/v0.10.0-prerelease/all-with-dependencies.yaml + +# Install the Solr Operator from OCI registry +helm install solr-operator oci://docker.io/apache/solr-operator-chart --version 0.10.0-prerelease ``` -### Installing the Chart +#### Installation via HTTPS Repository (Traditional) -To install the Solr Operator for the first time in your cluster, you can use the latest version or a specific version, run with the following commands: +If you prefer the traditional method, you can add the Helm repository and install from there. ```bash +# Add the repository (only needed once) +helm repo add apache-solr https://solr.apache.org/charts + +# Install CRDs first kubectl create -f https://solr.apache.org/operator/downloads/crds/v0.10.0-prerelease/all-with-dependencies.yaml + +# Install the Solr Operator from HTTPS repository helm install solr-operator apache-solr/solr-operator --version 0.10.0-prerelease ``` @@ -57,7 +72,13 @@ _Note that the Helm chart version does not contain a `v` prefix, which the downl If you are upgrading your Solr Operator deployment, you should always use a specific version of the chart and pre-install the Solr CRDS: ```bash +# Upgrade CRDs first kubectl replace -f https://solr.apache.org/operator/downloads/crds/v0.10.0-prerelease/all-with-dependencies.yaml + +# Upgrade via OCI registry (recommended) +helm upgrade solr-operator oci://docker.io/apache/solr-operator-chart --version 0.10.0-prerelease + +# Or upgrade via HTTPS repository (traditional) helm upgrade solr-operator apache-solr/solr-operator --version 0.10.0-prerelease ``` @@ -67,18 +88,20 @@ If you want to specify the namespace for the installation, use the `--namespace` All resources will be deployed to the given namespace. ```bash -helm install solr-operator apache-solr/solr-operator --namespace solr +helm install solr-operator oci://docker.io/apache/solr-operator-chart --version 0.10.0-prerelease --namespace solr ``` If you want to only watch that namespace, or others, then you will have to provide the `watchNamespaces` option. ```bash # Watch the namespace where the operator is deployed to (just pass the boolean true) -helm install solr-operator apache-solr/solr-operator --namespace solr --set watchNamespaces=true +helm install solr-operator oci://docker.io/apache/solr-operator-chart --version 0.10.0-prerelease --namespace solr --set watchNamespaces=true + # Watch a single namespace different than the one being deployed to -helm install solr-operator apache-solr/solr-operator --namespace solr --set watchNamespaces=other -# Watch multiple namespaces (commmas must be escaped in the set string) -helm install solr-operator apache-solr/solr-operator --namespace solr --set watchNamespaces="team1\,team2\,team3" +helm install solr-operator oci://docker.io/apache/solr-operator-chart --version 0.10.0-prerelease --namespace solr --set watchNamespaces=other + +# Watch multiple namespaces (commas must be escaped in the set string) +helm install solr-operator oci://docker.io/apache/solr-operator-chart --version 0.10.0-prerelease --namespace solr --set watchNamespaces="team1\,team2\,team3" ``` Note: Passing `false` or `""` to the `watchNamespaces` variable will both result in the operator watchting all namespaces in the Kube cluster. @@ -91,7 +114,11 @@ If you have solr operator installations in multiple namespaces that are managed This can be done with the `--skip-crds` helm option. ```bash -helm install solr-operator apache-solr/solr-operator --skip-crds --namespace solr +# Via OCI registry +helm install solr-operator oci://docker.io/apache/solr-operator-chart --version 0.10.0-prerelease --skip-crds --namespace solr + +# Or via HTTPS repository +helm install solr-operator apache-solr/solr-operator --version 0.10.0-prerelease --skip-crds --namespace solr ``` **Helm will not upgrade CRDs once they have been installed. diff --git a/helm/solr/README.md b/helm/solr/README.md index 52eaa4cf..a6ee68e8 100644 --- a/helm/solr/README.md +++ b/helm/solr/README.md @@ -33,9 +33,15 @@ There may be breaking changes between the version you are using and the version ### Installing the Chart -To install a SolrCloud for the first time in your cluster, you can use the latest version or a specific version, run with the following commands: +The Solr Helm chart can be installed using either the OCI registry (recommended) or the traditional HTTPS helm repository. + +To install a SolrCloud for the first time in your cluster, you can use the latest version or a specific version: ```bash +# Via OCI registry (recommended) +helm install example oci://docker.io/apache/solr-chart --version 0.10.0-prerelease --set image.tag=9.10.0 + +# Or via HTTPS helm repository (traditional) helm install example apache-solr/solr --version 0.10.0-prerelease --set image.tag=9.10.0 ``` @@ -50,6 +56,10 @@ _Note that the Helm chart version does not contain a `v` prefix, which the Solr If you are upgrading your SolrCloud deployment, you should always use a specific version of the chart and upgrade **after [upgrading the Solr Operator](https://artifacthub.io/packages/helm/apache-solr/solr-operator#upgrading-the-solr-operator) to the same version**: ```bash +# Via OCI registry (recommended) +helm upgrade example oci://docker.io/apache/solr-chart --version 0.10.0-prerelease --reuse-values --set image.tag=9.10.0 + +# Or via HTTPS repository (traditional) helm upgrade example apache-solr/solr --version 0.10.0-prerelease --reuse-values --set image.tag=9.10.0 ``` From 59513bd3ed15ccda9180c66fea0dc67b373fb63e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Wed, 14 Jan 2026 20:36:44 +0100 Subject: [PATCH 2/3] Dry-run flag in workflow Validate url Validate checksum --- .github/workflows/publish-helm-oci.yaml | 154 +++++++++++++++++++++--- hack/release/wizard/releaseWizard.yaml | 14 ++- 2 files changed, 146 insertions(+), 22 deletions(-) diff --git a/.github/workflows/publish-helm-oci.yaml b/.github/workflows/publish-helm-oci.yaml index 9eb6aa3c..f8509d69 100644 --- a/.github/workflows/publish-helm-oci.yaml +++ b/.github/workflows/publish-helm-oci.yaml @@ -28,6 +28,14 @@ on: description: 'URL to solr Helm chart tarball (e.g., https://dist.apache.org/repos/dist/release/solr/solr-operator/v0.10.0/helm-charts/solr-0.10.0.tgz)' required: true type: string + dry-run: + description: 'Dry run - download and verify charts but do not push to OCI registry' + required: false + type: boolean + default: false + +permissions: + contents: read jobs: publish-oci: @@ -39,44 +47,152 @@ jobs: with: version: 'latest' + - name: Login to Docker Hub + if: ${{ !inputs.dry-run }} + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USER }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Validate Input URLs + run: | + # Validate URLs are from expected Apache dist domain + if [[ ! "${{ inputs.solr-operator-chart-url }}" =~ ^https://dist\.apache\.org/repos/dist/(release|dev)/solr/ ]]; then + echo "Error: solr-operator-chart-url must be from dist.apache.org" + exit 1 + fi + if [[ ! "${{ inputs.solr-chart-url }}" =~ ^https://dist\.apache\.org/repos/dist/(release|dev)/solr/ ]]; then + echo "Error: solr-chart-url must be from dist.apache.org" + exit 1 + fi + echo "✓ URLs validated" + - name: Download Helm Charts run: | + set -e echo "Downloading solr-operator chart from: ${{ inputs.solr-operator-chart-url }}" - wget -O solr-operator.tgz "${{ inputs.solr-operator-chart-url }}" + curl --fail --show-error --location --retry 3 --retry-delay 5 \ + -o solr-operator.tgz "${{ inputs.solr-operator-chart-url }}" echo "Downloading solr chart from: ${{ inputs.solr-chart-url }}" - wget -O solr.tgz "${{ inputs.solr-chart-url }}" + curl --fail --show-error --location --retry 3 --retry-delay 5 \ + -o solr.tgz "${{ inputs.solr-chart-url }}" - echo "Charts downloaded successfully" + echo "Charts downloaded successfully:" ls -lh *.tgz - - name: Login to Docker Hub + # Verify they are valid tar files + echo "Verifying chart integrity..." + tar -tzf solr-operator.tgz > /dev/null + tar -tzf solr.tgz > /dev/null + echo "✓ Charts are valid tarballs" + + - name: Download and Verify Checksums run: | - echo "Logging in to Docker Hub as ${{ secrets.DOCKERHUB_USER }}" - echo "${{ secrets.DOCKERHUB_TOKEN }}" | helm registry login docker.io -u "${{ secrets.DOCKERHUB_USER }}" --password-stdin - echo "Login successful" + set -e + echo "Downloading checksums..." + + # Download SHA512 checksums + curl --fail --show-error --location --retry 3 --retry-delay 5 \ + -o solr-operator.tgz.sha512 "${{ inputs.solr-operator-chart-url }}.sha512" + + curl --fail --show-error --location --retry 3 --retry-delay 5 \ + -o solr.tgz.sha512 "${{ inputs.solr-chart-url }}.sha512" + + echo "Checksums downloaded:" + ls -lh *.sha512 + + # Verify SHA512 checksums + echo "Verifying solr-operator chart checksum..." + sha512sum -c solr-operator.tgz.sha512 + echo "✓ solr-operator chart checksum verified" + + echo "Verifying solr chart checksum..." + sha512sum -c solr.tgz.sha512 + echo "✓ solr chart checksum verified" + + echo "" + echo "✅ All checksums verified successfully" + + - name: Extract Chart Versions + id: versions + run: | + # Extract version from solr-operator chart + OPERATOR_VERSION=$(tar -xzOf solr-operator.tgz solr-operator/Chart.yaml | grep '^version:' | awk '{print $2}') + echo "operator-version=${OPERATOR_VERSION}" >> $GITHUB_OUTPUT + echo "Solr Operator Chart Version: ${OPERATOR_VERSION}" + + # Extract version from solr chart + SOLR_VERSION=$(tar -xzOf solr.tgz solr/Chart.yaml | grep '^version:' | awk '{print $2}') + echo "solr-version=${SOLR_VERSION}" >> $GITHUB_OUTPUT + echo "Solr Chart Version: ${SOLR_VERSION}" - name: Push solr-operator chart to OCI registry + if: ${{ !inputs.dry-run }} run: | - echo "Pushing solr-operator chart to oci://docker.io/apache/solr-operator-chart" + echo "Pushing solr-operator chart (version ${{ steps.versions.outputs.operator-version }}) to oci://docker.io/apache/solr-operator-chart" helm push solr-operator.tgz oci://docker.io/apache/solr-operator-chart - echo "solr-operator chart pushed successfully" + echo "✓ solr-operator chart pushed successfully" - name: Push solr chart to OCI registry + if: ${{ !inputs.dry-run }} run: | - echo "Pushing solr chart to oci://docker.io/apache/solr-chart" + echo "Pushing solr chart (version ${{ steps.versions.outputs.solr-version }}) to oci://docker.io/apache/solr-chart" helm push solr.tgz oci://docker.io/apache/solr-chart - echo "solr chart pushed successfully" + echo "✓ solr chart pushed successfully" + + - name: Dry Run Summary + if: ${{ inputs.dry-run }} + run: | + echo "## 🧪 Dry Run Mode - No Charts Published" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Validation Results" >> $GITHUB_STEP_SUMMARY + echo "- ✅ URLs validated from dist.apache.org" >> $GITHUB_STEP_SUMMARY + echo "- ✅ Charts downloaded successfully" >> $GITHUB_STEP_SUMMARY + echo "- ✅ Chart integrity verified (valid tarballs)" >> $GITHUB_STEP_SUMMARY + echo "- ✅ SHA512 checksums verified" >> $GITHUB_STEP_SUMMARY + echo "- ✅ Chart versions extracted" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Chart Information" >> $GITHUB_STEP_SUMMARY + echo "- **Solr Operator Version**: \`${{ steps.versions.outputs.operator-version }}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Solr Chart Version**: \`${{ steps.versions.outputs.solr-version }}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Next Steps" >> $GITHUB_STEP_SUMMARY + echo "Run this workflow again with **dry-run = false** to publish the charts to OCI registries." >> $GITHUB_STEP_SUMMARY - - name: Logout from Docker Hub - if: always() + - name: Verify Published Charts + if: ${{ !inputs.dry-run }} run: | - helm registry logout docker.io - echo "Logged out from Docker Hub" + echo "Verifying charts are accessible from OCI registry..." + + # Verify solr-operator chart + echo "Pulling solr-operator chart version ${{ steps.versions.outputs.operator-version }}..." + helm pull oci://docker.io/apache/solr-operator-chart --version ${{ steps.versions.outputs.operator-version }} + echo "✓ solr-operator chart verified" + + # Verify solr chart + echo "Pulling solr chart version ${{ steps.versions.outputs.solr-version }}..." + helm pull oci://docker.io/apache/solr-chart --version ${{ steps.versions.outputs.solr-version }} + echo "✓ solr chart verified" - name: Summary - if: success() + if: ${{ success() && !inputs.dry-run }} run: | - echo "✅ Successfully published Helm charts to OCI registries:" - echo " - oci://docker.io/apache/solr-operator-chart" - echo " - oci://docker.io/apache/solr-chart" + echo "## ✅ Successfully Published Helm Charts" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "The following charts have been published to OCI registries:" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Solr Operator Chart" >> $GITHUB_STEP_SUMMARY + echo "- **Registry**: \`oci://docker.io/apache/solr-operator-chart\`" >> $GITHUB_STEP_SUMMARY + echo "- **Version**: \`${{ steps.versions.outputs.operator-version }}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Install**: \`helm install solr-operator oci://docker.io/apache/solr-operator-chart --version ${{ steps.versions.outputs.operator-version }}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Solr Chart" >> $GITHUB_STEP_SUMMARY + echo "- **Registry**: \`oci://docker.io/apache/solr-chart\`" >> $GITHUB_STEP_SUMMARY + echo "- **Version**: \`${{ steps.versions.outputs.solr-version }}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Install**: \`helm install solr oci://docker.io/apache/solr-chart --version ${{ steps.versions.outputs.solr-version }}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Verification" >> $GITHUB_STEP_SUMMARY + echo "- ✅ Charts downloaded and checksums verified" >> $GITHUB_STEP_SUMMARY + echo "- ✅ Charts pushed to OCI registries" >> $GITHUB_STEP_SUMMARY + echo "- ✅ Charts verified as accessible from OCI registry" >> $GITHUB_STEP_SUMMARY diff --git a/hack/release/wizard/releaseWizard.yaml b/hack/release/wizard/releaseWizard.yaml index 30840e56..53f82485 100644 --- a/hack/release/wizard/releaseWizard.yaml +++ b/hack/release/wizard/releaseWizard.yaml @@ -1145,16 +1145,24 @@ groups: 3. Fill in the workflow inputs: - solr-operator-chart-url: {{ solr_operator_chart_url }} - solr-chart-url: {{ solr_chart_url }} + - dry-run: false (set to true for validation without publishing) - 4. Click "Run workflow" to start the publishing job + 4. Optional: Run with dry-run=true first to verify: + - URLs are valid and accessible + - Charts download successfully + - SHA512 checksums match + - Chart versions are correct - 5. Monitor the workflow execution for any errors + 5. Click "Run workflow" to start the job - 6. Verify successful completion by checking that both charts are accessible: + 6. Monitor the workflow execution for any errors + + 7. Verify successful completion by checking that both charts are accessible: helm pull oci://docker.io/apache/solr-operator-chart --version {{ release_version[1:] }} helm pull oci://docker.io/apache/solr-chart --version {{ release_version[1:] }} Note: The workflow uses repository secrets DOCKERHUB_USER and DOCKERHUB_TOKEN for authentication. + The workflow automatically verifies SHA512 checksums before publishing. links: - '{{ workflow_url }}' - '{{ solr_operator_chart_url }}' From 3fe79e15120084803e8289d7bf71be3155beb42c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 3 Sep 2026 16:21:49 +0200 Subject: [PATCH 3/3] Publish Helm charts as OCI artifacts to GHCR instead of Docker Hub Docker Hub only supports a single namespace level, so 'helm push' (which appends the chart name from Chart.yaml) can only produce apache/solr and apache/solr-operator there. That burns the apache/solr name on a chart rather than a future Solr server image, and mixes chart tags with image tags in one tag list. The previous target, apache/solr-operator-chart, would have resolved to a three-level path and failed at push. ghcr.io supports nested paths, so the charts go to ghcr.io/apache/solr-operator/helm/{solr,solr-operator}, keeping the chart name 'solr' while leaving apache/solr free everywhere. Public ghcr.io packages are anonymously pullable, so no credentials are needed to install. Workflow changes beyond the registry switch: - Keep the downloaded basenames. The .sha512 and .prov files reference the chart's original filename, so renaming to solr.tgz broke 'sha512sum -c'. - Download and push the .prov file, so 'helm install --verify' works against the OCI copy. - Verify the detached GPG signatures against the Solr KEYS file. The checksums alone come from the same host as the charts. - Authenticate with the built-in GITHUB_TOKEN rather than Docker Hub secrets. - After pushing, log out and pull both charts back anonymously, checking they are byte-identical to the released artifacts. ghcr.io creates packages as private, and this is what catches that. - Pass inputs through the environment and pin azure/setup-helm to a SHA. Charts are published to both the OCI registry and the deprecated HTTPS repository throughout the 0.x releases. Starting with v1.0.0 they will be published to the OCI registry only. test_cluster.sh gains an -o flag to smoke test the published OCI artifacts. Claude-Session: https://claude.ai/code/session_017UoVFe4S1qkbw4KurD77Fi --- .github/workflows/publish-helm-oci.yaml | 302 ++++++++++-------- README.md | 1 + .../getting-started/pages/local-tutorial.adoc | 24 +- .../pages/running-the-operator.adoc | 26 +- .../upgrade-notes/pages/upgrade-notes.adoc | 33 +- hack/release/smoke_test/test_cluster.sh | 30 +- hack/release/wizard/releaseWizard.yaml | 50 +-- helm/solr-operator/README.md | 31 +- helm/solr/README.md | 14 +- 9 files changed, 320 insertions(+), 191 deletions(-) diff --git a/.github/workflows/publish-helm-oci.yaml b/.github/workflows/publish-helm-oci.yaml index f8509d69..bb74fcaf 100644 --- a/.github/workflows/publish-helm-oci.yaml +++ b/.github/workflows/publish-helm-oci.yaml @@ -17,6 +17,15 @@ name: Publish Helm Charts to OCI Registry +# Publishes already-released, already-voted-on Helm charts from dist.apache.org to the +# GitHub Container Registry, as OCI artifacts. +# +# The charts on dist.apache.org remain the canonical, signed release artifacts; the OCI +# copies are convenience binaries. This workflow therefore never builds a chart, it only +# re-publishes a verified copy of one that has already been released. +# +# This workflow is also used to backfill previously released versions. + on: workflow_dispatch: inputs: @@ -29,13 +38,24 @@ on: required: true type: string dry-run: - description: 'Dry run - download and verify charts but do not push to OCI registry' + description: 'Dry run - download and verify charts but do not push to the OCI registry' required: false type: boolean default: false permissions: contents: read + packages: write + +env: + # 'helm push' appends the chart name from Chart.yaml to this target, producing: + # ghcr.io/apache/solr-operator/helm/solr-operator + # ghcr.io/apache/solr-operator/helm/solr + # The charts are namespaced under the repository name because ghcr.io/apache/* is a + # single namespace shared by every ASF project. Keeping the charts here also leaves + # 'apache/solr' free for a future Solr server image. + OCI_TARGET: oci://ghcr.io/apache/solr-operator/helm + ASF_KEYS_URL: https://dist.apache.org/repos/dist/release/solr/KEYS jobs: publish-oci: @@ -43,156 +63,184 @@ jobs: runs-on: ubuntu-latest steps: - name: Install Helm - uses: azure/setup-helm@v4 + uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1 with: version: 'latest' - - name: Login to Docker Hub - if: ${{ !inputs.dry-run }} - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USER }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Validate Input URLs + # Inputs are passed through the environment rather than interpolated into the + # script body, so that a malicious input cannot inject shell commands. + - name: Validate input URLs + id: inputs + env: + OPERATOR_CHART_URL: ${{ inputs.solr-operator-chart-url }} + SOLR_CHART_URL: ${{ inputs.solr-chart-url }} run: | - # Validate URLs are from expected Apache dist domain - if [[ ! "${{ inputs.solr-operator-chart-url }}" =~ ^https://dist\.apache\.org/repos/dist/(release|dev)/solr/ ]]; then - echo "Error: solr-operator-chart-url must be from dist.apache.org" + set -euo pipefail + + for url in "${OPERATOR_CHART_URL}" "${SOLR_CHART_URL}"; do + if [[ ! "${url}" =~ ^https://dist\.apache\.org/repos/dist/(release|dev)/solr/ ]]; then + echo "Error: chart URLs must be from dist.apache.org: ${url}" >&2 + exit 1 + fi + done + + # The .sha512 and .prov files both reference the chart's original filename, so + # the downloads must keep their basenames rather than being renamed. + OPERATOR_CHART_FILE="$(basename "${OPERATOR_CHART_URL}")" + SOLR_CHART_FILE="$(basename "${SOLR_CHART_URL}")" + + if [[ ! "${OPERATOR_CHART_FILE}" =~ ^solr-operator-[0-9][A-Za-z0-9.+_-]*\.tgz$ ]]; then + echo "Error: unexpected solr-operator chart filename: ${OPERATOR_CHART_FILE}" >&2 exit 1 fi - if [[ ! "${{ inputs.solr-chart-url }}" =~ ^https://dist\.apache\.org/repos/dist/(release|dev)/solr/ ]]; then - echo "Error: solr-chart-url must be from dist.apache.org" + if [[ ! "${SOLR_CHART_FILE}" =~ ^solr-[0-9][A-Za-z0-9.+_-]*\.tgz$ ]]; then + echo "Error: unexpected solr chart filename: ${SOLR_CHART_FILE}" >&2 exit 1 fi - echo "✓ URLs validated" - - name: Download Helm Charts - run: | - set -e - echo "Downloading solr-operator chart from: ${{ inputs.solr-operator-chart-url }}" - curl --fail --show-error --location --retry 3 --retry-delay 5 \ - -o solr-operator.tgz "${{ inputs.solr-operator-chart-url }}" + echo "operator-chart-file=${OPERATOR_CHART_FILE}" >> "$GITHUB_OUTPUT" + echo "solr-chart-file=${SOLR_CHART_FILE}" >> "$GITHUB_OUTPUT" + echo "URLs validated" + echo " solr-operator chart: ${OPERATOR_CHART_FILE}" + echo " solr chart: ${SOLR_CHART_FILE}" - echo "Downloading solr chart from: ${{ inputs.solr-chart-url }}" - curl --fail --show-error --location --retry 3 --retry-delay 5 \ - -o solr.tgz "${{ inputs.solr-chart-url }}" - - echo "Charts downloaded successfully:" - ls -lh *.tgz - - # Verify they are valid tar files - echo "Verifying chart integrity..." - tar -tzf solr-operator.tgz > /dev/null - tar -tzf solr.tgz > /dev/null - echo "✓ Charts are valid tarballs" - - - name: Download and Verify Checksums + - name: Download charts, checksums, signatures and provenance + env: + OPERATOR_CHART_URL: ${{ inputs.solr-operator-chart-url }} + SOLR_CHART_URL: ${{ inputs.solr-chart-url }} run: | - set -e - echo "Downloading checksums..." - - # Download SHA512 checksums - curl --fail --show-error --location --retry 3 --retry-delay 5 \ - -o solr-operator.tgz.sha512 "${{ inputs.solr-operator-chart-url }}.sha512" - - curl --fail --show-error --location --retry 3 --retry-delay 5 \ - -o solr.tgz.sha512 "${{ inputs.solr-chart-url }}.sha512" - - echo "Checksums downloaded:" - ls -lh *.sha512 - - # Verify SHA512 checksums - echo "Verifying solr-operator chart checksum..." - sha512sum -c solr-operator.tgz.sha512 - echo "✓ solr-operator chart checksum verified" - - echo "Verifying solr chart checksum..." - sha512sum -c solr.tgz.sha512 - echo "✓ solr chart checksum verified" - - echo "" - echo "✅ All checksums verified successfully" - - - name: Extract Chart Versions + set -euo pipefail + mkdir -p charts && cd charts + + # The .prov file is what makes 'helm install --verify' work against the OCI + # copy: 'helm push' uploads it automatically when it sits next to the chart. + for url in "${OPERATOR_CHART_URL}" "${SOLR_CHART_URL}"; do + for suffix in "" .sha512 .asc .prov; do + curl --fail --show-error --silent --location --retry 3 --retry-delay 5 \ + -O "${url}${suffix}" + done + done + + echo "Downloaded:" + ls -lh + + - name: Verify SHA512 checksums + working-directory: charts + run: | + set -euo pipefail + sha512sum -c ./*.tgz.sha512 + echo "SHA512 checksums verified" + + # The checksums come from the same host as the charts, so on their own they only + # prove the download was not corrupted. The detached GPG signatures are what prove + # the artifacts are the ones the PMC voted on. + - name: Verify GPG signatures + working-directory: charts + run: | + set -euo pipefail + curl --fail --show-error --silent --location "${ASF_KEYS_URL}" | gpg --import --quiet + for asc in ./*.tgz.asc; do + gpg --verify "${asc}" "${asc%.asc}" + done + echo "GPG signatures verified" + + - name: Extract chart versions id: versions + working-directory: charts + env: + OPERATOR_CHART_FILE: ${{ steps.inputs.outputs.operator-chart-file }} + SOLR_CHART_FILE: ${{ steps.inputs.outputs.solr-chart-file }} run: | - # Extract version from solr-operator chart - OPERATOR_VERSION=$(tar -xzOf solr-operator.tgz solr-operator/Chart.yaml | grep '^version:' | awk '{print $2}') - echo "operator-version=${OPERATOR_VERSION}" >> $GITHUB_OUTPUT - echo "Solr Operator Chart Version: ${OPERATOR_VERSION}" + set -euo pipefail + OPERATOR_VERSION="$(tar -xzOf "${OPERATOR_CHART_FILE}" solr-operator/Chart.yaml | awk '$1 == "version:" {print $2; exit}')" + SOLR_VERSION="$(tar -xzOf "${SOLR_CHART_FILE}" solr/Chart.yaml | awk '$1 == "version:" {print $2; exit}')" - # Extract version from solr chart - SOLR_VERSION=$(tar -xzOf solr.tgz solr/Chart.yaml | grep '^version:' | awk '{print $2}') - echo "solr-version=${SOLR_VERSION}" >> $GITHUB_OUTPUT - echo "Solr Chart Version: ${SOLR_VERSION}" + echo "operator-version=${OPERATOR_VERSION}" >> "$GITHUB_OUTPUT" + echo "solr-version=${SOLR_VERSION}" >> "$GITHUB_OUTPUT" + echo "Solr Operator chart version: ${OPERATOR_VERSION}" + echo "Solr chart version: ${SOLR_VERSION}" - - name: Push solr-operator chart to OCI registry + - name: Log in to GitHub Container Registry if: ${{ !inputs.dry-run }} run: | - echo "Pushing solr-operator chart (version ${{ steps.versions.outputs.operator-version }}) to oci://docker.io/apache/solr-operator-chart" - helm push solr-operator.tgz oci://docker.io/apache/solr-operator-chart - echo "✓ solr-operator chart pushed successfully" + set -euo pipefail + echo "${{ secrets.GITHUB_TOKEN }}" | \ + helm registry login ghcr.io -u "${{ github.actor }}" --password-stdin + echo "Logged in to ghcr.io" - - name: Push solr chart to OCI registry + - name: Push charts to OCI registry if: ${{ !inputs.dry-run }} + working-directory: charts + env: + OPERATOR_CHART_FILE: ${{ steps.inputs.outputs.operator-chart-file }} + SOLR_CHART_FILE: ${{ steps.inputs.outputs.solr-chart-file }} run: | - echo "Pushing solr chart (version ${{ steps.versions.outputs.solr-version }}) to oci://docker.io/apache/solr-chart" - helm push solr.tgz oci://docker.io/apache/solr-chart - echo "✓ solr chart pushed successfully" - - - name: Dry Run Summary - if: ${{ inputs.dry-run }} - run: | - echo "## 🧪 Dry Run Mode - No Charts Published" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Validation Results" >> $GITHUB_STEP_SUMMARY - echo "- ✅ URLs validated from dist.apache.org" >> $GITHUB_STEP_SUMMARY - echo "- ✅ Charts downloaded successfully" >> $GITHUB_STEP_SUMMARY - echo "- ✅ Chart integrity verified (valid tarballs)" >> $GITHUB_STEP_SUMMARY - echo "- ✅ SHA512 checksums verified" >> $GITHUB_STEP_SUMMARY - echo "- ✅ Chart versions extracted" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Chart Information" >> $GITHUB_STEP_SUMMARY - echo "- **Solr Operator Version**: \`${{ steps.versions.outputs.operator-version }}\`" >> $GITHUB_STEP_SUMMARY - echo "- **Solr Chart Version**: \`${{ steps.versions.outputs.solr-version }}\`" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Next Steps" >> $GITHUB_STEP_SUMMARY - echo "Run this workflow again with **dry-run = false** to publish the charts to OCI registries." >> $GITHUB_STEP_SUMMARY - - - name: Verify Published Charts + set -euo pipefail + # helm appends each chart's name, so both charts share one push target. + helm push "${OPERATOR_CHART_FILE}" "${OCI_TARGET}" + helm push "${SOLR_CHART_FILE}" "${OCI_TARGET}" + + # Packages are created private by default on ghcr.io. Re-pulling anonymously is what + # catches that: it fails loudly rather than leaving a chart nobody can install. + - name: Verify published charts are anonymously pullable if: ${{ !inputs.dry-run }} + env: + OPERATOR_VERSION: ${{ steps.versions.outputs.operator-version }} + SOLR_VERSION: ${{ steps.versions.outputs.solr-version }} + OPERATOR_CHART_FILE: ${{ steps.inputs.outputs.operator-chart-file }} + SOLR_CHART_FILE: ${{ steps.inputs.outputs.solr-chart-file }} run: | - echo "Verifying charts are accessible from OCI registry..." + set -euo pipefail + helm registry logout ghcr.io || true + + # 'helm pull --verify' reads the pushed .prov, so this also proves provenance + # survived the round-trip. helm looks for the legacy public keyring. + gpg --export > ~/.gnupg/pubring.gpg - # Verify solr-operator chart - echo "Pulling solr-operator chart version ${{ steps.versions.outputs.operator-version }}..." - helm pull oci://docker.io/apache/solr-operator-chart --version ${{ steps.versions.outputs.operator-version }} - echo "✓ solr-operator chart verified" + mkdir -p pulled + helm pull --verify "${OCI_TARGET}/solr-operator" --version "${OPERATOR_VERSION}" -d pulled + helm pull --verify "${OCI_TARGET}/solr" --version "${SOLR_VERSION}" -d pulled - # Verify solr chart - echo "Pulling solr chart version ${{ steps.versions.outputs.solr-version }}..." - helm pull oci://docker.io/apache/solr-chart --version ${{ steps.versions.outputs.solr-version }} - echo "✓ solr chart verified" + # The pulled charts must be byte-identical to the released ones. + cmp "pulled/${OPERATOR_CHART_FILE}" "charts/${OPERATOR_CHART_FILE}" + cmp "pulled/${SOLR_CHART_FILE}" "charts/${SOLR_CHART_FILE}" + echo "Charts are public, verifiable and identical to the released artifacts" - name: Summary - if: ${{ success() && !inputs.dry-run }} + if: ${{ success() }} + env: + OPERATOR_VERSION: ${{ steps.versions.outputs.operator-version }} + SOLR_VERSION: ${{ steps.versions.outputs.solr-version }} run: | - echo "## ✅ Successfully Published Helm Charts" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "The following charts have been published to OCI registries:" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Solr Operator Chart" >> $GITHUB_STEP_SUMMARY - echo "- **Registry**: \`oci://docker.io/apache/solr-operator-chart\`" >> $GITHUB_STEP_SUMMARY - echo "- **Version**: \`${{ steps.versions.outputs.operator-version }}\`" >> $GITHUB_STEP_SUMMARY - echo "- **Install**: \`helm install solr-operator oci://docker.io/apache/solr-operator-chart --version ${{ steps.versions.outputs.operator-version }}\`" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Solr Chart" >> $GITHUB_STEP_SUMMARY - echo "- **Registry**: \`oci://docker.io/apache/solr-chart\`" >> $GITHUB_STEP_SUMMARY - echo "- **Version**: \`${{ steps.versions.outputs.solr-version }}\`" >> $GITHUB_STEP_SUMMARY - echo "- **Install**: \`helm install solr oci://docker.io/apache/solr-chart --version ${{ steps.versions.outputs.solr-version }}\`" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Verification" >> $GITHUB_STEP_SUMMARY - echo "- ✅ Charts downloaded and checksums verified" >> $GITHUB_STEP_SUMMARY - echo "- ✅ Charts pushed to OCI registries" >> $GITHUB_STEP_SUMMARY - echo "- ✅ Charts verified as accessible from OCI registry" >> $GITHUB_STEP_SUMMARY + set -euo pipefail + REGISTRY="${OCI_TARGET}" + + if [[ "${{ inputs.dry-run }}" == "true" ]]; then + echo "## Dry run - nothing was published" >> "$GITHUB_STEP_SUMMARY" + else + echo "## Helm charts published" >> "$GITHUB_STEP_SUMMARY" + fi + { + echo "" + echo "| Check | Result |" + echo "| --- | --- |" + echo "| URLs from dist.apache.org | passed |" + echo "| SHA512 checksums | verified |" + echo "| GPG signatures | verified |" + echo "| solr-operator chart version | \`${OPERATOR_VERSION}\` |" + echo "| solr chart version | \`${SOLR_VERSION}\` |" + echo "" + } >> "$GITHUB_STEP_SUMMARY" + + if [[ "${{ inputs.dry-run }}" == "true" ]]; then + echo "Re-run with **dry-run = false** to publish." >> "$GITHUB_STEP_SUMMARY" + else + { + echo "Anonymously pulled back and verified against the released artifacts." + echo "" + echo '```bash' + echo "helm install solr-operator ${REGISTRY}/solr-operator --version ${OPERATOR_VERSION}" + echo "helm install example ${REGISTRY}/solr --version ${SOLR_VERSION}" + echo '```' + } >> "$GITHUB_STEP_SUMMARY" + fi diff --git a/README.md b/README.md index 5236850a..2bf751a7 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ Please visit the following pages for documentation on using and developing the S - **Solr Operator**: `helm install solr-operator oci://ghcr.io/apache/solr-operator/helm/solr-operator --version ` - **Solr Cloud**: `helm install solr oci://ghcr.io/apache/solr-operator/helm/solr --version ` - Or via the deprecated HTTPS repository: [Helm Instructions via Artifact Hub](https://artifacthub.io/packages/helm/apache-solr/solr-operator) + - Charts are published to both locations throughout the 0.x releases. Starting with `v1.0.0`, charts will be published to the OCI registry only. - The released helm charts and their instructions should be used for all safe and stable deployments. The charts found in `helm/` are not guaranteed to be compatible with the last stable release, and should only be used for development purposes. - [Running the Solr Operator](https://solr.apache.org/guide/operator/latest/getting-started/running-the-operator.html) diff --git a/docs/modules/getting-started/pages/local-tutorial.adoc b/docs/modules/getting-started/pages/local-tutorial.adoc index c1da57b9..42a86a50 100644 --- a/docs/modules/getting-started/pages/local-tutorial.adoc +++ b/docs/modules/getting-started/pages/local-tutorial.adoc @@ -79,15 +79,10 @@ You can follow along here, or follow the instructions in the https://artifacthub Now that we have the prerequisites setup, let us install Solr Operator which will let us easily manage a large Solr cluster: -Now add the Solr Operator Helm repository. (You should only need to do this once) +The Helm charts are published to the GitHub Container Registry as OCI artifacts, so there is +no Helm repository to add and no credentials to configure. -[source,bash] ----- -$ helm repo add apache-solr https://solr.apache.org/charts -$ helm repo update ----- - -Next, install the Solr Operator chart. Note this is using Helm v3, in order to use Helm v2 please consult the https://hub.helm.sh/charts/solr-operator/solr-operator[Helm Chart documentation]. +Install the Solr Operator chart with the commands below. This will install the https://github.com/pravega/zookeeper-operator[Zookeeper Operator] by default. [source,bash,subs="verbatim,attributes"] @@ -95,9 +90,16 @@ This will install the https://github.com/pravega/zookeeper-operator[Zookeeper Op # Install the Solr & Zookeeper CRDs $ kubectl create -f https://solr.apache.org/operator/downloads/crds/v{operator-version}/all-with-dependencies.yaml # Install the Solr operator and Zookeeper Operator -$ helm install solr-operator apache-solr/solr-operator --version {operator-version} +$ helm install solr-operator oci://ghcr.io/apache/solr-operator/helm/solr-operator --version {operator-version} ---- +[NOTE] +==== +The charts are also still served from the HTTPS Helm repository at `https://solr.apache.org/charts`, +which is deprecated. Charts are published to both locations throughout the 0.x releases. +Starting with `v1.0.0`, charts will be published to the OCI registry only. +==== + _Note that the Helm chart version does not contain a `v` prefix, which the downloads version does. The Helm chart version is the only part of the Solr Operator release that does not use the `v` prefix._ After installing, you can check to see what lives in the cluster to make sure that the Solr and ZooKeeper operators have started correctly. @@ -128,7 +130,7 @@ To start a Solr Cloud cluster, we will create a yaml that will tell the Solr Ope [source,bash,subs="verbatim,attributes"] ---- # Create a 3-node cluster v9.10.0 with 300m Heap each: -helm install example-solr apache-solr/solr --version {operator-version} \ +helm install example-solr oci://ghcr.io/apache/solr-operator/helm/solr --version {operator-version} \ --set image.tag=9.10.0 \ --set solrOptions.javaMemory="-Xms300m -Xmx300m" \ --set addressability.external.method=Ingress \ @@ -224,7 +226,7 @@ So we wish to upgrade to a newer Solr version: curl -s http://default-example-solrcloud.ing.local.domain/solr/admin/info/system | grep solr-i # Update the solrCloud configuration with the new version, keeping all previous settings and the number of nodes set by the autoscaler. -helm upgrade example-solr apache-solr/solr --version {operator-version} \ +helm upgrade example-solr oci://ghcr.io/apache/solr-operator/helm/solr --version {operator-version} \ --reuse-values \ --set image.tag=9.10.0 diff --git a/docs/modules/getting-started/pages/running-the-operator.adoc b/docs/modules/getting-started/pages/running-the-operator.adoc index 93fc388a..02d3bc34 100644 --- a/docs/modules/getting-started/pages/running-the-operator.adoc +++ b/docs/modules/getting-started/pages/running-the-operator.adoc @@ -26,23 +26,33 @@ The helm chart provides abstractions over the Input Arguments described below, a The official documentation for installing the Solr Operator Helm chart can be found on https://artifacthub.io/packages/helm/apache-solr/solr-operator[Artifact Hub]. -The first step is to add the Solr Operator helm repository. +The chart is published to the GitHub Container Registry as an OCI artifact. +Nothing needs to be added or configured first, and no credentials are required. -[source,bash] +Install the Solr Operator chart with the command below. +This will install the https://github.com/pravega/zookeeper-operator[Zookeeper Operator] by default. + +[source,bash,subs="verbatim,attributes"] ---- -$ helm repo add apache-solr https://solr.apache.org/charts -$ helm repo update +$ kubectl create -f https://solr.apache.org/operator/downloads/crds/v{operator-version}/all-with-dependencies.yaml +$ helm install solr-operator oci://ghcr.io/apache/solr-operator/helm/solr-operator --version {operator-version} ---- -Next, install the Solr Operator chart. Note this is using Helm v3, use the official Helm chart documentation linked to above. -This will install the https://github.com/pravega/zookeeper-operator[Zookeeper Operator] by default. +[NOTE] +==== +The chart is also still served from the HTTPS Helm repository at `https://solr.apache.org/charts`, which is deprecated: [source,bash,subs="verbatim,attributes"] ---- -$ kubectl create -f https://solr.apache.org/operator/downloads/crds/v{operator-version}/all-with-dependencies.yaml +$ helm repo add apache-solr https://solr.apache.org/charts +$ helm repo update $ helm install solr-operator apache-solr/solr-operator --version {operator-version} ---- +Charts are published to both locations throughout the 0.x releases. +Starting with `v1.0.0`, charts will be published to the OCI registry only. +==== + _Note that the Helm chart version does not contain a `v` prefix, which the downloads version does. The Helm chart version is the only part of the Solr Operator release that does not use the `v` prefix._ After installing, you can check to see what lives in the cluster to make sure that the Solr and ZooKeeper operators have started correctly. @@ -75,7 +85,7 @@ This can be done with the `--skip-crds` helm option. [source,bash] ---- -helm install solr-operator apache-solr/solr-operator --skip-crds --namespace solr +helm install solr-operator oci://ghcr.io/apache/solr-operator/helm/solr-operator --skip-crds --namespace solr ---- *Helm will not upgrade CRDs once they have been installed. diff --git a/docs/modules/upgrade-notes/pages/upgrade-notes.adoc b/docs/modules/upgrade-notes/pages/upgrade-notes.adoc index e0d5a26c..e76679e9 100644 --- a/docs/modules/upgrade-notes/pages/upgrade-notes.adoc +++ b/docs/modules/upgrade-notes/pages/upgrade-notes.adoc @@ -97,6 +97,30 @@ It is always encouraged to upgrade to the latest patch version of the minor and There is no need to upgrade one patch version at a time (e.g. `v0.2.5` -> `v0.2.6` -> `v0.2.7` -> `v0.2.8`), instead you can leap to the latest patch version (e.g. `v0.2.5` -> `v0.2.8`). +== Where the Helm charts are published + +The Solr Operator and Solr Helm charts are published as OCI artifacts to the GitHub Container Registry: + +[source,bash,subs="verbatim,attributes"] +---- +helm install solr-operator oci://ghcr.io/apache/solr-operator/helm/solr-operator --version {operator-version} +helm install example oci://ghcr.io/apache/solr-operator/helm/solr --version {operator-version} +---- + +Installing from an OCI registry requires no `helm repo add`, and no credentials. + +[WARNING] +==== +The HTTPS Helm repository at `https://solr.apache.org/charts` is *deprecated*. + +Charts are published to both the OCI registry and the HTTPS repository throughout the 0.x releases, +so there is no rush to migrate. Starting with `v1.0.0`, charts will be published to the OCI registry +only, and the HTTPS repository will receive no further releases. + +If you install or upgrade the charts through automation, update it to use the `oci://` URLs above +before upgrading to `v1.0.0`. +==== + == Installing the Solr Operator vs Solr CRDs Installing the Solr Operator, especially via the https://artifacthub.io/packages/helm/apache-solr/solr-operator[Helm Chart], @@ -127,7 +151,7 @@ If you are using the Solr Helm chart to deploy the Zookeeper operator, then you ---- # Just replace the Solr CRDs and all CRDs it might depend on (e.g. ZookeeperCluster) kubectl replace -f "http://solr.apache.org/operator/downloads/crds/v{operator-version}/all-with-dependencies.yaml" -helm upgrade solr-operator apache-solr/solr-operator --version {operator-version} +helm upgrade solr-operator oci://ghcr.io/apache/solr-operator/helm/solr-operator --version {operator-version} ---- _Note that the Helm chart version does not contain a `v` prefix, which the downloads version does. The Helm chart version is the only part of the Solr Operator release that does not use the `v` prefix._ @@ -136,6 +160,13 @@ _Note that the Helm chart version does not contain a `v` prefix, which the downl === v0.10.0 +* *Helm charts are now published to an OCI registry* ++ +The charts are published as OCI artifacts to `oci://ghcr.io/apache/solr-operator/helm`, alongside the +existing HTTPS Helm repository. The HTTPS repository at `https://solr.apache.org/charts` is deprecated +and will receive no further releases starting with `v1.0.0`. +See <>. + * *Logging now defaults to JSON format* + The new default for CLI flag `--zap-devel` is now `false`, causing log encoding to be `json` and log level to be `info`. diff --git a/hack/release/smoke_test/test_cluster.sh b/hack/release/smoke_test/test_cluster.sh index b99e7227..75c0b30b 100755 --- a/hack/release/smoke_test/test_cluster.sh +++ b/hack/release/smoke_test/test_cluster.sh @@ -23,7 +23,7 @@ set -u show_help() { cat << EOF -Usage: ./hack/release/smoke_test/test_cluster.sh [-h] [-i IMAGE] [-k KUBERNETES_VERSION] [-t SOLR_IMAGE] [-g GPG_KEY] -v VERSION -l LOCATION +Usage: ./hack/release/smoke_test/test_cluster.sh [-h] [-i IMAGE] [-k KUBERNETES_VERSION] [-t SOLR_IMAGE] [-g GPG_KEY] [-o OCI_REGISTRY] -v VERSION -l LOCATION Test the release candidate in a Kind cluster @@ -34,11 +34,14 @@ Test the release candidate in a Kind cluster -g GPG Key (fingerprint) used to sign the artifacts (Optional, if not provided then the helm chart will not be verified) -k Kubernetes Version to test with (full tag, e.g. v1.26.6) (Optional, defaults to a compatible version) -t Full solr image, or image tag (for the official Solr image), to test with (e.g. apache/solr-nightly:9.0.0, 9.10.0). (Optional, defaults to a compatible version) + -o OCI registry to install the Helm charts from, e.g. oci://ghcr.io/apache/solr-operator/helm (Optional) + Use this after a release has been published, to smoke test the published OCI artifacts. + The CRDs are still taken from LOCATION, since they are not part of the OCI artifacts. EOF } OPTIND=1 -while getopts hv:i:l:g:k:t: opt; do +while getopts hv:i:l:g:k:t:o: opt; do case $opt in h) show_help @@ -56,6 +59,8 @@ while getopts hv:i:l:g:k:t: opt; do ;; t) SOLR_IMAGE=$OPTARG ;; + o) OCI_REGISTRY=$OPTARG + ;; *) show_help >&2 exit 1 @@ -86,14 +91,15 @@ fi export LOCATION="$LOCATION" export VERSION="$VERSION" +# An OCI registry is never a helm repo, so there is nothing to add or remove for it. function add_solr_helm_repo() { - if (echo "${LOCATION}" | grep "http"); then + if [[ -z "${OCI_REGISTRY:-}" ]] && (echo "${LOCATION}" | grep "http"); then helm repo add --force-update "apache-solr-test-${VERSION}" "${LOCATION}/helm-charts" fi } function remove_solr_helm_repo() { - if (echo "${LOCATION}" | grep "http"); then + if [[ -z "${OCI_REGISTRY:-}" ]] && (echo "${LOCATION}" | grep "http"); then helm repo remove "apache-solr-test-${VERSION}" fi } @@ -113,6 +119,16 @@ else SOLR_HELM_CHART="apache-solr-test-${VERSION}/solr" fi +# The charts published to an OCI registry are the same artifacts that were staged at +# LOCATION, so only where the charts are pulled from changes. CRDs still come from LOCATION. +# Unlike a helm repo, an OCI reference has no index, so the version must be given explicitly. +CHART_VERSION_ARG=() +if [[ -n "${OCI_REGISTRY:-}" ]]; then + OP_HELM_CHART="${OCI_REGISTRY}/solr-operator" + SOLR_HELM_CHART="${OCI_REGISTRY}/solr" + CHART_VERSION_ARG=(--version "${VERSION#v}") +fi + if ! (which kind); then echo "Install Kind (Kubernetes in Docker)" GO111MODULE="on" go install sigs.k8s.io/kind@v0.20.0 @@ -163,13 +179,13 @@ add_solr_helm_repo # Install the Solr Operator kubectl create -f "${LOCATION}/crds/all-with-dependencies.yaml" || kubectl replace -f "${LOCATION}/crds/all-with-dependencies.yaml" -helm install --kube-context "${KUBE_CONTEXT}" ${VERIFY_OR_NOT} solr-operator "${OP_HELM_CHART}" \ +helm install --kube-context "${KUBE_CONTEXT}" ${VERIFY_OR_NOT} solr-operator "${OP_HELM_CHART}" ${CHART_VERSION_ARG[@]+"${CHART_VERSION_ARG[@]}"} \ --set-string image.tag="${IMAGE##*:}" \ --set image.repository="${IMAGE%%:*}" \ --set image.pullPolicy="Never" printf "\nInstall a test Solr Cluster\n" -helm install --kube-context "${KUBE_CONTEXT}" ${VERIFY_OR_NOT} example "${SOLR_HELM_CHART}" \ +helm install --kube-context "${KUBE_CONTEXT}" ${VERIFY_OR_NOT} example "${SOLR_HELM_CHART}" ${CHART_VERSION_ARG[@]+"${CHART_VERSION_ARG[@]}"} \ --set replicas=2 \ --set image.repository="${SOLR_IMAGE%%:*}" \ --set-string image.tag="${SOLR_IMAGE##*:}" \ @@ -291,7 +307,7 @@ fi printf "\nDo a rolling restart and make sure the cluster is healthy afterwards\n" add_solr_helm_repo -helm upgrade --kube-context "${KUBE_CONTEXT}" ${VERIFY_OR_NOT} example "${SOLR_HELM_CHART}" --reuse-values \ +helm upgrade --kube-context "${KUBE_CONTEXT}" ${VERIFY_OR_NOT} example "${SOLR_HELM_CHART}" ${CHART_VERSION_ARG[@]+"${CHART_VERSION_ARG[@]}"} --reuse-values \ --set-string podOptions.annotations.restart="true" printf '\nWait for the rolling restart to begin.\n\n' grep -q "2 [[:digit:]] [[:digit:]] 0" <(exec kubectl get solrcloud example -w); kill $! diff --git a/hack/release/wizard/releaseWizard.yaml b/hack/release/wizard/releaseWizard.yaml index 53f82485..14a5c2d6 100644 --- a/hack/release/wizard/releaseWizard.yaml +++ b/hack/release/wizard/releaseWizard.yaml @@ -1122,7 +1122,7 @@ groups: tee: true - !Todo id: publish_helm_charts_oci - title: Publish Helm charts to OCI registry (Docker Hub) + title: Publish Helm charts to the OCI registry (GHCR) depends: publish_helm_charts vars: dist_release_url: https://dist.apache.org/repos/dist/release/solr/solr-operator/{{ release_version }} @@ -1130,11 +1130,13 @@ groups: solr_chart_url: '{{ dist_release_url }}/helm-charts/solr-{{ release_version[1:] }}.tgz' workflow_url: https://github.com/apache/solr-operator/actions/workflows/publish-helm-oci.yaml description: | - Publish the Helm charts to OCI registries on Docker Hub using the GitHub Actions workflow. + Publish the released Helm charts as OCI artifacts to the GitHub Container Registry, + using the "Publish Helm Charts to OCI Registry" GitHub Actions workflow. - This task publishes the voted Helm charts to OCI registries, making them available via: - - oci://docker.io/apache/solr-operator-chart - - oci://docker.io/apache/solr-chart + The charts on dist.apache.org remain the canonical, signed release artifacts. + The OCI copies are convenience binaries, published to: + - oci://ghcr.io/apache/solr-operator/helm/solr-operator + - oci://ghcr.io/apache/solr-operator/helm/solr Steps to publish: 1. Navigate to the GitHub Actions workflow: @@ -1145,24 +1147,33 @@ groups: 3. Fill in the workflow inputs: - solr-operator-chart-url: {{ solr_operator_chart_url }} - solr-chart-url: {{ solr_chart_url }} - - dry-run: false (set to true for validation without publishing) + - dry-run: true - 4. Optional: Run with dry-run=true first to verify: - - URLs are valid and accessible - - Charts download successfully - - SHA512 checksums match - - Chart versions are correct + 4. The dry-run verifies, without publishing anything, that: + - The URLs are valid and point at dist.apache.org + - The charts, checksums, signatures and provenance files all download + - The SHA512 checksums match + - The GPG signatures verify against the Solr KEYS file + - The chart versions are what you expect - 5. Click "Run workflow" to start the job + 5. Re-run the workflow with dry-run = false to actually publish - 6. Monitor the workflow execution for any errors + 6. Monitor the workflow execution for any errors. After pushing, the workflow logs + out of the registry and pulls both charts back anonymously, verifying their + provenance and checking they are byte-identical to the released artifacts. + If this step fails with an authorization error, the ghcr.io packages are still + private and INFRA needs to make them public - see the note below. - 7. Verify successful completion by checking that both charts are accessible: - helm pull oci://docker.io/apache/solr-operator-chart --version {{ release_version[1:] }} - helm pull oci://docker.io/apache/solr-chart --version {{ release_version[1:] }} + 7. Confirm for yourself that the charts are installable, with no credentials: - Note: The workflow uses repository secrets DOCKERHUB_USER and DOCKERHUB_TOKEN for authentication. - The workflow automatically verifies SHA512 checksums before publishing. + helm registry logout ghcr.io + helm show chart oci://ghcr.io/apache/solr-operator/helm/solr-operator --version {{ release_version[1:] }} + helm show chart oci://ghcr.io/apache/solr-operator/helm/solr --version {{ release_version[1:] }} + + Note: the workflow authenticates with the built-in GITHUB_TOKEN, so no secrets need + to be configured. However, ghcr.io creates new packages as *private*. The very first + time a chart name is published, an INFRA ticket is needed to make the package public. + This is a one-time action per chart name; later versions inherit the visibility. links: - '{{ workflow_url }}' - '{{ solr_operator_chart_url }}' @@ -1233,7 +1244,8 @@ groups: The ChangeLog is very finicky, so make sure that it renders correctly. - Also verify that the OCI registry information is correctly displayed on ArtifactHub. + Note that ArtifactHub still indexes the HTTPS chart repository, not the OCI registry, + so the OCI copies published in the previous step will not show up here. links: - https://artifacthub.io/packages/helm/apache-solr/solr-operator - https://artifacthub.io/packages/helm/apache-solr/solr diff --git a/helm/solr-operator/README.md b/helm/solr-operator/README.md index b632a185..cd185d5e 100644 --- a/helm/solr-operator/README.md +++ b/helm/solr-operator/README.md @@ -33,23 +33,28 @@ If you do not wish to use the Zookeeper Operator, set: ### Installing the Chart -The Solr Operator Helm chart can be installed using either the OCI registry (recommended) or the traditional HTTPS repository. +The Solr Operator Helm chart can be installed either from the OCI registry (recommended) or from the deprecated HTTPS repository. + +> **Note:** The HTTPS Helm repository at `https://solr.apache.org/charts` is deprecated. +> Charts are published to both locations throughout the 0.x releases. +> Starting with `v1.0.0`, charts will be published to the OCI registry only. #### Installation via OCI Registry (Recommended) -The Helm chart is available directly from Docker Hub as an OCI artifact, which provides a more reliable distribution mechanism and doesn't require adding a repository. +The Helm chart is published to the GitHub Container Registry as an OCI artifact. +No repository needs to be added, and no credentials are required. ```bash # Install CRDs first kubectl create -f https://solr.apache.org/operator/downloads/crds/v0.10.0-prerelease/all-with-dependencies.yaml # Install the Solr Operator from OCI registry -helm install solr-operator oci://docker.io/apache/solr-operator-chart --version 0.10.0-prerelease +helm install solr-operator oci://ghcr.io/apache/solr-operator/helm/solr-operator --version 0.10.0-prerelease ``` -#### Installation via HTTPS Repository (Traditional) +#### Installation via HTTPS Repository (Deprecated) -If you prefer the traditional method, you can add the Helm repository and install from there. +The chart is also still served from the deprecated HTTPS Helm repository. ```bash # Add the repository (only needed once) @@ -58,7 +63,7 @@ helm repo add apache-solr https://solr.apache.org/charts # Install CRDs first kubectl create -f https://solr.apache.org/operator/downloads/crds/v0.10.0-prerelease/all-with-dependencies.yaml -# Install the Solr Operator from HTTPS repository +# Install the Solr Operator from the HTTPS repository helm install solr-operator apache-solr/solr-operator --version 0.10.0-prerelease ``` @@ -76,9 +81,9 @@ If you are upgrading your Solr Operator deployment, you should always use a spec kubectl replace -f https://solr.apache.org/operator/downloads/crds/v0.10.0-prerelease/all-with-dependencies.yaml # Upgrade via OCI registry (recommended) -helm upgrade solr-operator oci://docker.io/apache/solr-operator-chart --version 0.10.0-prerelease +helm upgrade solr-operator oci://ghcr.io/apache/solr-operator/helm/solr-operator --version 0.10.0-prerelease -# Or upgrade via HTTPS repository (traditional) +# Or upgrade via the deprecated HTTPS repository helm upgrade solr-operator apache-solr/solr-operator --version 0.10.0-prerelease ``` @@ -88,20 +93,20 @@ If you want to specify the namespace for the installation, use the `--namespace` All resources will be deployed to the given namespace. ```bash -helm install solr-operator oci://docker.io/apache/solr-operator-chart --version 0.10.0-prerelease --namespace solr +helm install solr-operator oci://ghcr.io/apache/solr-operator/helm/solr-operator --version 0.10.0-prerelease --namespace solr ``` If you want to only watch that namespace, or others, then you will have to provide the `watchNamespaces` option. ```bash # Watch the namespace where the operator is deployed to (just pass the boolean true) -helm install solr-operator oci://docker.io/apache/solr-operator-chart --version 0.10.0-prerelease --namespace solr --set watchNamespaces=true +helm install solr-operator oci://ghcr.io/apache/solr-operator/helm/solr-operator --version 0.10.0-prerelease --namespace solr --set watchNamespaces=true # Watch a single namespace different than the one being deployed to -helm install solr-operator oci://docker.io/apache/solr-operator-chart --version 0.10.0-prerelease --namespace solr --set watchNamespaces=other +helm install solr-operator oci://ghcr.io/apache/solr-operator/helm/solr-operator --version 0.10.0-prerelease --namespace solr --set watchNamespaces=other # Watch multiple namespaces (commas must be escaped in the set string) -helm install solr-operator oci://docker.io/apache/solr-operator-chart --version 0.10.0-prerelease --namespace solr --set watchNamespaces="team1\,team2\,team3" +helm install solr-operator oci://ghcr.io/apache/solr-operator/helm/solr-operator --version 0.10.0-prerelease --namespace solr --set watchNamespaces="team1\,team2\,team3" ``` Note: Passing `false` or `""` to the `watchNamespaces` variable will both result in the operator watchting all namespaces in the Kube cluster. @@ -115,7 +120,7 @@ This can be done with the `--skip-crds` helm option. ```bash # Via OCI registry -helm install solr-operator oci://docker.io/apache/solr-operator-chart --version 0.10.0-prerelease --skip-crds --namespace solr +helm install solr-operator oci://ghcr.io/apache/solr-operator/helm/solr-operator --version 0.10.0-prerelease --skip-crds --namespace solr # Or via HTTPS repository helm install solr-operator apache-solr/solr-operator --version 0.10.0-prerelease --skip-crds --namespace solr diff --git a/helm/solr/README.md b/helm/solr/README.md index a6ee68e8..ffae7b49 100644 --- a/helm/solr/README.md +++ b/helm/solr/README.md @@ -33,15 +33,19 @@ There may be breaking changes between the version you are using and the version ### Installing the Chart -The Solr Helm chart can be installed using either the OCI registry (recommended) or the traditional HTTPS helm repository. +The Solr Helm chart can be installed either from the OCI registry (recommended) or from the deprecated HTTPS helm repository. + +> **Note:** The HTTPS Helm repository at `https://solr.apache.org/charts` is deprecated. +> Charts are published to both locations throughout the 0.x releases. +> Starting with `v1.0.0`, charts will be published to the OCI registry only. To install a SolrCloud for the first time in your cluster, you can use the latest version or a specific version: ```bash # Via OCI registry (recommended) -helm install example oci://docker.io/apache/solr-chart --version 0.10.0-prerelease --set image.tag=9.10.0 +helm install example oci://ghcr.io/apache/solr-operator/helm/solr --version 0.10.0-prerelease --set image.tag=9.10.0 -# Or via HTTPS helm repository (traditional) +# Or via the deprecated HTTPS helm repository helm install example apache-solr/solr --version 0.10.0-prerelease --set image.tag=9.10.0 ``` @@ -57,9 +61,9 @@ If you are upgrading your SolrCloud deployment, you should always use a specific ```bash # Via OCI registry (recommended) -helm upgrade example oci://docker.io/apache/solr-chart --version 0.10.0-prerelease --reuse-values --set image.tag=9.10.0 +helm upgrade example oci://ghcr.io/apache/solr-operator/helm/solr --version 0.10.0-prerelease --reuse-values --set image.tag=9.10.0 -# Or via HTTPS repository (traditional) +# Or via the deprecated HTTPS helm repository helm upgrade example apache-solr/solr --version 0.10.0-prerelease --reuse-values --set image.tag=9.10.0 ```