Skip to content

Conversation

liam-howe-maersk
Copy link
Contributor

Fixes #12534

Currently, when unmarshalling some relabel config from YAML, if the regex field is not provided we set this to be equal to the default value. If we then want to marshal this config back in to YAML, it will generate the YAML with the regex field set equal to the default YAML value, meaning that unmarshalling and then marshalling again doesn't give the same output as the original input. For the keepequal and dropequal actions we expect that no regex field is set and therefore an error is returned if we try to unmarshal, then marshal and again unmarshal one of these actions, because the regex field will be set on the marshal step. By implementing the MarshalYAML function and ensuring the regex field is not set if it was not provided originally, we fix this bug.

… regex field if it was not provided in the first place

Signed-off-by: Liam Howe <liam.howe@maersk.com>
@bboreham
Copy link
Member

This seems workable, but I was rather confused for a while. I was unfamiliar with the MarshalYAML method, which is not expected to do any marshalling, but to return an object based on its input which is then marshalled.

Having got that deep into the workings, I discovered an alternative approach: since the field is declared as omitempty we can explain that the default regexp should be taken as empty. What do you think?

diff --git model/relabel/relabel.go model/relabel/relabel.go
index d29c3d07a..b92b4e903 100644
--- model/relabel/relabel.go
+++ model/relabel/relabel.go
@@ -205,6 +205,11 @@ func (re Regexp) MarshalYAML() (interface{}, error) {
        return nil, nil
 }
 
+// MarshalYAML implements the yaml.IsZeroer interface.
+func (re Regexp) IsZero() bool {
+       return re.Regexp == DefaultRelabelConfig.Regex.Regexp
+}
+
 // String returns the original string used to compile the regular expression.
 func (re Regexp) String() string {
        str := re.Regexp.String()

Signed-off-by: Liam Howe <liam.howe@maersk.com>
@liam-howe-maersk
Copy link
Contributor Author

@bboreham Thanks for reviewing, this is good to know and I agree that the IsZero implementation is a cleaner approach, I have updated the PR as suggested!

@bboreham bboreham changed the title configuration: Implement MarshalYAML for relabel.Config to remove default regex configuration: Implement IsZero for relabel.Regex to remove default regex Apr 30, 2024
bboreham
bboreham previously approved these changes Apr 30, 2024
Copy link
Member

@bboreham bboreham left a comment

Choose a reason for hiding this comment

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

lgtm

@liam-howe-maersk
Copy link
Contributor Author

lgtm

Thanks for the review @bboreham! I don't have permissions to merge, will this PR be merged by someone else?

@bboreham
Copy link
Member

bboreham commented May 3, 2024

Yes I can merge, was just waiting to see if anyone else had a view.

Copy link
Member

@machine424 machine424 left a comment

Choose a reason for hiding this comment

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

lgtm, thanks.

Not related to the PR:
Even though we have a default regex, I don't see why we fallback on the empty regex here

func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
*c = DefaultRelabelConfig
type plain Config
if err := unmarshal((*plain)(c)); err != nil {
return err
}
if c.Regex.Regexp == nil {
c.Regex = MustNewRegexp("")
}

Also empty regex is marshalled differently
func (re Regexp) MarshalYAML() (interface{}, error) {
if re.String() != "" {
return re.String(), nil
}
return nil, nil
}
, we kind of have the same issue: "user provides empty regex and after unmarshal/marshal, they'll get null"

@@ -205,6 +205,11 @@ func (re Regexp) MarshalYAML() (interface{}, error) {
return nil, nil
}

// IsZero implements the yaml.IsZeroer interface.
func (re Regexp) IsZero() bool {
return re.Regexp == DefaultRelabelConfig.Regex.Regexp
Copy link
Member

Choose a reason for hiding this comment

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

I assume this takes into account cases where the default (.*) regex is explicitly provided, as we compare pointers here.
It'd be great to have a regression test for it though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good suggestion, I have added a test case for the default regex being explicitly provided, thanks.

Copy link
Member

Choose a reason for hiding this comment

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

The test shows that this change is not good... Because the input and the marshalled should be different then

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure I follow, if the regex is not provided in the original yaml, then when we unmarshal and marshal again it will still not be in the resulting yaml. If the default regex is explicitly provided then when we unmarshal and marshal it will still be there explicitly in the yaml, is that not expected?

Signed-off-by: Liam Howe <liam.howe@maersk.com>
Copy link
Member

@machine424 machine424 left a comment

Choose a reason for hiding this comment

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

lgtm.

@roidelapluie
Copy link
Member

I think the last test is wrong and should error. We might just call String() to compare the regexes.

@bboreham
Copy link
Member

@roidelapluie the whole idea of this PR is to avoid comparing the regexp as a string, since "never set" and "set to a string equal to the default" are not the same.

@beorn7
Copy link
Member

beorn7 commented Jun 26, 2024

I tried to reach @roidelapluie out of band. Let's wait for another day or so if he comes back to us with an explanation. Otherwise, we have to assume @bboreham and @machine424 are right and this is the way to go.

@beorn7 beorn7 mentioned this pull request Jun 26, 2024
@roidelapluie
Copy link
Member

OK, let's move forward with this.

@beorn7 beorn7 merged commit cb73061 into prometheus:main Jun 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

KeepEqual/DropEqual should compare Regex.String instead of instance values
5 participants