Skip to content
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 support for empty maps or lists #863

Merged

Conversation

Danil-Grigorev
Copy link
Member

Fixes: #550

This PR adds support for kubebuilder:default={} type of annotations in controller tools.

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Nov 23, 2023
@k8s-ci-robot k8s-ci-robot added the size/XS Denotes a PR that changes 0-9 lines, ignoring generated files. label Nov 23, 2023
@JoelSpeed
Copy link
Contributor

What is the motivation here, it's unclear to me why you'd want to default to an empty struct?
What happens if there are defaults defined within the struct that is being defaulted to empty?
What happens if there are required fields in the struct that is being defaulted to empty?

@Danil-Grigorev
Copy link
Member Author

Danil-Grigorev commented Nov 24, 2023

The motivation here is to fix a small bug here.

  1. Empty default for a map/struct is a subset of a default with some specified values. {a: b} should work the same way as {}.
  2. This would result in an empty field present in the resource. Like status: {}. Useful when a serialized version of the resource is sent as an input (data) for some other request.
  3. Any type of default here is contradictory I think.

This is more wasteful to the storage space, but if this is needed, controller-gen would support this.

@sttts
Copy link
Contributor

sttts commented Nov 24, 2023

You must default to an empty object to activate the defaults deep in the object. This is intentionally the way this works in CRDs. Compare https://github.com/kube-bind/kube-bind/blob/main/deploy/patches/kube-bind.io_apiserviceexportrequests.yaml-patch.

@JoelSpeed
Copy link
Contributor

You must default to an empty object to activate the defaults deep in the object. This is intentionally the way this works in CRDs. Compare https://github.com/kube-bind/kube-bind/blob/main/deploy/patches/kube-bind.io_apiserviceexportrequests.yaml-patch.

This is kinda what I was looking for, some proof that defaulting to the empty object would allow recursive defaults to work. I wasn't sure if that's how the API server worked or not. As we have an example of that, I have no objection to fixing this bug.

@JoelSpeed
Copy link
Contributor

I think we should update the cronjob types and the tests that rely on them to cover this case at the integration layer as well

@Danil-Grigorev Danil-Grigorev force-pushed the support-empty-maps-lists branch from 681f4d1 to 000c63f Compare November 24, 2023 13:31
@k8s-ci-robot k8s-ci-robot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. and removed size/XS Denotes a PR that changes 0-9 lines, ignoring generated files. labels Nov 24, 2023
@Danil-Grigorev
Copy link
Member Author

Added a test case in the cronjobs testdata, hope this look good.

@@ -297,6 +309,11 @@ type MinMaxObject struct {
Baz string `json:"baz,omitempty"`
}

type EmpiableObject struct {
Foo string `json:"foo,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a default to the field so that we can prove that the empty default on the parent triggers the inner field to be defaulted.

Copy link
Member Author

Choose a reason for hiding this comment

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

So with a modified version of CRD, where only these 2 new fields are present, this is how the applied CR looks like:

kind: CronJob
apiVersion: testdata.kubebuilder.io/v1
metadata:
  name: test
  namespace: default
spec: {}

results in

apiVersion: testdata.kubebuilder.io/v1
kind: CronJob
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"testdata.kubebuilder.io/v1","kind":"CronJob","metadata":{"annotations":{},"name":"test","namespace":"default"},"spec":{}}
  creationTimestamp: "2023-11-24T16:21:31Z"
  generation: 1
  name: test
  namespace: default
  resourceVersion: "23165"
  uid: d86f95e1-54be-4e04-b789-cb997bc3dd17
spec:
  defaultedEmptyObject:
    foo: forty-two
  defaultedEmptySlice: []

Copy link
Member Author

Choose a reason for hiding this comment

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

@JoelSpeed Do you think all the comments are addressed? This is quite useful functionality, and it would be best to avoid manually patching resource, and rely on the annotation instead.

@@ -120,6 +120,18 @@ type CronJobSpec struct {
// +kubebuilder:example={{nested: {foo: "baz", bar: true}},{nested: {bar: false}}}
DefaultedObject []RootObject `json:"defaultedObject"`

// This tests that empty slice defaulting can be performed.
// +kubebuilder:default={}
Copy link
Contributor

Choose a reason for hiding this comment

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

Is {} a valid default for slice?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good question, this needs to be fixed. CRD does not complain for deafult: [] though

Copy link
Member Author

Choose a reason for hiding this comment

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

Everything is fixed in the current commit.

Copy link
Contributor

Choose a reason for hiding this comment

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

image

It seems like {} is the correct syntax for an empty array.

Copy link
Member

Choose a reason for hiding this comment

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

This is strange. But I guess fine given it's not JSON but our custom syntax (?)

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree it's strange, but too late to change it now? Probably a reason for not using the obvious [] for arrays in marker syntax?

Copy link
Member

Choose a reason for hiding this comment

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

Yup seems definitely too late to change it now. Given that non-empty arrays worked already in the past :)

@Danil-Grigorev Danil-Grigorev force-pushed the support-empty-maps-lists branch from 000c63f to 5af596e Compare November 24, 2023 14:53
Copy link
Contributor

@erikgb erikgb left a comment

Choose a reason for hiding this comment

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

Thanks @Danil-Grigorev! This looks like an important fix to me.

/lgtm

@@ -120,6 +120,18 @@ type CronJobSpec struct {
// +kubebuilder:example={{nested: {foo: "baz", bar: true}},{nested: {bar: false}}}
DefaultedObject []RootObject `json:"defaultedObject"`

// This tests that empty slice defaulting can be performed.
// +kubebuilder:default={}
Copy link
Contributor

Choose a reason for hiding this comment

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

image

It seems like {} is the correct syntax for an empty array.

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Dec 5, 2023
@JoelSpeed
Copy link
Contributor

/lgtm

Thanks @Danil-Grigorev

@joelanford
Copy link
Member

/approve

Thanks!

@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: Danil-Grigorev, joelanford

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Dec 6, 2023
@k8s-ci-robot k8s-ci-robot merged commit 72d3440 into kubernetes-sigs:master Dec 6, 2023
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cannot use an empty map with kubebuilder:default marker
7 participants