Repository: VictoriaMetrics/operator

Issue:
adjust `maxDiskUsagePerURL` based on `VMAgent` configuration. 

 Currently there is hard-coded value of `1GB`.  It'd be great to auto-magically change it based on the following conditions:
1) `statefulMode: true` 
2) `statefulStorage.volumeClaimTemplate` is defined.

 Use `storage.requests` from `volumeClaimTemplate` as default value for `maxDiskUsagePerURL` flag. 

Hints from issue comments:
@f41gh7: The feature was included into [v0.61.0](https://docs.victoriametrics.com/operator/changelog/#v0610) release

Solution patch:
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index e550f14d..7d87e39e 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -16,12 +16,16 @@ aliases:
 * Dependency: [vmoperator](https://docs.victoriametrics.com/operator/): Updated default versions for VL apps to [v1.25.0](https://github.com/VictoriaMetrics/VictoriaLogs/releases/tag/v1.25.0).
 * Dependency: [vmoperator](https://docs.victoriametrics.com/operator/): Updated default versions for VM apps to [v1.121.0](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/docs/victoriametrics/changelog/CHANGELOG.md#v11210) version.
 
+* BUGFIX: [VLCluster](https://docs.victoriametrics.com/operator/resources/vlcluster/) and [VMCluster](https://docs.victoriametrics.com/operator/resources/vmcluster/): do not add `spec.clusterVersion`  to the `spec.requestsLoadBalancer.spec.image.tag` as default value. See this [1365](https://github.com/VictoriaMetrics/operator/issues/1365) issue for details.
+
 * FEATURE: [vmanomaly](https://docs.victoriametrics.com/anomaly-detection/): update shards concurrently. See [#1434](https://github.com/VictoriaMetrics/operator/issues/1434).
 * FEATURE: [vmoperator](https://docs.victoriametrics.com/operator/): deprecated acceptEula parameter in VMBackup. See [#1319](https://github.com/VictoriaMetrics/operator/issues/1319).
 * FEATURE: [vmoperator](https://docs.victoriametrics.com/operator/): add new field persistentVolumeClaimRetentionPolicy in VMAnomaly, VMCluster, VMAlertmanager and VMAgent CRs, that support StatefulSet mode. See [#1226](https://github.com/VictoriaMetrics/operator/issues/1226).
+* FEATURE: [vmoperator](https://docs.victoriametrics.com/operator/): add `-enterprise` suffix to default `image.tag` value, if `license` configuration is defined for CustomResource. See this [1365](https://github.com/VictoriaMetrics/operator/issues/1365) issue for details.
 * FEATURE: [vmagent](https://docs.victoriametrics.com/operator/resources/vmagent/): added AWS section to VMAgent remoteWrite spec. See [#928](https://github.com/VictoriaMetrics/operator/issues/928).
 * FEATURE: [vmagent](https://docs.victoriametrics.com/operator/resources/vmagent/): introduce global scrape config for VMAgent. See [#1179](https://github.com/VictoriaMetrics/operator/issues/1179).
 * FEATURE: [vmcluster](https://docs.victoriametrics.com/operator/resources/vmcluster/): added the `maxUnavailable` field to VMStorage and VMSelect specs to allow customization of rolling update behavior. See [#1457](https://github.com/VictoriaMetrics/operator/issues/1457).
+* FEATURE: [vmagent](https://docs.victoriametrics.com/operator/resources/vmagent/): Modify default `remoteWrite.maxDiskUsagePerURL` when statefulStorage.volumeClaimTemplate is set. See [#1209](https://github.com/VictoriaMetrics/operator/issues/1209)
 
 ## [v0.60.2](https://github.com/VictoriaMetrics/operator/releases/tag/v0.60.2)
 
diff --git a/docs/resources/vmagent.md b/docs/resources/vmagent.md
index af107f60..4d83ea44 100644
--- a/docs/resources/vmagent.md
+++ b/docs/resources/vmagent.md
@@ -212,6 +212,8 @@ and `VMAgent` loses state of the PersistentQueue on pod restarts.
 
 In `StatefulMode` `VMAgent` doesn't lose state of the PersistentQueue (file-based buffer size for unsent data) on pod restarts.
 Operator creates `StatefulSet` and, with provided `PersistentVolumeClaimTemplate` at `StatefulStorage` configuration param, metrics queue is stored on disk.
+Operator automatically configures [remoteWrite.maxDiskUsagePerURL](https://docs.victoriametrics.com/victoriametrics/vmagent/#on-disk-persistence) based on provided `requests.storage`.
+It uses the following formula for calculation: `requests.storage/count(remoteWrite)`
 
 Example of configuration for `StatefulMode`:
 
@@ -596,7 +598,7 @@ metadata:
 spec:
   image:
     repository: victoriametrics/vmagent
-    tag: v1.93.4
+    tag: v1.110.13
     pullPolicy: Always
   # ...
 ```
@@ -611,7 +613,7 @@ metadata:
 spec:
   image:
     repository: victoriametrics/vmagent
-    tag: v1.93.4
+    tag: v1.110.13
     pullPolicy: Always
   imagePullSecrets:
     - name: my-repo-secret
@@ -664,12 +666,9 @@ Also, you can specify requests without limits - in this case default values for
 VMAgent supports feature [Kafka integration](https://docs.victoriametrics.com/vmagent#kafka-integration)
 from [VictoriaMetrics Enterprise](https://docs.victoriametrics.com/enterprise#victoriametrics-enterprise).
 
-For using Enterprise version of [vmagent](https://docs.victoriametrics.com/vmagent)
-you need to change version of `vmagent` to version with `-enterprise` suffix using [Version management](#version-management).
-
-All the enterprise apps require `-eula` command-line flag to be passed to them.
-This flag acknowledges that your usage fits one of the cases listed on [this page](https://docs.victoriametrics.com/enterprise#victoriametrics-enterprise).
-So you can use [extraArgs](./#extra-arguments) for passing this flag to `VMAgent`:
+For using Enterprise version of [vmagent](https://docs.victoriametrics.com/vmagent) you need to:
+ - specify license at [`spec.license.key`](https://docs.victoriametrics.com/operator/api/#license-key) or at [`spec.license.keyRef`](https://docs.victoriametrics.com/operator/api/#license-keyref).
+ - change version of `vmagent` to version with `-enterprise` suffix using [Version management](#version-management).
 
 After that you can pass [Kafka integration](https://docs.victoriametrics.com/vmagent#kafka-integration)
 flags to `VMAgent` with [extraArgs](./#extra-arguments).
@@ -685,15 +684,13 @@ metadata:
   name: ent-example
 spec:
   # enabling enterprise features
+  license:
+    keyRef:
+      name: k8s-secret-that-contains-license
+      key: key-in-a-secret-that-contains-license
   image:
-    # enterprise version of vmagent
-    tag: v1.93.5-enterprise
+    tag: v1.110.13-enterprise
   extraArgs:
-    # should be true and means that you have the legal right to run a vmagent enterprise
-    # that can either be a signed contract or an email with confirmation to run the service in a trial period
-    # https://victoriametrics.com/legal/esa/
-    eula: true
-    
     # using enterprise features: reading metrics from kafka
     # more details about kafka integration you can read on https://docs.victoriametrics.com/vmagent#kafka-integration
     # more details about these and other flags you can read on https://docs.victoriametrics.com/vmagent#command-line-flags-for-kafka-consumer
@@ -716,15 +713,12 @@ metadata:
   name: ent-example
 spec:
   # enabling enterprise features
+  license:
+    keyRef:
+      name: k8s-secret-that-contains-license
+      key: key-in-a-secret-that-contains-license
   image:
-    # enterprise version of vmagent
-    tag: v1.93.5-enterprise
-  extraArgs:
-    # should be true and means that you have the legal right to run a vmagent enterprise
-    # that can either be a signed contract or an email with confirmation to run the service in a trial period
-    # https://victoriametrics.com/legal/esa/
-    eula: true
-  
+    tag: v1.110.13-enterprise
   # using enterprise features: writing metrics to Kafka
   # more details about kafka integration you can read on https://docs.victoriametrics.com/vmagent/#kafka-integration
   remoteWrite:
diff --git a/docs/resources/vmalert.md b/docs/resources/vmalert.md
index 9b6fc2d8..f1270695 100644
--- a/docs/resources/vmalert.md
+++ b/docs/resources/vmalert.md
@@ -235,7 +235,7 @@ metadata:
 spec:
   image:
     repository: victoriametrics/vmalert
-    tag: v1.93.4
+    tag: v1.110.13
     pullPolicy: Always
   # ...
 ```
@@ -250,7 +250,7 @@ metadata:
 spec:
   image:
     repository: victoriametrics/vmalert
-    tag: v1.93.4
+    tag: v1.110.13
     pullPolicy: Always
   imagePullSecrets:
     - name: my-repo-secret
@@ -304,12 +304,9 @@ VMAlert supports features [Reading rules from object storage](https://docs.victo
 and [Multitenancy](https://docs.victoriametrics.com/vmalert#multitenancy)
 from [VictoriaMetrics Enterprise](https://docs.victoriametrics.com/enterprise#victoriametrics-enterprise).
 
-For using Enterprise version of [vmalert](https://docs.victoriametrics.com/vmalert)
-you need to change version of `VMAlert` to version with `-enterprise` suffix using [Version management](#version-management).
-
-All the enterprise apps require `-eula` command-line flag to be passed to them.
-This flag acknowledges that your usage fits one of the cases listed on [this page](https://docs.victoriametrics.com/enterprise#victoriametrics-enterprise).
-So you can use [extraArgs](./#extra-arguments) for passing this flag to `VMAlert`:
+For using Enterprise version of [vmalert](https://docs.victoriametrics.com/vmalert) you need to
+ - specify license at [`spec.license.key`](https://docs.victoriametrics.com/operator/api/#license-key) or at [`spec.license.keyRef`](https://docs.victoriametrics.com/operator/api/#license-keyref).
+ - change version of `vmalert` to version with `-enterprise` suffix using [Version management](#version-management).
 
 ### Reading rules from object storage
 
@@ -327,15 +324,13 @@ metadata:
   name: ent-example
 spec:
   # enabling enterprise features
+  license:
+    keyRef:
+      name: k8s-secret-that-contains-license
+      key: key-in-a-secret-that-contains-license
   image:
-    # enterprise version of vmalert
-    tag: v1.93.5-enterprise
+    tag: v1.110.13-enterprise
   extraArgs:
-    # should be true and means that you have the legal right to run a vmalert enterprise
-    # that can either be a signed contract or an email with confirmation to run the service in a trial period
-    # https://victoriametrics.com/legal/esa/
-    eula: true
-    
     # using enterprise features: Reading rules from object storage
     # more details about reading rules from object storage you can read on https://docs.victoriametrics.com/vmalert#reading-rules-from-object-storage
     rule: s3://bucket/dir/alert.rules
@@ -360,15 +355,13 @@ metadata:
   name: ent-example
 spec:
   # enabling enterprise features
+  license:
+    keyRef:
+      name: k8s-secret-that-contains-license
+      key: key-in-a-secret-that-contains-license
   image:
-    # enterprise version of vmalert
-    tag: v1.93.5-enterprise
+    tag: v1.110.13-enterprise
   extraArgs:
-    # should be true and means that you have the legal right to run a vmalert enterprise
-    # that can either be a signed contract or an email with confirmation to run the service in a trial period
-    # https://victoriametrics.com/legal/esa/
-    eula: true
-
     # using enterprise features: Multitenancy
     # more details about multitenancy you can read on https://docs.victoriametrics.com/vmalert#multitenancy
     clusterMode: true 
diff --git a/docs/resources/vmauth.md b/docs/resources/vmauth.md
index 582c1b63..08519007 100644
--- a/docs/resources/vmauth.md
+++ b/docs/resources/vmauth.md
@@ -139,7 +139,7 @@ metadata:
 spec:
   image:
     repository: victoriametrics/vmauth
-    tag: v1.93.4
+    tag: v1.110.13
     pullPolicy: Always
   # ...
 ```
@@ -154,7 +154,7 @@ metadata:
 spec:
   image:
     repository: victoriametrics/vmauth
-    tag: v1.93.4
+    tag: v1.110.13
     pullPolicy: Always
   imagePullSecrets:
     - name: my-repo-secret
@@ -207,12 +207,9 @@ Also, you can specify requests without limits - in this case default values for
 Custom resource `VMAuth` supports feature [IP filters](https://docs.victoriametrics.com/vmauth#ip-filters)
 from [VictoriaMetrics Enterprise](https://docs.victoriametrics.com/enterprise#victoriametrics-enterprise).
 
-For using Enterprise version of [vmauth](https://docs.victoriametrics.com/vmauth)
-you need to change version of `vmauth` to version with `-enterprise` suffix using [Version management](#version-management).
-
-All the enterprise apps require `-eula` command-line flag to be passed to them. 
-This flag acknowledges that your usage fits one of the cases listed on [this page](https://docs.victoriametrics.com/enterprise#victoriametrics-enterprise).
-So you can use [extraArgs](./#extra-arguments) for passing this flag to `VMAuth`:
+For using Enterprise version of [vmauth](https://docs.victoriametrics.com/vmauth) you need to:
+ - specify license at [`spec.license.key`](https://docs.victoriametrics.com/operator/api/#license-key) or at [`spec.license.keyRef`](https://docs.victoriametrics.com/operator/api/#license-keyref).
+ - change version of `vmauth` to version with `-enterprise` suffix using [Version management](#version-management).
 
 ### IP Filters
 
@@ -228,15 +225,12 @@ metadata:
   name: ent-example
 spec:
   # enabling enterprise features
+  license:
+    keyRef:
+      name: k8s-secret-that-contains-license
+      key: key-in-a-secret-that-contains-license
   image:
-    # enterprise version of vmauth
-    tag: v1.93.5-enterprise
-  extraArgs:
-    # should be true and means that you have the legal right to run a vmauth enterprise
-    # that can either be a signed contract or an email with confirmation to run the service in a trial period
-    # https://victoriametrics.com/legal/esa/
-    eula: true
-  
+    tag: v1.110.13-enterprise
   # using enterprise features: ip filters for vmauth
   # more details about ip filters you can read in https://docs.victoriametrics.com/vmauth#ip-filters
   ip_filters:
diff --git a/docs/resources/vmcluster.md b/docs/resources/vmcluster.md
index 5cb3635c..08d4814d 100644
--- a/docs/resources/vmcluster.md
+++ b/docs/resources/vmcluster.md
@@ -205,22 +205,33 @@ spec:
     replicaCount: 2
     image:
       repository: victoriametrics/vmstorage
-      tag: v1.93.4-cluster
+      tag: v1.110.13-cluster
       pullPolicy: Always
   vmselect:
     replicaCount: 2
     image:
       repository: victoriametrics/vmselect
-      tag: v1.93.4-cluster
+      tag: v1.110.13-cluster
       pullPolicy: Always
   vminsert:
     replicaCount: 2
     image:
       repository: victoriametrics/vminsert
-      tag: v1.93.4-cluster
+      tag: v1.110.13-cluster
       pullPolicy: Always
 ```
 
+or for all cluster components all together, using `clusterVersion` property:
+
+```yaml
+apiVersion: operator.victoriametrics.com/v1beta1
+kind: VMCluster
+metadata:
+  name: example
+spec:
+  clusterVersion: v1.110.13-cluster
+```
+
 Also, you can specify `imagePullSecrets` if you are pulling images from private repo, 
 but `imagePullSecrets` is global setting for all `VMCluster` specification:
 
@@ -234,19 +245,19 @@ spec:
     replicaCount: 2
     image:
       repository: victoriametrics/vmstorage
-      tag: v1.93.4-cluster
+      tag: v1.110.13-cluster
       pullPolicy: Always
   vmselect:
     replicaCount: 2
     image:
       repository: victoriametrics/vmselect
-      tag: v1.93.4-cluster
+      tag: v1.110.13-cluster
       pullPolicy: Always
   vminsert:
     replicaCount: 2
     image:
       repository: victoriametrics/vminsert
-      tag: v1.93.4-cluster
+      tag: v1.110.13-cluster
       pullPolicy: Always
   imagePullSecrets:
     - name: my-repo-secret
@@ -317,7 +328,7 @@ These default parameters will be used if:
 Field `resources` in `VMCluster/*` spec have higher priority than operator parameters.
 
 If you set `VM_VMCLUSTERDEFAULT_USEDEFAULTRESOURCES` to `false` and don't specify `resources` in `VMCluster/*` CRD,
-then `VMCluste/*r` pods will be created without resource requests and limits.
+then `VMCluster/*` pods will be created without resource requests and limits.
 
 Also, you can specify requests without limits - in this case default values for limits will not be used.
 
@@ -335,12 +346,9 @@ from [VictoriaMetrics Enterprise](https://docs.victoriametrics.com/enterprise#vi
 VMCluster doesn't support yet feature 
 [Automatic discovery for vmstorage nodes](https://docs.victoriametrics.com/Cluster-VictoriaMetrics#automatic-vmstorage-discovery).
 
-For using Enterprise version of [vmcluster](https://docs.victoriametrics.com/Cluster-VictoriaMetrics)
-you need to change version of `VMCluster` to version with `-enterprise` suffix using [Version management](#version-management).
-
-All the enterprise apps require `-eula` command-line flag to be passed to them.
-This flag acknowledges that your usage fits one of the cases listed on [this page](https://docs.victoriametrics.com/enterprise#victoriametrics-enterprise).
-So you can use [extraArgs](./#extra-arguments) for passing this flag to `VMCluster`.
+For using Enterprise version of [vmcluster](https://docs.victoriametrics.com/Cluster-VictoriaMetrics) you need to:
+ - specify license at [`spec.license.key`](https://docs.victoriametrics.com/operator/api/#license-key) or at [`spec.license.keyRef`](https://docs.victoriametrics.com/operator/api/#license-keyref).
+ - change version of `vmcluster` to version with `-enterprise-cluster` suffix using [Version management](#version-management).
 
 ### Downsampling
 
@@ -355,33 +363,21 @@ kind: VMCluster
 metadata:
   name: ent-example
 spec:
-  
+  # enabling enterprise features
+  license:
+    keyRef:
+      name: k8s-secret-that-contains-license
+      key: key-in-a-secret-that-contains-license
+  clusterVersion: v1.110.13-enterprise-cluster
   vmselect:
     # enabling enterprise features for vmselect
-    image:
-      # enterprise version of vmselect
-      tag: v1.93.5-enterprise-cluster
     extraArgs:
-      # should be true and means that you have the legal right to run a vmselect enterprise
-      # that can either be a signed contract or an email with confirmation to run the service in a trial period
-      # https://victoriametrics.com/legal/esa/
-      eula: true
-      
       # using enterprise features: Downsampling
       # more details about downsampling you can read on https://docs.victoriametrics.com/Cluster-VictoriaMetrics#downsampling
       downsampling.period: 30d:5m,180d:1h,1y:6h,2y:1d
-      
   vmstorage:
     # enabling enterprise features for vmstorage
-    image:
-      # enterprise version of vmstorage
-      tag: v1.93.5-enterprise-cluster
     extraArgs:
-      # should be true and means that you have the legal right to run a vmstorage enterprise
-      # that can either be a signed contract or an email with confirmation to run the service in a trial period
-      # https://victoriametrics.com/legal/esa/
-      eula: true
-
       # using enterprise features: Downsampling
       # more details about downsampling you can read on https://docs.victoriametrics.com/Cluster-VictoriaMetrics#downsampling
       downsampling.period: 30d:5m,180d:1h,1y:6h,2y:1d
@@ -402,18 +398,14 @@ kind: VMCluster
 metadata:
   name: ent-example
 spec:
-  
+  # enabling enterprise features
+  license:
+    keyRef:
+      name: k8s-secret-that-contains-license
+      key: key-in-a-secret-that-contains-license
+  clusterVersion: v1.110.13-enterprise-cluster
   vmstorage:
-    # enabling enterprise features for vmstorage
-    image:
-      # enterprise version of vmstorage
-      tag: v1.93.5-enterprise-cluster
     extraArgs:
-      # should be true and means that you have the legal right to run a vmstorage enterprise
-      # that can either be a signed contract or an email with confirmation to run the service in a trial period
-      # https://victoriametrics.com/legal/esa/
-      eula: true
-
       # using enterprise features: Retention filters
       # more details about retention filters you can read on https://docs.victoriametrics.com/Cluster-VictoriaMetrics#retention-filters
       retentionFilter: '{vm_account_id="5",env="dev"}:5d,{vm_account_id="5",env="prod"}:5y'
@@ -434,39 +426,12 @@ kind: VMCluster
 metadata:
   name: ent-example
 spec:
-  
-  vmselect:
-    # enabling enterprise features for vmselect
-    image:
-      # enterprise version of vmselect
-      tag: v1.93.5-enterprise-cluster
-    extraArgs:
-      # should be true and means that you have the legal right to run a vmselect enterprise
-      # that can either be a signed contract or an email with confirmation to run the service in a trial period
-      # https://victoriametrics.com/legal/esa/
-      eula: true
-      
-  vminsert:
-    # enabling enterprise features for vminsert
-    image:
-      # enterprise version of vminsert
-      tag: v1.93.5-enterprise-cluster
-    extraArgs:
-      # should be true and means that you have the legal right to run a vminsert enterprise
-      # that can either be a signed contract or an email with confirmation to run the service in a trial period
-      # https://victoriametrics.com/legal/esa/
-      eula: true
-      
-  vmstorage:
-    # enabling enterprise features for vmstorage
-    image:
-      # enterprise version of vmstorage
-      tag: v1.93.5-enterprise-cluster
-    extraArgs:
-      # should be true and means that you have the legal right to run a vmstorage enterprise
-      # that can either be a signed contract or an email with confirmation to run the service in a trial period
-      # https://victoriametrics.com/legal/esa/
-      eula: true
+  # enabling enterprise features
+  license:
+    keyRef:
+      name: k8s-secret-that-contains-license
+      key: key-in-a-secret-that-contains-license
+  clusterVersion: v1.110.13-enterprise-cluster
 
   # ...other fields...
 ```
@@ -488,18 +453,14 @@ kind: VMCluster
 metadata:
   name: ent-example
 spec:
-  
+  # enabling enterprise features
+  license:
+    keyRef:
+      name: k8s-secret-that-contains-license
+      key: key-in-a-secret-that-contains-license
+  clusterVersion: v1.110.13-enterprise-cluster
   vmselect:
-    # enabling enterprise features for vmselect
-    image:
-      # enterprise version of vmselect
-      tag: v1.93.5-enterprise-cluster
     extraArgs:
-      # should be true and means that you have the legal right to run a vmselect enterprise
-      # that can either be a signed contract or an email with confirmation to run the service in a trial period
-      # https://victoriametrics.com/legal/esa/
-      eula: true
-      
       # using enterprise features: mTLS protection
       # more details about mTLS protection you can read on https://docs.victoriametrics.com/Cluster-VictoriaMetrics#mtls-protection
       cluster.tls: true
@@ -515,16 +476,7 @@ spec:
         mountPath: /etc/mtls
       
   vminsert:
-    # enabling enterprise features for vminsert
-    image:
-      # enterprise version of vminsert
-      tag: v1.93.5-enterprise-cluster
     extraArgs:
-      # should be true and means that you have the legal right to run a vminsert enterprise
-      # that can either be a signed contract or an email with confirmation to run the service in a trial period
-      # https://victoriametrics.com/legal/esa/
-      eula: true
-
       # using enterprise features: mTLS protection
       # more details about mTLS protection you can read on https://docs.victoriametrics.com/Cluster-VictoriaMetrics#mtls-protection
       cluster.tls: true
@@ -540,21 +492,12 @@ spec:
         mountPath: /etc/mtls
       
   vmstorage:
-    # enabling enterprise features for vmstorage
-    image:
-      # enterprise version of vmstorage
-      tag: v1.93.5-enterprise-cluster
     env:
       - name: POD
         valueFrom:
           fieldRef:
             fieldPath: metadata.name
     extraArgs:
-      # should be true and means that you have the legal right to run a vmstorage enterprise
-      # that can either be a signed contract or an email with confirmation to run the service in a trial period
-      # https://victoriametrics.com/legal/esa/
-      eula: true
-
       # using enterprise features: mTLS protection
       # more details about mTLS protection you can read on https://docs.victoriametrics.com/Cluster-VictoriaMetrics#mtls-protection
       cluster.tls: true
diff --git a/docs/resources/vmsingle.md b/docs/resources/vmsingle.md
index 29c8565d..28a6a704 100644
--- a/docs/resources/vmsingle.md
+++ b/docs/resources/vmsingle.md
@@ -50,7 +50,7 @@ metadata:
 spec:
   image:
     repository: victoriametrics/victoria-metrics
-    tag: v1.93.4
+    tag: v1.110.13
     pullPolicy: Always
   # ...
 ```
@@ -65,7 +65,7 @@ metadata:
 spec:
   image:
     repository: victoriametrics/victoria-metrics
-    tag: v1.93.4
+    tag: v1.110.13
     pullPolicy: Always
   imagePullSecrets:
     - name: my-repo-secret
@@ -121,12 +121,9 @@ VMSingle supports features from [VictoriaMetrics Enterprise](https://docs.victor
 - [Multiple retentions / Retention filters](https://docs.victoriametrics.com/#retention-filters)
 - [Backup automation](https://docs.victoriametrics.com/vmbackupmanager)
 
-For using Enterprise version of [vmsingle](https://docs.victoriametrics.com/)
-you need to change version of `VMSingle` to version with `-enterprise` suffix using [Version management](#version-management).
-
-All the enterprise apps require `-eula` command-line flag to be passed to them.
-This flag acknowledges that your usage fits one of the cases listed on [this page](https://docs.victoriametrics.com/enterprise#victoriametrics-enterprise).
-So you can use [extraArgs](./#extra-arguments) for passing this flag to `VMSingle`.
+For using Enterprise version of [vmsingle](https://docs.victoriametrics.com/) you need to:
+ - specify license at [`spec.license.key`](https://docs.victoriametrics.com/operator/api/#license-key) or at [`spec.license.keyRef`](https://docs.victoriametrics.com/operator/api/#license-keyref).
+ - change version of `vmsingle` to version with `-enterprise` suffix using [Version management](#version-management).
 
 ### Downsampling
 
@@ -142,15 +139,13 @@ metadata:
   name: ent-example
 spec:
   # enabling enterprise features
+  license:
+    keyRef:
+      name: k8s-secret-that-contains-license
+      key: key-in-a-secret-that-contains-license
   image:
-    # enterprise version of vmsingle
-    tag: v1.93.5-enterprise
+    tag: v1.110.13-enterprise
   extraArgs:
-    # should be true and means that you have the legal right to run a vmsingle enterprise
-    # that can either be a signed contract or an email with confirmation to run the service in a trial period
-    # https://victoriametrics.com/legal/esa/
-    eula: true
-    
     # using enterprise features: Downsampling
     # more details about downsampling you can read on https://docs.victoriametrics.com/#downsampling
     downsampling.period: 30d:5m,180d:1h,1y:6h,2y:1d
@@ -169,15 +164,13 @@ metadata:
   name: ent-example
 spec:
   # enabling enterprise features
+  license:
+    keyRef:
+      name: k8s-secret-that-contains-license
+      key: key-in-a-secret-that-contains-license
   image:
-    # enterprise version of vmsingle
-    tag: v1.93.5-enterprise
+    tag: v1.110.13-enterprise
   extraArgs:
-    # should be true and means that you have the legal right to run a vmsingle enterprise
-    # that can either be a signed contract or an email with confirmation to run the service in a trial period
-    # https://victoriametrics.com/legal/esa/
-    eula: true
-    
     # using enterprise features: Retention filters
     # more details about retention filters you can read on https://docs.victoriametrics.com/#retention-filters
     retentionFilter: '{team="juniors"}:3d,{env=~"dev|staging"}:30d'
@@ -201,13 +194,14 @@ kind: VMSingle
 metadata:
   name: example
 spec:
-
+  # enabling enterprise features
+  license:
+    keyRef:
+      name: k8s-secret-that-contains-license
+      key: key-in-a-secret-that-contains-license
+  image:
+    tag: v1.110.13-enterprise
   vmBackup:
-    # should be true and means that you have the legal right to run a vmsingle enterprise
-    # that can either be a signed contract or an email with confirmation to run the service in a trial period
-    # https://victoriametrics.com/legal/esa/
-    acceptEULA: true
-
     # using enterprise features: Backup automation
     # more details about backup automation you can read on https://docs.victoriametrics.com/vmbackupmanager/
     destination: "s3://your_bucket/folder"
@@ -262,13 +256,14 @@ Steps:
     metadata:
       name: vmsingle
     spec:
-    
+      # enabling enterprise features
+      license:
+        keyRef:
+          name: k8s-secret-that-contains-license
+          key: key-in-a-secret-that-contains-license
+      image:
+        tag: v1.110.13-enterprise
       vmBackup:
-        # should be true and means that you have the legal right to run a vmsingle enterprise
-        # that can either be a signed contract or an email with confirmation to run the service in a trial period
-        # https://victoriametrics.com/legal/esa/
-        acceptEULA: true
-    
         # using enterprise features: Backup automation
         # more details about backup automation you can read https://docs.victoriametrics.com/vmbackupmanager/
         destination: "s3://your_bucket/folder"
diff --git a/internal/controller/operator/factory/build/defaults.go b/internal/controller/operator/factory/build/defaults.go
index d1bf6e85..f2b90aa3 100644
--- a/internal/controller/operator/factory/build/defaults.go
+++ b/internal/controller/operator/factory/build/defaults.go
@@ -1,6 +1,8 @@
 package build
 
 import (
+	"strings"
+
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/runtime"
@@ -184,7 +186,7 @@ func addVMAuthDefaults(objI any) {
 		}
 	}
 	cv := config.ApplicationDefaults(c.VMAuthDefault)
-	addDefaultsToCommonParams(&cr.Spec.CommonDefaultableParams, &cv)
+	addDefaultsToCommonParams(&cr.Spec.CommonDefaultableParams, cr.Spec.License, &cv)
 	addDefaultsToConfigReloader(&cr.Spec.CommonConfigReloaderParams, ptr.Deref(cr.Spec.UseDefaultResources, false), &cv)
 }
 
@@ -193,7 +195,7 @@ func addVMAlertDefaults(objI any) {
 	c := getCfg()
 
 	cv := config.ApplicationDefaults(c.VMAlertDefault)
-	addDefaultsToCommonParams(&cr.Spec.CommonDefaultableParams, &cv)
+	addDefaultsToCommonParams(&cr.Spec.CommonDefaultableParams, cr.Spec.License, &cv)
 	addDefaultsToConfigReloader(&cr.Spec.CommonConfigReloaderParams, ptr.Deref(cr.Spec.UseDefaultResources, false), &cv)
 	if cr.Spec.ConfigReloaderImageTag == "" {
 		panic("cannot be empty")
@@ -205,7 +207,7 @@ func addVMAgentDefaults(objI any) {
 	c := getCfg()
 
 	cv := config.ApplicationDefaults(c.VMAgentDefault)
-	addDefaultsToCommonParams(&cr.Spec.CommonDefaultableParams, &cv)
+	addDefaultsToCommonParams(&cr.Spec.CommonDefaultableParams, cr.Spec.License, &cv)
 	addDefaultsToConfigReloader(&cr.Spec.CommonConfigReloaderParams, ptr.Deref(cr.Spec.UseDefaultResources, false), &cv)
 }
 
@@ -214,7 +216,7 @@ func addVMSingleDefaults(objI any) {
 	c := getCfg()
 	useBackupDefaultResources := c.VMBackup.UseDefaultResources
 	cv := config.ApplicationDefaults(c.VMSingleDefault)
-	addDefaultsToCommonParams(&cr.Spec.CommonDefaultableParams, &cv)
+	addDefaultsToCommonParams(&cr.Spec.CommonDefaultableParams, cr.Spec.License, &cv)
 	if cr.Spec.UseDefaultResources != nil {
 		useBackupDefaultResources = *cr.Spec.UseDefaultResources
 	}
@@ -241,7 +243,7 @@ func addVLogsDefaults(objI any) {
 	cr := objI.(*vmv1beta1.VLogs)
 	c := getCfg()
 	cv := config.ApplicationDefaults(c.VLogsDefault)
-	addDefaultsToCommonParams(&cr.Spec.CommonDefaultableParams, &cv)
+	addDefaultsToCommonParams(&cr.Spec.CommonDefaultableParams, nil, &cv)
 }
 
 func addVMAnomalyDefaults(objI any) {
@@ -264,7 +266,7 @@ func addVMAnomalyDefaults(objI any) {
 	}
 	c := getCfg()
 	cv := config.ApplicationDefaults(c.VMAnomalyDefault)
-	addDefaultsToCommonParams(&cr.Spec.CommonDefaultableParams, &cv)
+	addDefaultsToCommonParams(&cr.Spec.CommonDefaultableParams, nil, &cv)
 	if cr.Spec.Monitoring == nil {
 		cr.Spec.Monitoring = &vmv1.VMAnomalyMonitoringSpec{
 			Pull: &vmv1.VMAnomalyMonitoringPullSpec{
@@ -278,7 +280,7 @@ func addVLSingleDefaults(objI any) {
 	cr := objI.(*vmv1.VLSingle)
 	c := getCfg()
 	cv := config.ApplicationDefaults(c.VLSingleDefault)
-	addDefaultsToCommonParams(&cr.Spec.CommonDefaultableParams, &cv)
+	addDefaultsToCommonParams(&cr.Spec.CommonDefaultableParams, nil, &cv)
 }
 
 func addVMAlertmanagerDefaults(objI any) {
@@ -320,7 +322,7 @@ func addVMAlertmanagerDefaults(objI any) {
 	if cr.Spec.TerminationGracePeriodSeconds == nil {
 		cr.Spec.TerminationGracePeriodSeconds = ptr.To[int64](120)
 	}
-	addDefaultsToCommonParams(&cr.Spec.CommonDefaultableParams, &cv)
+	addDefaultsToCommonParams(&cr.Spec.CommonDefaultableParams, nil, &cv)
 	addDefaultsToConfigReloader(&cr.Spec.CommonConfigReloaderParams, ptr.Deref(cr.Spec.UseDefaultResources, false), &cv)
 }
 
@@ -505,11 +507,9 @@ func addVMClusterDefaults(objI any) {
 			cr.Spec.RequestsLoadBalancer.Spec.DisableSelfServiceScrape = &c.DisableSelfServiceScrapeCreation
 		}
 		cr.Spec.RequestsLoadBalancer.Spec.ImagePullSecrets = append(cr.Spec.RequestsLoadBalancer.Spec.ImagePullSecrets, cr.Spec.ImagePullSecrets...)
-		if cr.Spec.RequestsLoadBalancer.Spec.Image.Tag == "" {
-			cr.Spec.RequestsLoadBalancer.Spec.Image.Tag = cr.Spec.ClusterVersion
-		}
+
 		cv := config.ApplicationDefaults(c.VMAuthDefault)
-		addDefaultsToCommonParams(&cr.Spec.RequestsLoadBalancer.Spec.CommonDefaultableParams, &cv)
+		addDefaultsToCommonParams(&cr.Spec.RequestsLoadBalancer.Spec.CommonDefaultableParams, cr.Spec.License, &cv)
 		spec := &cr.Spec.RequestsLoadBalancer.Spec
 		if spec.EmbeddedProbes == nil {
 			spec.EmbeddedProbes = &vmv1beta1.EmbeddedProbes{}
@@ -527,7 +527,7 @@ func addVMClusterDefaults(objI any) {
 	}
 }
 
-func addDefaultsToCommonParams(common *vmv1beta1.CommonDefaultableParams, appDefaults *config.ApplicationDefaults) {
+func addDefaultsToCommonParams(common *vmv1beta1.CommonDefaultableParams, license *vmv1beta1.License, appDefaults *config.ApplicationDefaults) {
 	c := getCfg()
 
 	if common.Image.Repository == "" {
@@ -539,7 +539,11 @@ func addDefaultsToCommonParams(common *vmv1beta1.CommonDefaultableParams, appDef
 	common.Image.Repository = formatContainerImage(c.ContainerRegistry, common.Image.Repository)
 	if common.Image.Tag == "" {
 		common.Image.Tag = appDefaults.Version
+		if license.IsProvided() {
+			common.Image.Tag = addEntSuffixToTag(common.Image.Tag)
+		}
 	}
+
 	if common.Port == "" {
 		common.Port = appDefaults.Port
 	}
@@ -610,6 +614,8 @@ func addDefaultsToVMBackup(cr *vmv1beta1.VMBackup, useDefaultResources bool, app
 	cr.Image.Repository = formatContainerImage(c.ContainerRegistry, cr.Image.Repository)
 	if cr.Image.Tag == "" {
 		cr.Image.Tag = appDefaults.Version
+		// vmbackup always uses enterprise version
+		cr.Image.Tag = addEntSuffixToTag(cr.Image.Tag)
 	}
 	if cr.Port == "" {
 		cr.Port = appDefaults.Port
@@ -779,11 +785,9 @@ func addVLClusterDefaults(objI any) {
 			cr.Spec.RequestsLoadBalancer.Spec.DisableSelfServiceScrape = &c.DisableSelfServiceScrapeCreation
 		}
 		cr.Spec.RequestsLoadBalancer.Spec.ImagePullSecrets = append(cr.Spec.RequestsLoadBalancer.Spec.ImagePullSecrets, cr.Spec.ImagePullSecrets...)
-		if cr.Spec.RequestsLoadBalancer.Spec.Image.Tag == "" {
-			cr.Spec.RequestsLoadBalancer.Spec.Image.Tag = cr.Spec.ClusterVersion
-		}
+
 		cv := config.ApplicationDefaults(c.VMAuthDefault)
-		addDefaultsToCommonParams(&cr.Spec.RequestsLoadBalancer.Spec.CommonDefaultableParams, &cv)
+		addDefaultsToCommonParams(&cr.Spec.RequestsLoadBalancer.Spec.CommonDefaultableParams, nil, &cv)
 		spec := &cr.Spec.RequestsLoadBalancer.Spec
 		if spec.EmbeddedProbes == nil {
 			spec.EmbeddedProbes = &vmv1beta1.EmbeddedProbes{}
@@ -799,5 +803,25 @@ func addVLClusterDefaults(objI any) {
 			spec.AdditionalServiceSpec.UseAsDefault = true
 		}
 	}
+}
+
+func addEntSuffixToTag(versionTag string) string {
+	// expected version tag is:
+	// vX.Y.Z with optional suffix -
+	if !strings.HasPrefix(versionTag, "v") || strings.Count(versionTag, ".") != 2 {
+		return versionTag
+	}
+	idx := strings.Index(versionTag, "-")
+	if idx > 0 {
+		suffix := versionTag[idx:]
+		switch suffix {
+		case "-enterprise", "-enterprise-cluster":
+		case "-cluster":
+			versionTag = versionTag[:idx] + "-enterprise-cluster"
+		}
+	} else {
+		versionTag += "-enterprise"
+	}
 
+	return versionTag
 }
diff --git a/internal/controller/operator/factory/k8stools/client_utils.go b/internal/controller/operator/factory/k8stools/client_utils.go
index 1b98b156..f5b9b95d 100644
--- a/internal/controller/operator/factory/k8stools/client_utils.go
+++ b/internal/controller/operator/factory/k8stools/client_utils.go
@@ -110,8 +110,8 @@ func UpdatePodAnnotations(ctx context.Context, rclient client.Client, selector m
 }
 
 // ListObjectsByNamespace performs object list for given namespaces
-func ListObjectsByNamespace[L any, PL listing[L]](ctx context.Context, rclient client.Client, nss []string, collect func(PL), opts ...client.ListOption) error {
-	dst := PL(new(L))
+func ListObjectsByNamespace[T any, PT listing[T]](ctx context.Context, rclient client.Client, nss []string, collect func(PT), opts ...client.ListOption) error {
+	dst := PT(new(T))
 	if len(nss) == 0 {
 		if err := rclient.List(ctx, dst, opts...); err != nil {
 			return fmt.Errorf("cannot list objects at cluster scope: %w", err)
@@ -152,10 +152,7 @@ type ObjectWatcherForNamespaces struct {
 
 // NewObjectWatcherForNamespaces returns a watcher for events at multiple namespaces  for given object
 // in case of empty namespaces, performs cluster wide watch
-func NewObjectWatcherForNamespaces[T any, PT interface {
-	*T
-	client.ObjectList
-}](ctx context.Context, rclient client.WithWatch, crdTypeName string, namespaces []string) (watch.Interface, error) {
+func NewObjectWatcherForNamespaces[T any, PT listing[T]](ctx context.Context, rclient client.WithWatch, crdTypeName string, namespaces []string) (watch.Interface, error) {
 	initMetrics.Do(func() {
 		metrics.Registry.MustRegister(activeWatchers, watchEventsTotalByType)
 	})
diff --git a/internal/controller/operator/factory/k8stools/selectors.go b/internal/controller/operator/factory/k8stools/selectors.go
index c22b1576..d3c03e1b 100644
--- a/internal/controller/operator/factory/k8stools/selectors.go
+++ b/internal/controller/operator/factory/k8stools/selectors.go
@@ -32,7 +32,7 @@ func (s *SelectorOpts) isUnmanaged() bool {
 }
 
 // VisitSelected applies given function to any T child object matched by selectors defined in parent obj selectors
-func VisitSelected[L any, PL listing[L]](ctx context.Context, rclient client.Client, s *SelectorOpts, cb func(PL)) error {
+func VisitSelected[T any, PT listing[T]](ctx context.Context, rclient client.Client, s *SelectorOpts, cb func(PT)) error {
 	if s.isUnmanaged() {
 		return nil
 	}
diff --git a/internal/controller/operator/factory/vmagent/vmagent.go b/internal/controller/operator/factory/vmagent/vmagent.go
index 0f2da4d2..51aba9bd 100644
--- a/internal/controller/operator/factory/vmagent/vmagent.go
+++ b/internal/controller/operator/factory/vmagent/vmagent.go
@@ -491,14 +491,11 @@ func buildSTSServiceName(cr *vmv1beta1.VMAgent) string {
 func makeSpec(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) (*corev1.PodSpec, error) {
 	var args []string
 
-	if len(cr.Spec.RemoteWrite) > 0 {
-		rwArgs, err := buildRemoteWrites(cr, ac)
-		if err != nil {
-			return nil, err
-		}
+	if rwArgs, err := buildRemoteWriteArgs(cr, ac); err != nil {
+		return nil, fmt.Errorf("failed to build remote write args: %w", err)
+	} else {
 		args = append(args, rwArgs...)
 	}
-	args = append(args, buildRemoteWriteSettings(cr)...)
 
 	args = append(args, fmt.Sprintf("-httpListenAddr=:%s", cr.Spec.Port))
 
@@ -945,82 +942,6 @@ func createOrUpdateStreamAggrConfig(ctx context.Context, rclient client.Client,
 	return reconcile.ConfigMap(ctx, rclient, streamAggrCM, prevConfigMeta)
 }
 
-func buildRemoteWriteSettings(cr *vmv1beta1.VMAgent) []string {
-	// limit to 1GB
-	// most people do not care about this setting,
-	// but it may harmfully affect kubernetes cluster health
-	maxDiskUsage := defaultMaxDiskUsage
-	var containsMaxDiskUsage bool
-	for i := range cr.Spec.RemoteWrite {
-		rws := cr.Spec.RemoteWrite[i]
-		if rws.MaxDiskUsage != nil {
-			containsMaxDiskUsage = true
-			break
-		}
-	}
-	var args []string
-	if cr.Spec.RemoteWriteSettings == nil {
-		// fast path
-		pqMountPath := vmAgentPersistentQueueDir
-		if cr.Spec.StatefulMode {
-			pqMountPath = vmAgentPersistentQueueSTSDir
-		}
-		args = append(args,
-			fmt.Sprintf("-remoteWrite.tmpDataPath=%s", pqMountPath))
-
-		if !containsMaxDiskUsage {
-			args = append(args, fmt.Sprintf("-remoteWrite.maxDiskUsagePerURL=%s", maxDiskUsage))
-		}
-		return args
-	}
-
-	rws := *cr.Spec.RemoteWriteSettings
-	if rws.FlushInterval != nil {
-		args = append(args, fmt.Sprintf("-remoteWrite.flushInterval=%s", *rws.FlushInterval))
-	}
-	if rws.MaxBlockSize != nil {
-		args = append(args, fmt.Sprintf("-remoteWrite.maxBlockSize=%d", *rws.MaxBlockSize))
-	}
-
-	if rws.Queues != nil {
-		args = append(args, fmt.Sprintf("-remoteWrite.queues=%d", *rws.Queues))
-	}
-	if rws.ShowURL != nil {
-		args = append(args, fmt.Sprintf("-remoteWrite.showURL=%t", *rws.ShowURL))
-	}
-	pqMountPath := vmAgentPersistentQueueDir
-	if cr.Spec.StatefulMode {
-		pqMountPath = vmAgentPersistentQueueSTSDir
-	}
-	if rws.TmpDataPath != nil {
-		pqMountPath = *rws.TmpDataPath
-	}
-	args = append(args, fmt.Sprintf("-remoteWrite.tmpDataPath=%s", pqMountPath))
-
-	if rws.MaxDiskUsagePerURL != nil {
-		maxDiskUsage = rws.MaxDiskUsagePerURL.String()
-	}
-	if !containsMaxDiskUsage {
-		args = append(args, "-remoteWrite.maxDiskUsagePerURL="+maxDiskUsage)
-	}
-	if rws.Labels != nil {
-		lbls := sortMap(rws.Labels)
-		flagValue := "-remoteWrite.label="
-		if len(lbls) > 0 {
-			flagValue += fmt.Sprintf("%s=%s", lbls[0].key, lbls[0].value)
-			for _, lv := range lbls[1:] {
-				flagValue += fmt.Sprintf(",%s=%s", lv.key, lv.value)
-			}
-			args = append(args, flagValue)
-		}
-
-	}
-	if rws.UseMultiTenantMode {
-		args = append(args, "-enableMultitenantHandlers=true")
-	}
-	return args
-}
-
 type item struct {
 	key, value string
 }
@@ -1036,155 +957,221 @@ func sortMap(m map[string]string) []item {
 	return kv
 }
 
-func buildRemoteWrites(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) ([]string, error) {
-	remoteTargets := cr.Spec.RemoteWrite
-
+func buildRemoteWriteArgs(cr *vmv1beta1.VMAgent, ac *build.AssetsCache) ([]string, error) {
 	maxDiskUsage := defaultMaxDiskUsage
 	if cr.Spec.RemoteWriteSettings != nil && cr.Spec.RemoteWriteSettings.MaxDiskUsagePerURL != nil {
 		maxDiskUsage = cr.Spec.RemoteWriteSettings.MaxDiskUsagePerURL.String()
 	}
-	url := build.NewFlag("-remoteWrite.url", "")
-	authUser := build.NewFlag("-remoteWrite.basicAuth.username", `""`)
-	authPasswordFile := build.NewFlag("-remoteWrite.basicAuth.passwordFile", "")
-	bearerTokenFile := build.NewFlag("-remoteWrite.bearerTokenFile", `""`)
-	urlRelabelConfig := build.NewFlag("-remoteWrite.urlRelabelConfig", "")
-	sendTimeout := build.NewFlag("-remoteWrite.sendTimeout", "")
-	tlsCAs := build.NewFlag("-remoteWrite.tlsCAFile", "")
-	tlsCerts := build.NewFlag("-remoteWrite.tlsCertFile", "")
-	tlsKeys := build.NewFlag("-remoteWrite.tlsKeyFile", "")
-	tlsInsecure := build.NewFlag("-remoteWrite.tlsInsecureSkipVerify", "false")
-	tlsServerName := build.NewFlag("-remoteWrite.tlsServerName", "")
-	oauth2ClientID := build.NewFlag("-remoteWrite.oauth2.clientID", "")
-	oauth2ClientSecretFile := build.NewFlag("-remoteWrite.oauth2.clientSecretFile", "")
-	oauth2Scopes := build.NewFlag("-remoteWrite.oauth2.scopes", "")
-	oauth2TokenURL := build.NewFlag("-remoteWrite.oauth2.tokenUrl", "")
-	headers := build.NewFlag("-remoteWrite.headers", "")
-	maxDiskUsagePerURL := build.NewFlag("-remoteWrite.maxDiskUsagePerURL", maxDiskUsage)
-	forceVMProto := build.NewFlag("-remoteWrite.forceVMProto", "false")
-	proxyURL := build.NewFlag("-remoteWrite.proxyURL", "")
-	awsEC2Endpoint := build.NewFlag("-remoteWrite.aws.ec2Endpoint", "")
-	awsRegion := build.NewFlag("-remoteWrite.aws.region", "")
-	awsRoleARN := build.NewFlag("-remoteWrite.aws.roleARN", "")
-	awsService := build.NewFlag("-remoteWrite.aws.service", "")
-	awsSTSEndpoint := build.NewFlag("-remoteWrite.aws.stsEndpoint", "")
-	awsUseSigv4 := build.NewFlag("-remoteWrite.aws.useSigv4", "false")
-
-	var streamAggrConfigs []*vmv1beta1.StreamAggrConfig
-	var streamAggrKeys []string
-
-	for i := range remoteTargets {
-		rws := remoteTargets[i]
-		url.Add(rws.URL, i)
-		if rws.TLSConfig != nil {
-			creds, err := ac.BuildTLSCreds(cr.Namespace, rws.TLSConfig)
-			if err != nil {
-				return nil, err
-			}
-			tlsCAs.Add(creds.CAFile, i)
-			tlsCerts.Add(creds.CertFile, i)
-			tlsKeys.Add(creds.KeyFile, i)
-			if rws.TLSConfig.InsecureSkipVerify {
-				tlsInsecure.Add("true", i)
+
+	var args []string
+	var hasAnyDiskUsagesSet bool
+	var storageLimit int64
+
+	pqMountPath := vmAgentPersistentQueueDir
+	if cr.Spec.StatefulMode {
+		pqMountPath = vmAgentPersistentQueueSTSDir
+		if cr.Spec.StatefulStorage != nil {
+			if storage, ok := cr.Spec.StatefulStorage.VolumeClaimTemplate.Spec.Resources.Requests[corev1.ResourceStorage]; ok {
+				storageInt, ok := storage.AsInt64()
+				if ok {
+					storageLimit = storageInt
+				}
 			}
-			tlsServerName.Add(rws.TLSConfig.ServerName, i)
 		}
-		if rws.BasicAuth != nil {
-			user, err := ac.LoadKeyFromSecret(cr.Namespace, &rws.BasicAuth.Username)
-			if err != nil {
-				return nil, fmt.Errorf("cannot load BasicAuth username: %w", err)
-			}
-			authUser.Add(strconv.Quote(user), i)
-			if len(rws.BasicAuth.Password.Name) > 0 {
-				passFile, err := ac.LoadPathFromSecret(build.SecretConfigResourceKind, cr.Namespace, &rws.BasicAuth.Password)
+	}
+
+	if len(cr.Spec.RemoteWrite) > 0 {
+		remoteTargets := cr.Spec.RemoteWrite
+		url := build.NewFlag("-remoteWrite.url", "")
+		authUser := build.NewFlag("-remoteWrite.basicAuth.username", `""`)
+		authPasswordFile := build.NewFlag("-remoteWrite.basicAuth.passwordFile", "")
+		bearerTokenFile := build.NewFlag("-remoteWrite.bearerTokenFile", `""`)
+		urlRelabelConfig := build.NewFlag("-remoteWrite.urlRelabelConfig", "")
+		sendTimeout := build.NewFlag("-remoteWrite.sendTimeout", "")
+		tlsCAs := build.NewFlag("-remoteWrite.tlsCAFile", "")
+		tlsCerts := build.NewFlag("-remoteWrite.tlsCertFile", "")
+		tlsKeys := build.NewFlag("-remoteWrite.tlsKeyFile", "")
+		tlsInsecure := build.NewFlag("-remoteWrite.tlsInsecureSkipVerify", "false")
+		tlsServerName := build.NewFlag("-remoteWrite.tlsServerName", "")
+		oauth2ClientID := build.NewFlag("-remoteWrite.oauth2.clientID", "")
+		oauth2ClientSecretFile := build.NewFlag("-remoteWrite.oauth2.clientSecretFile", "")
+		oauth2Scopes := build.NewFlag("-remoteWrite.oauth2.scopes", "")
+		oauth2TokenURL := build.NewFlag("-remoteWrite.oauth2.tokenUrl", "")
+		headers := build.NewFlag("-remoteWrite.headers", "")
+		forceVMProto := build.NewFlag("-remoteWrite.forceVMProto", "false")
+		proxyURL := build.NewFlag("-remoteWrite.proxyURL", "")
+		awsEC2Endpoint := build.NewFlag("-remoteWrite.aws.ec2Endpoint", "")
+		awsRegion := build.NewFlag("-remoteWrite.aws.region", "")
+		awsRoleARN := build.NewFlag("-remoteWrite.aws.roleARN", "")
+		awsService := build.NewFlag("-remoteWrite.aws.service", "")
+		awsSTSEndpoint := build.NewFlag("-remoteWrite.aws.stsEndpoint", "")
+		awsUseSigv4 := build.NewFlag("-remoteWrite.aws.useSigv4", "false")
+
+		var streamAggrConfigs []*vmv1beta1.StreamAggrConfig
+		var streamAggrKeys []string
+		var maxDiskUsagesPerRW []string
+
+		if storageLimit > 0 && maxDiskUsage == defaultMaxDiskUsage {
+			// conditionally change default value of maxDiskUsage
+			// user defined value must have prioirty over automatically calculated.
+			//
+			// it's fine to have over-provisioing of total disk usage
+			// however, we should return warning during validation.
+			maxDiskUsage = strconv.FormatInt((storageLimit)/int64(len(remoteTargets)), 10)
+		}
+		for i, rw := range remoteTargets {
+			url.Add(rw.URL, i)
+			if rw.TLSConfig != nil {
+				creds, err := ac.BuildTLSCreds(cr.Namespace, rw.TLSConfig)
 				if err != nil {
-					return nil, fmt.Errorf("cannot load BasicAuth password: %w", err)
+					return nil, err
 				}
-				authPasswordFile.Add(passFile, i)
-			}
-			if len(rws.BasicAuth.PasswordFile) > 0 {
-				authPasswordFile.Add(rws.BasicAuth.PasswordFile, i)
+				tlsCAs.Add(creds.CAFile, i)
+				tlsCerts.Add(creds.CertFile, i)
+				tlsKeys.Add(creds.KeyFile, i)
+				if rw.TLSConfig.InsecureSkipVerify {
+					tlsInsecure.Add("true", i)
+				}
+				tlsServerName.Add(rw.TLSConfig.ServerName, i)
 			}
-		}
-		if rws.BearerTokenSecret != nil && rws.BearerTokenSecret.Name != "" {
-			value, err := ac.LoadPathFromSecret(build.SecretConfigResourceKind, cr.Namespace, rws.BearerTokenSecret)
-			if err != nil {
-				return nil, fmt.Errorf("cannot load BearerTokenSecret: %w", err)
+			if rw.BasicAuth != nil {
+				user, err := ac.LoadKeyFromSecret(cr.Namespace, &rw.BasicAuth.Username)
+				if err != nil {
+					return nil, fmt.Errorf("cannot load BasicAuth username: %w", err)
+				}
+				authUser.Add(strconv.Quote(user), i)
+				if len(rw.BasicAuth.Password.Name) > 0 {
+					passFile, err := ac.LoadPathFromSecret(build.SecretConfigResourceKind, cr.Namespace, &rw.BasicAuth.Password)
+					if err != nil {
+						return nil, fmt.Errorf("cannot load BasicAuth password: %w", err)
+					}
+					authPasswordFile.Add(passFile, i)
+				}
+				if len(rw.BasicAuth.PasswordFile) > 0 {
+					authPasswordFile.Add(rw.BasicAuth.PasswordFile, i)
+				}
 			}
-			bearerTokenFile.Add(strconv.Quote(value), i)
-		}
-		if rws.UrlRelabelConfig != nil || len(rws.InlineUrlRelabelConfig) > 0 {
-			urlRelabelConfig.Add(path.Join(vmv1beta1.RelabelingConfigDir, fmt.Sprintf(urlRelabelingName, i)), i)
-		}
-		if rws.SendTimeout != nil {
-			sendTimeout.Add(*rws.SendTimeout, i)
-		}
-		if len(rws.Headers) > 0 {
-			value := ""
-			for _, headerValue := range rws.Headers {
-				value += headerValue + "^^"
+			if rw.BearerTokenSecret != nil && rw.BearerTokenSecret.Name != "" {
+				value, err := ac.LoadPathFromSecret(build.SecretConfigResourceKind, cr.Namespace, rw.BearerTokenSecret)
+				if err != nil {
+					return nil, fmt.Errorf("cannot load BearerTokenSecret: %w", err)
+				}
+				bearerTokenFile.Add(strconv.Quote(value), i)
 			}
-			value = strings.TrimSuffix(value, "^^")
-			headers.Add(value, i)
-		}
-		if rws.OAuth2 != nil {
-			if len(rws.OAuth2.TokenURL) > 0 {
-				oauth2TokenURL.Add(rws.OAuth2.TokenURL, i)
+			if rw.UrlRelabelConfig != nil || len(rw.InlineUrlRelabelConfig) > 0 {
+				urlRelabelConfig.Add(path.Join(vmv1beta1.RelabelingConfigDir, fmt.Sprintf(urlRelabelingName, i)), i)
 			}
-
-			if len(rws.OAuth2.Scopes) > 0 {
-				oauth2Scopes.Add(strings.Join(rws.OAuth2.Scopes, ","), i)
+			if rw.SendTimeout != nil {
+				sendTimeout.Add(*rw.SendTimeout, i)
 			}
-
-			if len(rws.OAuth2.ClientSecretFile) > 0 {
-				oauth2ClientSecretFile.Add(rws.OAuth2.ClientSecretFile, i)
+			if len(rw.Headers) > 0 {
+				value := ""
+				for _, headerValue := range rw.Headers {
+					value += headerValue + "^^"
+				}
+				value = strings.TrimSuffix(value, "^^")
+				headers.Add(value, i)
 			}
-
-			if rws.OAuth2.ClientSecret != nil {
-				oaSecretKeyFile, err := ac.LoadPathFromSecret(build.SecretConfigResourceKind, cr.Namespace, rws.OAuth2.ClientSecret)
+			if rw.OAuth2 != nil {
+				if len(rw.OAuth2.TokenURL) > 0 {
+					oauth2TokenURL.Add(rw.OAuth2.TokenURL, i)
+				}
+				if len(rw.OAuth2.Scopes) > 0 {
+					oauth2Scopes.Add(strings.Join(rw.OAuth2.Scopes, ","), i)
+				}
+				if len(rw.OAuth2.ClientSecretFile) > 0 {
+					oauth2ClientSecretFile.Add(rw.OAuth2.ClientSecretFile, i)
+				}
+				if rw.OAuth2.ClientSecret != nil {
+					oaSecretKeyFile, err := ac.LoadPathFromSecret(build.SecretConfigResourceKind, cr.Namespace, rw.OAuth2.ClientSecret)
+					if err != nil {
+						return nil, fmt.Errorf("cannot load OAuth2 ClientSecret: %w", err)
+					}
+					oauth2ClientSecretFile.Add(oaSecretKeyFile, i)
+				}
+				secret, err := ac.LoadKeyFromSecretOrConfigMap(cr.Namespace, &rw.OAuth2.ClientID)
 				if err != nil {
-					return nil, fmt.Errorf("cannot load OAuth2 ClientSecret: %w", err)
+					return nil, err
 				}
-				oauth2ClientSecretFile.Add(oaSecretKeyFile, i)
+				oauth2ClientID.Add(secret, i)
 			}
-			secret, err := ac.LoadKeyFromSecretOrConfigMap(cr.Namespace, &rws.OAuth2.ClientID)
-			if err != nil {
-				return nil, err
+			if rw.AWS != nil {
+				awsEC2Endpoint.Add(rw.AWS.EC2Endpoint, i)
+				awsRegion.Add(rw.AWS.Region, i)
+				awsRoleARN.Add(rw.AWS.RoleARN, i)
+				awsService.Add(rw.AWS.Service, i)
+				awsSTSEndpoint.Add(rw.AWS.STSEndpoint, i)
+				awsUseSigv4.Add(strconv.FormatBool(rw.AWS.UseSigv4), i)
+			}
+			streamAggrConfigs = append(streamAggrConfigs, rw.StreamAggrConfig)
+			streamAggrKeys = append(streamAggrKeys, rw.AsConfigMapKey(i, "stream-aggr-conf"))
+			if rw.MaxDiskUsage != nil {
+				maxDiskUsagesPerRW = append(maxDiskUsagesPerRW, rw.MaxDiskUsage.String())
+				hasAnyDiskUsagesSet = true
+			} else {
+				maxDiskUsagesPerRW = append(maxDiskUsagesPerRW, maxDiskUsage)
+			}
+			forceVMProto.Add(strconv.FormatBool(rw.ForceVMProto), i)
+			if rw.ProxyURL != nil {
+				proxyURL.Add(*rw.ProxyURL, i)
 			}
-			oauth2ClientID.Add(secret, i)
-
 		}
-
-		if rws.AWS != nil {
-			awsEC2Endpoint.Add(rws.AWS.EC2Endpoint, i)
-			awsRegion.Add(rws.AWS.Region, i)
-			awsRoleARN.Add(rws.AWS.RoleARN, i)
-			awsService.Add(rws.AWS.Service, i)
-			awsSTSEndpoint.Add(rws.AWS.STSEndpoint, i)
-			awsUseSigv4.Add(strconv.FormatBool(rws.AWS.UseSigv4), i)
+		maxDiskUsagePerURL := build.NewFlag("-remoteWrite.maxDiskUsagePerURL", maxDiskUsage)
+		if hasAnyDiskUsagesSet {
+			for i, usage := range maxDiskUsagesPerRW {
+				maxDiskUsagePerURL.Add(usage, i)
+			}
 		}
 
-		streamAggrConfigs = append(streamAggrConfigs, rws.StreamAggrConfig)
-		streamAggrKeys = append(streamAggrKeys, rws.AsConfigMapKey(i, "stream-aggr-conf"))
+		totalCount := len(remoteTargets)
+		args = build.AppendFlagsToArgs(args, totalCount, url, authUser, bearerTokenFile, urlRelabelConfig, tlsInsecure, sendTimeout, proxyURL)
+		args = build.AppendFlagsToArgs(args, totalCount, tlsServerName, tlsKeys, tlsCerts, tlsCAs)
+		args = build.AppendFlagsToArgs(args, totalCount, oauth2ClientID, oauth2ClientSecretFile, oauth2Scopes, oauth2TokenURL)
+		args = build.AppendFlagsToArgs(args, totalCount, headers, authPasswordFile, maxDiskUsagePerURL, forceVMProto)
+		args = build.StreamAggrArgsTo(args, "remoteWrite.streamAggr", streamAggrKeys, streamAggrConfigs...)
+		args = build.AppendFlagsToArgs(args, totalCount, awsEC2Endpoint, awsRegion, awsRoleARN, awsService, awsSTSEndpoint, awsUseSigv4)
+	}
 
-		if rws.MaxDiskUsage != nil {
-			maxDiskUsagePerURL.Add(rws.MaxDiskUsage.String(), i)
+	if cr.Spec.RemoteWriteSettings != nil {
+		rws := cr.Spec.RemoteWriteSettings
+		if rws.MaxDiskUsagePerURL != nil {
+			maxDiskUsage = rws.MaxDiskUsagePerURL.String()
 		}
-
-		forceVMProto.Add(strconv.FormatBool(rws.ForceVMProto), i)
-		if rws.ProxyURL != nil {
-			proxyURL.Add(*rws.ProxyURL, i)
+		if rws.FlushInterval != nil {
+			args = append(args, fmt.Sprintf("-remoteWrite.flushInterval=%s", *rws.FlushInterval))
+		}
+		if rws.Queues != nil {
+			args = append(args, fmt.Sprintf("-remoteWrite.queues=%d", *rws.Queues))
+		}
+		if rws.ShowURL != nil {
+			args = append(args, fmt.Sprintf("-remoteWrite.showURL=%t", *rws.ShowURL))
+		}
+		if rws.TmpDataPath != nil {
+			pqMountPath = *rws.TmpDataPath
+		}
+		if rws.MaxBlockSize != nil {
+			args = append(args, fmt.Sprintf("-remoteWrite.maxBlockSize=%d", *rws.MaxBlockSize))
+		}
+		if rws.Labels != nil {
+			lbls := sortMap(rws.Labels)
+			flagValue := "-remoteWrite.label="
+			if len(lbls) > 0 {
+				flagValue += fmt.Sprintf("%s=%s", lbls[0].key, lbls[0].value)
+				for _, lv := range lbls[1:] {
+					flagValue += fmt.Sprintf(",%s=%s", lv.key, lv.value)
+				}
+				args = append(args, flagValue)
+			}
+		}
+		if rws.UseMultiTenantMode {
+			args = append(args, "-enableMultitenantHandlers=true")
 		}
 	}
 
-	var args []string
-	totalCount := len(remoteTargets)
-	args = build.AppendFlagsToArgs(args, totalCount, url, authUser, bearerTokenFile, urlRelabelConfig, tlsInsecure, sendTimeout, proxyURL)
-	args = build.AppendFlagsToArgs(args, totalCount, tlsServerName, tlsKeys, tlsCerts, tlsCAs)
-	args = build.AppendFlagsToArgs(args, totalCount, oauth2ClientID, oauth2ClientSecretFile, oauth2Scopes, oauth2TokenURL)
-	args = build.AppendFlagsToArgs(args, totalCount, headers, authPasswordFile)
-	args = build.StreamAggrArgsTo(args, "remoteWrite.streamAggr", streamAggrKeys, streamAggrConfigs...)
-	args = build.AppendFlagsToArgs(args, totalCount, maxDiskUsagePerURL, forceVMProto)
-	args = build.AppendFlagsToArgs(args, totalCount, awsEC2Endpoint, awsRegion, awsRoleARN, awsService, awsSTSEndpoint, awsUseSigv4)
+	args = append(args, fmt.Sprintf("-remoteWrite.tmpDataPath=%s", pqMountPath))
+	if !hasAnyDiskUsagesSet {
+		args = append(args, fmt.Sprintf("-remoteWrite.maxDiskUsagePerURL=%s", maxDiskUsage))
+	}
 	return args, nil
 }
 



Test patch:
diff --git a/internal/controller/operator/factory/build/defaults_test.go b/internal/controller/operator/factory/build/defaults_test.go
new file mode 100644
index 00000000..f93004ae
--- /dev/null
+++ b/internal/controller/operator/factory/build/defaults_test.go
@@ -0,0 +1,57 @@
+package build
+
+import (
+	"testing"
+
+	"k8s.io/utils/ptr"
+
+	vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1"
+	"github.com/VictoriaMetrics/operator/internal/config"
+)
+
+func TestAddEnterpriseTagToAppCommonDefaults(t *testing.T) {
+	f := func(specVersion, defaultVersion string, hasLicense bool, wantVersion string) {
+		t.Helper()
+		cdp := &vmv1beta1.CommonDefaultableParams{
+			Image: vmv1beta1.Image{
+				Tag: specVersion,
+			},
+		}
+		appDefaults := &config.ApplicationDefaults{
+			Version: defaultVersion,
+		}
+		var license *vmv1beta1.License
+		if hasLicense {
+			license = &vmv1beta1.License{
+				Key: ptr.To("license-key-value"),
+			}
+		}
+		addDefaultsToCommonParams(cdp, license, appDefaults)
+		if cdp.Image.Tag != wantVersion {
+			t.Fatalf("unexpected spec version: (+%s,-%s)", cdp.Image.Tag, wantVersion)
+		}
+	}
+
+	// preserve spec version
+	f("v1.120.0", "", false, "v1.120.0")
+	f("v1.120.0", "v1.119.0", false, "v1.120.0")
+	f("v1.120.0", "v1.119.0", true, "v1.120.0")
+	f("v1.120.0", "", true, "v1.120.0")
+	f("v1.120.0-enterprise", "", true, "v1.120.0-enterprise")
+	f("v1.120.0-enterprise-cluster", "", true, "v1.120.0-enterprise-cluster")
+
+	// change default value
+	f("", "v1.120.0", true, "v1.120.0-enterprise")
+	f("", "v1.120.0-cluster", true, "v1.120.0-enterprise-cluster")
+
+	// preserve enterprise version
+	f("", "v1.120.0-enterprise-cluster", true, "v1.120.0-enterprise-cluster")
+	f("", "v1.120.0-enterprise", true, "v1.120.0-enterprise")
+
+	// preserve unsupported tag
+	f("", "v1", true, "v1")
+	f("", "1.120.0", true, "1.120.0")
+	f("", "v1.120.0-rc1", true, "v1.120.0-rc1")
+	f("", "v1.120.0-enterprise-rc1", true, "v1.120.0-enterprise-rc1")
+	f("", "v1.120.0-enterprise-cluster-rc1", true, "v1.120.0-enterprise-cluster-rc1")
+}
diff --git a/internal/controller/operator/factory/vmagent/vmagent_test.go b/internal/controller/operator/factory/vmagent/vmagent_test.go
index f600fe80..e04bbdbf 100644
--- a/internal/controller/operator/factory/vmagent/vmagent_test.go
+++ b/internal/controller/operator/factory/vmagent/vmagent_test.go
@@ -5,7 +5,6 @@ import (
 	"encoding/json"
 	"fmt"
 	"path"
-	"reflect"
 	"slices"
 	"sort"
 	"strings"
@@ -755,7 +754,7 @@ func TestCreateOrUpdate(t *testing.T) {
 	}
 }
 
-func TestBuildRemoteWrites(t *testing.T) {
+func TestBuildRemoteWriteArgs(t *testing.T) {
 	tests := []struct {
 		name              string
 		cr                *vmv1beta1.VMAgent
@@ -813,7 +812,13 @@ func TestBuildRemoteWrites(t *testing.T) {
 					},
 				},
 			},
-			want: []string{"-remoteWrite.tlsCAFile=/etc/vmagent-tls/certs/default_tls-secret_ca,/path/to_ca", "-remoteWrite.tlsCertFile=,/etc/vmagent-tls/certs/default_tls-secret_cert", "-remoteWrite.url=localhost:8429,localhost:8429"},
+			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
+				`-remoteWrite.tlsCAFile=/etc/vmagent-tls/certs/default_tls-secret_ca,/path/to_ca`,
+				`-remoteWrite.tlsCertFile=,/etc/vmagent-tls/certs/default_tls-secret_cert`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
+				`-remoteWrite.url=localhost:8429,localhost:8429`,
+			},
 		},
 		{
 			name: "test insecure with key only",
@@ -850,7 +855,13 @@ func TestBuildRemoteWrites(t *testing.T) {
 					},
 				},
 			},
-			want: []string{"-remoteWrite.url=localhost:8429", "-remoteWrite.tlsInsecureSkipVerify=true", "-remoteWrite.tlsKeyFile=/etc/vmagent-tls/certs/default_tls-secret_key"},
+			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
+				`-remoteWrite.url=localhost:8429`,
+				`-remoteWrite.tlsInsecureSkipVerify=true`,
+				`-remoteWrite.tlsKeyFile=/etc/vmagent-tls/certs/default_tls-secret_key`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
+			},
 		},
 		{
 			name: "test insecure",
@@ -869,7 +880,12 @@ func TestBuildRemoteWrites(t *testing.T) {
 					},
 				}},
 			},
-			want: []string{"-remoteWrite.url=localhost:8429", "-remoteWrite.tlsInsecureSkipVerify=true"},
+			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
+				`-remoteWrite.url=localhost:8429`,
+				`-remoteWrite.tlsInsecureSkipVerify=true`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
+			},
 		},
 		{
 			name: "test inline relabeling",
@@ -911,7 +927,13 @@ func TestBuildRemoteWrites(t *testing.T) {
 					},
 				},
 			},
-			want: []string{"-remoteWrite.url=localhost:8429,remote-1:8429,remote-1:8429", "-remoteWrite.tlsInsecureSkipVerify=true,true,true", "-remoteWrite.urlRelabelConfig=/etc/vm/relabeling/url_relabeling-0.yaml,,/etc/vm/relabeling/url_relabeling-2.yaml"},
+			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
+				`-remoteWrite.url=localhost:8429,remote-1:8429,remote-1:8429`,
+				`-remoteWrite.tlsInsecureSkipVerify=true,true,true`,
+				`-remoteWrite.urlRelabelConfig=/etc/vm/relabeling/url_relabeling-0.yaml,,/etc/vm/relabeling/url_relabeling-2.yaml`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
+			},
 		},
 		{
 			name: "test sendTimeout",
@@ -932,7 +954,12 @@ func TestBuildRemoteWrites(t *testing.T) {
 					},
 				}},
 			},
-			want: []string{"-remoteWrite.url=localhost:8429,localhost:8431", "-remoteWrite.sendTimeout=10s,15s"},
+			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
+				`-remoteWrite.url=localhost:8429,localhost:8431`,
+				`-remoteWrite.sendTimeout=10s,15s`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
+			},
 		},
 		{
 			name: "test multi-tenant",
@@ -958,7 +985,13 @@ func TestBuildRemoteWrites(t *testing.T) {
 					},
 				},
 			},
-			want: []string{"-remoteWrite.url=http://vminsert-cluster-1:8480/insert/multitenant/prometheus/api/v1/write,http://vmagent-aggregation:8429", "-remoteWrite.sendTimeout=10s,15s"},
+			want: []string{
+				`-enableMultitenantHandlers=true`,
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
+				`-remoteWrite.url=http://vminsert-cluster-1:8480/insert/multitenant/prometheus/api/v1/write,http://vmagent-aggregation:8429`,
+				`-remoteWrite.sendTimeout=10s,15s`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
+			},
 		},
 		{
 			name: "test maxDiskUsage",
@@ -981,7 +1014,92 @@ func TestBuildRemoteWrites(t *testing.T) {
 					},
 				}},
 			},
-			want: []string{"-remoteWrite.url=localhost:8429,localhost:8431,localhost:8432", "-remoteWrite.maxDiskUsagePerURL=1500MB,500MB,1073741824"},
+			want: []string{
+				`-remoteWrite.url=localhost:8429,localhost:8431,localhost:8432`,
+				`-remoteWrite.maxDiskUsagePerURL=1500MB,500MB,1073741824`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
+			},
+		},
+		{
+			name: "test automatic maxDiskUsage",
+			cr: &vmv1beta1.VMAgent{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "default-vmagent",
+					Namespace: "default",
+				},
+				Spec: vmv1beta1.VMAgentSpec{
+					StatefulMode: true,
+					StatefulStorage: &vmv1beta1.StorageSpec{
+						VolumeClaimTemplate: vmv1beta1.EmbeddedPersistentVolumeClaim{
+							Spec: corev1.PersistentVolumeClaimSpec{
+								StorageClassName: ptr.To("embed-sc"),
+								Resources: corev1.VolumeResourceRequirements{
+									Requests: map[corev1.ResourceName]resource.Quantity{
+										corev1.ResourceStorage: resource.MustParse("10Gi"),
+									},
+								},
+							},
+						},
+					},
+					RemoteWrite: []vmv1beta1.VMAgentRemoteWriteSpec{
+						{
+							URL: "localhost:8429",
+						},
+						{
+							URL: "localhost:8431",
+						},
+						{
+							URL: "localhost:8432",
+						},
+					},
+				},
+			},
+			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=3579139413`,
+				`-remoteWrite.url=localhost:8429,localhost:8431,localhost:8432`,
+				`-remoteWrite.tmpDataPath=/vmagent_pq/vmagent-remotewrite-data`,
+			},
+		},
+		{
+			name: "test automatic maxDiskUsage with at least one defined",
+			cr: &vmv1beta1.VMAgent{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "default-vmagent",
+					Namespace: "default",
+				},
+				Spec: vmv1beta1.VMAgentSpec{
+					StatefulMode: true,
+					StatefulStorage: &vmv1beta1.StorageSpec{
+						VolumeClaimTemplate: vmv1beta1.EmbeddedPersistentVolumeClaim{
+							Spec: corev1.PersistentVolumeClaimSpec{
+								StorageClassName: ptr.To("embed-sc"),
+								Resources: corev1.VolumeResourceRequirements{
+									Requests: map[corev1.ResourceName]resource.Quantity{
+										corev1.ResourceStorage: resource.MustParse("10Gi"),
+									},
+								},
+							},
+						},
+					},
+					RemoteWrite: []vmv1beta1.VMAgentRemoteWriteSpec{
+						{
+							URL:          "localhost:8429",
+							MaxDiskUsage: ptr.To(vmv1beta1.BytesString("5000MB")),
+						},
+						{
+							URL: "localhost:8431",
+						},
+						{
+							URL: "localhost:8432",
+						},
+					},
+				},
+			},
+			want: []string{
+				`-remoteWrite.url=localhost:8429,localhost:8431,localhost:8432`,
+				`-remoteWrite.maxDiskUsagePerURL=5000MB,3579139413,3579139413`,
+				`-remoteWrite.tmpDataPath=/vmagent_pq/vmagent-remotewrite-data`,
+			},
 		},
 		{
 			name: "test forceVMProto",
@@ -1004,7 +1122,12 @@ func TestBuildRemoteWrites(t *testing.T) {
 					},
 				}},
 			},
-			want: []string{"-remoteWrite.url=localhost:8429,localhost:8431,localhost:8432", "-remoteWrite.forceVMProto=true,false,true"},
+			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
+				`-remoteWrite.url=localhost:8429,localhost:8431,localhost:8432`,
+				`-remoteWrite.forceVMProto=true,false,true`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
+			},
 		},
 		{
 			name: "test oauth2",
@@ -1059,12 +1182,14 @@ func TestBuildRemoteWrites(t *testing.T) {
 				},
 			},
 			want: []string{
-				"-remoteWrite.oauth2.clientID=,some-id",
-				"-remoteWrite.oauth2.clientSecretFile=,/etc/vmagent/config/default_some-cm_some-secret",
-				"-remoteWrite.oauth2.scopes=,scope-1",
-				"-remoteWrite.oauth2.tokenUrl=,http://some-url",
-				"-remoteWrite.url=localhost:8429,localhost:8431",
-				"-remoteWrite.sendTimeout=10s,15s",
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
+				`-remoteWrite.oauth2.clientID=,some-id`,
+				`-remoteWrite.oauth2.clientSecretFile=,/etc/vmagent/config/default_some-cm_some-secret`,
+				`-remoteWrite.oauth2.scopes=,scope-1`,
+				`-remoteWrite.oauth2.tokenUrl=,http://some-url`,
+				`-remoteWrite.url=localhost:8429,localhost:8431`,
+				`-remoteWrite.sendTimeout=10s,15s`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
 			},
 		},
 		{
@@ -1100,7 +1225,13 @@ func TestBuildRemoteWrites(t *testing.T) {
 					},
 				},
 			},
-			want: []string{"-remoteWrite.bearerTokenFile=\"\",\"/etc/vmagent/config/default_some-secret_some-key\"", "-remoteWrite.url=localhost:8429,localhost:8431", "-remoteWrite.sendTimeout=10s,15s"},
+			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
+				`-remoteWrite.bearerTokenFile="","/etc/vmagent/config/default_some-secret_some-key"`,
+				`-remoteWrite.url=localhost:8429,localhost:8431`,
+				`-remoteWrite.sendTimeout=10s,15s`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
+			},
 		},
 		{
 			name: "test with headers",
@@ -1136,7 +1267,14 @@ func TestBuildRemoteWrites(t *testing.T) {
 					},
 				},
 			},
-			want: []string{"-remoteWrite.bearerTokenFile=\"\",\"/etc/vmagent/config/default_some-secret_some-key\"", "-remoteWrite.headers=,key: value^^second-key: value2", "-remoteWrite.url=localhost:8429,localhost:8431", "-remoteWrite.sendTimeout=10s,15s"},
+			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
+				`-remoteWrite.bearerTokenFile="","/etc/vmagent/config/default_some-secret_some-key"`,
+				`-remoteWrite.headers=,key: value^^second-key: value2`,
+				`-remoteWrite.url=localhost:8429,localhost:8431`,
+				`-remoteWrite.sendTimeout=10s,15s`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
+			},
 		},
 		{
 			name: "test with stream aggr",
@@ -1171,10 +1309,12 @@ func TestBuildRemoteWrites(t *testing.T) {
 				}},
 			},
 			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
 				`-remoteWrite.streamAggr.config=/etc/vm/stream-aggr/RWS_0-CM-STREAM-AGGR-CONF,/etc/vm/stream-aggr/RWS_1-CM-STREAM-AGGR-CONF`,
 				`-remoteWrite.streamAggr.dedupInterval=10s,`,
 				`-remoteWrite.streamAggr.keepInput=false,true`,
 				`-remoteWrite.url=localhost:8429,localhost:8431`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
 			},
 		},
 		{
@@ -1200,10 +1340,12 @@ func TestBuildRemoteWrites(t *testing.T) {
 				}},
 			},
 			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
 				`-remoteWrite.streamAggr.config=/etc/vm/stream-aggr/RWS_0-CM-STREAM-AGGR-CONF`,
 				`-remoteWrite.streamAggr.dedupInterval=10s`,
 				`-remoteWrite.streamAggr.keepInput=true`,
 				`-remoteWrite.url=localhost:8431`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
 			},
 		},
 		{
@@ -1227,8 +1369,10 @@ func TestBuildRemoteWrites(t *testing.T) {
 				}},
 			},
 			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
 				`-remoteWrite.streamAggr.config=/etc/vm/stream-aggr/RWS_0-CM-STREAM-AGGR-CONF`,
 				`-remoteWrite.url=localhost:8431`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
 			},
 		},
 		{
@@ -1275,10 +1419,12 @@ func TestBuildRemoteWrites(t *testing.T) {
 				}},
 			},
 			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
 				`-remoteWrite.streamAggr.config=,/etc/vm/stream-aggr/RWS_1-CM-STREAM-AGGR-CONF,,/etc/vm/stream-aggr/RWS_3-CM-STREAM-AGGR-CONF,`,
 				`-remoteWrite.streamAggr.dedupInterval=,10s,,,`,
 				`-remoteWrite.streamAggr.keepInput=false,true,false,false,false`,
 				`-remoteWrite.url=localhost:8428,localhost:8429,localhost:8430,localhost:8431,localhost:8432`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
 			},
 		},
 		{
@@ -1318,9 +1464,11 @@ func TestBuildRemoteWrites(t *testing.T) {
 				},
 			},
 			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
 				`-remoteWrite.aws.roleARN=arn:aws:iam::account:role/role-1,,`,
 				`-remoteWrite.aws.useSigv4=false,false,true`,
 				`-remoteWrite.url=localhost:8429,localhost:8431,localhost:8431`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
 			},
 		},
 		{
@@ -1346,8 +1494,174 @@ func TestBuildRemoteWrites(t *testing.T) {
 				},
 			},
 			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
 				`-remoteWrite.proxyURL=,http://proxy.example.com,`,
 				`-remoteWrite.url=http://localhost:8431,http://localhost:8432,http://localhost:8433`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
+			},
+		},
+		{
+			name: "test with StatefulMode",
+			cr: &vmv1beta1.VMAgent{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "default-vmagent",
+					Namespace: "default",
+				},
+				Spec: vmv1beta1.VMAgentSpec{StatefulMode: true},
+			},
+			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
+				`-remoteWrite.tmpDataPath=/vmagent_pq/vmagent-remotewrite-data`,
+			},
+		},
+		{
+			name: "test simple ok",
+			cr: &vmv1beta1.VMAgent{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "default-vmagent",
+					Namespace: "default",
+				},
+			},
+			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
+			},
+		},
+		{
+			name: "test labels",
+			cr: &vmv1beta1.VMAgent{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "default-vmagent",
+					Namespace: "default",
+				},
+				Spec: vmv1beta1.VMAgentSpec{
+					RemoteWriteSettings: &vmv1beta1.VMAgentRemoteWriteSettings{
+						Labels: map[string]string{
+							"label-1": "value1",
+							"label-2": "value2",
+						},
+					},
+				},
+			},
+			want: []string{
+				`-remoteWrite.label=label-1=value1,label-2=value2`,
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
+			},
+		},
+		{
+			name: "test label",
+			cr: &vmv1beta1.VMAgent{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "default-vmagent",
+					Namespace: "default",
+				},
+				Spec: vmv1beta1.VMAgentSpec{
+					RemoteWriteSettings: &vmv1beta1.VMAgentRemoteWriteSettings{
+						ShowURL: ptr.To(true),
+						Labels: map[string]string{
+							"label-1": "value1",
+						},
+					},
+				},
+			},
+			want: []string{
+				`-remoteWrite.label=label-1=value1`,
+				`-remoteWrite.showURL=true`,
+				`-remoteWrite.maxDiskUsagePerURL=1073741824`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
+			},
+		},
+		{
+			name: "with remoteWriteSettings",
+			cr: &vmv1beta1.VMAgent{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "default-vmagent",
+					Namespace: "default",
+				},
+				Spec: vmv1beta1.VMAgentSpec{
+					RemoteWriteSettings: &vmv1beta1.VMAgentRemoteWriteSettings{
+						ShowURL:            ptr.To(true),
+						TmpDataPath:        ptr.To("/tmp/my-path"),
+						MaxDiskUsagePerURL: ptr.To(vmv1beta1.BytesString("1000")),
+						UseMultiTenantMode: true,
+					},
+				},
+			},
+			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=1000`,
+				`-remoteWrite.tmpDataPath=/tmp/my-path`,
+				`-remoteWrite.showURL=true`,
+				`-enableMultitenantHandlers=true`,
+			},
+		},
+		{
+			name: "maxDiskUsage already set in RemoteWriteSpec",
+			cr: &vmv1beta1.VMAgent{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "default-vmagent",
+					Namespace: "default",
+				},
+				Spec: vmv1beta1.VMAgentSpec{
+					RemoteWrite: []vmv1beta1.VMAgentRemoteWriteSpec{
+						{
+							URL:          "localhost:8431",
+							MaxDiskUsage: ptr.To(vmv1beta1.BytesString("500MB")),
+						},
+					},
+					RemoteWriteSettings: &vmv1beta1.VMAgentRemoteWriteSettings{
+						MaxDiskUsagePerURL: ptr.To(vmv1beta1.BytesString("1000")),
+					},
+				},
+			},
+			want: []string{
+				`-remoteWrite.maxDiskUsagePerURL=500MB`,
+				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
+				`-remoteWrite.url=localhost:8431`,
+			},
+		},
+		{
+			name: "maxDiskUsage already set in RemoteWriteSpec",
+			cr: &vmv1beta1.VMAgent{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "default-vmagent",
+					Namespace: "default",
+				},
+				Spec: vmv1beta1.VMAgentSpec{
+					RemoteWrite: []vmv1beta1.VMAgentRemoteWriteSpec{
+						{
+							URL: "localhost:8429",
+						},
+						{
+							URL: "localhost:8431",
+						},
+						{
+							URL: "localhost:8432",
+						},
+					},
+					RemoteWriteSettings: &vmv1beta1.VMAgentRemoteWriteSettings{
+						MaxBlockSize: ptr.To(int32(1000)),
+					},
+					StatefulMode: true,
+					StatefulStorage: &vmv1beta1.StorageSpec{
+						VolumeClaimTemplate: vmv1beta1.EmbeddedPersistentVolumeClaim{
+							Spec: corev1.PersistentVolumeClaimSpec{
+								StorageClassName: ptr.To("embed-sc"),
+								Resources: corev1.VolumeResourceRequirements{
+									Requests: map[corev1.ResourceName]resource.Quantity{
+										corev1.ResourceStorage: resource.MustParse("10Gi"),
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			want: []string{
+				`-remoteWrite.url=localhost:8429,localhost:8431,localhost:8432`,
+				`-remoteWrite.maxBlockSize=1000`,
+				`-remoteWrite.maxDiskUsagePerURL=3579139413`,
+				`-remoteWrite.tmpDataPath=/vmagent_pq/vmagent-remotewrite-data`,
 			},
 		},
 	}
@@ -1357,7 +1671,7 @@ func TestBuildRemoteWrites(t *testing.T) {
 			fclient := k8stools.GetTestClientWithObjects(tt.predefinedObjects)
 			ac := getAssetsCache(ctx, fclient, tt.cr)
 			sort.Strings(tt.want)
-			got, err := buildRemoteWrites(tt.cr, ac)
+			got, err := buildRemoteWriteArgs(tt.cr, ac)
 			if err != nil {
 				t.Fatalf("unexpected error: %s", err)
 			}
@@ -1970,121 +2284,6 @@ func Test_buildConfigReloaderArgs(t *testing.T) {
 	}
 }
 
-func TestBuildRemoteWriteSettings(t *testing.T) {
-	tests := []struct {
-		name string
-		cr   *vmv1beta1.VMAgent
-		want []string
-	}{
-		{
-			name: "test with StatefulMode",
-			cr: &vmv1beta1.VMAgent{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "default-vmagent",
-					Namespace: "default",
-				},
-				Spec: vmv1beta1.VMAgentSpec{StatefulMode: true},
-			},
-			want: []string{"-remoteWrite.maxDiskUsagePerURL=1073741824", "-remoteWrite.tmpDataPath=/vmagent_pq/vmagent-remotewrite-data"},
-		},
-		{
-			name: "test simple ok",
-			cr: &vmv1beta1.VMAgent{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "default-vmagent",
-					Namespace: "default",
-				},
-			},
-			want: []string{"-remoteWrite.maxDiskUsagePerURL=1073741824", "-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data"},
-		},
-		{
-			name: "test labels",
-			cr: &vmv1beta1.VMAgent{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "default-vmagent",
-					Namespace: "default",
-				},
-				Spec: vmv1beta1.VMAgentSpec{
-					RemoteWriteSettings: &vmv1beta1.VMAgentRemoteWriteSettings{
-						Labels: map[string]string{
-							"label-1": "value1",
-							"label-2": "value2",
-						},
-					},
-				},
-			},
-			want: []string{"-remoteWrite.label=label-1=value1,label-2=value2", "-remoteWrite.maxDiskUsagePerURL=1073741824", "-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data"},
-		},
-		{
-			name: "test label",
-			cr: &vmv1beta1.VMAgent{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "default-vmagent",
-					Namespace: "default",
-				},
-				Spec: vmv1beta1.VMAgentSpec{
-					RemoteWriteSettings: &vmv1beta1.VMAgentRemoteWriteSettings{
-						ShowURL: ptr.To(true),
-						Labels: map[string]string{
-							"label-1": "value1",
-						},
-					},
-				},
-			},
-			want: []string{"-remoteWrite.label=label-1=value1", "-remoteWrite.showURL=true", "-remoteWrite.maxDiskUsagePerURL=1073741824", "-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data"},
-		},
-		{
-			name: "with remoteWriteSettings",
-			cr: &vmv1beta1.VMAgent{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "default-vmagent",
-					Namespace: "default",
-				},
-				Spec: vmv1beta1.VMAgentSpec{
-					RemoteWriteSettings: &vmv1beta1.VMAgentRemoteWriteSettings{
-						ShowURL:            ptr.To(true),
-						TmpDataPath:        ptr.To("/tmp/my-path"),
-						MaxDiskUsagePerURL: ptr.To(vmv1beta1.BytesString("1000")),
-						UseMultiTenantMode: true,
-					},
-				},
-			},
-			want: []string{"-remoteWrite.maxDiskUsagePerURL=1000", "-remoteWrite.tmpDataPath=/tmp/my-path", "-remoteWrite.showURL=true", "-enableMultitenantHandlers=true"},
-		},
-		{
-			name: "maxDiskUsage already set in RemoteWriteSpec",
-			cr: &vmv1beta1.VMAgent{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "default-vmagent",
-					Namespace: "default",
-				},
-				Spec: vmv1beta1.VMAgentSpec{
-					RemoteWrite: []vmv1beta1.VMAgentRemoteWriteSpec{
-						{
-							URL:          "localhost:8431",
-							MaxDiskUsage: ptr.To(vmv1beta1.BytesString("500MB")),
-						},
-					},
-					RemoteWriteSettings: &vmv1beta1.VMAgentRemoteWriteSettings{
-						MaxDiskUsagePerURL: ptr.To(vmv1beta1.BytesString("1000")),
-					},
-				},
-			},
-			want: []string{"-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data"},
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			got := buildRemoteWriteSettings(tt.cr)
-			sort.Strings(got)
-			sort.Strings(tt.want)
-			if !reflect.DeepEqual(got, tt.want) {
-				t.Errorf("BuildRemoteWriteSettings() = \n%v\n, want \n%v\n", got, tt.want)
-			}
-		})
-	}
-}
-
 func TestMakeSpecForAgentOk(t *testing.T) {
 	f := func(cr *vmv1beta1.VMAgent, predefinedObjects []runtime.Object, wantYaml string) {
 		t.Helper()