Skip to content

Commit

Permalink
Remove the unused Deployment finalizer
Browse files Browse the repository at this point in the history
Previous code added a finalizer on the Deployment running the controller
when pruneObjectBehavior was used. This commit removes that unnecessary
finalizer if present.

Relates:
https://issues.redhat.com/browse/ACM-2923

Signed-off-by: mprahl <mprahl@users.noreply.github.com>
  • Loading branch information
mprahl authored and openshift-merge-robot committed Feb 16, 2023
1 parent 8203f5f commit 22d3bd3
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 3 deletions.
51 changes: 48 additions & 3 deletions controllers/configurationpolicy_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,18 @@ func (r *ConfigurationPolicyReconciler) PeriodicallyExecConfigPolicies(
const waiting = 10 * time.Minute

exiting := false
deploymentFinalizerRemoved := false

for !exiting {
if !deploymentFinalizerRemoved {
err := r.removeLegacyDeploymentFinalizer()
if err == nil {
deploymentFinalizerRemoved = true
} else {
log.Error(err, "Failed to remove the legacy Deployment finalizer. Will try again.")
}
}

start := time.Now()
policiesList := policyv1.ConfigurationPolicyList{}

Expand Down Expand Up @@ -2777,25 +2787,60 @@ func convertPolicyStatusToString(plc *policyv1.ConfigurationPolicy) (results str
return result
}

func (r *ConfigurationPolicyReconciler) isBeingUninstalled() (bool, error) {
// getDeployment gets the Deployment object associated with this controller. If the controller is running outside of
// a cluster, no Deployment object or error will be returned.
func (r *ConfigurationPolicyReconciler) getDeployment() (*appsv1.Deployment, error) {
key, err := common.GetOperatorNamespacedName()
if err != nil {
// Running locally
if errors.Is(err, common.ErrNoNamespace) || errors.Is(err, common.ErrRunLocal) {
return false, nil
return nil, nil
}

return false, err
return nil, err
}

deployment := appsv1.Deployment{}
if err := r.Client.Get(context.TODO(), key, &deployment); err != nil {
return nil, err
}

return &deployment, nil
}

func (r *ConfigurationPolicyReconciler) isBeingUninstalled() (bool, error) {
deployment, err := r.getDeployment()
if deployment == nil || err != nil {
return false, err
}

return deployment.Annotations[common.UninstallingAnnotation] == "true", nil
}

// removeLegacyDeploymentFinalizer removes the policy.open-cluster-management.io/delete-related-objects on the
// Deployment object. This finalizer is no longer needed on the Deployment object, so it is removed.
func (r *ConfigurationPolicyReconciler) removeLegacyDeploymentFinalizer() error {
deployment, err := r.getDeployment()
if deployment == nil || err != nil {
return err
}

for i, finalizer := range deployment.Finalizers {
if finalizer == pruneObjectFinalizer {
newFinalizers := append(deployment.Finalizers[:i], deployment.Finalizers[i+1:]...)
deployment.SetFinalizers(newFinalizers)

log.Info("Removing the legacy finalizer on the controller Deployment")

err := r.Client.Update(context.TODO(), deployment)

return err
}
}

return nil
}

func recoverFlow() {
if r := recover(); r != nil {
// V(-2) is the error level
Expand Down
56 changes: 56 additions & 0 deletions test/e2e/case29_trigger_uninstall_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,59 @@ var _ = Describe("Clean up during uninstalls", Label("running-in-cluster"), Orde
}, defaultTimeoutSeconds, 1).Should(Succeed())
})
})

// This test only works when the controller is running in the cluster.
var _ = Describe("Clean up the finalizer on the Deployment", Label("running-in-cluster"), Ordered, func() {
const (
deploymentName string = "config-policy-controller"
deploymentNamespace string = "open-cluster-management-agent-addon"
pruneObjectFinalizer string = "policy.open-cluster-management.io/delete-related-objects"
)

It("verifies that the Deployment finalizer is removed", func() {
deploymentRsrc := clientManaged.AppsV1().Deployments(deploymentNamespace)

By("Adding a finalizer to the Deployment")
Eventually(func(g Gomega) {
deployment, err := deploymentRsrc.Get(context.TODO(), deploymentName, metav1.GetOptions{})
g.Expect(err).To(BeNil())

deployment.SetFinalizers(append(deployment.Finalizers, pruneObjectFinalizer))
_, err = deploymentRsrc.Update(context.TODO(), deployment, metav1.UpdateOptions{})
g.Expect(err).To(BeNil())
}, defaultTimeoutSeconds, 1).Should(Succeed())

// Trigger a restart so that the finalizer removal logic is executed.
utils.Kubectl("-n", deploymentNamespace, "rollout", "restart", "deployment/"+deploymentName)

By("Waiting for the finalizer on the Deployment to be removed")
Eventually(func(g Gomega) {
deployment, err := deploymentRsrc.Get(context.TODO(), deploymentName, metav1.GetOptions{})
g.Expect(err).To(BeNil())

g.Expect(deployment.Finalizers).ToNot(ContainElement(pruneObjectFinalizer))
}, defaultTimeoutSeconds*2, 1).Should(Succeed())
})

AfterAll(func() {
deploymentRsrc := clientManaged.AppsV1().Deployments(deploymentNamespace)

// Use an eventually in case there are update conflicts and there needs to be a retry
Eventually(func(g Gomega) {
deployment, err := deploymentRsrc.Get(context.TODO(), deploymentName, metav1.GetOptions{})
g.Expect(err).To(BeNil())

for i, finalizer := range deployment.Finalizers {
if finalizer == pruneObjectFinalizer {
newFinalizers := append(deployment.Finalizers[:i], deployment.Finalizers[i+1:]...)
deployment.SetFinalizers(newFinalizers)

_, err := deploymentRsrc.Update(context.TODO(), deployment, metav1.UpdateOptions{})
g.Expect(err).To(BeNil())

break
}
}
}, defaultTimeoutSeconds, 1).Should(Succeed())
})
})

0 comments on commit 22d3bd3

Please sign in to comment.