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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/operator/v1/vlagent_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ func (cr *VLAgent) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := vmv1beta1.UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VLAgentSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1/vlcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@ func (cr *VLCluster) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := vmv1beta1.UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VLClusterSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1/vlsingle_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ func (cr *VLSingle) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := vmv1beta1.UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VLSingleSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1/vmanomaly_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ func (cr *VMAnomaly) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := vmv1beta1.UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VMAnomalySpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1/vtcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ func (cr *VTCluster) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := vmv1beta1.UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VTClusterSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1/vtsingle_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func (cr *VTSingle) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := vmv1beta1.UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VTSingleSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1alpha1/vmdistributed_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ func (cr *VMDistributed) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := vmv1beta1.UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VMDistributedSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1beta1/vlogs_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ func (cr *VLogs) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VLogsSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1beta1/vmagent_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ func (cr *VMAgent) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VMAgentSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1beta1/vmalert_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func (cr *VMAlert) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VMAlertSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1beta1/vmalertmanager_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ func (cr *VMAlertmanager) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VMAlertmanagerSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1beta1/vmalertmanagerconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ func (cr *VMAlertmanagerConfig) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VMAlertmanagerConfigSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
12 changes: 6 additions & 6 deletions api/operator/v1beta1/vmalertmanagerconfig_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -781,7 +781,10 @@ func TestValidateVMAlertmanagerConfigOk(t *testing.T) {
"name": "vo-access",
"key": "SECRET_URL"
},
"routing_key": "CRITICAL"
"routing_key": "CRITICAL",
"custom_fields": {
"key": "value"
}
}
]
}
Expand All @@ -796,13 +799,13 @@ func TestValidateVMAlertmanagerConfigOk(t *testing.T) {
"apiVersion": "v1",
"kind": "VMAlertmanagerConfig",
"metadata": {
"name": "wechat"
"name": "msteams"
},
"spec": {
"receivers": [
{
"name": "wc",
"wechat_configs": [
"msteams_configs": [
{
"webhook_url": "https://open-for-all.example"
},
Expand Down Expand Up @@ -835,9 +838,6 @@ func TestValidateVMAlertmanagerConfigOk(t *testing.T) {
"routing_key": {
"name": "pd-access",
"key": "secret"
},
"custom_fields": {
"key": "value"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1beta1/vmauth_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ func (cr *VMAuth) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VMAuthSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1beta1/vmcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ func (cr *VMCluster) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VMClusterSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
8 changes: 8 additions & 0 deletions api/operator/v1beta1/vmextra_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,14 @@ func (c *TLSConfig) appendForbiddenProperties(props []string) []string {
return props
}

// UnmarshalSpecStrict decodes spec JSON and rejects unknown fields,
// preventing CRs with unsupported fields from being silently accepted by the webhook.
func UnmarshalSpecStrict(data []byte, v any) error {
d := json.NewDecoder(bytes.NewReader(data))
d.DisallowUnknownFields()
return d.Decode(v)
}

// UnmarshalJSON implements json.Unmarshaller interface
func (c *TLSConfig) UnmarshalJSON(data []byte) error {
decoder := json.NewDecoder(bytes.NewReader(data))
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1beta1/vmnodescrape_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func (cr *VMNodeScrape) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VMNodeScrapeSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1beta1/vmpodscrape_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func (cr *VMPodScrape) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VMPodScrapeSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1beta1/vmprobe_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ func (cr *VMProbe) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VMProbeSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1beta1/vmrule_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ func (cr *VMRule) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VMRuleSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1beta1/vmscrapeconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ func (cr *VMScrapeConfig) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VMScrapeConfigSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1beta1/vmservicescrape_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func (cr *VMServiceScrape) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VMServiceScrapeSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1beta1/vmsingle_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ func (cr *VMSingle) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VMSingleSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1beta1/vmstaticscrape_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func (cr *VMStaticScrape) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VMStaticScrapeSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/operator/v1beta1/vmuser_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ func (cr *VMUser) UnmarshalJSON(src []byte) error {
return err
}
if len(s.Spec) > 0 {
if err := json.Unmarshal(s.Spec, &cr.Spec); err != nil {
if err := UnmarshalSpecStrict(s.Spec, &cr.Spec); err != nil {
cr.Status.ParsingSpecError = fmt.Sprintf("cannot parse VMUserSpec: %s, err: %s", string(s.Spec), err)
}
}
Expand Down
4 changes: 3 additions & 1 deletion docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@ aliases:

* FEATURE: [vmoperator](https://docs.victoriametrics.com/operator/): support enableServiceLinks property in all CRs. See [#2194](https://github.com/VictoriaMetrics/operator/pull/2194).

* BUGFIX: [vmoperator](https://docs.victoriametrics.com/operator/): enable strict CR spec unmarshalling. See [#2882](https://github.com/VictoriaMetrics/helm-charts/issues/2882).

## [v0.70.1](https://github.com/VictoriaMetrics/operator/releases/tag/v0.70.0)
**Release date:** 20 May 2026

* FEATURE: [vmauth](https://docs.victoriametrics.com/operator/resources/vmauth/): support HPA for requests load balancer.

* BUGFIX: [vmagent](https://docs.victoriametrics.com/operator/resources/vmagent/): skip replica count update when VMAgent is in stateful mode and HPA is enabled. See [#2190](https://github.com/VictoriaMetrics/operator/issues/2190).
* BUGFIX: [vmalertmanagerconfig](https://docs.victoriametrics.com/operator/resources/vmalertmanagerconfig/): Remove prefix from empty subroute receiver. See [#2185](https://github.com/VictoriaMetrics/operator/issues/2185).
* BUGFIX: [vmoperator](https://docs.victoriametrics.com/operator/): updated OLM configuration to fix OpenShift catalog publishing. See [#]


## [v0.70.0](https://github.com/VictoriaMetrics/operator/releases/tag/v0.70.0)
**Release date:** 18 May 2026
Expand Down