Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions api/operator/v1beta1/vmcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ type VMClusterSpec struct {
// +optional
License *License `json:"license,omitempty"`

// Downsampling defines downsampling rules applied to vmselect and vmstorage components.
// Requires enterprise license. See https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/#downsampling
// +optional
Downsampling *DownsamplingConfig `json:"downsampling,omitempty"`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If I understood correctly this would add more params in extraArgs.downsampling - would it crash if there are duplicates? We should add some more tests on a mix of spec.downsampling + spec.extraArgs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

if downsampling section is defined it rewrites extraArgs

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

right, we should add this to the docs / API documentation


// +optional
VMSelect *VMSelect `json:"vmselect,omitempty"`
// +optional
Expand Down Expand Up @@ -462,6 +467,10 @@ type VMStorage struct {
// VMBackup configuration for backup
// +optional
VMBackup *VMBackup `json:"vmBackup,omitempty"`
// RetentionFilters defines per-series retention filters for vmstorage.
// Requires enterprise license. See https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/#retention-filters
// +optional
RetentionFilters *RetentionFiltersConfig `json:"retentionFilters,omitempty"`
// ServiceSpec that will be create additional service for vmstorage
// +optional
ServiceSpec *AdditionalServiceSpec `json:"serviceSpec,omitempty"`
Expand Down Expand Up @@ -679,6 +688,9 @@ func (cr *VMCluster) Validate() error {
}
}
}
if err := cr.Spec.Downsampling.validate(cr.Spec.License); err != nil {
return err
}
if cr.Spec.VMStorage != nil {
vms := cr.Spec.VMStorage
name := cr.PrefixedName(ClusterComponentSelect)
Expand All @@ -690,6 +702,9 @@ func (cr *VMCluster) Validate() error {
return err
}
}
if err := vms.RetentionFilters.validate(cr.Spec.License, cr.Spec.RetentionPeriod); err != nil {
return err
}
if vms.RollingUpdateStrategyBehavior != nil {
if err := vms.RollingUpdateStrategyBehavior.Validate(); err != nil {
return fmt.Errorf("vmstorage: %w", err)
Expand Down
142 changes: 142 additions & 0 deletions api/operator/v1beta1/vmcluster_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,145 @@ func TestVMCluster_AvailableStorageNodeIDs(t *testing.T) {
},
}, ClusterComponentSelect, []int32{0, 1, 2})
}

func TestVMCluster_Validate(t *testing.T) {
f := func(spec VMClusterSpec, wantErr bool) {
t.Helper()
cr := &VMCluster{Spec: spec}
if wantErr {
assert.Error(t, cr.Validate())
} else {
assert.NoError(t, cr.Validate())
}
}

// empty spec
f(VMClusterSpec{}, false)

// downsampling without license
f(VMClusterSpec{
Downsampling: &DownsamplingConfig{
Rules: []DownsamplingRule{{Periods: []DownsamplingPeriod{{Offset: "30d", Interval: "10m"}}}},
},
}, true)

// downsampling with valid config
f(VMClusterSpec{
License: testLicense,
Downsampling: &DownsamplingConfig{
Rules: []DownsamplingRule{{Periods: []DownsamplingPeriod{{Offset: "30d", Interval: "10m"}}}},
},
}, false)

// downsampling with filter and dedupInterval
f(VMClusterSpec{
License: testLicense,
Downsampling: &DownsamplingConfig{
Rules: []DownsamplingRule{{Filter: `{env="prod"}`, Periods: []DownsamplingPeriod{{Offset: "90d", Interval: "1h"}}}},
DedupInterval: "1m",
},
}, false)

// downsampling - multiple periods per rule
f(VMClusterSpec{
License: testLicense,
Downsampling: &DownsamplingConfig{
Rules: []DownsamplingRule{{Periods: []DownsamplingPeriod{
{Offset: "30d", Interval: "10m"},
{Offset: "180d", Interval: "1h"},
}}},
},
}, false)

// downsampling - duplicate filter
f(VMClusterSpec{
License: testLicense,
Downsampling: &DownsamplingConfig{
Rules: []DownsamplingRule{
{Periods: []DownsamplingPeriod{{Offset: "30d", Interval: "10m"}}},
{Periods: []DownsamplingPeriod{{Offset: "180d", Interval: "1h"}}},
},
},
}, true)

// downsampling - offset not a multiple of interval
f(VMClusterSpec{
License: testLicense,
Downsampling: &DownsamplingConfig{
Rules: []DownsamplingRule{{Periods: []DownsamplingPeriod{{Offset: "1d", Interval: "7m"}}}},
},
}, true)

// downsampling - period interval not a multiple of dedupInterval
f(VMClusterSpec{
License: testLicense,
Downsampling: &DownsamplingConfig{
Rules: []DownsamplingRule{{Periods: []DownsamplingPeriod{{Offset: "30d", Interval: "10m"}}}},
DedupInterval: "7m",
},
}, true)

// downsampling - period interval is a multiple of dedupInterval
f(VMClusterSpec{
License: testLicense,
Downsampling: &DownsamplingConfig{
Rules: []DownsamplingRule{{Periods: []DownsamplingPeriod{{Offset: "30d", Interval: "10m"}}}},
DedupInterval: "5m",
},
}, false)

// retention filters without vmstorage section — no error (vmstorage is nil)
f(VMClusterSpec{
License: testLicense,
}, false)

// retention filters without license
f(VMClusterSpec{
VMStorage: &VMStorage{
RetentionFilters: &RetentionFiltersConfig{{Filter: `{env="dev"}`, Retention: "3d"}},
},
}, true)

// retention filters with valid config
f(VMClusterSpec{
License: testLicense,
RetentionPeriod: "30",
VMStorage: &VMStorage{
RetentionFilters: &RetentionFiltersConfig{{Filter: `{env="dev"}`, Retention: "3d"}},
},
}, false)

// retention filters - invalid filter
f(VMClusterSpec{
License: testLicense,
VMStorage: &VMStorage{
RetentionFilters: &RetentionFiltersConfig{{Filter: "not-a-filter", Retention: "3d"}},
},
}, true)

// retention filters - invalid retention
f(VMClusterSpec{
License: testLicense,
VMStorage: &VMStorage{
RetentionFilters: &RetentionFiltersConfig{{Filter: `{env="dev"}`, Retention: "bad"}},
},
}, true)

// retention filters - retention exceeds retentionPeriod
f(VMClusterSpec{
License: testLicense,
RetentionPeriod: "30d",
VMStorage: &VMStorage{
RetentionFilters: &RetentionFiltersConfig{{Filter: `{env="dev"}`, Retention: "1y"}},
},
}, true)

// retention filters - retention equal to retentionPeriod is ok
f(VMClusterSpec{
License: testLicense,
RetentionPeriod: "1y",
VMStorage: &VMStorage{
RetentionFilters: &RetentionFiltersConfig{{Filter: `{env="dev"}`, Retention: "1y"}},
},
}, false)
}
Loading