From dc5c3dc9bc11e2f160094432dd709c8a912999d1 Mon Sep 17 00:00:00 2001 From: Myasnikov Daniil Date: Mon, 2 Mar 2026 15:36:20 +0500 Subject: [PATCH] [rabbitmq] Added app version selection Signed-off-by: Myasnikov Daniil --- packages/apps/rabbitmq/Chart.yaml | 2 +- packages/apps/rabbitmq/Makefile | 4 + packages/apps/rabbitmq/README.md | 1 + packages/apps/rabbitmq/files/versions.yaml | 4 + .../apps/rabbitmq/hack/update-versions.sh | 129 ++++++++++++++++++ .../apps/rabbitmq/templates/_versions.tpl | 8 ++ .../apps/rabbitmq/templates/rabbitmq.yaml | 1 + packages/apps/rabbitmq/values.schema.json | 11 ++ packages/apps/rabbitmq/values.yaml | 9 ++ .../platform/images/migrations/migrations/34 | 37 +++++ packages/core/platform/values.yaml | 2 +- .../system/rabbitmq-rd/cozyrds/rabbitmq.yaml | 4 +- 12 files changed, 208 insertions(+), 4 deletions(-) create mode 100644 packages/apps/rabbitmq/files/versions.yaml create mode 100755 packages/apps/rabbitmq/hack/update-versions.sh create mode 100644 packages/apps/rabbitmq/templates/_versions.tpl create mode 100755 packages/core/platform/images/migrations/migrations/34 diff --git a/packages/apps/rabbitmq/Chart.yaml b/packages/apps/rabbitmq/Chart.yaml index 13500669..e764e7dd 100644 --- a/packages/apps/rabbitmq/Chart.yaml +++ b/packages/apps/rabbitmq/Chart.yaml @@ -4,4 +4,4 @@ description: Managed RabbitMQ service icon: /logos/rabbitmq.svg type: application version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process -appVersion: "3.13.2" +appVersion: "4.2.4" diff --git a/packages/apps/rabbitmq/Makefile b/packages/apps/rabbitmq/Makefile index d1cfda8e..aa9b0ccc 100644 --- a/packages/apps/rabbitmq/Makefile +++ b/packages/apps/rabbitmq/Makefile @@ -3,3 +3,7 @@ include ../../../hack/package.mk generate: cozyvalues-gen -v values.yaml -s values.schema.json -r README.md ../../../hack/update-crd.sh + +update: + hack/update-versions.sh + make generate diff --git a/packages/apps/rabbitmq/README.md b/packages/apps/rabbitmq/README.md index 4b19c7b3..b1f01f21 100644 --- a/packages/apps/rabbitmq/README.md +++ b/packages/apps/rabbitmq/README.md @@ -23,6 +23,7 @@ The service utilizes official RabbitMQ operator. This ensures the reliability an | `size` | Persistent Volume Claim size available for application data. | `quantity` | `10Gi` | | `storageClass` | StorageClass used to store the data. | `string` | `""` | | `external` | Enable external access from outside the cluster. | `bool` | `false` | +| `version` | RabbitMQ major.minor version to deploy | `string` | `v4.2` | ### Application-specific parameters diff --git a/packages/apps/rabbitmq/files/versions.yaml b/packages/apps/rabbitmq/files/versions.yaml new file mode 100644 index 00000000..0cf87dd0 --- /dev/null +++ b/packages/apps/rabbitmq/files/versions.yaml @@ -0,0 +1,4 @@ +"v4.2": "4.2.4" +"v4.1": "4.1.8" +"v4.0": "4.0.9" +"v3.13": "3.13.7" diff --git a/packages/apps/rabbitmq/hack/update-versions.sh b/packages/apps/rabbitmq/hack/update-versions.sh new file mode 100755 index 00000000..7dec5a84 --- /dev/null +++ b/packages/apps/rabbitmq/hack/update-versions.sh @@ -0,0 +1,129 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +RABBITMQ_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +VALUES_FILE="${RABBITMQ_DIR}/values.yaml" +VERSIONS_FILE="${RABBITMQ_DIR}/files/versions.yaml" +GITHUB_API_URL="https://api.github.com/repos/rabbitmq/rabbitmq-server/releases" + +# Check if jq is installed +if ! command -v jq &> /dev/null; then + echo "Error: jq is not installed. Please install jq and try again." >&2 + exit 1 +fi + +# Fetch releases from GitHub API +echo "Fetching releases from GitHub API..." +RELEASES_JSON=$(curl -sSL "${GITHUB_API_URL}?per_page=100") + +if [ -z "$RELEASES_JSON" ]; then + echo "Error: Could not fetch releases from GitHub API" >&2 + exit 1 +fi + +# Extract stable release tags (format: v3.13.7, v4.0.3, etc.) +# Filter out pre-releases and draft releases +RELEASE_TAGS=$(echo "$RELEASES_JSON" | jq -r '.[] | select(.prerelease == false) | select(.draft == false) | .tag_name' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V) + +if [ -z "$RELEASE_TAGS" ]; then + echo "Error: Could not find any stable release tags" >&2 + exit 1 +fi + +echo "Found release tags: $(echo "$RELEASE_TAGS" | tr '\n' ' ')" + +# Supported major.minor versions (newest first) +# We support the last few minor releases of each active major +SUPPORTED_MAJORS=("4.2" "4.1" "4.0" "3.13") + +# Build versions map: major.minor -> latest patch version +declare -A VERSION_MAP +MAJOR_VERSIONS=() + +for major_minor in "${SUPPORTED_MAJORS[@]}"; do + # Find the latest patch version for this major.minor + MATCHING=$(echo "$RELEASE_TAGS" | grep -E "^v${major_minor//./\\.}\.[0-9]+$" | tail -n1) + + if [ -n "$MATCHING" ]; then + # Strip the 'v' prefix for the value (Docker tag format is e.g. 3.13.7) + TAG_VERSION="${MATCHING#v}" + VERSION_MAP["v${major_minor}"]="${TAG_VERSION}" + MAJOR_VERSIONS+=("v${major_minor}") + echo "Found version: v${major_minor} -> ${TAG_VERSION}" + else + echo "Warning: No stable releases found for ${major_minor}, skipping..." >&2 + fi +done + +if [ ${#MAJOR_VERSIONS[@]} -eq 0 ]; then + echo "Error: No matching versions found" >&2 + exit 1 +fi + +echo "Major versions to add: ${MAJOR_VERSIONS[*]}" + +# Create/update versions.yaml file +echo "Updating $VERSIONS_FILE..." +{ + for major_ver in "${MAJOR_VERSIONS[@]}"; do + echo "\"${major_ver}\": \"${VERSION_MAP[$major_ver]}\"" + done +} > "$VERSIONS_FILE" + +echo "Successfully updated $VERSIONS_FILE" + +# Update values.yaml - enum with major.minor versions only +TEMP_FILE=$(mktemp) +trap "rm -f $TEMP_FILE" EXIT + +# Build new version section +NEW_VERSION_SECTION="## @enum {string} Version" +for major_ver in "${MAJOR_VERSIONS[@]}"; do + NEW_VERSION_SECTION="${NEW_VERSION_SECTION} +## @value $major_ver" +done +NEW_VERSION_SECTION="${NEW_VERSION_SECTION} + +## @param {Version} version - RabbitMQ major.minor version to deploy +version: ${MAJOR_VERSIONS[0]}" + +# Check if version section already exists +if grep -q "^## @enum {string} Version" "$VALUES_FILE"; then + # Version section exists, update it using awk + echo "Updating existing version section in $VALUES_FILE..." + + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @enum {string} Version/ { + in_section = 1 + print new_section + next + } + in_section && /^version: / { + in_section = 0 + next + } + in_section { + next + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +else + # Version section doesn't exist, insert it before Application-specific parameters section + echo "Inserting new version section in $VALUES_FILE..." + + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @section Application-specific parameters/ { + print new_section + print "" + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +fi + +echo "Successfully updated $VALUES_FILE with major.minor versions: ${MAJOR_VERSIONS[*]}" diff --git a/packages/apps/rabbitmq/templates/_versions.tpl b/packages/apps/rabbitmq/templates/_versions.tpl new file mode 100644 index 00000000..76955b33 --- /dev/null +++ b/packages/apps/rabbitmq/templates/_versions.tpl @@ -0,0 +1,8 @@ +{{- define "rabbitmq.versionMap" }} +{{- $versionMap := .Files.Get "files/versions.yaml" | fromYaml }} +{{- if not (hasKey $versionMap .Values.version) }} + {{- printf `RabbitMQ version %s is not supported, allowed versions are %s` $.Values.version (keys $versionMap) | fail }} +{{- end }} +{{- index $versionMap .Values.version }} +{{- end }} + diff --git a/packages/apps/rabbitmq/templates/rabbitmq.yaml b/packages/apps/rabbitmq/templates/rabbitmq.yaml index b111285e..bbf2efbe 100644 --- a/packages/apps/rabbitmq/templates/rabbitmq.yaml +++ b/packages/apps/rabbitmq/templates/rabbitmq.yaml @@ -7,6 +7,7 @@ metadata: app.kubernetes.io/managed-by: {{ .Release.Service }} spec: replicas: {{ .Values.replicas }} + image: 'rabbitmq:{{ include "rabbitmq.versionMap" $ }}-management' {{- if .Values.external }} service: type: LoadBalancer diff --git a/packages/apps/rabbitmq/values.schema.json b/packages/apps/rabbitmq/values.schema.json index 04b8fa11..87b1a6da 100644 --- a/packages/apps/rabbitmq/values.schema.json +++ b/packages/apps/rabbitmq/values.schema.json @@ -92,6 +92,17 @@ } } }, + "version": { + "description": "RabbitMQ major.minor version to deploy", + "type": "string", + "default": "v4.2", + "enum": [ + "v4.2", + "v4.1", + "v4.0", + "v3.13" + ] + }, "vhosts": { "description": "Virtual hosts configuration map.", "type": "object", diff --git a/packages/apps/rabbitmq/values.yaml b/packages/apps/rabbitmq/values.yaml index 65d5de44..08b6f5e6 100644 --- a/packages/apps/rabbitmq/values.yaml +++ b/packages/apps/rabbitmq/values.yaml @@ -34,6 +34,15 @@ storageClass: "" external: false ## +## @enum {string} Version +## @value v4.2 +## @value v4.1 +## @value v4.0 +## @value v3.13 + +## @param {Version} version - RabbitMQ major.minor version to deploy +version: v4.2 + ## @section Application-specific parameters ## diff --git a/packages/core/platform/images/migrations/migrations/34 b/packages/core/platform/images/migrations/migrations/34 new file mode 100755 index 00000000..57204ff0 --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/34 @@ -0,0 +1,37 @@ +#!/bin/sh +# Migration 34 --> 35 +# Backfill spec.version on rabbitmq.apps.cozystack.io resources. +# +# Before this migration RabbitMQ had no user-selectable version; the +# operator always used its built-in default image (v3.x). A version field +# was added in this release. Without this migration every existing cluster +# would be upgraded to the new default (v4.2) on the next reconcile. +# +# Set spec.version to "v3.13" for any rabbitmq app resource that does not +# already have it set. + +set -euo pipefail + +DEFAULT_VERSION="v3.13" +RABBITMQS=$(kubectl get rabbitmqs.apps.cozystack.io -A -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}') +for resource in $RABBITMQS; do + NS="${resource%%/*}" + APP_NAME="${resource##*/}" + + # Skip if spec.version is already set + CURRENT_VER=$(kubectl get rabbitmqs.apps.cozystack.io -n "$NS" "$APP_NAME" \ + -o jsonpath='{.spec.version}') + if [ -n "$CURRENT_VER" ]; then + echo "SKIP $NS/$APP_NAME: spec.version already set to '$CURRENT_VER'" + continue + fi + + echo "Patching rabbitmq/$APP_NAME in $NS: setting version=$DEFAULT_VERSION" + + kubectl patch rabbitmqs.apps.cozystack.io -n "$NS" "$APP_NAME" --type=merge \ + --patch "{\"spec\":{\"version\":\"${DEFAULT_VERSION}\"}}" +done + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=35 --dry-run=client -o yaml | kubectl apply -f- diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml index 155cc78a..80ebb936 100644 --- a/packages/core/platform/values.yaml +++ b/packages/core/platform/values.yaml @@ -6,7 +6,7 @@ sourceRef: migrations: enabled: false image: ghcr.io/cozystack/cozystack/platform-migrations:v1.0.0@sha256:68dabdebc38ac439228ae07031cc70e0fa184a24bd4e5b3b22c17466b2a55201 - targetVersion: 34 + targetVersion: 35 # Bundle deployment configuration bundles: system: diff --git a/packages/system/rabbitmq-rd/cozyrds/rabbitmq.yaml b/packages/system/rabbitmq-rd/cozyrds/rabbitmq.yaml index 1bbed02d..6ca2b79f 100644 --- a/packages/system/rabbitmq-rd/cozyrds/rabbitmq.yaml +++ b/packages/system/rabbitmq-rd/cozyrds/rabbitmq.yaml @@ -8,7 +8,7 @@ spec: plural: rabbitmqs singular: rabbitmq openAPISchema: |- - {"title":"Chart Values","type":"object","properties":{"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"replicas":{"description":"Number of RabbitMQ replicas.","type":"integer","default":3},"resources":{"description":"Explicit CPU and memory configuration for each RabbitMQ replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"users":{"description":"Users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"password":{"description":"Password for the user.","type":"string"}}}},"vhosts":{"description":"Virtual hosts configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","required":["roles"],"properties":{"roles":{"description":"Virtual host roles list.","type":"object","properties":{"admin":{"description":"List of admin users.","type":"array","items":{"type":"string"}},"readonly":{"description":"List of readonly users.","type":"array","items":{"type":"string"}}}}}}}}} + {"title":"Chart Values","type":"object","properties":{"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"replicas":{"description":"Number of RabbitMQ replicas.","type":"integer","default":3},"resources":{"description":"Explicit CPU and memory configuration for each RabbitMQ replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"users":{"description":"Users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"password":{"description":"Password for the user.","type":"string"}}}},"version":{"description":"RabbitMQ major.minor version to deploy","type":"string","default":"v4.2","enum":["v4.2","v4.1","v4.0","v3.13"]},"vhosts":{"description":"Virtual hosts configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","required":["roles"],"properties":{"roles":{"description":"Virtual host roles list.","type":"object","properties":{"admin":{"description":"List of admin users.","type":"array","items":{"type":"string"}},"readonly":{"description":"List of readonly users.","type":"array","items":{"type":"string"}}}}}}}}} release: prefix: rabbitmq- labels: @@ -25,7 +25,7 @@ spec: tags: - messaging icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHg9Ii0wLjAwMTk1MzEyIiB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgcng9IjI0IiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXJfNjgzXzI5NzIpIi8+CjxwYXRoIGQ9Ik0xMTEuNDExIDYyLjhIODIuNDkzOUM4MS43OTY5IDYyLjc5OTcgODEuMTI4NSA2Mi41MjI4IDgwLjYzNTYgNjIuMDMwMUM4MC4xNDI3IDYxLjUzNzMgNzkuODY1NiA2MC44NjkxIDc5Ljg2NTMgNjAuMTcyMlYzMC4wNDEyQzc5Ljg2NTMgMjcuODEgNzguMDU1NiAyNiA3NS44MjQ5IDI2SDY1LjUwMjFDNjMuMjcgMjYgNjEuNDYxNCAyNy44MSA2MS40NjE0IDMwLjA0MTJWNTkuOTg5OEM2MS40NjE0IDYxLjU0MzUgNjAuMjA1IDYyLjgwNjUgNTguNjUwOCA2Mi44MTMzTDQ5LjE3NDMgNjIuODU4NEM0Ny42MDY5IDYyLjg2NjkgNDYuMzMzNiA2MS41OTU1IDQ2LjMzNjYgNjAuMDI5OEw0Ni4zOTU0IDMwLjA0OEM0Ni40MDA1IDI3LjgxMzQgNDQuNTkwMiAyNiA0Mi4zNTUgMjZIMzIuMDQwN0MyOS44MDgzIDI2IDI4IDI3LjgxIDI4IDMwLjA0MTJWMTE0LjQxMkMyOCAxMTYuMzk0IDI5LjYwNjEgMTE4IDMxLjU4NzEgMTE4SDExMS40MTFDMTEzLjM5NCAxMTggMTE1IDExNi4zOTQgMTE1IDExNC40MTJWNjYuMzg4QzExNSA2NC40MDU4IDExMy4zOTQgNjIuOCAxMTEuNDExIDYyLjhaTTk3Ljg1MDggOTQuNDc3OUM5Ny44NTA4IDk3LjA3NTUgOTUuNzQ0NSA5OS4xODE3IDkzLjE0NjQgOTkuMTgxN0g4NC45ODg0QzgyLjM5IDk5LjE4MTcgODAuMjgzNiA5Ny4wNzU1IDgwLjI4MzYgOTQuNDc3OVY4Ni4zMjE3QzgwLjI4MzYgODMuNzIzOCA4Mi4zOSA4MS42MTc5IDg0Ljk4ODQgODEuNjE3OUg5My4xNDY0Qzk1Ljc0NDUgODEuNjE3OSA5Ny44NTA4IDgzLjcyMzggOTcuODUwOCA4Ni4zMjE3Vjk0LjQ3NzlaIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4M18yOTcyIiB4MT0iNSIgeTE9Ii03LjUiIHgyPSIxNDEiIHkyPSIxMjQuNSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjRkY4MjJGIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI0ZGNjYwMCIvPgo8L2xpbmVhckdyYWRpZW50Pgo8L2RlZnM+Cjwvc3ZnPgo= - keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "users"], ["spec", "vhosts"]] + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "version"], ["spec", "users"], ["spec", "vhosts"]] secrets: exclude: [] include: