-
Notifications
You must be signed in to change notification settings - Fork 452
🐛 Fix normalize {} to [] for slice defaults in CRDs #1287
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
base: main
Are you sure you want to change the base?
Conversation
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: kvaps The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
// +kubebuilder:title=DefaultedSlice | ||
DefaultedSlice []string `json:"defaultedSlice"` | ||
|
||
// +kubebuilder:default:={"md0":{"gpus":{}}} |
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.
Why would we translate {}
to []
? One is an object, the other is a list - We should likely just error out, as that is invalid.
I also am not sure if I like the idea of nesting defaulting expressions like this - I would prefer it if we would only default the map entry here and do the defaulting of the map key in its own type efinition, i.E. on the Gpus
field of the NodeProfile
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.
Why would we translate {} to []? One is an object, the other is a list - We should likely just error out, as that is invalid.
Agree
I also am not sure if I like the idea of nesting defaulting expressions like this - I would prefer it if we would only default the map entry here and do the defaulting of the map key in its own type efinition, i.E. on the Gpus field of the NodeProfile struct.
I would prefer to keep supporting both as we do today. This e.g. allows having different defaults if some part of the nested object structure is used in different places. I think there also might be different behaviors possible based on how the kube-apiserver does defaulting ("top-down"). I think we should leave that choice to our users.
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 have a case when I need to specify defaults for map[string]Object
, for example:
type ConfigSpec struct {
// Cluster addons configuration
Addons Addons `json:"addons"`
// Control Plane Configuration
ControlPlane ControlPlane `json:"controlPlane"`
// Hostname used to access the Kubernetes cluster externally. Defaults to `<cluster-name>.<tenant-host>` when empty.
Host string `json:"host"`
// Worker nodes configuration
// +kubebuilder:default:={"md0":{"ephemeralStorage":"20Gi","gpus":{},"instanceType":"u1.medium","maxReplicas":10,"minReplicas":0,"resources":{},"roles":{"ingress-nginx"}}}
NodeGroups map[string]NodeGroup `json:"nodeGroups,omitempty"`
// StorageClass used to store the data
StorageClass string `json:"storageClass"`
// Kubernetes version given as vMAJOR.MINOR. Available are versions from 1.28 to 1.33.
Version string `json:"version"`
}
type NodeGroup struct {
// Ephemeral storage size
EphemeralStorage resource.Quantity `json:"ephemeralStorage"`
// List of GPUs to attach (WARN: NVIDIA driver requires at least 4 GiB of RAM)
Gpus []Gpu `json:"gpus,omitempty"`
// Virtual machine instance type
InstanceType string `json:"instanceType"`
// Maximum amount of replicas
MaxReplicas int `json:"maxReplicas"`
// Minimum amount of replicas
MinReplicas int `json:"minReplicas"`
// Resources available to each worker node
Resources Resources `json:"resources"`
// List of node's roles
Roles []string `json:"roles,omitempty"`
}
I don't need to have defaults for every NodeGroup
added, but I need to add one NodeGroup
with example defaults if NodeGroups
is not specified
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 this is a corner case but is up to discussion
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.
Why would we translate {} to []? One is an object, the other is a list - We should likely just error out, as that is invalid.
According to the kubebuilder notaion logic:
-
{}
will be converted to{}
-
[]
will be converted to"[]"
-
{aaa}
will be converted to["aaa"]
-
{aaa:bbb}
will be converted to{"aaa":"bbb"}
-
{}
can be converted to[]
but only on a top level, nested values have not checked (before this PR)
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.
// +kubebuilder:default:={"md0":{"gpus":[]}}
yelds to string:
default:
md0:
gpus: "[]"
not to array:
default:
md0:
gpus: []
Kubebuilder annotations do not support square brackets notation.
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.
Kubebuilder annotations do not support square brackets notation.
Okay, that does seem like a bug. Will fixing this break anyone?
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.
Personally I would be super glad of using standard json arrays []
. On the other hand, I did a some research and found out that kubebuilder uses its own annotation format.
For example, if you want to default list, you'd need to specify:
// +kubebuilder:default:={1,2,3}
not
// +kubebuilder:default:=[1,2,3]
and default empty list works already as:
// +kubebuilder:default:={}
not
// +kubebuilder:default:=[]
this was introduced by
#863
this way I prepared my PR which fixes already existing notation to make it working for nested lists, instead of introducing a new format.
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.
@JoelSpeed Do you know what the syntax of existing and potentially upcoming k/k default markers is?
Can we maybe use that instead? As we want to support these anyway (We already support +default
, but I don't remember what format it supports and if that's identical to how k/k is interpreting the +default
marker)
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 don't see a default marker implemented yet, see the tag catalog, I'll raise this and see what the plans are for the new defaulting behaviour
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
4876004
to
5c175b9
Compare
PR needs rebase. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
What this fixes
Right now if you set a default with an inline object that contains a slice, and use {} as the value, the generator ends up treating it as an object instead of an empty list.
For example, if I use:
// +kubebuilder:default:={"md0":{"ephemeralStorage":"20Gi","gpus":{},"instanceType":"u1.medium","maxReplicas":10,"minReplicas":0,"resources":{},"roles":{"ingress-nginx"}}}
the generated CRD gives me:
but since gpus is a slice, what I actually want (and what users would expect) is:
What changed
Why
It’s a small thing, but it avoids confusion when writing defaults for slices. Before this patch, the CRD schema would show gpus: {}, which is wrong and makes clients unhappy. Now it consistently produces [].