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

Respect controllers on PVCs for retention policy #122499

Merged
merged 1 commit into from
Jun 7, 2024

Conversation

mattcary
Copy link
Contributor

@mattcary mattcary commented Dec 27, 2023

/kind bug

Fixes #122400

/assign @msau42

StatefulSet autodelete will respect controlling owners on PVC claims as described in https://github.com/kubernetes/enhancements/pull/4375

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

@k8s-ci-robot k8s-ci-robot added the release-note Denotes a PR that will be considered when it comes time to generate release notes. label Dec 27, 2023
@k8s-ci-robot k8s-ci-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. kind/bug Categorizes issue or PR as related to a bug. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. do-not-merge/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. labels Dec 27, 2023
@mattcary
Copy link
Contributor Author

/sig apps
/priority-soon

@k8s-ci-robot k8s-ci-robot added sig/apps Categorizes an issue or PR as relevant to SIG Apps. area/test sig/testing Categorizes an issue or PR as relevant to SIG Testing. and removed do-not-merge/needs-sig Indicates an issue or PR lacks a `sig/foo` label and requires one. labels Dec 27, 2023
@mattcary
Copy link
Contributor Author

/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 Dec 27, 2023
@mattcary
Copy link
Contributor Author

/priority important-soon

@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 Dec 27, 2023
@msau42
Copy link
Member

msau42 commented Dec 28, 2023

/lgtm
/approve

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

LGTM label has been added.

Git tree hash: 3af13a5ff2cc1cd46ea27a3174fd1f2f9597b125

@carlory
Copy link
Member

carlory commented Jan 8, 2024

/assign @soltysh

Copy link
Member

@atiratree atiratree left a comment

Choose a reason for hiding this comment

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

@mattcary I found couple of problems with the current implementation

I feel that hasOwnerRef should have a bool checkController parameter. And we should not check the controller flag if we want to delete the owner ref, but we should check it if we want to introduce it / overwrite it.

I think this goes for all the cases in both claimOwnerMatchesSetAndPod and updateClaimOwnerRefForSetAndPod functions.

+ would be good to document why we are doing it

@@ -305,6 +333,7 @@ func setOwnerRef(target, owner metav1.Object, ownerType *metav1.TypeMeta) bool {
Kind: ownerType.Kind,
Name: owner.GetName(),
UID: owner.GetUID(),
Controller: ptr.To(true),
Copy link
Member

Choose a reason for hiding this comment

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

If there is already existing owner reference, this append will duplicate it. So there will be one reference without a controller and one with. Can we deduplicate it?

Copy link
Contributor Author

@mattcary mattcary Jan 16, 2024

Choose a reason for hiding this comment

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

hasOwnerRef checks that there is not an owner with the same UID, regardless of the value of the controller. Oops wait I did add that check to controller in there. Thx

Although, it occurs to me, if the StatefulSet is updated, the UID will change. So we probably want hasOwnerRef to check on api version + kind + name + namespace, which will be unique?

Copy link
Member

Choose a reason for hiding this comment

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

What do you mean by updated? Normally the UID shouldn't change and should be present and is used by the garbage collector. And if a person deletes the StatefulSet using the orphan strategy it should also remove the owner reference.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah I didn't know the ownerref was removed with the orphan strategy.

Mostly I think I got confused.

I guess the problem could be a pvc that's slow to delete, and a statefulset that's deleted and recreated (the same case the stale pod claim check deals with). In that case though a new pod won't bind to a deleted PVC, and so it should eventually delete and the statefulset controller will recreate a new PVC.

So yeah, we should just look at UIDs (except for the stale pod case).

@@ -305,6 +333,7 @@ func setOwnerRef(target, owner metav1.Object, ownerType *metav1.TypeMeta) bool {
Kind: ownerType.Kind,
Name: owner.GetName(),
UID: owner.GetUID(),
Controller: ptr.To(true),
})
target.SetOwnerReferences(ownerRefs)
return true
Copy link
Member

