Skip to content

Fake client does not delete objects containing deletion timestamp #2184

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

Closed
lleshchi opened this issue Feb 7, 2023 · 7 comments · Fixed by #2316
Closed

Fake client does not delete objects containing deletion timestamp #2184

lleshchi opened this issue Feb 7, 2023 · 7 comments · Fixed by #2316
Assignees
Labels
kind/bug Categorizes issue or PR as related to a bug. lifecycle/active Indicates that an issue or PR is actively being worked on by a contributor.
Milestone

Comments

@lleshchi
Copy link
Contributor

lleshchi commented Feb 7, 2023

The fake client Get(), List(), Patch() methods do not account for objects that have been marked for deletion, allowing for viewing of and changes to objects that are expected to be deleted. The Update() method does delete the object, but I believe it should return an error, since the update of a deleted object has failed.

This is a separate issue from #138

@2uasimojo
Copy link
Contributor

The Update() method does delete the object, but I believe it should return an error, since the update of a deleted object has failed.

So actually there are two possibilities here:

  • If this Update() removed the last finalizer(s), then the current behavior is correct. However...
  • If there were no finalizers before this Update() was called, we should simulate gc having happened prior to the Update() and error NotFound.

Glancing at the code, it should be easy enough to make this distinction:

if len(oldAccessor.GetFinalizers()) > 0 && len(accessor.GetFinalizers()) == 0 {

@alvaroaleman
Copy link
Member

How did you get an object with a non-nil deletionTimestamp into the fakeclient in the first place?

@lleshchi
Copy link
Contributor Author

Hi @alvaroaleman, we use WithRuntimeObjects() here to add a DeletionTimestamp. Since the k8s api does not allow a user to add a deletion timestamp when creating an object, and ignores attempts to add/edit the timestamp, perhaps the fake client should handle deletion timestamps similarly, in order to prevent tests such as the one above.

@2uasimojo
Copy link
Contributor

Right, so to expand on this:

In general we want to be able to test reconciler behavior on deleted objects. With the fake client as it stands, we've been able to write test cases where we just init the fake client With[Runtime]Objects() that have deletionTimestamp set, but no finalizers -- which is not a valid state in real k8s (ignoring delete propagation, which we're not looking to solve here).

The argument of this issue is that test authors should be disallowed from getting into this state, as it throws the validity of the test case into question.

Originally we were thinking that the fake client should just stealthily treat those objects the way k8s would: by deleting them from the database any time it sees them. But your comment has made us discuss and realize that it would be better to prevent getting into that situation at all. So I think we're now proposing:

  • Reader methods (Get(), List()) remain unchanged.
  • Update() and Patch() should reject changes that set a previously-unset deletionTimestamp, like real k8s does.
  • Create() should ignore a deletionTimestamp on an object, like real k8s does. (This doesn't seem ideal as it may be tough for test authors to figure out what broke when they upgrade their fake client to include this fix -- but getting closer to parity with real k8s is the only thing that makes sense. IDK if there's a way for the fake client to generate a warning message?)
  • The builder should error if initialized with an object that has a deletionTimestamp but no finalizers; but accept a deleted object (including keeping its deletionTimestamp set) if it has finalizers.

That last bullet is important: We don't have equivalent k8s behavior to guide us, so we have the freedom to make it as useful as possible for test writers. If the builder ignored deletionTimestamp like Create(), test authors would need to explicitly Delete() the object after building. In table-driven tests like the ones hive uses, that would often/usually entail adding a field to the test config struct telling the driver to issue the Delete(). And if the test relies on multiple objects being deleted, that would need to be done for each. Also, this behavior change would be difficult to understand when upgrading the fake client to include this change. Whereas if we throw an error, we can make it nice and descriptive: "Refusing to initialize with an object that has a deletionTimestamp but no finalizers. You must either include one or more finalizers or explicitly Delete() the object via the built client."

@vincepri
Copy link
Member

vincepri commented May 8, 2023

/milestone v0.15.x

@k8s-ci-robot k8s-ci-robot added this to the v0.15.x milestone May 8, 2023
@vincepri
Copy link
Member

vincepri commented May 8, 2023

/assign @lleshchi
/lifecycle active

@k8s-ci-robot k8s-ci-robot added the lifecycle/active Indicates that an issue or PR is actively being worked on by a contributor. label May 8, 2023
@vincepri
Copy link
Member

vincepri commented May 8, 2023

/kind bug

