Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
9 changes: 1 addition & 8 deletions api/operator/v1beta1/vmcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,13 +468,6 @@ type VMStorage struct {
}

type VMBackup struct {
// AcceptEULA accepts enterprise feature usage, must be set to true.
// otherwise backupmanager cannot be added to single/cluster version.
// https://victoriametrics.com/legal/esa/
// Deprecated: use license.key or license.keyRef instead
// +deprecated
// +optional
AcceptEULA bool `json:"acceptEULA"`
Copy link
Collaborator

@f41gh7 f41gh7 Jul 5, 2025

Choose a reason for hiding this comment

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

I suggest to make it no-op first at VictoriaMetrics ent version. Operator could produce a warning for validation webhook and suggest a migration. And add eual flag as is.

It'll simplify management of resource and provide a straightforward path for operator version rollback.

Copy link
Contributor

Choose a reason for hiding this comment

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

EULA is noop starting from v1.122.0:

Update Note 2: all the VictoriaMetrics Enterprise components: -eula command-line flag is skipped when validating VictoriaMetrics enterprise license. Instead, the -license or -licenseFile command-line flags must be used to provide a valid license key. See these docs for configuration examples.

// SnapshotCreateURL overwrites url for snapshot create
// +optional
SnapshotCreateURL string `json:"snapshotCreateURL,omitempty"`
Expand Down Expand Up @@ -552,7 +545,7 @@ type VMBackup struct {
}

func (cr *VMBackup) validate(l *License) error {
if !l.IsProvided() && !cr.AcceptEULA {
if !l.IsProvided() {
return fmt.Errorf("it is required to provide license key. See [here](https://docs.victoriametrics.com/victoriametrics/enterprise/)")
}

Expand Down
14 changes: 0 additions & 14 deletions config/crd/overlay/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27737,13 +27737,6 @@ spec:
vmBackup:
description: VMBackup configuration for backup
properties:
acceptEULA:
description: |-
AcceptEULA accepts enterprise feature usage, must be set to true.
otherwise backupmanager cannot be added to single/cluster version.
https://victoriametrics.com/legal/esa/
Deprecated: use license.key or license.keyRef instead
type: boolean
concurrency:
description: Defines number of concurrent workers. Higher
concurrency may reduce backup duration (default 10)
Expand Down Expand Up @@ -37261,13 +37254,6 @@ spec:
vmBackup:
description: VMBackup configuration for backup
properties:
acceptEULA:
description: |-
AcceptEULA accepts enterprise feature usage, must be set to true.
otherwise backupmanager cannot be added to single/cluster version.
https://victoriametrics.com/legal/esa/
Deprecated: use license.key or license.keyRef instead
type: boolean
concurrency:
description: Defines number of concurrent workers. Higher concurrency
may reduce backup duration (default 10)
Expand Down
2 changes: 2 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ aliases:

## tip

* FEATURE: [vmoperator](https://docs.victoriametrics.com/operator/): remove deprecated acceptEULA. Replaced it with license in tests. See [#1319](https://github.com/VictoriaMetrics/operator/issues/1319).

## [v0.61.0](https://github.com/VictoriaMetrics/operator/releases/tag/v0.61.0)

**Release date:** 15 July 2025
Expand Down
1 change: 0 additions & 1 deletion docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -3668,7 +3668,6 @@ Appears in: [VMSingleSpec](#vmsinglespec), [VMStorage](#vmstorage)

| Field | Description |
| --- | --- |
| acceptEULA<a href="#vmbackup-accepteula" id="vmbackup-accepteula">#</a><br/>_boolean_ | _(Optional)_<br/>AcceptEULA accepts enterprise feature usage, must be set to true.<br />otherwise backupmanager cannot be added to single/cluster version.<br />https://victoriametrics.com/legal/esa/<br />Deprecated: use license.key or license.keyRef instead |
| concurrency<a href="#vmbackup-concurrency" id="vmbackup-concurrency">#</a><br/>_integer_ | _(Optional)_<br/>Defines number of concurrent workers. Higher concurrency may reduce backup duration (default 10) |
| credentialsSecret<a href="#vmbackup-credentialssecret" id="vmbackup-credentialssecret">#</a><br/>_[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#secretkeyselector-v1-core)_ | _(Optional)_<br/>CredentialsSecret is secret in the same namespace for access to remote storage<br />The secret is mounted into /etc/vm/creds. |
| customS3Endpoint<a href="#vmbackup-customs3endpoint" id="vmbackup-customs3endpoint">#</a><br/>_string_ | _(Optional)_<br/>Custom S3 endpoint for use with S3-compatible storages (e.g. MinIO). S3 is used if not set |
Expand Down
6 changes: 3 additions & 3 deletions internal/controller/operator/factory/build/backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ func VMBackupManager(
isCluster bool,
license *vmv1beta1.License,
) (*corev1.Container, error) {
if !cr.AcceptEULA && !license.IsProvided() {
logger.WithContext(ctx).Info("EULA or license wasn't defined, update your backup settings." +
" Follow https://docs.victoriametrics.com/enterprise.html for further instructions.")
if !license.IsProvided() {
logger.WithContext(ctx).Info("license wasn't defined, update your backup settings." +
" Follow https://docs.victoriametrics.com/victoriametrics/enterprise/ for further instructions.")
return nil, nil
}
snapshotCreateURL := cr.SnapshotCreateURL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,9 @@ spec:
f("storage", &vmv1beta1.VMCluster{
ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default-1"},
Spec: vmv1beta1.VMClusterSpec{
License: &vmv1beta1.License{
Key: ptr.To("test-key"),
},
VMStorage: &vmv1beta1.VMStorage{
ServiceSpec: &vmv1beta1.AdditionalServiceSpec{
UseAsDefault: true,
Expand All @@ -564,9 +567,7 @@ spec:
},
},
},
VMBackup: &vmv1beta1.VMBackup{
AcceptEULA: true,
},
VMBackup: &vmv1beta1.VMBackup{},
},
},
}, `
Expand Down
8 changes: 0 additions & 8 deletions internal/webhook/operator/v1beta1/vmcluster_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,6 @@ func (*VMClusterCustomValidator) ValidateCreate(ctx context.Context, obj runtime
if err = r.Validate(); err != nil {
return
}
if r.Spec.VMStorage != nil && r.Spec.VMStorage.VMBackup != nil && r.Spec.VMStorage.VMBackup.AcceptEULA {
warnings = append(warnings, "deprecated property is defined `spec.vmstorage.vmbackup.acceptEula`, use `spec.license.key` or `spec.license.keyRef` instead.")
logger.WithContext(ctx).Info("deprecated property is defined `spec.vmstorage.vmbackup.acceptEula`, use `spec.license.key` or `spec.license.keyRef` instead.")
}
if r.Spec.VMSelect != nil && r.Spec.VMSelect.StorageSpec != nil {
warnings = append(warnings, "deprecated property is defined `spec.vmselect.persistentVolume`, use `storage` instead.")
logger.WithContext(ctx).Info("deprecated property is defined `spec.vmselect.persistentVolume`, use `storage` instead.")
Expand All @@ -81,10 +77,6 @@ func (*VMClusterCustomValidator) ValidateUpdate(ctx context.Context, _, newObj r
if err = r.Validate(); err != nil {
return
}
if r.Spec.VMStorage != nil && r.Spec.VMStorage.VMBackup != nil && r.Spec.VMStorage.VMBackup.AcceptEULA {
warnings = append(warnings, "deprecated property is defined `spec.vmbackup.acceptEula`, use `spec.license.key` or `spec.license.keyRef` instead.")
logger.WithContext(ctx).Info("deprecated property is defined `spec.vmbackup.acceptEula`, use `spec.license.key` or `spec.license.keyRef` instead.")
}
if r.Spec.VMSelect != nil && r.Spec.VMSelect.StorageSpec != nil {
warnings = append(warnings, "deprecated property is defined `vmcluster.spec.vmselect.persistentVolume`, use `storage` instead.")
logger.WithContext(ctx).Info("deprecated property is defined `vmcluster.spec.vmselect.persistentVolume`, use `storage` instead.")
Expand Down
9 changes: 0 additions & 9 deletions internal/webhook/operator/v1beta1/vmsingle_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1"
"github.com/VictoriaMetrics/operator/internal/controller/operator/factory/logger"
)

// SetupVMSingleWebhookWithManager will setup the manager to manage the webhooks
Expand Down Expand Up @@ -56,10 +55,6 @@ func (*VMSingleCustomValidator) ValidateCreate(ctx context.Context, obj runtime.
if err = r.Validate(); err != nil {
return
}
if r.Spec.VMBackup != nil && r.Spec.VMBackup.AcceptEULA {
warnings = append(warnings, "deprecated property is defined `spec.vmbackup.acceptEula`, use `spec.license.key` or `spec.license.keyRef` instead.")
logger.WithContext(ctx).Info("deprecated property is defined `spec.vmbackup.acceptEula`, use `spec.license.key` or `spec.license.keyRef` instead.")
}
return
}

Expand All @@ -77,10 +72,6 @@ func (*VMSingleCustomValidator) ValidateUpdate(ctx context.Context, _, newObj ru
if err = r.Validate(); err != nil {
return
}
if r.Spec.VMBackup != nil && r.Spec.VMBackup.AcceptEULA {
warnings = append(warnings, "deprecated property is defined `spec.vmbackup.acceptEula`, use `spec.license.key` or `spec.license.keyRef` instead.")
logger.WithContext(ctx).Info("deprecated property is defined `spec.vmbackup.acceptEula`, use `spec.license.key` or `spec.license.keyRef` instead.")
}
return
}

Expand Down
170 changes: 80 additions & 90 deletions test/e2e/prometheus_converter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ var (
Scheme: ptr.To("HTTPS"),
StaticConfigs: []promv1alpha1.StaticConfig{
{

Targets: []promv1alpha1.Target{
"localhost:9100",
},
Expand All @@ -61,7 +60,6 @@ var (
return nil
},
},

{
name: "PrometheusScrapeConfig",
source: &promv1alpha1.ScrapeConfig{
Expand Down Expand Up @@ -297,106 +295,98 @@ func getObject(ctx context.Context, obj client.Object) (client.Object, error) {
return obj, err
}

var _ = Describe("test prometheusConverter Controller", func() {
Context("e2e prome converter", func() {
for _, testCaseIt := range testCases {
testCase := testCaseIt
var _ = Describe("prometheus converter", Label("vm", "prom"), func() {
for _, tc := range testCases {
Context(fmt.Sprintf("crud %s", tc.name), func() {
// adapt test for parallel execution
// https://onsi.github.io/ginkgo/#patterns-for-parallel-integration-specs
procSuffix := fmt.Sprintf("-%d", GinkgoParallelProcess())
testCase.source.SetName(testCase.source.GetName() + procSuffix)
testCase.targetTpl.SetName(testCase.targetTpl.GetName() + procSuffix)
tc.source.SetName(tc.source.GetName() + procSuffix)
tc.targetTpl.SetName(tc.targetTpl.GetName() + procSuffix)
ctx := context.Background()
Context(fmt.Sprintf("crud %s", testCase.name), func() {
AfterEach(func() {
k8sClient.Delete(ctx, testCase.source) // nolint:errcheck
Eventually(func() error {
_, err := getObject(ctx, testCase.source)
AfterEach(func() {
k8sClient.Delete(ctx, tc.source) // nolint:errcheck
Eventually(func() error {
_, err := getObject(ctx, tc.source)
return err
}, eventualDeletionTimeout, 1).Should(MatchError(k8serrors.IsNotFound, "IsNotFound"))
k8sClient.Delete(ctx, tc.targetTpl) // nolint:errcheck
Eventually(func() error {
_, err := getObject(ctx, tc.targetTpl)
if err == nil {
return fmt.Errorf("Should be deleted")
}
return nil
}, 60, 1).Should(Succeed())
})
It("Should convert the object", func() {
source := tc.source.DeepCopyObject().(client.Object)
Expect(k8sClient.Create(ctx, source)).To(Succeed())
Eventually(func() error {
target, err := getObject(ctx, tc.targetTpl)
if err != nil {
return err
}, eventualDeletionTimeout, 1).Should(MatchError(k8serrors.IsNotFound, "IsNotFound"))

k8sClient.Delete(ctx, testCase.targetTpl) // nolint:errcheck
Eventually(func() error {
_, err := getObject(ctx, testCase.targetTpl)
if err == nil {
return fmt.Errorf("Should be deleted")
}
return nil
}, 60, 1).Should(Succeed())
})

It("Should convert the object", func() {
source := testCase.source.DeepCopyObject().(client.Object)
}
return tc.targetValidator(target)
}, 60, 1).Should(Succeed())
})

Expect(k8sClient.Create(ctx, source)).To(Succeed())
Eventually(func() error {
target, err := getObject(ctx, testCase.targetTpl)
if err != nil {
return err
}
return testCase.targetValidator(target)
}, 60, 1).Should(Succeed())
})
It("Should update the converted object", func() {
source := tc.source.DeepCopyObject().(client.Object)
Expect(k8sClient.Create(ctx, source)).To(Succeed())
Eventually(func() error {
_, err := getObject(ctx, tc.targetTpl)
return err
}, 60, 1).Should(Succeed())

It("Should update the converted object", func() {
source := testCase.source.DeepCopyObject().(client.Object)
labels := source.GetLabels()
if labels == nil {
labels = make(map[string]string)
}
// Use this hack to trigger update manually for GenerationChange predicate
// It's not a problem for production workloads
// Since operator performs period syncs for parent objects
source.SetGeneration(source.GetGeneration() + 1)
labels["testKey"] = "testValue"
source.SetLabels(labels)

Expect(k8sClient.Create(ctx, source)).To(Succeed())
Eventually(func() error {
_, err := getObject(ctx, testCase.targetTpl)
Expect(k8sClient.Update(ctx, source)).To(Succeed())
Eventually(func() error {
target, err := getObject(ctx, tc.targetTpl)
if err != nil {
return err
}, 60, 1).Should(Succeed())

labels := source.GetLabels()
if labels == nil {
labels = make(map[string]string)
}
// Use this hack to trigger update manually for GenerationChange predicate
// It's not a problem for production workloads
// Since operator performs period syncs for parent objects
source.SetGeneration(source.GetGeneration() + 1)
labels["testKey"] = "testValue"
source.SetLabels(labels)

Expect(k8sClient.Update(ctx, source)).To(Succeed())
Eventually(func() error {
target, err := getObject(ctx, testCase.targetTpl)
if err != nil {
return err
}
if target.GetLabels() == nil || target.GetLabels()["testKey"] != "testValue" {
return fmt.Errorf("unexpected labels, want testKey=testValue, got: %v", target.GetLabels())
}
return nil
}, 60, 1).Should(Succeed())
})
if target.GetLabels() == nil || target.GetLabels()["testKey"] != "testValue" {
return fmt.Errorf("unexpected labels, want testKey=testValue, got: %v", target.GetLabels())
}
return nil
}, 60, 1).Should(Succeed())
})

It("Should delete the converted object", func() {
source := testCase.source.DeepCopyObject().(client.Object)
It("Should delete the converted object", func() {
source := tc.source.DeepCopyObject().(client.Object)
Expect(k8sClient.Create(ctx, source)).To(Succeed())
Eventually(func() error {
_, err := getObject(ctx, tc.targetTpl)
return err
}, 60, 1).Should(Succeed())

Expect(k8sClient.Create(ctx, source)).To(Succeed())
Eventually(func() error {
_, err := getObject(ctx, testCase.targetTpl)
Expect(func() error {
target, err := getObject(ctx, tc.targetTpl)
if err != nil {
return err
}, 60, 1).Should(Succeed())

Expect(func() error {
target, err := getObject(ctx, testCase.targetTpl)
if err != nil {
return err
}
if target.GetOwnerReferences() == nil {
return fmt.Errorf("expected owner reference to be non nil, object :%s", target.GetName())
}
return nil
}()).To(Succeed())
Expect(k8sClient.Delete(ctx, source)).To(Succeed())
Eventually(func() error {
_, err := getObject(ctx, testCase.targetTpl)
return err
}, eventualDeletionTimeout, 1).Should(MatchError(k8serrors.IsNotFound, "IsNotFound"))
})
}
if target.GetOwnerReferences() == nil {
return fmt.Errorf("expected owner reference to be non nil, object: %s", target.GetName())
}
return nil
}()).To(Succeed())
Expect(k8sClient.Delete(ctx, source)).To(Succeed())
Eventually(func() error {
_, err := getObject(ctx, tc.targetTpl)
return err
}, eventualDeletionTimeout, 1).Should(MatchError(k8serrors.IsNotFound, "IsNotFound"))
})
}
})
})
}
})
1 change: 0 additions & 1 deletion test/e2e/suite/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"github.com/VictoriaMetrics/operator/internal/manager"
)

// var cfg *rest.Config
var testEnv *envtest.Environment
var cancelManager context.CancelFunc
var stopped = make(chan struct{})
Expand Down
5 changes: 2 additions & 3 deletions test/e2e/vlcluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ import (
)

//nolint:dupl,lll
var _ = Describe("test vlcluster Controller", Label("vl", "cluster", "vlcluster"), func() {

Context("e2e vlcluster", func() {
var _ = Describe("vlsingle", Label("vl", "cluster"), func() {
Context("crud", func() {
var ctx context.Context
namespace := fmt.Sprintf("default-%d", GinkgoParallelProcess())
namespacedName := types.NamespacedName{
Expand Down
Loading
Loading