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

CRs: Default non-nullable nulls #95423

Merged
merged 1 commit into from Nov 7, 2020

Conversation

apelisse
Copy link
Member

@apelisse apelisse commented Oct 8, 2020

What type of PR is this?
/kind feature

What this PR does / why we need it:

Which issue(s) this PR fixes:

Special notes for your reviewer:

Does this PR introduce a user-facing change?:

CRDs: For structural schemas, non-nullable null map fields will now be dropped and defaulted if a default is available. null items in list will continue being preserved, and fail validation if not nullable.

Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.:


@k8s-ci-robot k8s-ci-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. release-note Denotes a PR that will be considered when it comes time to generate release notes. kind/feature Categorizes issue or PR as related to a new feature. size/M Denotes a PR that changes 30-99 lines, ignoring generated files. needs-sig Indicates an issue or PR lacks a `sig/foo` label and requires one. needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. needs-priority Indicates a PR lacks a `priority/foo` label and requires one. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. labels Oct 8, 2020
@k8s-ci-robot k8s-ci-robot added sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. and removed needs-sig Indicates an issue or PR lacks a `sig/foo` label and requires one. labels Oct 8, 2020
@apelisse
Copy link
Member Author

apelisse commented Oct 8, 2020

/assign @sttts @liggitt

@fedebongio
Copy link
Contributor

/triage accepted