Choose a reason for hiding this comment

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

also removeOwnerRef seems it will not work correctly if there is an owner reference in the old format because hasOwnerRef is more strict now

Copy link
Contributor Author

Choose a reason for hiding this comment

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

+1 this will be fixed

case hasUnexpectedController(claim, set, pod):
// Do not set any ownerRefs if there is an unexpected controller.
msg := fmt.Sprintf("Claim %s has a conflicting controller, the retention policy is ignored for this claim", claimName)
spc.recorder.Event(set, v1.EventTypeWarning, "ConflictingController", msg)
Copy link
Member

Choose a reason for hiding this comment

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

also this part from the KEP seems not to be satisfied and should apply for all policy combinations:

If there is another controller, the existing non-controller StatefulSet or Pod reference will be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for taking a look at this! You make some good points.

Let's resolve the conversation on the KEP first about what the proper semantics should be, then I'll work through your comments here -- you raise some excellent points.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

argh, you are correct. Thank you.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Change is in progress. It was better to make a little more complete re-vamp of the logic to keep it from getting too complicated.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for looking at that. And yeah, there are a lot of cases that need to be covered. It would be nice to have them all covered by the tests.

@k8s-ci-robot k8s-ci-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Apr 26, 2024
@k8s-ci-robot k8s-ci-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Apr 30, 2024
Copy link
Member

@atiratree atiratree left a comment

Choose a reason for hiding this comment

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

@mattcary there are still some nits and testing considerations

