-
Notifications
You must be signed in to change notification settings - Fork 71
Update schema to support oneOf, and normalize objects #72
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
Conversation
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: apelisse The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
/assign @lavalamp @kwiesmueller @jennybuckley |
typed/union.go
Outdated
| @@ -0,0 +1,130 @@ | |||
| /* | |||
| Copyright 2018 The Kubernetes Authors. | |||
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.
2019
typed/union_test.go
Outdated
| @@ -0,0 +1,224 @@ | |||
| /* | |||
| Copyright 2018 The Kubernetes Authors. | |||
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.
2019
typed/union.go
Outdated
| return set | ||
| } | ||
|
|
||
| // Set the discriminator to a specific value |
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.
get
typed/union.go
Outdated
| if union.Discriminator != nil { | ||
| df = uncapitalize(*union.Discriminator) | ||
| odv := getDiscriminatorValue(old, df) | ||
| ndv := getDiscriminatorValue(new, df) |
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.
Do we also need to uncapitalize the odv and ndv? It seems a bit kubernetes specific.
typed/union_test.go
Outdated
| unions: | ||
| - discriminator: discriminator | ||
| fields: [a, b, c] | ||
| - fields: [one, two, three]`) |
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.
Test looks good, maybe we should also try some nested structs
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.
Also we should test that creating a new object should still set the discriminator correctly
typed/union.go
Outdated
|
|
||
| for field := range ofs { | ||
| if _, ok := nfs[field]; !ok { | ||
| out.MapValue.Delete(field) |
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.
Maybe we could use the same
for _, field := range union.Fields {
if field != ndv {
out.MapValue.Delete(field)
}
}
loop from before (or a function that does that) and not worry about ofs or nfs anymore?
typed/union.go
Outdated
| } | ||
|
|
||
| if df != "" { | ||
| out.MapValue.Set(df, value.StringValue(dv)) |
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.
value.StringValue(capitalize(dv))?
schema/elements.go
Outdated
| // one or more fields in the above list. A given field from the above | ||
| // list may be referenced in exactly 0 or 1 places in the below list. | ||
| // Unions []Union `yaml:"unions,omitempty"` | ||
| Unions []Union `yaml:"unions,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.
One of the reasons this was commented out is that I wasn't sure if I wanted to do it the way you've added it, or if it would be better to use a struct per union and support embedding a list of structs. The other way would make it impossible to try and put the same field into multiple unions. I'm not sure where, but it'd be nice to see a discussion of why this format is chosen. (Maybe you have it and I haven't seen it yet.)
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 way it's going, we're only going to accept one union per structure in the OpenAPI, which would prevent any sort of overlap between fields
schema/elements.go
Outdated
| // one or more fields in the above list. A given field from the above | ||
| // list may be referenced in exactly 0 or 1 places in the below list. | ||
| // Unions []Union `yaml:"unions,omitempty"` | ||
| Unions []Union `yaml:"unions,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.
Also consider a different name, since you have to explain "Union". Maybe Exclusivities or OneOfs?
lavalamp
left a comment
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.
Super exciting change, I especially appreciate the thorough tests!
schema/elements.go
Outdated
| } | ||
|
|
||
| // Union, or oneof, means that only one of multiple fields of a structure can be | ||
| // set at all times. For backward compatibility reasons, and to help "dumb |
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.
| // set at all times. For backward compatibility reasons, and to help "dumb | |
| // set at a time. For backward compatibility reasons, and to help "dumb |
schema/elements.go
Outdated
| // set at all times. For backward compatibility reasons, and to help "dumb | ||
| // clients" that are not aware of union (or can't be aware of this because they | ||
| // don't know what fields are part of the union), the code tolerates multiple | ||
| // fields to be set but will try to detect which fields must be cleaned (there |
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.
| // fields to be set but will try to detect which fields must be cleaned (there | |
| // fields to be set but will try to detect which fields must be cleared (there |
schema/elements.go
Outdated
| // don't know what fields are part of the union), the code tolerates multiple | ||
| // fields to be set but will try to detect which fields must be cleaned (there | ||
| // should never be more than two though): | ||
| // - If the Discriminator field exist, the value of the field will be used to |
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 the Discriminator field exist, the value of the field will be used to | |
| // - If the Discriminator field exists, the value of the field will be used to |
schema/elements.go
Outdated
|
|
||
| // Union, or oneof, means that only one of multiple fields of a structure can be | ||
| // set at all times. For backward compatibility reasons, and to help "dumb | ||
| // clients" that are not aware of union (or can't be aware of this because they |
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.
| // clients" that are not aware of union (or can't be aware of this because they | |
| // clients" which are not aware of the union (or can't be aware of it, because they |
schema/elements.go
Outdated
| // fields to be set but will try to detect which fields must be cleaned (there | ||
| // should never be more than two though): | ||
| // - If the Discriminator field exist, the value of the field will be used to | ||
| // decide which field to clean and which field to keep |
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.
| // decide which field to clean and which field to keep | |
| // decide which field to clear and which field to keep |
typed/union_test.go
Outdated
| { | ||
| name: "client sends multiple with discriminator", | ||
| old: `{}`, | ||
| new: `{"a": 1, "b": 1, "discriminator": "a"}`, |
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.
I also think this should cause an 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.
Actually, the use-case in mind here is the following:
- I'm using kustomize
- my base deployment uses an emptyDir
- my overlay uses a persistent disk
- kustomize typically merges this by having both (you have to explicitely set
emptyDirtonull)
In that case, you could use the discriminator to clarify (which is much better than setting discriminator to null)
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.
It sounds like kustomize should use this library to do the merges. It'd be pretty nifty if customize produced output which had each overlay as a separate field manager.
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.
So this would mean someone could send
deploymentStrategyType: Recreate
rollingUpdate:
maxUnavailable: 1
and it would be accepted and treated as this now?
deploymentStrategyType: Recreate
rollingUpdate: {}
| name: "change discriminator, nothing else", | ||
| old: `{"discriminator": "a"}`, | ||
| new: `{"discriminator": "random"}`, | ||
| out: `{"discriminator": "random"}`, |
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.
random discriminator values should cause an error, don't 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.
I think this is similar to the one below, which is to make sure changing a DeploymentStrategyType from RollingUpdate to Recreate clears the RollingUpdate field.
Recreate isn't a name of a field in the Union but it is an allowed value of DeploymentStrategyType. If it's not allowed as a DeploymentStrategyType, I think validation outside smd could handle that kind of thing.
typed/union_test.go
Outdated
| name: "remove discriminator, nothing else", | ||
| old: `{"discriminator": "a", "a": 1}`, | ||
| new: `{"a": 1}`, | ||
| out: `{"a": 1}`, |
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.
I guess I would have expected a to be cleared also--not 100% sure.
typed/union_test.go
Outdated
| { | ||
| name: "new object has three of same union set", | ||
| old: `{"a": 1}`, | ||
| new: `{"a": 2, "b": 1, "c": 3}`, |
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 should cause an error, 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.
I think this would cause an error outside smd as well
typed/union_test.go
Outdated
| { | ||
| name: "old object has two of same union set", | ||
| old: `{"a": 1, "b": 2}`, | ||
| new: `{"a": 2, "b": 1}`, |
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.
I'd like a test case exactly like this except only one of the values changes.
schema/elements.go
Outdated
| // parent structure. Discriminator (if oneOf has one), is NOT included | ||
| // in this list. The value for field is how we map the name of the field | ||
| // to actual value for discriminator. | ||
| Fields map[string]string `yaml:"fields,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.
can a value be mapped to from multiple keys?
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.
Also maybe this should be a list, since we use lists in all the other schema pieces
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.
Also maybe this should be a list, since we use lists in all the other schema pieces
Good point
can a value be mapped to from multiple keys?
No, it shouldn't. The part that converts the openapi into this schema is going to verify that this is not possible. If it still happens that we have two mappings going to the same key, it will probably use the last one in the list.
4f934de to
ceb39c1
Compare
schema/elements.go
Outdated
| FieldName string `yaml:"fieldName"` | ||
| // DiscriminatedBy is the value of the discriminator to select that | ||
| // field. | ||
| DiscriminatedBy string `yaml:"DiscriminatedBy"` |
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.
What would this field be set to in the case of Unions that don't have a discriminator?
schema/elements.go
Outdated
| Discriminator *string `yaml:"discriminator,omitempty"` | ||
|
|
||
| // This is the list of fields that belong to this union. This fields are | ||
| // required to not be part of another union, or be the discriminator for |
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.
Only one union now
|
Fixed |
Normalization can return errors if something very wrong is happening, like setting two new fields, or if setting a new field while also changing the discriminator.
|
/lgtm |
|
I forgot to cc @sttts, I'll happily update code based on your comments Stefan! |
This does mostly two things:
And adds tests. This is still not plugged anyway though, so it's not going to do anything.