1
0
Fork 0
mirror of https://github.com/prometheus-operator/prometheus-operator.git synced 2025-04-15 16:56:24 +00:00

[FEAT] - Add metric_name_validation_scheme (#7116)

---------

Signed-off-by: Hélia Barroso <helia_barroso@hotmail.com>
Co-authored-by: Simon Pasquier <spasquie@redhat.com>
This commit is contained in:
Hélia Barroso 2024-11-20 10:23:37 +00:00 committed by GitHub
parent c84773ab0b
commit ef69943905
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 329 additions and 5 deletions

95
Documentation/api.md generated
View file

@ -2704,6 +2704,20 @@ If Prometheus version is &gt;= 2.45.0 and the <code>enforcedBodySizeLimit</code>
</tr>
<tr>
<td>
<code>nameValidationScheme</code><br/>
<em>
<a href="#monitoring.coreos.com/v1.NameValidationSchemeOptions">
NameValidationSchemeOptions
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>Specifies the validation scheme for metric and label names.</p>
</td>
</tr>
<tr>
<td>
<code>minReadySeconds</code><br/>
<em>
uint32
@ -7695,6 +7709,20 @@ If Prometheus version is &gt;= 2.45.0 and the <code>enforcedBodySizeLimit</code>
</tr>
<tr>
<td>
<code>nameValidationScheme</code><br/>
<em>
<a href="#monitoring.coreos.com/v1.NameValidationSchemeOptions">
NameValidationSchemeOptions
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>Specifies the validation scheme for metric and label names.</p>
</td>
</tr>
<tr>
<td>
<code>minReadySeconds</code><br/>
<em>
uint32
@ -9540,6 +9568,31 @@ Duration
</tr>
</tbody>
</table>
<h3 id="monitoring.coreos.com/v1.NameValidationSchemeOptions">NameValidationSchemeOptions
(<code>string</code> alias)</h3>
<p>
(<em>Appears on:</em><a href="#monitoring.coreos.com/v1.CommonPrometheusFields">CommonPrometheusFields</a>)
</p>
<div>
<p>Specifies the validation scheme for metric and label names.
Supported values are:
* <code>UTF8NameValidationScheme</code> for UTF-8 support.
* <code>LegacyNameValidationScheme</code> for letters, numbers, colons, and underscores.</p>
<p>Note that <code>LegacyNameValidationScheme</code> cannot be used along with the OpenTelemetry <code>NoUTF8EscapingWithSuffixes</code> translation strategy (if enabled).</p>
</div>
<table>
<thead>
<tr>
<th>Value</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr><td><p>&#34;Legacy&#34;</p></td>
<td></td>
</tr><tr><td><p>&#34;UTF8&#34;</p></td>
<td></td>
</tr></tbody>
</table>
<h3 id="monitoring.coreos.com/v1.NamespaceSelector">NamespaceSelector
</h3>
<p>
@ -12433,6 +12486,20 @@ If Prometheus version is &gt;= 2.45.0 and the <code>enforcedBodySizeLimit</code>
</tr>
<tr>
<td>
<code>nameValidationScheme</code><br/>
<em>
<a href="#monitoring.coreos.com/v1.NameValidationSchemeOptions">
NameValidationSchemeOptions
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>Specifies the validation scheme for metric and label names.</p>
</td>
</tr>
<tr>
<td>
<code>minReadySeconds</code><br/>
<em>
uint32
@ -19082,6 +19149,20 @@ If Prometheus version is &gt;= 2.45.0 and the <code>enforcedBodySizeLimit</code>
</tr>
<tr>
<td>
<code>nameValidationScheme</code><br/>
<em>
<a href="#monitoring.coreos.com/v1.NameValidationSchemeOptions">
NameValidationSchemeOptions
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>Specifies the validation scheme for metric and label names.</p>
</td>
</tr>
<tr>
<td>
<code>minReadySeconds</code><br/>
<em>
uint32
@ -26953,6 +27034,20 @@ If Prometheus version is &gt;= 2.45.0 and the <code>enforcedBodySizeLimit</code>
</tr>
<tr>
<td>
<code>nameValidationScheme</code><br/>
<em>
<a href="#monitoring.coreos.com/v1.NameValidationSchemeOptions">
NameValidationSchemeOptions
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>Specifies the validation scheme for metric and label names.</p>
</td>
</tr>
<tr>
<td>
<code>minReadySeconds</code><br/>
<em>
uint32

14
bundle.yaml generated
View file

@ -25669,6 +25669,13 @@ spec:
- StatefulSet
- DaemonSet
type: string
nameValidationScheme:
description: Specifies the validation scheme for metric and label
names.
enum:
- UTF8
- Legacy
type: string
nodeSelector:
additionalProperties:
type: string
@ -37019,6 +37026,13 @@ spec:
enabling the StatefulSetMinReadySeconds feature gate.
format: int32
type: integer
nameValidationScheme:
description: Specifies the validation scheme for metric and label
names.
enum:
- UTF8
- Legacy
type: string
nodeSelector:
additionalProperties:
type: string

View file

@ -4726,6 +4726,13 @@ spec:
- StatefulSet
- DaemonSet
type: string
nameValidationScheme:
description: Specifies the validation scheme for metric and label
names.
enum:
- UTF8
- Legacy
type: string
nodeSelector:
additionalProperties:
type: string

View file

@ -5435,6 +5435,13 @@ spec:
enabling the StatefulSetMinReadySeconds feature gate.
format: int32
type: integer
nameValidationScheme:
description: Specifies the validation scheme for metric and label
names.
enum:
- UTF8
- Legacy
type: string
nodeSelector:
additionalProperties:
type: string

View file

@ -4727,6 +4727,13 @@ spec:
- StatefulSet
- DaemonSet
type: string
nameValidationScheme:
description: Specifies the validation scheme for metric and label
names.
enum:
- UTF8
- Legacy
type: string
nodeSelector:
additionalProperties:
type: string

View file

@ -5436,6 +5436,13 @@ spec:
enabling the StatefulSetMinReadySeconds feature gate.
format: int32
type: integer
nameValidationScheme:
description: Specifies the validation scheme for metric and label
names.
enum:
- UTF8
- Legacy
type: string
nodeSelector:
additionalProperties:
type: string

View file

@ -4023,6 +4023,14 @@
],
"type": "string"
},
"nameValidationScheme": {
"description": "Specifies the validation scheme for metric and label names.",
"enum": [
"UTF8",
"Legacy"
],
"type": "string"
},
"nodeSelector": {
"additionalProperties": {
"type": "string"

View file

@ -4624,6 +4624,14 @@
"format": "int32",
"type": "integer"
},
"nameValidationScheme": {
"description": "Specifies the validation scheme for metric and label names.",
"enum": [
"UTF8",
"Legacy"
],
"type": "string"
},
"nodeSelector": {
"additionalProperties": {
"type": "string"

View file

@ -674,6 +674,10 @@ type CommonPrometheusFields struct {
//
EnforcedBodySizeLimit ByteSize `json:"enforcedBodySizeLimit,omitempty"`
// Specifies the validation scheme for metric and label names.
// +optional
NameValidationScheme *NameValidationSchemeOptions `json:"nameValidationScheme,omitempty"`
// Minimum number of seconds for which a newly created Pod should be ready
// without any of its container crashing for it to be considered available.
// Defaults to 0 (pod will be considered available as soon as it is ready)
@ -846,6 +850,20 @@ type CommonPrometheusFields struct {
Runtime *RuntimeConfig `json:"runtime,omitempty"`
}
// Specifies the validation scheme for metric and label names.
// Supported values are:
// * `UTF8NameValidationScheme` for UTF-8 support.
// * `LegacyNameValidationScheme` for letters, numbers, colons, and underscores.
//
// Note that `LegacyNameValidationScheme` cannot be used along with the OpenTelemetry `NoUTF8EscapingWithSuffixes` translation strategy (if enabled).
// +kubebuilder:validation:Enum=UTF8;Legacy
type NameValidationSchemeOptions string
const (
UTF8NameValidationScheme NameValidationSchemeOptions = "UTF8"
LegacyNameValidationScheme NameValidationSchemeOptions = "Legacy"
)
// +kubebuilder:validation:Enum=HTTP;ProcessSignal
type ReloadStrategyType string

View file

@ -920,6 +920,11 @@ func (in *CommonPrometheusFields) DeepCopyInto(out *CommonPrometheusFields) {
*out = new(uint64)
**out = **in
}
if in.NameValidationScheme != nil {
in, out := &in.NameValidationScheme, &out.NameValidationScheme
*out = new(NameValidationSchemeOptions)
**out = **in
}
if in.MinReadySeconds != nil {
in, out := &in.MinReadySeconds, &out.MinReadySeconds
*out = new(uint32)

View file

@ -94,6 +94,7 @@ type CommonPrometheusFieldsApplyConfiguration struct {
EnforcedLabelValueLengthLimit *uint64 `json:"enforcedLabelValueLengthLimit,omitempty"`
EnforcedKeepDroppedTargets *uint64 `json:"enforcedKeepDroppedTargets,omitempty"`
EnforcedBodySizeLimit *monitoringv1.ByteSize `json:"enforcedBodySizeLimit,omitempty"`
NameValidationScheme *monitoringv1.NameValidationSchemeOptions `json:"nameValidationScheme,omitempty"`
MinReadySeconds *uint32 `json:"minReadySeconds,omitempty"`
HostAliases []HostAliasApplyConfiguration `json:"hostAliases,omitempty"`
AdditionalArgs []ArgumentApplyConfiguration `json:"additionalArgs,omitempty"`
@ -711,6 +712,14 @@ func (b *CommonPrometheusFieldsApplyConfiguration) WithEnforcedBodySizeLimit(val
return b
}
// WithNameValidationScheme sets the NameValidationScheme field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the NameValidationScheme field is set to the value of the last call.
func (b *CommonPrometheusFieldsApplyConfiguration) WithNameValidationScheme(value monitoringv1.NameValidationSchemeOptions) *CommonPrometheusFieldsApplyConfiguration {
b.NameValidationScheme = &value
return b
}
// WithMinReadySeconds sets the MinReadySeconds field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the MinReadySeconds field is set to the value of the last call.

View file

@ -645,6 +645,14 @@ func (b *PrometheusSpecApplyConfiguration) WithEnforcedBodySizeLimit(value monit
return b
}
// WithNameValidationScheme sets the NameValidationScheme field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the NameValidationScheme field is set to the value of the last call.
func (b *PrometheusSpecApplyConfiguration) WithNameValidationScheme(value monitoringv1.NameValidationSchemeOptions) *PrometheusSpecApplyConfiguration {
b.NameValidationScheme = &value
return b
}
// WithMinReadySeconds sets the MinReadySeconds field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the MinReadySeconds field is set to the value of the last call.

View file

@ -633,6 +633,14 @@ func (b *PrometheusAgentSpecApplyConfiguration) WithEnforcedBodySizeLimit(value
return b
}
// WithNameValidationScheme sets the NameValidationScheme field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the NameValidationScheme field is set to the value of the last call.
func (b *PrometheusAgentSpecApplyConfiguration) WithNameValidationScheme(value monitoringv1.NameValidationSchemeOptions) *PrometheusAgentSpecApplyConfiguration {
b.NameValidationScheme = &value
return b
}
// WithMinReadySeconds sets the MinReadySeconds field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the MinReadySeconds field is set to the value of the last call.

View file

@ -4497,6 +4497,8 @@ func (cg *ConfigGenerator) generateScrapeConfig(
func (cg *ConfigGenerator) appendOTLPConfig(cfg yaml.MapSlice) (yaml.MapSlice, error) {
otlpConfig := cg.prom.GetCommonPrometheusFields().OTLP
nameValidationScheme := cg.prom.GetCommonPrometheusFields().NameValidationScheme
if otlpConfig == nil {
return cfg, nil
}
@ -4505,6 +4507,10 @@ func (cg *ConfigGenerator) appendOTLPConfig(cfg yaml.MapSlice) (yaml.MapSlice, e
return cfg, fmt.Errorf("OTLP configuration is only supported from Prometheus version 2.55.0")
}
if ptr.Deref(otlpConfig.TranslationStrategy, "") == monitoringv1.NoUTF8EscapingWithSuffixes && ptr.Deref(nameValidationScheme, "") == monitoringv1.LegacyNameValidationScheme {
return cfg, fmt.Errorf("nameValidationScheme %q is not compatible with OTLP translation strategy %q", monitoringv1.LegacyNameValidationScheme, monitoringv1.NoUTF8EscapingWithSuffixes)
}
otlp := yaml.MapSlice{}
if len(otlpConfig.PromoteResourceAttributes) > 0 {
@ -4664,11 +4670,15 @@ func (cg *ConfigGenerator) addFiltersToYaml(cfg yaml.MapSlice, filters []monitor
}
func (cg *ConfigGenerator) buildGlobalConfig() yaml.MapSlice {
cpf := cg.prom.GetCommonPrometheusFields()
cfg := yaml.MapSlice{}
cfg = cg.appendScrapeIntervals(cfg)
cfg = cg.addScrapeProtocols(cfg, cg.prom.GetCommonPrometheusFields().ScrapeProtocols)
cfg = cg.appendExternalLabels(cfg)
cfg = cg.appendScrapeLimits(cfg)
if cpf.NameValidationScheme != nil {
cg.WithMinimumVersion("3.0.0").AppendMapItem(cfg, "metric_name_validation_scheme", *cpf.NameValidationScheme)
}
return cfg
}

View file

@ -8582,13 +8582,76 @@ func TestScrapeConfigSpecConfigWithHetznerSD(t *testing.T) {
}
}
func TestAppendNameValidationScheme(t *testing.T) {
testCases := []struct {
name string
version string
nameValidationScheme *monitoringv1.NameValidationSchemeOptions
expectedCfg string
}{
{
name: "UTF8 nameValidationScheme withPrometheus Version 3",
version: "v3.0.0-beta.0",
nameValidationScheme: ptr.To(monitoringv1.UTF8NameValidationScheme),
expectedCfg: "NameValidationSchemeUTF8WithPrometheusV3.golden",
},
{
name: "Legacy nameValidationScheme with Prometheus Version 3",
version: "v3.0.0-beta.0",
nameValidationScheme: ptr.To(monitoringv1.LegacyNameValidationScheme),
expectedCfg: "NameValidationSchemeLegacyWithPrometheusV3.golden",
},
{
name: "Legacy nameValidationScheme with Prometheus Version 3",
version: "v2.55.0",
nameValidationScheme: ptr.To(monitoringv1.LegacyNameValidationScheme),
expectedCfg: "NameValidationSchemeLegacyWithPrometheusLowerThanV3.golden",
},
{
name: "Legacy nameValidationScheme with Prometheus Version 3",
version: "v2.55.0",
nameValidationScheme: ptr.To(monitoringv1.LegacyNameValidationScheme),
expectedCfg: "NameValidationSchemeLegacyWithPrometheusLowerThanV3.golden",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
p := defaultPrometheus()
if tc.version != "" {
p.Spec.CommonPrometheusFields.Version = tc.version
}
if tc.nameValidationScheme != nil {
p.Spec.CommonPrometheusFields.NameValidationScheme = tc.nameValidationScheme
}
cg := mustNewConfigGenerator(t, p)
cfg, err := cg.GenerateServerConfiguration(
p,
nil,
nil,
nil,
nil,
&assets.StoreBuilder{},
nil,
nil,
nil,
nil,
)
require.NoError(t, err)
golden.Assert(t, string(cfg), tc.expectedCfg)
})
}
}
func TestOTLPConfig(t *testing.T) {
testCases := []struct {
otlpConfig *monitoringv1.OTLPConfig
name string
version string
expectedErr bool
golden string
otlpConfig *monitoringv1.OTLPConfig
nameValScheme *monitoringv1.NameValidationSchemeOptions
name string
version string
expectedErr bool
golden string
}{
{
name: "Config promote resource attributes",
@ -8638,6 +8701,24 @@ func TestOTLPConfig(t *testing.T) {
},
golden: "OTLPConfig_Config_translation_strategy_with_unsupported_version.golden",
},
{
name: "Config Legacy nameValidationScheme with OTLP translation strategy NoUTF8",
version: "v3.0.0",
otlpConfig: &monitoringv1.OTLPConfig{
TranslationStrategy: ptr.To(monitoringv1.NoUTF8EscapingWithSuffixes),
},
nameValScheme: ptr.To(monitoringv1.LegacyNameValidationScheme),
expectedErr: true,
},
{
name: "Config Legacy nameValidationScheme with OTLP translation strategy UnderscoreEscapingWithSuffixes",
version: "v3.0.0",
otlpConfig: &monitoringv1.OTLPConfig{
TranslationStrategy: ptr.To(monitoringv1.UnderscoreEscapingWithSuffixes),
},
nameValScheme: ptr.To(monitoringv1.LegacyNameValidationScheme),
golden: "OTLPConfig_Config_translation_strategy_with_suffixes_and_name_validation_scheme.golden",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
@ -8650,6 +8731,8 @@ func TestOTLPConfig(t *testing.T) {
p.Spec.CommonPrometheusFields.OTLP = tc.otlpConfig
p.Spec.CommonPrometheusFields.NameValidationScheme = tc.nameValScheme
cg := mustNewConfigGenerator(t, p)
cfg, err := cg.GenerateServerConfiguration(

View file

@ -0,0 +1,7 @@
global:
scrape_interval: 30s
external_labels:
prometheus: default/test
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []

View file

@ -0,0 +1,7 @@
global:
scrape_interval: 30s
external_labels:
prometheus: default/test
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []

View file

@ -0,0 +1,7 @@
global:
scrape_interval: 30s
external_labels:
prometheus: default/test
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []

View file

@ -0,0 +1,9 @@
global:
scrape_interval: 30s
external_labels:
prometheus: default/test
prometheus_replica: $(POD_NAME)
evaluation_interval: 30s
scrape_configs: []
otlp:
translation_strategy: UnderscoreEscapingWithSuffixes