Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Temporary Build Files
build/_output
build/_test
catalog/
# Created by https://www.gitignore.io/api/go,vim,emacs,visualstudiocode
### Emacs ###
# -*- mode: gitignore; -*-
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ jobs:
make manifests
make api-gen
make docs
make olm
# check for uncommited changes to crds, docs or API
git diff --exit-code
make test
Expand Down
57 changes: 34 additions & 23 deletions .github/workflows/operatorhub.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
repository: ${{ matrix.repo.upstream }}
ref: main
token: ${{ secrets.VM_BOT_GH_TOKEN }}
path: __k8s-operatorhub-repo
path: __operatorhub-repo

- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v6
Expand All @@ -48,58 +48,69 @@ jobs:
passphrase: ${{ secrets.VM_BOT_PASSPHRASE }}
git_user_signingkey: true
git_commit_gpgsign: true
workdir: __k8s-operatorhub-repo
workdir: __operatorhub-repo

- uses: dawidd6/action-download-artifact@v11
with:
name: olm
workflow: main.yaml
workflow: release.yaml
github_token: ${{ secrets.VM_BOT_GH_TOKEN }}
run_id: ${{ github.event.workflow_run.id }}
path: bundle

- name: Install opm
run: |
curl -sL https://github.com/operator-framework/operator-registry/releases/download/v1.65.0/linux-amd64-opm -o /usr/local/bin/opm
chmod +x /usr/local/bin/opm
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated

- name: Add operatorhub bundle
id: update
run: |
if [ ! -d bundle ]; then
echo "No bundle directory found"
exit 1;
fi
OPERATOR_DIR=__k8s-operatorhub-repo/operators/victoriametrics-operator
CATALOGS_DIR=__k8s-operatorhub-repo/catalogs
CATALOGS_DIR=__operatorhub-repo/catalogs
NEW_VERSION=$(ls bundle | head -1)
CATALOG_FILE=${CATALOGS_DIR}/latest/victoriametrics-operator/catalog.yaml
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Initialize PREV_CATALOG to a valid default before conditional assignment; it is currently used unconditionally and can break the workflow when no prior catalog exists.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/operatorhub.yaml, line 75:

<comment>Initialize `PREV_CATALOG` to a valid default before conditional assignment; it is currently used unconditionally and can break the workflow when no prior catalog exists.</comment>

<file context>
@@ -48,58 +48,69 @@ jobs:
-          CATALOGS_DIR=__k8s-operatorhub-repo/catalogs
+          CATALOGS_DIR=__operatorhub-repo/catalogs
+          NEW_VERSION=$(ls bundle | head -1)
+          CATALOG_FILE=${CATALOGS_DIR}/latest/victoriametrics-operator/catalog.yaml
+          mkdir -p ${CATALOGS_DIR}/latest/victoriametrics-operator
 
</file context>
Suggested change
CATALOG_FILE=${CATALOGS_DIR}/latest/victoriametrics-operator/catalog.yaml
CATALOG_FILE=${CATALOGS_DIR}/latest/victoriametrics-operator/catalog.yaml
PREV_CATALOG=/dev/null
Fix with Cubic

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not an issue - prior catalog exists

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for clarifying—the prior catalog exists, so this isn’t an issue here.

mkdir -p ${CATALOGS_DIR}/latest/victoriametrics-operator

mkdir -p ${CATALOGS_DIR}
mkdir -p ${OPERATOR_DIR}
# Save existing catalog as PREV_CATALOG before overwriting
if [ -f "${CATALOG_FILE}" ]; then
cp "${CATALOG_FILE}" /tmp/vm-prev-catalog.yaml
PREV_CATALOG=/tmp/vm-prev-catalog.yaml
fi