// nonController returns true if the pod or set is an owner but not controller of the claim.
func nonController(claim *v1.PersistentVolumeClaim, set *apps.StatefulSet, pod *v1.Pod) bool {
for _, ownerRef := range claim.GetOwnerReferences() {
if ownerRef.UID == set.GetUID() || ownerRef.UID == pod.GetUID() {
Copy link
Member

Choose a reason for hiding this comment

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

good, although it would be better to have it reflected in the function name as well

claim := v1.PersistentVolumeClaim{}
claim.SetOwnerReferences(tc.originalRefs)
updateClaimOwnerRefForSetAndPod(logger, &claim, &set, &pod)
if ownerRefsChanged(tc.expectedRefs, claim.GetOwnerReferences()) {
Copy link
Member

Choose a reason for hiding this comment

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

Okay. In that case, I think it would be appropriate to have a unit test for the new function.

}

if hasNonController(claim, set, pod) {
return false
Copy link
Member

Choose a reason for hiding this comment

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

Some other resource besides our set or pod has an owner ref

It seems that other resources do not necessarily have to be registered as owners in the references to get to this line. That is, it can be just one owner reference (e.g. our set or pod).

BlockOwnerDeletion: ptr.To(true),
},
}
ginkgo.By("Expect claims 0 and 2 to have ownerRefs to the statefulset, and 3 to have a stale reference")
Copy link
Member

Choose a reason for hiding this comment

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

TY. Let's also change the description:

Suggested change
ginkgo.By("Expect claims 0 and 2 to have ownerRefs to the statefulset, and 3 to have a stale reference")
ginkgo.By("Expect claims 0,1 and 2 to have ownerRefs to the statefulset, and 3 to have a stale reference")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops, thx, done.

test/e2e/apps/statefulset.go Show resolved Hide resolved
@mattcary mattcary force-pushed the oref branch 3 times, most recently from fc472e6 to 8400017 Compare May 7, 2024 19:46
Copy link
Member

@atiratree atiratree left a comment

Choose a reason for hiding this comment

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

There are 2 nits, but the PR lgtm.

Nevertheless, it would be good to get another set of eyes on it.

cc @soltysh

test/e2e/apps/statefulset.go Outdated Show resolved Hide resolved
test/e2e/apps/statefulset.go Show resolved Hide resolved
@atiratree
Copy link
Member

unit test flaking due to #124526
/test pull-kubernetes-unit

Copy link
Contributor

@soltysh soltysh left a comment

Choose a reason for hiding this comment

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

A few questions and suggestions to resolve before the merge.


ginkgo.By("Remove PVC 1 owner ref")
pvc.OwnerReferences = nil
_, err = c.CoreV1().PersistentVolumeClaims(ns).Update(ctx, pvc, metav1.UpdateOptions{})
Copy link
Contributor

Choose a reason for hiding this comment

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

I've tried running this test locally and the first two invocations I hit:

  [FAILED] Operation cannot be fulfilled on persistentvolumeclaims "datadir-ss-1": the object has been modified; please apply your changes to the latest version and try again
  In [It] at: k8s.io/kubernetes/test/e2e/apps/statefulset.go:1402 @ 06/04/24 12:13:52.29

so I'd suggest to go through all the PVCs update operations and make them retriable. Similarly StatefulSet updates should be changed to use updateStatefrulSetWithRetries most likely.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Interesting, I've been using kind and never hit that. But +1 to fewer flakes.

// claimOwnerMatchesSetAndPod returns false if the ownerRefs of the claim are not set consistently with the
// matchesRef returns true when the object matches the owner reference, that is the name and GVK are the same.
func matchesRef(ref *metav1.OwnerReference, obj metav1.Object, gvk schema.GroupVersionKind) bool {
return gvk.GroupVersion().String() == ref.APIVersion && gvk.Kind == ref.Kind && ref.Name == obj.GetName()
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 using IsControlledBy from k8s.io/apimachinery/pkg/apis/meta/v1

Copy link
Contributor Author

@mattcary mattcary Jun 5, 2024

Choose a reason for hiding this comment

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

That matches on the UID, not on the GVK & name. So if, eg, the statefulset was updated, IsControlledBy won't return true until the UID is updated? In particular, matchRef is used to update stale UIDs.

return true
}
continue // This is us.
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need to match both statefulset and pod in the loop above?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

PVC are controlled by the statefulset for the WhenDeleted retention type, and controlled by the pod for the WhenScaled retention type.

return true
}

if hasNonControllerOwner(claim, set, pod) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't understand why we should react in such a situation? It doesn't matter that we don't own it, and furthermore who owns it. We just don't react on it.

Copy link
Contributor

Choose a reason for hiding this comment

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

At most we can warn the user about such situation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The implementation before this change makes statefulsets & pods owners but not controllers -- that's what this PR is fixing. So we have to handle at least that case to correctly update existing statefulsets from before this bugfix.

@mattcary mattcary force-pushed the oref branch 2 times, most recently from 6b706a7 to a42e6e4 Compare June 5, 2024 18:16
Copy link
Contributor

@soltysh soltysh left a comment

Choose a reason for hiding this comment

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

/lgtm
/approve

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

LGTM label has been added.

Git tree hash: ba293b2cf2ee1f935175f95b7d0ef82769516a45

@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: mattcary, msau42, soltysh

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 Jun 7, 2024
@k8s-ci-robot k8s-ci-robot merged commit c6b5191 into kubernetes:master Jun 7, 2024
15 checks passed
@k8s-ci-robot k8s-ci-robot added this to the v1.31 milestone Jun 7, 2024
@mattcary
Copy link
Contributor Author

mattcary commented Jun 7, 2024

/cherry-pick release-1.30

^^ This didn't work, #125389 created manually instead.

@mattcary
Copy link
Contributor Author

mattcary commented Aug 7, 2024

/cherry-pick release-1.29

^^ I guess this doesn't work. #126580 created

@mattcary
Copy link
Contributor Author

mattcary commented Aug 7, 2024

/cherry-pick release-1.28

^^ #126581 created.

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. area/test cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/bug Categorizes issue or PR as related to a bug. lgtm "Looks good to me", indicates that a PR is ready to be merged. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. 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/apps Categorizes an issue or PR as relevant to SIG Apps. sig/testing Categorizes an issue or PR as relevant to SIG Testing. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. triage/accepted Indicates an issue or PR is ready to be actively worked on.
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

StatefulSet Autodelete owner references should respect controller
6 participants