@k8s-ci-robot k8s-ci-robot added the kind/bug Categorizes issue or PR as related to a bug. label May 8, 2023
oliviassss pushed a commit to kubernetes-sigs/aws-load-balancer-controller that referenced this issue May 24, 2024
…ernetes libs to v0.30.0 (#3707)

* go version, dep version

* refactor for controller-runtime udpate

* update tests, fix if statement

the controller-runtime strips DeletionTimestamp from manifests on
Create(). kubernetes-sigs/controller-runtime#2316

* refactor tests

* remove placeholder comments

* remove reconciler from WithOptions

* remove DefaultNamespace cache option

* remote `&& !hasGroupFinalizer`

This was causing e2e tests to fail when an ingress did not have the
group finalizer. The unit tests ing-1_been_deleted, and ing-6_been_deleted
will need reworked due to changes in the controller-runtime that cause
them to fail.

* update unit tests for ctrl client/fake >0.15

controller-runtime >=0.15 does not support creating (or adding the field via Update()) objects with a DeletionTimestamp. To work around this we add an annotation `unit-test/delete` to mark the ingresses that we want to test deletion. We check for this annotation and then call Delete(). This will set the DeletionTimestamp to the current date and time so we use IgnoreOtherFields to skip then comparing want to got.

relevant controller-runtime discussion/pr:

- kubernetes-sigs/controller-runtime#2184 (comment)
- kubernetes-sigs/controller-runtime#2316

* remove unused contexts

* add DefaultNamespaces cache config

* set opt.Cache.DefaultNamespaces conditionally

If WatchNamespace is set to corev1.NamespaceAll we should not set
DefaultNamespaces.

This code assumes that only one namespace is specified for
WatchNamespace. That decision was based on the help text for the flag
`watch-namespace`.

Related controller-runtime issue: kubernetes-sigs/controller-runtime#2628

* make crds

* set go to v1.22.3
oliviassss pushed a commit to oliviassss/aws-load-balancer-controller that referenced this issue May 30, 2024
…ernetes libs to v0.30.0 (kubernetes-sigs#3707)

* go version, dep version

* refactor for controller-runtime udpate

* update tests, fix if statement

the controller-runtime strips DeletionTimestamp from manifests on
Create(). kubernetes-sigs/controller-runtime#2316

* refactor tests

* remove placeholder comments

* remove reconciler from WithOptions

* remove DefaultNamespace cache option

* remote `&& !hasGroupFinalizer`

This was causing e2e tests to fail when an ingress did not have the
group finalizer. The unit tests ing-1_been_deleted, and ing-6_been_deleted
will need reworked due to changes in the controller-runtime that cause
them to fail.

* update unit tests for ctrl client/fake >0.15

controller-runtime >=0.15 does not support creating (or adding the field via Update()) objects with a DeletionTimestamp. To work around this we add an annotation `unit-test/delete` to mark the ingresses that we want to test deletion. We check for this annotation and then call Delete(). This will set the DeletionTimestamp to the current date and time so we use IgnoreOtherFields to skip then comparing want to got.

relevant controller-runtime discussion/pr:

- kubernetes-sigs/controller-runtime#2184 (comment)
- kubernetes-sigs/controller-runtime#2316

* remove unused contexts

* add DefaultNamespaces cache config

* set opt.Cache.DefaultNamespaces conditionally

If WatchNamespace is set to corev1.NamespaceAll we should not set
DefaultNamespaces.

This code assumes that only one namespace is specified for
WatchNamespace. That decision was based on the help text for the flag
`watch-namespace`.

Related controller-runtime issue: kubernetes-sigs/controller-runtime#2628

* make crds

* set go to v1.22.3
oliviassss added a commit to kubernetes-sigs/aws-load-balancer-controller that referenced this issue May 30, 2024
* update the traffic test for ingress (#3725)

* update the traffic test for ingress

* make crds

* prevent controller runtime complaining about SetupLogger() was never called (#3724)

* Update go to v1.22, controller-runtime dependency to v0.18.2, and kubernetes libs to v0.30.0 (#3707)

* go version, dep version

* refactor for controller-runtime udpate

* update tests, fix if statement

the controller-runtime strips DeletionTimestamp from manifests on
Create(). kubernetes-sigs/controller-runtime#2316

* refactor tests

* remove placeholder comments

* remove reconciler from WithOptions

* remove DefaultNamespace cache option

* remote `&& !hasGroupFinalizer`

This was causing e2e tests to fail when an ingress did not have the
group finalizer. The unit tests ing-1_been_deleted, and ing-6_been_deleted
will need reworked due to changes in the controller-runtime that cause
them to fail.

* update unit tests for ctrl client/fake >0.15

controller-runtime >=0.15 does not support creating (or adding the field via Update()) objects with a DeletionTimestamp. To work around this we add an annotation `unit-test/delete` to mark the ingresses that we want to test deletion. We check for this annotation and then call Delete(). This will set the DeletionTimestamp to the current date and time so we use IgnoreOtherFields to skip then comparing want to got.

relevant controller-runtime discussion/pr:

- kubernetes-sigs/controller-runtime#2184 (comment)
- kubernetes-sigs/controller-runtime#2316

* remove unused contexts

* add DefaultNamespaces cache config

* set opt.Cache.DefaultNamespaces conditionally

If WatchNamespace is set to corev1.NamespaceAll we should not set
DefaultNamespaces.

This code assumes that only one namespace is specified for
WatchNamespace. That decision was based on the help text for the flag
`watch-namespace`.

Related controller-runtime issue: kubernetes-sigs/controller-runtime#2628

* make crds

* set go to v1.22.3

* restrict resolve resolveViaVPCENIs to fargate only (#3709)

* Added helm envFrom value parameter for cluster-name (#3683)

* Added helm envFrom value parameter for cluster-name

* Update README.md file

* Add envFrom configuration to values.yaml

* Remove empty line in values.yaml

* feat: disable default helm labels (#3574)

* feat: disable helm labels

* fix: doc

* Update README.md (#3638)

Remove extra / in crds

---------

Co-authored-by: Luke Arntz <[email protected]>
Co-authored-by: Omer Aplatony <[email protected]>
Co-authored-by: Rémi BUISSON <[email protected]>
Co-authored-by: Mike Wilson <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Categorizes issue or PR as related to a bug. lifecycle/active Indicates that an issue or PR is actively being worked on by a contributor.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants