Repository: kubean-io/kubean
Pull request #889 (2023-07-19 07:46:28)

Set ownReference for clusterOperation releated with cluster
<!--  

Thanks for sending a pull request!  Here are some tips for you:

* make sure your commit is signed off

-->

**What type of PR is this?**
<!-- 
Uncomment only one ` /kind <>` line, hit enter to put that in a new line, and remove leading whitespaces from that line:

/kind api-change
/kind bug
/kind cleanup
/kind design
/kind documentation
/kind failing-test
/kind feature
/kind flake
-->

/kind bug

**What this PR does / why we need it**:

**Which issue(s) this PR fixes**:
<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
-->
Fixes # https://github.com/kubean-io/kubean/issues/890 

**Special notes for your reviewer**:



kubean-pr-robot[bot]: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubean-io/kubean/pull/889#" title="Author self-approved">hangscer8</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubean-io%2Fkubean).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubean-io/kubean/blob/main/OWNERS)~~ [hangscer8]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/pkg/controllers/clusterops/controller.go b/pkg/controllers/clusterops/controller.go
index baec8af4c..15154f849 100644
--- a/pkg/controllers/clusterops/controller.go
+++ b/pkg/controllers/clusterops/controller.go
@@ -252,8 +252,15 @@ func (c *Controller) Reconcile(ctx context.Context, req controllerruntime.Reques
 		}
 		return controllerruntime.Result{}, nil
 	}
