-
Notifications
You must be signed in to change notification settings - Fork 128
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
feat: add entities defaults from their schemas #573
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #573 +/- ##
==========================================
- Coverage 51.15% 51.06% -0.10%
==========================================
Files 73 73
Lines 8009 8139 +130
==========================================
+ Hits 4097 4156 +59
- Misses 3542 3605 +63
- Partials 370 378 +8 ☔ View full report in Codecov by Sentry. |
file/builder.go
Outdated
@@ -551,6 +551,9 @@ func (b *stateBuilder) services() { | |||
} | |||
|
|||
func (b *stateBuilder) ingestService(s *FService) error { | |||
if err := b.addEntityDefaults("services", &s.Service); err != nil { | |||
return fmt.Errorf("add defaults to service '%v': %v", *s.Name, err) | |||
} |
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.
See line below:
b.defaulter.MustSet(&s.Service)
Can we please keep the defaulting logic in the defaulter?
Take "Defaulter" as an input to StateBuilder if that is required.
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.
This is looking much better.
With the change, I'm requesting here (prioritized defaults), this can get a bit more complex but the complexity should be hidden in the "Deafulter".
file/builder.go
Outdated
b.defaulter, err = defaulter(kongDefaults) | ||
if err != nil { | ||
return nil, nil, fmt.Errorf("creating defaulter: %w", err) | ||
} |
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 KongDefaults thing hasn't been around for long enough and most users won't fill it in.
We should have a precedence order here:
- Take an entity, populate fields take first priority
- Fill defaults as present in KongDefaults
- Fill defaults via the API
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.
A couple of comments after my last commit:
- this change makes the hardcoded defaults in
deck
obsolete, so I'm removing them here - which means I had to adapt a bit the tests too. I moved the "old" default objects inside the test files in order to minimize the changes on tests, since we are already changing a lot of code. This should keep confidence of changes higher
let me know what you think!
452b037
to
bcbe6f6
Compare
@rainest This is a high-risk change. Could you please review and test this change? |
Loading the branch into the ingress controller and running integration tests surfaced one issue--possibly more, but they're not obvious (the same tests fail repeatedly, but there's no schema violation shown). Some entities are effectively several different entities under a trench coat, and those sub-entities can swap out different parts of the parent schema as they choose. Routes use and require a different default for
to the example route in the OP, you get
It doesn't look like anything other than routes exhibits that problem (at least as far as file naming--nothing else has a Checking further on the other things that failed (mostly UDP routes). |
Other KIC failures are poorly-configured timeouts on our end and can be ignored. For actual deck usage the only thing that comes to mind is the existing defaults system, and this is apparently overriding that. After syncing test1.yaml.txt with current main, syncing again with this branch overwrites the value from the manifest default:
That seems unwanted, since the defaults in the manifest are user-specified, and should take precedence as such. Other than that and base functionality (which seems fine), are there any other feature interactions we'd want to review? Tangentially, why the heck does syncing test2.yaml.txt just delete everything with the defaults in place? If you remove that block, it syncs the resources normally (excluding the invalid route). This happens on current main also, it's not something this branch broke. |
Apparently |
Actually, the manifest default is supported here, and it takes precedence over schemas defaults:
What's happening in your case is that current version of Would you mind testing this again? I just pushed a commit updating go-kong from this Kong/go-kong#125 , which is a patch that will enable us to fix this and other related issues. Note: we can do the dependency update on another PR to not make this too big, but let's first test and validate the whole package if possible |
b67f04d
to
4a70657
Compare
Works for me with the change, and importing the modified into KIC didn't trigger any test failures, so Kong/go-kong#126 |
9609b41
to
f6d2719
Compare
@hbagdi @rainest I made few changes to make sure to achieve the following order of precedence:
Let me know what you think! |
We'd very much like to avoid having all users set It looks like we can work around the non-standard schema behavior by having a conditional in the middle of ingestRoute(): after running Prior to setting the defaults, we should have the same condition check if there's a user-set |
@rainest can you please check the last commit? I added a patch to handle the case you mentioned. |
With the latest changes, automated KIC tests pass without modification, so we're good from my perspective: https://github.com/Kong/kubernetes-ingress-controller/runs/5102116046?check_suite_focus=true |
file/builder.go
Outdated
kongDefaults = b.targetContent.Info.Defaults | ||
} | ||
b.defaulter, err = defaulter(kongDefaults) | ||
defaulter, err := defaulter(b.ctx, b.client, b.targetContent, b.isKonnect) |
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.
Not in scope but we really need to pas the defaulter as an input to rather than constructing 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.
The only reason I did it so is to avoid duplicating the same exact lines for Kong and Konnect
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.
Separation of concern takes priority over superficial duplication here because it is worth the complexity that will be removed once this is moved out will help test and maintain code.
utils/defaulter.go
Outdated
func GetKongDefaulter() (*Defaulter, error) { | ||
var d Defaulter | ||
err := d.Register(&serviceDefaults) | ||
func GetKongDefaulter(kongDefaults interface{}, isKonnect bool) (*Defaulter, error) { |
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.
Take input DefaulterOpts with these two.
Rename isKonnect to disableDynamicDefaults
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.
done
utils/defaulter.go
Outdated
// 3. schema defaults coming from Admin API (excluded Konnect) | ||
// 4. hardcoded defaults under utils/constants.go (Konnect-only) | ||
func GetDefaulter( | ||
ctx context.Context, client *kong.Client, kongDefaults interface{}, isKonnect bool, |
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.
Take in all args as options, except ctx.
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.
done
utils/defaulter.go
Outdated
if client != nil && !isKonnect { | ||
return getKongDefaulterWithClient(ctx, client, kongDefaults) | ||
} | ||
return GetKongDefaulter(kongDefaults, isKonnect) |
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.
Can we only export a single method - either this or the parent one? KISS - keep it simple silly.
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.
done
@@ -52,7 +52,7 @@ func testKongState( | |||
t.Errorf(err.Error()) | |||
} | |||
opt := []cmp.Option{ | |||
cmpopts.IgnoreFields(kong.Service{}, "ID", "CreatedAt", "UpdatedAt"), | |||
cmpopts.IgnoreFields(kong.Service{}, "ID", "CreatedAt", "UpdatedAt", "Enabled"), |
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.
code smell: we will have new properties being defined all the time. Our tests should handle these.
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 will take care of this in the other "test" PR along with other test-related changes.
5a0a28a
to
3bb2182
Compare
Today deck populates entities defaults defining them as part of the Defaulter utility. This PR introduces the ability to pull the schema of an entity from the Admin API and to add its defaults from there. What this PR doesn't do is change a thing on Defaulter. A refactoring PR will follow.
3bb2182
to
e9d0bfd
Compare
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.
Please merge with approval from @rainest
return initialStripPath, nil | ||
} | ||
return kong.Bool(false), nil | ||
} |
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.
Question: If strip path can't be set when protocol is grpc, why return false on the two returns above?
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.
strip_path
is a required field, so when protocol is grpc it needs to be set to false
(true
being the schema default)
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.
for _, p := range route.Protocols {
if *p == "grpc" || *p == "grpcs" {
if stripPath != nil { return nil, fmt.Errorf("strip path not allowed")
return kong.Bool(false), nil
}
}
Is that not sufficient?
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.
Not directly...I just reworked/cleaned a bit the code to have something like you are suggesting (67d1dcc)
Pull entity schemas from the admin API to fill in their default values rather than using default values in the deck codebase.
Today deck populates entities defaults defining them as part
of the Defaulter utility. This PR introduces the ability
to pull the schema of an entity from the Admin API and to
add its defaults from there.
What this PR doesn't do is change a thing on Defaulter.
A refactoring PR will follow.
This needs Kong/go-kong#119
before this change: deck keep showing diffs for unfilled defaults
after this change: all defaults are added