Repository: VictoriaMetrics/operator

Issue:
`StreamAggrRule` is missing `IgnoreFirstSampleInterval` attribute
The `IgnoreFirstSampleInterval` is missing from the streaming aggregation rule struct and CRD. 

https://github.com/VictoriaMetrics/VictoriaMetrics/blob/63a6b9b8631985a000486d1ee11cc87c6b5b282a/lib/streamaggr/streamaggr.go#L182-L185

<img width="788" height="494" alt="Image" src="https://github.com/user-attachments/assets/8d4ad701-5c3a-4dc0-815d-1a5ce44c8904" />

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

Solution patch:
diff --git a/api/operator/v1beta1/vmextra_types.go b/api/operator/v1beta1/vmextra_types.go
index 88cb9231..bf20db58 100644
--- a/api/operator/v1beta1/vmextra_types.go
+++ b/api/operator/v1beta1/vmextra_types.go
@@ -519,6 +519,8 @@ type StreamAggrConfig struct {
 	// IgnoreFirstIntervals instructs to ignore first interval
 	// +optional
 	IgnoreFirstIntervals int `json:"ignoreFirstIntervals,omitempty"`
+	// IgnoreFirstSampleInterval sets interval for total and prometheus_total during which first samples will be ignored
+	IgnoreFirstSampleInterval string `json:"ignoreFirstSampleInterval,omitempty"`
 	// IgnoreOldSamples instructs to ignore samples with old timestamps outside the current aggregation interval.
 	// +optional
 	IgnoreOldSamples bool `json:"ignoreOldSamples,omitempty"`
@@ -613,6 +615,9 @@ type StreamAggrRule struct {
 
 	IgnoreFirstIntervals *int `json:"ignore_first_intervals,omitempty" yaml:"ignore_first_intervals,omitempty"`
 
+	// IgnoreFirstSampleInterval sets interval for total and prometheus_total during which first samples will be ignored
+	IgnoreFirstSampleInterval string `json:"ignoreFirstSampleInterval,omitempty" yaml:"ignore_first_sample_interval,omitempty"`
+
 	// DropInputLabels is an optional list with labels, which must be dropped before further processing of input samples.
 	//
 	// Labels are dropped before de-duplication and aggregation.
diff --git a/config/crd/overlay/crd.yaml b/config/crd/overlay/crd.yaml
index 3cec3aff..186c1f98 100644
--- a/config/crd/overlay/crd.yaml
+++ b/config/crd/overlay/crd.yaml
@@ -9016,6 +9016,11 @@ spec:
                           description: IgnoreFirstIntervals instructs to ignore first
                             interval
                           type: integer
+                        ignoreFirstSampleInterval:
+                          description: IgnoreFirstSampleInterval sets interval for
+                            total and prometheus_total during which first samples
+                            will be ignored
+                          type: string
                         ignoreOldSamples:
                           description: IgnoreOldSamples instructs to ignore samples
                             with old timestamps outside the current aggregation interval.
@@ -9070,6 +9075,11 @@ spec:
                                   samples with old timestamps outside the current
                                   aggregation interval.
                                 type: boolean
+                              ignoreFirstSampleInterval:
+                                description: IgnoreFirstSampleInterval sets interval
+                                  for total and prometheus_total during which first
+                                  samples will be ignored
+                                type: string
                               input_relabel_configs:
                                 description: |-
                                   InputRelabelConfigs is an optional relabeling rules, which are applied on the input
@@ -10806,6 +10816,10 @@ spec:
                   ignoreFirstIntervals:
                     description: IgnoreFirstIntervals instructs to ignore first interval
                     type: integer
+                  ignoreFirstSampleInterval:
+                    description: IgnoreFirstSampleInterval sets interval for total
+                      and prometheus_total during which first samples will be ignored
+                    type: string
                   ignoreOldSamples:
                     description: IgnoreOldSamples instructs to ignore samples with
                       old timestamps outside the current aggregation interval.
@@ -10858,6 +10872,11 @@ spec:
                           description: IgnoreOldSamples instructs to ignore samples
                             with old timestamps outside the current aggregation interval.
                           type: boolean
+                        ignoreFirstSampleInterval:
+                          description: IgnoreFirstSampleInterval sets interval for
+                            total and prometheus_total during which first samples
+                            will be ignored
+                          type: string
                         input_relabel_configs:
                           description: |-
                             InputRelabelConfigs is an optional relabeling rules, which are applied on the input
@@ -36912,6 +36931,10 @@ spec:
                   ignoreFirstIntervals:
                     description: IgnoreFirstIntervals instructs to ignore first interval
                     type: integer
+                  ignoreFirstSampleInterval:
+                    description: IgnoreFirstSampleInterval sets interval for total
+                      and prometheus_total during which first samples will be ignored
+                    type: string
                   ignoreOldSamples:
                     description: IgnoreOldSamples instructs to ignore samples with
                       old timestamps outside the current aggregation interval.
@@ -36964,6 +36987,11 @@ spec:
                           description: IgnoreOldSamples instructs to ignore samples
                             with old timestamps outside the current aggregation interval.
                           type: boolean
+                        ignoreFirstSampleInterval:
+                          description: IgnoreFirstSampleInterval sets interval for
+                            total and prometheus_total during which first samples
+                            will be ignored
+                          type: string
                         input_relabel_configs:
                           description: |-
                             InputRelabelConfigs is an optional relabeling rules, which are applied on the input
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index dba48ef8..d06fbcd1 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -18,6 +18,7 @@ aliases:
 
 * FEATURE: [vmuser](https://docs.victoriametrics.com/operator/resources/vmuser/): add `VLSingle`, `VLAgent`,`VLCluster/vlinsert`,`VLCluster/vlselect`, `VLCluster/vlstorage`, `VTSingle`, `VTCluster/vtinsert`,`VTCluster/vtselect`, `VTCluster/vtstorage` to the `targetRef.crd.kind`.
 * FEATURE: [operator](https://docs.victoriametrics.com/operator/api/): introduce new resources `VLSingle` and `VTCluster`. See [#1498](https://github.com/VictoriaMetrics/operator/issues/1498) for details.
+* FEATURE: [vmagent](https://docs.victoriametrics.com/operator/resources/vmagent/): support stream aggregation `ignore_first_sample_interval` property. See [#1518](https://github.com/VictoriaMetrics/operator/issues/1518).
 
 * BUGFIX: [vmoperator](https://docs.victoriametrics.com/operator/): properly reconcile `Service` on value of `loadbalancerClass` change. Previously it produced error `may not change once set`. See PR [#1522](https://github.com/VictoriaMetrics/operator/pull/1522) for details.
 * BUGFIX: [vmuser](https://docs.victoriametrics.com/operator/resources/vmuser/): simplify path based routing for  `src_paths` when using `VMCluster/vminsert` or `VMCluster/vmselect` as targetRefs. See this PR [#1519](https://github.com/VictoriaMetrics/operator/pull/1519) for details.
diff --git a/internal/controller/operator/factory/build/build.go b/internal/controller/operator/factory/build/build.go
index c632405a..a73baa26 100644
--- a/internal/controller/operator/factory/build/build.go
+++ b/internal/controller/operator/factory/build/build.go
@@ -153,6 +153,7 @@ func StreamAggrArgsTo(args []string, prefix string, keys []string, cs ...*vmv1be
 	keepInputFlag := NewFlag(fmt.Sprintf("-%s.keepInput", prefix), "false")
 	dropInputFlag := NewFlag(fmt.Sprintf("-%s.dropInput", prefix), "false")
 	ignoreFirstIntervalsFlag := NewFlag(fmt.Sprintf("-%s.ignoreFirstIntervals", prefix), "0")
+	ignoreFirstSampleIntervalFlag := NewFlag(fmt.Sprintf("-%s.ignoreFirstSampleInterval", prefix), "")
 	ignoreOldSamplesFlag := NewFlag(fmt.Sprintf("-%s.ignoreOldSamples", prefix), "false")
 	enableWindowsFlag := NewFlag(fmt.Sprintf("-%s.enableWindows", prefix), "false")
 	dedupIntervalFlag := NewFlag(fmt.Sprintf("-%s.dedupInterval", prefix), "")
@@ -167,6 +168,7 @@ func StreamAggrArgsTo(args []string, prefix string, keys []string, cs ...*vmv1be
 			keepInputFlag.Add(strconv.FormatBool(c.KeepInput), i)
 			dropInputFlag.Add(strconv.FormatBool(c.DropInput), i)
 			ignoreFirstIntervalsFlag.Add(strconv.Itoa(c.IgnoreFirstIntervals), i)
+			ignoreFirstSampleIntervalFlag.Add(c.IgnoreFirstSampleInterval, i)
 			ignoreOldSamplesFlag.Add(strconv.FormatBool(c.IgnoreOldSamples), i)
 			enableWindowsFlag.Add(strconv.FormatBool(c.EnableWindows), i)
 		}
@@ -174,7 +176,7 @@ func StreamAggrArgsTo(args []string, prefix string, keys []string, cs ...*vmv1be
 		dedupIntervalFlag.Add(c.DedupInterval, i)
 		dropInputLabelsFlag.Add(strings.Join(c.DropInputLabels, ","), i)
 	}
-	args = AppendFlagsToArgs(args, len(cs), configFlag, keepInputFlag, dropInputFlag, ignoreFirstIntervalsFlag, ignoreOldSamplesFlag, enableWindowsFlag)
+	args = AppendFlagsToArgs(args, len(cs), configFlag, keepInputFlag, dropInputFlag, ignoreFirstIntervalsFlag, ignoreFirstSampleIntervalFlag, ignoreOldSamplesFlag, enableWindowsFlag)
 	args = AppendFlagsToArgs(args, len(cs), dedupIntervalFlag, dropInputLabelsFlag)
 	return args
 }



Test patch:
diff --git a/internal/controller/operator/factory/vmagent/vmagent_test.go b/internal/controller/operator/factory/vmagent/vmagent_test.go
index e6a3ed2e..2c58fc86 100644
--- a/internal/controller/operator/factory/vmagent/vmagent_test.go
+++ b/internal/controller/operator/factory/vmagent/vmagent_test.go
@@ -1292,7 +1292,8 @@ func TestBuildRemoteWriteArgs(t *testing.T) {
 									Outputs: []string{"total", "avg"},
 								},
 							},
-							DedupInterval: "10s",
+							DedupInterval:             "10s",
+							IgnoreFirstSampleInterval: "10m",
 						},
 					},
 					{
@@ -1300,7 +1301,8 @@ func TestBuildRemoteWriteArgs(t *testing.T) {
 						StreamAggrConfig: &vmv1beta1.StreamAggrConfig{
 							Rules: []vmv1beta1.StreamAggrRule{
 								{
-									Outputs: []string{"histogram_bucket"},
+									IgnoreFirstSampleInterval: "20m",
+									Outputs:                   []string{"histogram_bucket"},
 								},
 							},
 							KeepInput: true,
@@ -1312,6 +1314,7 @@ func TestBuildRemoteWriteArgs(t *testing.T) {
 				`-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.ignoreFirstSampleInterval=10m,`,
 				`-remoteWrite.streamAggr.keepInput=false,true`,
 				`-remoteWrite.url=localhost:8429,localhost:8431`,
 				`-remoteWrite.tmpDataPath=/tmp/vmagent-remotewrite-data`,
@@ -2086,12 +2089,13 @@ func TestCreateOrUpdateStreamAggrConfig(t *testing.T) {
 							URL: "localhost:8429",
 							StreamAggrConfig: &vmv1beta1.StreamAggrConfig{
 								Rules: []vmv1beta1.StreamAggrRule{{
-									Match:             []string{`{__name__="count1"}`, `{__name__="count2"}`},
-									Interval:          "1m",
-									StalenessInterval: "2m",
-									Outputs:           []string{"total", "avg"},
-									By:                []string{"job", "instance"},
-									Without:           []string{"pod"},
+									Match:                     []string{`{__name__="count1"}`, `{__name__="count2"}`},
+									Interval:                  "1m",
+									StalenessInterval:         "2m",
+									IgnoreFirstSampleInterval: "20m",
+									Outputs:                   []string{"total", "avg"},
+									By:                        []string{"job", "instance"},
+									Without:                   []string{"pod"},
 									OutputRelabelConfigs: []vmv1beta1.RelabelConfig{{
 										SourceLabels: []string{"__name__"},
 										TargetLabel:  "metric",
@@ -2121,6 +2125,7 @@ func TestCreateOrUpdateStreamAggrConfig(t *testing.T) {
   - instance
   without:
   - pod
+  ignore_first_sample_interval: 20m
   output_relabel_configs:
   - regex:
     - vmagent