-
-	needRequeue, err := c.UpdateClusterOpsStatusDigest(clusterOps)
+	needRequeue, err := c.UpdateOperationOwnReferenceForCluster(clusterOps, cluster)
+	if err != nil {
+		klog.ErrorS(err, "failed to update ownreference", "cluster", cluster.Name, "clusterOps", clusterOps.Name)
+		return controllerruntime.Result{RequeueAfter: RequeueAfter}, nil
+	}
+	if needRequeue {
+		return controllerruntime.Result{RequeueAfter: RequeueAfter}, nil
+	}
+	needRequeue, err = c.UpdateClusterOpsStatusDigest(clusterOps)
 	if err != nil {
 		klog.ErrorS(err, "failed to get update clusterOps status digest", "clusterOps", clusterOps.Name)
 		return controllerruntime.Result{RequeueAfter: RequeueAfter}, nil
@@ -335,6 +342,22 @@ func (c *Controller) Reconcile(ctx context.Context, req controllerruntime.Reques
 	return controllerruntime.Result{}, nil
 }
 
+func (c *Controller) UpdateOperationOwnReferenceForCluster(operation *clusteroperationv1alpha1.ClusterOperation, cluster *clusterv1alpha1.Cluster) (bool, error) {
+	if operation.Spec.Cluster != cluster.Name || len(cluster.UID) == 0 { // ignore and return
+		return false, nil
+	}
+	for i := range operation.OwnerReferences {
+		if operation.OwnerReferences[i].UID == cluster.UID {
+			return false, nil // has been set.
+		}
+	}
+	operation.OwnerReferences = append(operation.OwnerReferences, *metav1.NewControllerRef(cluster, clusterv1alpha1.SchemeGroupVersion.WithKind("Cluster")))
+	if err := c.Client.Update(context.Background(), operation); err != nil {
+		return false, err
+	}
+	return true, nil
+}
+
 func (c *Controller) ProcessKubeanOperationImage(oldImage, globalManifestImageTag string) string {
 	if strings.Contains(oldImage, ":") { // kubespray-job:v1
 		return oldImage


Test patch:
diff --git a/pkg/controllers/clusterops/controller_test.go b/pkg/controllers/clusterops/controller_test.go
index 218fc2c1d..81f0dbd79 100644
--- a/pkg/controllers/clusterops/controller_test.go
+++ b/pkg/controllers/clusterops/controller_test.go
@@ -2402,6 +2402,96 @@ func Test_ProcessKubeanOperationImage(t *testing.T) {
 	}
 }
 
+func TestUpdateOperationOwnReferenceForCluster(t *testing.T) {
+	genController := func() *Controller {
+		return &Controller{
+			Client:                newFakeClient(),
+			ClientSet:             clientsetfake.NewSimpleClientset(),
+			KubeanClusterSet:      clusterv1alpha1fake.NewSimpleClientset(),
+			KubeanClusterOpsSet:   clusteroperationv1alpha1fake.NewSimpleClientset(),
+			InfoManifestClientSet: manifestv1alpha1fake.NewSimpleClientset(),
+		}
+	}
+	tests := []struct {
+		name string
+		arg  func() bool
+		want bool
+	}{
+		{
+			name: "the names are not same",
+			arg: func() bool {
+				controller := genController()
+				clusterOps := &clusteroperationv1alpha1.ClusterOperation{}
+				clusterOps.Spec.Cluster = "cluster-origin"
+				cluster := &clusterv1alpha1.Cluster{}
+				cluster.Name = "cluster1"
+				needRequeue, err := controller.UpdateOperationOwnReferenceForCluster(clusterOps, cluster)
+				return err == nil && needRequeue == false
+			},
+			want: true,
+		},
+		{
+			name: "the ownreference has been set",
+			arg: func() bool {
+				controller := genController()
+				clusterOps := &clusteroperationv1alpha1.ClusterOperation{}
+				clusterOps.Spec.Cluster = "cluster-origin"
+
+				cluster := &clusterv1alpha1.Cluster{}
+				cluster.Name = "cluster-origin"
+				cluster.UID = "cluster-uid-1"
+				clusterOps.OwnerReferences = append(clusterOps.OwnerReferences, metav1.OwnerReference{UID: "cluster-uid-1"})
+				needRequeue, err := controller.UpdateOperationOwnReferenceForCluster(clusterOps, cluster)
+				return err == nil && needRequeue == false
+			},
+			want: true,
+		},
+		{
+			name: "the ownreference has been set",
+			arg: func() bool {
+				controller := genController()
+				clusterOps := &clusteroperationv1alpha1.ClusterOperation{}
+				clusterOps.Spec.Cluster = "cluster-origin"
+
+				cluster := &clusterv1alpha1.Cluster{}
+				cluster.Name = "cluster-origin"
+				cluster.UID = "cluster-uid-1"
+				clusterOps.OwnerReferences = append(clusterOps.OwnerReferences, metav1.OwnerReference{UID: "cluster-uid-1"})
+				needRequeue, err := controller.UpdateOperationOwnReferenceForCluster(clusterOps, cluster)
+				return err == nil && needRequeue == false
+			},
+			want: true,
+		},
+		{
+			name: "the ownreference has been not set",
+			arg: func() bool {
+				controller := genController()
+				clusterOps := &clusteroperationv1alpha1.ClusterOperation{}
+				clusterOps.Spec.Cluster = "cluster-origin"
+				clusterOps.Name = "ops-1"
+				controller.Client.Create(context.Background(), clusterOps)
+
+				cluster := &clusterv1alpha1.Cluster{}
+				cluster.Name = "cluster-origin"
+				cluster.UID = "cluster-uid-1"
+				clusterOps.OwnerReferences = nil
+				needRequeue, err := controller.UpdateOperationOwnReferenceForCluster(clusterOps, cluster)
+				clusterOpsResult := &clusteroperationv1alpha1.ClusterOperation{}
+				controller.Client.Get(context.Background(), types.NamespacedName{Name: "ops-1"}, clusterOpsResult)
+				return err == nil && needRequeue && len(clusterOpsResult.OwnerReferences) != 0 && clusterOpsResult.OwnerReferences[0].UID == cluster.UID
+			},
+			want: true,
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			if test.arg() != test.want {
+				t.Fatal()
+			}
+		})
+	}
+}
+
 func Test_FetchGlobalManifestImageTag(t *testing.T) {
 	controller := Controller{
 		Client:                newFakeClient(),