export OLD_VERSION=$(find ${OPERATOR_DIR}/* ! -path "*/catalog-templates" -maxdepth 0 -type d -exec basename {} \; | sort -V -r | head -1)
export OLD_ENTRY="victoriametrics-operator.v${OLD_VERSION}"
PREVIOUS_VERSION=$(yq 'select(.schema == "olm.channel") | .entries[0].name' \
${PREV_CATALOG} 2>/dev/null || true)

export NEW_VERSION=$(ls bundle | head -1)
opm render bundle/${NEW_VERSION} --output=yaml > /tmp/vm-bundle-rendered.yaml
yq 'select(.schema == "olm.package")' "${PREV_CATALOG}" > /tmp/vm-catalog-header.yaml
echo "---" >> /tmp/vm-catalog-header.yaml
yq '.entries[] | select(.schema == "olm.channel")' \
bundle/${NEW_VERSION}/catalog-templates/latest.yaml >> /tmp/vm-catalog-header.yaml

if [ ! -z $OLD_VERSION ]; then
export MANIFEST_PATH=bundle/${NEW_VERSION}/manifests/victoriametrics-operator.clusterserviceversion.yaml
yq -i '.spec.replaces = "victoriametrics-operator.v" + strenv(OLD_VERSION)' $MANIFEST_PATH
fi
# Include previous bundles from PREV_CATALOG (excludes current version to avoid duplicates)
yq "select(.schema == \"olm.bundle\" and .name != \"victoriametrics-operator.v${NEW_VERSION}\")" \
"${PREV_CATALOG}" > /tmp/vm-prev-bundles.yaml
yq eval-all '.' /tmp/vm-catalog-header.yaml /tmp/vm-bundle-rendered.yaml /tmp/vm-prev-bundles.yaml > ${CATALOG_FILE}

mv bundle/* ${OPERATOR_DIR}/
if [ -f ${OPERATOR_DIR}/Makefile ]; then
if [ ! -z $OLD_VERSION ]; then
yq -i -I2 '.catalog_templates.[].replaces = strenv(OLD_ENTRY)' ${OPERATOR_DIR}/${NEW_VERSION}/release-config.yaml
fi
else
rm -f ${OPERATOR_DIR}/${NEW_VERSION}/release-config.yaml
if [ -n "${PREVIOUS_VERSION}" ]; then
yq -i '(select(.schema == "olm.channel") | .entries[0]).replaces = strenv(PREVIOUS_VERSION)' ${CATALOG_FILE}
fi
opm validate ${CATALOGS_DIR}/latest/victoriametrics-operator

echo "VERSION=$NEW_VERSION" >> $GITHUB_OUTPUT

- name: Create Pull Request
if: ${{ steps.update.outputs.VERSION != '' }}
uses: peter-evans/create-pull-request@v7
with:
add-paths: operators/victoriametrics-operator,catalogs
add-paths: catalogs
commit-message: 'victoriametrics-operator: ${{ steps.update.outputs.VERSION }}'
signoff: true
committer: "Github Actions <${{ steps.import-gpg.outputs.email }}>"
path: __k8s-operatorhub-repo
path: __operatorhub-repo
push-to-fork: ${{ matrix.repo.fork }}
branch: vm-operator-release-${{ steps.update.outputs.VERSION }}
token: ${{ secrets.VM_BOT_GH_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
make lint test build build-installer
echo ${{secrets.REPO_KEY}} | docker login --username ${{secrets.REPO_USER}} --password-stdin
echo ${{secrets.QUAY_ACCESSKEY}} | docker login quay.io --username '${{secrets.QUAY_USER}}' --password-stdin
make publish
TAG=${TAG} make publish
TAG=${TAG} REGISTRY=quay.io make olm
gh release upload ${{github.event.release.tag_name}} ./dist/install-no-webhook.yaml#install-no-webhook.yaml --clobber || echo "fix me NOT enough security permissions"
gh release upload ${{github.event.release.tag_name}} ./dist/install-with-webhook.yaml#install-with-webhook.yaml --clobber || echo "fix me NOT enough security permissions"
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ report.xml
/bin/
/build*
/bundle*
/catalog*
release
operator.zip
coverage.txt
Expand Down
47 changes: 26 additions & 21 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ DATEINFO_TAG ?= $(shell date -u +'%Y%m%d-%H%M%S')
NAMESPACE ?= vm
OVERLAY ?= config/manager
E2E_TESTS_CONCURRENCY ?= $(shell getconf _NPROCESSORS_ONLN)
E2E_TARGET ?= ./test/e2e/...
FIPS_VERSION=v1.0.0
BASEIMAGE ?=scratch

Expand Down Expand Up @@ -160,26 +161,18 @@ test: manifests generate fmt vet envtest ## Run tests.

# Utilize Kind or modify the e2e tests to load the image locally, enabling compatibility with other vendors.
.PHONY: test-e2e # Run the e2e tests against a Kind k8s instance that is spun up.
BASE_REF ?= origin/master
SKIP_UPGRADE_TESTS ?= $(shell if git diff --quiet $(BASE_REF)...HEAD -- test/e2e/upgrade 2>/dev/null; then echo "--skip-package=upgrade"; fi)

test-e2e: load-kind ginkgo crust-gather mirrord
env CGO_ENABLED=1 OPERATOR_IMAGE=$(OPERATOR_IMAGE) REPORTS_DIR=$(shell pwd) CRUST_GATHER_BIN=$(CRUST_GATHER_BIN) $(MIRRORD_BIN) exec -f ./mirrord.json -- $(GINKGO_BIN) \
-ldflags="-linkmode=external" \
$(SKIP_UPGRADE_TESTS) \
--output-interceptor-mode=none \
-procs=$(E2E_TESTS_CONCURRENCY) \
-randomize-all \
-timeout=60m \
-junit-report=report.xml ./test/e2e/...
-junit-report=report.xml $(E2E_TARGET)

.PHONY: test-e2e-upgrade # Run only the e2e upgrade tests against a Kind k8s instance that is spun up.
test-e2e-upgrade: load-kind ginkgo crust-gather mirrord
env CGO_ENABLED=1 OPERATOR_IMAGE=$(OPERATOR_IMAGE) REPORTS_DIR=$(shell pwd) CRUST_GATHER_BIN=$(CRUST_GATHER_BIN) $(MIRRORD_BIN) exec -f ./mirrord.json -- $(GINKGO_BIN) \
-ldflags="-linkmode=external" \
-procs=$(E2E_TESTS_CONCURRENCY) \
-randomize-all \
-timeout=60m \
-junit-report=report.xml ./test/e2e/upgrade/...
test-e2e-upgrade: E2E_TARGET=./test/e2e/upgrade/...
test-e2e-upgrade: test-e2e

.PHONY: lint
lint: golangci-lint ## Run golangci-lint linter
Expand Down Expand Up @@ -281,25 +274,37 @@ build-installer: manifests generate kustomize ## Generate a consolidated YAML wi

olm: operator-sdk opm yq docs
$(eval DIGEST = $(shell $(CONTAINER_TOOL) buildx imagetools inspect $(REGISTRY)/$(ORG)/$(REPO):$(TAG)-ubi --format "{{print .Manifest.Digest}}"))
rm -rf bundle*
rm -rf bundle* catalog
$(OPERATOR_SDK) generate kustomize manifests -q
cd config/manifests && \
$(KUSTOMIZE) edit set image manager=$(REGISTRY)/$(ORG)/$(REPO)@$(DIGEST)
$(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle \
-q --overwrite --version $(VERSION) \
--channels=beta --default-channel=beta --output-dir=bundle/$(VERSION)
$(OPERATOR_SDK) bundle validate ./bundle/$(VERSION)
cp config/manifests/release-config.yaml bundle/$(VERSION)/
$(YQ) -i '.metadata.annotations.containerImage = "$(REGISTRY)/$(ORG)/$(REPO)@$(DIGEST)"' \
bundle/$(VERSION)/manifests/victoriametrics-operator.clusterserviceversion.yaml
$(YQ) -i '.spec.install.spec.deployments[0].spec.template.containers[0].image = "$(REGISTRY)/$(ORG)/$(REPO)@$(DIGEST)"' \
bundle/$(VERSION)/manifests/victoriametrics-operator.clusterserviceversion.yaml
$(YQ) -i '.spec.install.spec.deployments[0].spec.template.spec.containers[0].image = "$(REGISTRY)/$(ORG)/$(REPO)@$(DIGEST)"' \
bundle/$(VERSION)/manifests/victoriametrics-operator.clusterserviceversion.yaml
$(YQ) -i '.spec.relatedImages = [{"name": "victoriametrics-operator", "image": "$(REGISTRY)/$(ORG)/$(REPO)@$(DIGEST)"}]' \
$(YQ) -i '.metadata.annotations.containerImage = "$(REGISTRY)/$(ORG)/$(REPO)@$(DIGEST)" | .spec.install.spec.deployments[0].spec.template.containers[0].image = "$(REGISTRY)/$(ORG)/$(REPO)@$(DIGEST)" | .spec.install.spec.deployments[0].spec.template.spec.containers[0].image = "$(REGISTRY)/$(ORG)/$(REPO)@$(DIGEST)"' \
bundle/$(VERSION)/manifests/victoriametrics-operator.clusterserviceversion.yaml
$(YQ) -i '.annotations."com.redhat.openshift.versions" = "v4.12-v4.21"' \
bundle/$(VERSION)/metadata/annotations.yaml
mkdir -p bundle/$(VERSION)/catalog-templates catalog/latest
$(YQ) '.entries[] | select(.schema == "olm.channel") | .entries[] | select(.name != "victoriametrics-operator.v$(VERSION)") | .name' config/manifests/catalog-templates/latest.yaml > /tmp/vm-prev-names.txt
$(YQ) '.entries[] | select(.schema == "olm.channel") | .entries[] | select(.name != "victoriametrics-operator.v$(VERSION)") | .replaces | select(.)' config/manifests/catalog-templates/latest.yaml > /tmp/vm-prev-replaces.txt
PREV_HEAD=$$(grep -Fxvf /tmp/vm-prev-replaces.txt /tmp/vm-prev-names.txt | head -1); \
test -n "$$PREV_HEAD" || { echo "Error: could not determine previous channel head from catalog template"; exit 1; }; \
PREV_HEAD="$$PREV_HEAD" $(YQ) -i '(.entries[] | select(.schema == "olm.channel")).entries = [{"name": "victoriametrics-operator.v$(VERSION)", "replaces": strenv(PREV_HEAD)}] + (.entries[] | select(.schema == "olm.channel") | .entries | map(select(.name != "victoriametrics-operator.v$(VERSION)")))' \
config/manifests/catalog-templates/latest.yaml; \
PREV_HEAD="$$PREV_HEAD" $(YQ) -i '.spec.relatedImages = [{"name": "victoriametrics-operator", "image": "$(REGISTRY)/$(ORG)/$(REPO)@$(DIGEST)"}] | .spec.replaces = strenv(PREV_HEAD)' \
bundle/$(VERSION)/manifests/victoriametrics-operator.clusterserviceversion.yaml
cp config/manifests/catalog-templates/latest.yaml bundle/$(VERSION)/catalog-templates/latest.yaml
{ $(YQ) '.entries[] | select(.schema == "olm.package")' \
bundle/$(VERSION)/catalog-templates/latest.yaml; \
echo "---"; \
$(YQ) '(.entries[] | select(.schema == "olm.channel")) | .entries = [.entries[0]]' \
bundle/$(VERSION)/catalog-templates/latest.yaml; \
$(OPM) render bundle/$(VERSION) --output=yaml | \
$(YQ) '(select(.schema == "olm.bundle") | .image) = "$(REGISTRY)/$(ORG)/$(REPO)@$(DIGEST)" | (select(.schema == "olm.bundle") | .relatedImages) = [{"name": "victoriametrics-operator", "image": "$(REGISTRY)/$(ORG)/$(REPO)@$(DIGEST)"}]'; \
} > catalog/latest/catalog.yaml
$(OPM) validate catalog/latest

##@ Deployment

Expand Down
23 changes: 20 additions & 3 deletions api/operator/v1beta1/vmextra_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,23 +188,39 @@ type StorageSpec struct {

// IntoSTSVolume converts storageSpec into proper volume for statefulsetSpec
// by default, it adds emptyDir volume.
func (ss *StorageSpec) IntoSTSVolume(name string, sts *appsv1.StatefulSetSpec) {
func (ss *StorageSpec) IntoSTSVolume(name string, sts *appsv1.StatefulSetSpec) error {
podSpec := &sts.Template.Spec
foundVolume := false
for _, volume := range podSpec.Volumes {
if volume.Name == name {
foundVolume = true
}
}
switch {
case ss == nil:
sts.Template.Spec.Volumes = append(sts.Template.Spec.Volumes, corev1.Volume{
if foundVolume {
return nil
}
podSpec.Volumes = append(podSpec.Volumes, corev1.Volume{
Name: name,
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
})
case ss.EmptyDir != nil:
sts.Template.Spec.Volumes = append(sts.Template.Spec.Volumes, corev1.Volume{
if foundVolume {
return fmt.Errorf("either unset storage.emptyDir or remove volume=%q from spec", name)
}
podSpec.Volumes = append(podSpec.Volumes, corev1.Volume{
Name: name,
VolumeSource: corev1.VolumeSource{
EmptyDir: ss.EmptyDir,
},
})
default:
if foundVolume {
return fmt.Errorf("either unset storage.volumeClaimTemplate or remove volume=%q from spec", name)
}
claimTemplate := ss.VolumeClaimTemplate
stsClaim := corev1.PersistentVolumeClaim{
TypeMeta: metav1.TypeMeta{
Expand All @@ -224,6 +240,7 @@ func (ss *StorageSpec) IntoSTSVolume(name string, sts *appsv1.StatefulSetSpec) {
}
sts.VolumeClaimTemplates = append(sts.VolumeClaimTemplates, stsClaim)
}
return nil
}

// EmbeddedPersistentVolumeClaim is an embedded version of k8s.io/api/core/v1.PersistentVolumeClaim.
Expand Down
Loading
Loading