-
Notifications
You must be signed in to change notification settings - Fork 444
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add a mechanism to deprecate AppConfig settings w/ backwards-compat #7353
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The general approach looks good to me, I also like your alternative suggestion to avoid unmarshaling twice but it might cause additional issues when it comes to marshaling (i.e. it would require a custom marshaler to ignore the legacy fields, right? Could be worth it if everything else works fine though).
server/fleet/app.go
Outdated
} | ||
|
||
// TODO(roperzh): define and assign legacy settings to new fields. E.g: | ||
// c.Features = legacy.HostSettings |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The legacy approach makes sense to me.
Will we have tests for this in the future PR? At this point without any deprecation, the regular appconfig tests should cover this, correct? |
that's right, in this PR the goal is to make all existent tests pass, the next PR introduces |
Codecov Report
@@ Coverage Diff @@
## main #7353 +/- ##
==========================================
- Coverage 60.55% 60.54% -0.02%
==========================================
Files 409 409
Lines 38864 38919 +55
==========================================
+ Hits 23536 23564 +28
- Misses 13019 13044 +25
- Partials 2309 2311 +2
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some minor nits (mostly typos), the general idea LGTM!
// UnmarshalJSON implements the json.Unmarshaler interface. | ||
func (c *AppConfig) UnmarshalJSON(b []byte) error { | ||
// Define a new type, this is to prevent infinite recursion when | ||
// unmarshalling the AppConfig struct. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -39,6 +43,23 @@ type appConfigResponse struct { | |||
Err error `json:"error,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could Err
still be a field on appConfigResponse
? I feel like this is where it should belong, but there may be technical reasons not to put it there with the custom marshaling. Nothing critical if that's not possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
totally possible, but AFAIK, we will have to do another unmarshalling pass:
if err := json.Unmarshal(data, &r.Err); err != nil {
return err
}
what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I was gonna say outside of tests we only ever marshal that struct (since it's the response payload), but looks like it is used in service/client_appconfig.go
for fleetctl. Might not be worth the trouble.
Co-authored-by: Martin Angers <martin.n.angers@gmail.com>
} | ||
|
||
// TODO(roperzh): define and assign legacy settings to new fields. This has | ||
// the drawback of legacy fields taking precedence over new fields if both |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have to do it this way. We could assign the legacy fields if and only if the new fields are empty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's an excellent point, will adjust the related PR that actually uses this method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@michalnicp we would have to make the new fields pointers for that to work, right? I wonder if it's worth the hassle
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we make sure that when the appconfig is saved again, legacy fields are never saved (because anyway their values got transferred to the new fields), then having both new and legacy should never happen, and so this approach would be fine as-is? I believe this is what would happen with this implementation, correct me if I'm wrong (i.e. legacyConfig
is not part of AppConfig
and so would never get marshalled+saved).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that is correct, and I think I should make the comment in the code cleaner, but what I mean is that if an user specifies both a legacy config and a new config when applying a config, the legacy wins:
~/fleet $ cat /tmp/cfg.yml
apiVersion: v1
kind: config
spec:
features:
additional_queries:
- "this is new"
host_settings:
additional_queries:
- "this is old"
~/fleet $ ./build/fleetctl apply -f /tmp/cfg.yml
[+] applied fleet config
~/fleet $ ./build/fleetctl get config --json | jq '.spec.features'
{
"enable_host_users": false,
"enable_software_inventory": false,
"additional_queries": [
"this is old"
]
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see. There's this ticket we have that is coming up soon-ish: #5222
It would make a lot of sense to reject configs with legacy fields when we implement this, and that would alleviate the concern here. Of course there's still the case where the user force-applies a config, so it might still make sense to avoid the legacy-wins-over-new.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for the context on that, given that:
- if you only apply a legacy field, we're good
- if you only apply a new field, we're good
- if you apply both fields at the same time, legacy wins
the validation could be then that you can't specify both a legacy field + a new field at the same time. If despite all of that, you specify --force
, then I feel OK with this behavior as it's such an edge case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason why we should allow a legacy field at all, even if the new is not set? Keeping in mind that it's the fleet server instance that would do the validation (i.e. not fleetctl), so if the fleet instance knows that a field is legacy, it's because it knows about the new field, so there's no good reason to accept the legacy one
If despite all of that, you specify --force, then I feel OK with this behavior as it's such an edge case.
Yeah I'd agree with that too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No reason on my end! this epic specified to support both host_settings
(legacy) and features
(new) keys, but I guess that if there's an error message when you specify host_settings
we're good!
Only downside I see is that users will have to update all their configs as soon as the validation feature is implemented. Maybe we could allow both for a while? The whole deprecation/removal process definitely needs some discussion outside of both issues (this and #5222) I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely, thanks for the feedback and the example scenario, I'll make sure to discuss this with Noah when I start work on the validation part.
Co-authored-by: Martin Angers <martin.n.angers@gmail.com>
Co-authored-by: Martin Angers <martin.n.angers@gmail.com>
Co-authored-by: Martin Angers <martin.n.angers@gmail.com>
Co-authored-by: Martin Angers <martin.n.angers@gmail.com>
Related to #7312, the motivation behind these changes is to introduce a way to deprecate configurations in
AppConfig
, while still preserving backwards compatibility.From the Epic:
I will actually use this in a follow-up PR I have ready, but that's practically all noise from doing
s/host_settings/features
and I thought this deserves a conversation.Checklist for submitter
If some of the following don't apply, delete the relevant line.