@k8s-ci-robot k8s-ci-robot added triage/accepted Indicates an issue or PR is ready to be actively worked on. and removed needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. labels Oct 15, 2020
} else if s.AdditionalProperties != nil {
Default(v, s.AdditionalProperties.Structural)
if isNonNullableNull(x[k], s.AdditionalProperties.Structural) {
x[k] = runtime.DeepCopyJSONValue(s.AdditionalProperties.Structural.Default.Object)
Copy link
Contributor

Choose a reason for hiding this comment

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

you don't check that there is a default.

Copy link
Member Author

Choose a reason for hiding this comment

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

Does it matter? At that point, we know that x[k] is null, then that's going to reset it to null? That's a no-op.

Copy link
Member

Choose a reason for hiding this comment

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

don't we need to check if s.AdditionalProperties.Structural is non-nil so we don't panic? if so, add a unit test that would have caught this

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah good point

@k8s-ci-robot k8s-ci-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Nov 2, 2020
@apelisse
Copy link
Member Author

apelisse commented Nov 2, 2020

Updated, still missing some higher-level tests specifically.

@@ -1251,6 +1252,7 @@ func (v *unstructuredSchemaCoercer) apply(u *unstructured.Unstructured) error {
// TODO: switch over pruning and coercing at the root to schemaobjectmeta.Coerce too
structuralpruning.Prune(u.Object, v.structuralSchemas[gv.Version], false)
}
structuraldefaulting.PruneNulls(u.Object, v.structuralSchemas[gv.Version])
Copy link
Contributor

Choose a reason for hiding this comment

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

why not inside the if statement?

Copy link
Contributor

Choose a reason for hiding this comment

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

Now I am pretty sure we want this only for !v.preserveUnknownFields.

Copy link
Member Author

Choose a reason for hiding this comment

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

Now I am pretty sure we want this only for !v.preserveUnknownFields.

I'm trying to understand why. Clearly, unknownfields don't have a schema, so basically, they're always non-nullable non-defaulted, so all the nulls would be dropped. But I don't see why that's a problem, or consistent with what we're doing?

Copy link
Member

Choose a reason for hiding this comment

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

unknownfields don't have a schema, so basically, they're always non-nullable non-defaulted

I don't think that's true... with no schema, we allow any value, including null, so they are nullable non-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.

Ah, that's a good point. My perspective has been that "nullable" is false by default, so a lack of schema would imply non-nullable.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, good, that's what I expected.

Copy link
Member Author

Choose a reason for hiding this comment

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

OK fixed!

Copy link
Contributor

Choose a reason for hiding this comment

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

I consider the non-structural case as legacy we will never ever touch again. Hence, only change pruning of nulls in the if.

Copy link
Contributor

Choose a reason for hiding this comment

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

As @apelisse found in our validation (he was 2s faster than me):

		if spec.PreserveUnknownFields == nil || *spec.PreserveUnknownFields == true {
			allErrs = append(allErrs, field.Invalid(fldPath.Child("preserveUnknownFields"), true, "must be false in order to use defaults in the schema"))
		}

We forbid defaulting for preserveUnknownFields:true. Hence, pruning some nulls without defaulting would be confusing.

Copy link
Member Author

Choose a reason for hiding this comment

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

@liggitt
Copy link
Member

liggitt commented Nov 6, 2020

/approve
/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Nov 6, 2020
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: apelisse, liggitt

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 Nov 6, 2020
@apelisse
Copy link
Member Author

apelisse commented Nov 7, 2020

/priority important-soon
/retest

@k8s-ci-robot k8s-ci-robot added priority/important-soon Must be staffed and worked on either currently, or very soon, ideally in time for the next release. and removed needs-priority Indicates a PR lacks a `priority/foo` label and requires one. labels Nov 7, 2020
@k8s-ci-robot k8s-ci-robot merged commit 9253aa9 into kubernetes:master Nov 7, 2020
@k8s-ci-robot k8s-ci-robot added this to the v1.20 milestone Nov 7, 2020
howardjohn added a commit to howardjohn/istio that referenced this pull request Dec 3, 2020
Kubernetes 1.20 tests are currently broken, since our old invalid config
is now considered valid (see
kubernetes/kubernetes#95423). In fixing this, I
realized we don't have any validation for WorkloadGroup! This adds
validation, by applying the same validation WorkloadEntry has to the
template of workload group. However, workload entry validation is pretty
much nil, so this change isn't very beneficial beyond getting tests
passing.
istio-testing pushed a commit to istio/istio that referenced this pull request Dec 3, 2020
* Add validation for workload group

Kubernetes 1.20 tests are currently broken, since our old invalid config
is now considered valid (see
kubernetes/kubernetes#95423). In fixing this, I
realized we don't have any validation for WorkloadGroup! This adds
validation, by applying the same validation WorkloadEntry has to the
template of workload group. However, workload entry validation is pretty
much nil, so this change isn't very beneficial beyond getting tests
passing.

* gen

* fixes

* Update

* fmt
howardjohn added a commit to howardjohn/istio that referenced this pull request Feb 25, 2021
* Add validation for workload group

Kubernetes 1.20 tests are currently broken, since our old invalid config
is now considered valid (see
kubernetes/kubernetes#95423). In fixing this, I
realized we don't have any validation for WorkloadGroup! This adds
validation, by applying the same validation WorkloadEntry has to the
template of workload group. However, workload entry validation is pretty
much nil, so this change isn't very beneficial beyond getting tests
passing.

* gen

* fixes

* Update

* fmt

(cherry picked from commit 6e649ab)
istio-testing pushed a commit to istio/istio that referenced this pull request Feb 26, 2021
* Add validation for workload group (#29355)

* Add validation for workload group

Kubernetes 1.20 tests are currently broken, since our old invalid config
is now considered valid (see
kubernetes/kubernetes#95423). In fixing this, I
realized we don't have any validation for WorkloadGroup! This adds
validation, by applying the same validation WorkloadEntry has to the
template of workload group. However, workload entry validation is pretty
much nil, so this change isn't very beneficial beyond getting tests
passing.

* gen

* fixes

* Update

* fmt

(cherry picked from commit 6e649ab)

* fix extra file
Pothulapati added a commit to linkerd/linkerd2 that referenced this pull request Jun 16, 2021
Currently, Whenever a `SP` is created with `Spec.Routes`
field not being set from [golang types](https://github.com/linkerd/linkerd2/blob/main/controller/gen/apis/serviceprofile/v1alpha2/types.go#L13)
, k8s API rejects them with the following error

```bash
ServiceProfile.linkerd.io \"backend-svc.linkerd-smi-app.svc.cluster.local\" is invalid: spec.routes: Invalid value: \"null\": spec.routes in body must be of type array: \"null\"
```

This happens because, Golang automatically renders them it as
`Routes: Null` whenever it marshalled into json. This is rejected by
 k8s API server as it expects that field to be an array.

[**This is fixed in k8s >= 1.20**](kubernetes/kubernetes#95423)
as non-nullable nulls are defaulted, and hence this error happens only
in `<=1.19`.

As `1.19` is a pretty recent version of k8s, and things like
[smi-adaptor](https://github.com/linkerd/linkerd-smi/pull) may not
want to manage and make sure `Spec.Routes` is not null
all the time.

This can be easily be fixed by marking `Spec.Routes` as `omitempty` in
its json tagswhich means that the field is omitted whenever it is not
set while being marshalled.

This means that the k8s API won't error out, as that field isn't
set to anything invalid.

Signed-off-by: Tarun Pothulapati <tarunpothulapati@outlook.com>
Pothulapati added a commit to linkerd/linkerd2 that referenced this pull request Jun 17, 2021
## Context

Currently, Whenever a `SP` is created with `Spec.Routes` field not being set from [golang types](https://github.com/linkerd/linkerd2/blob/main/controller/gen/apis/serviceprofile/v1alpha2/types.go#L13), k8s API rejects them with the following error

```bash
ServiceProfile.linkerd.io \"backend-svc.linkerd-smi-app.svc.cluster.local\" is invalid: spec.routes: Invalid value: \"null\": spec.routes in body must be of type array: \"null\"
```

This happens because, Golang automatically renders them it as `Routes: Null` whenever it marshaled into json. This is rejected by k8s API server as it expects that field to be an array.

[This is fixed in k8s >= 1.20](kubernetes/kubernetes#95423) as non-nullable nulls are defaulted, and hence this error happens only in `<=1.19`.

## Problem

As `1.19` is a pretty recent version of k8s, and things like [smi-adaptor](https://github.com/linkerd/linkerd-smi/pull) may not want to manage and make sure `Spec.Routes` is not null all the time.

## Fix

This can be easily be fixed by marking `Spec.Routes` as `omitempty` in its json tags which means that the field is omitted whenever it is not set while being marshaled.

This means that the k8s API won't error out, as that field isn't set to anything invalid.

Signed-off-by: Tarun Pothulapati <tarunpothulapati@outlook.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-review Categorizes an issue or PR as actively needing an API review. 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. kind/feature Categorizes issue or PR as related to a new feature. lgtm "Looks good to me", indicates that a PR is ready to be merged. priority/important-soon Must be staffed and worked on either currently, or very soon, ideally in time for the next release. release-note Denotes a PR that will be considered when it comes time to generate release notes. sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. triage/accepted Indicates an issue or PR is ready to be actively worked on.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants