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

feat(HACBS-2422): add finalizer to Release PRs #236

Merged
merged 1 commit into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 32 additions & 8 deletions controllers/release/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@
syncer *syncer.Syncer
}

// finalizerName is the finalizer name to be added to the Releases
const finalizerName string = "appstudio.redhat.com/release-finalizer"

// newAdapter creates and returns an adapter instance.
func newAdapter(ctx context.Context, client client.Client, release *v1alpha1.Release, loader loader.ObjectLoader, logger *logr.Logger) *adapter {
return &adapter{
Expand All @@ -79,13 +76,13 @@
return controller.ContinueProcessing()
}

if controllerutil.ContainsFinalizer(a.release, finalizerName) {
if controllerutil.ContainsFinalizer(a.release, metadata.ReleaseFinalizer) {
if err := a.finalizeRelease(); err != nil {
return controller.RequeueWithError(err)
}

patch := client.MergeFrom(a.release.DeepCopy())
controllerutil.RemoveFinalizer(a.release, finalizerName)
controllerutil.RemoveFinalizer(a.release, metadata.ReleaseFinalizer)
err := a.client.Patch(a.ctx, a.release, patch)
if err != nil {
return controller.RequeueWithError(err)
Expand All @@ -100,15 +97,15 @@
func (a *adapter) EnsureFinalizerIsAdded() (controller.OperationResult, error) {
var finalizerFound bool
for _, finalizer := range a.release.GetFinalizers() {
if finalizer == finalizerName {
if finalizer == metadata.ReleaseFinalizer {
finalizerFound = true
}
}

if !finalizerFound {
a.logger.Info("Adding Finalizer to the Release")
patch := client.MergeFrom(a.release.DeepCopy())
controllerutil.AddFinalizer(a.release, finalizerName)
controllerutil.AddFinalizer(a.release, metadata.ReleaseFinalizer)
err := a.client.Patch(a.ctx, a.release, patch)

return controller.RequeueOnErrorOrContinue(err)
Expand Down Expand Up @@ -290,7 +287,20 @@
return controller.RequeueWithError(err)
}
if pipelineRun != nil {
return controller.RequeueOnErrorOrContinue(a.registerProcessingStatus(pipelineRun))
err = a.registerProcessingStatus(pipelineRun)
if err != nil {
return controller.RequeueWithError(err)
}

Check warning on line 293 in controllers/release/adapter.go

View check run for this annotation

Codecov / codecov/patch

controllers/release/adapter.go#L292-L293

Added lines #L292 - L293 were not covered by tests
}

// This condition can only be true if the call to registerProcessingStatus changed the state
if a.release.HasProcessingFinished() {
// At this point it's safe to remove the PipelineRun, so the finalizer can be removed
if controllerutil.ContainsFinalizer(pipelineRun, metadata.ReleaseFinalizer) {
patch := client.MergeFrom(pipelineRun.DeepCopy())
controllerutil.RemoveFinalizer(pipelineRun, metadata.ReleaseFinalizer)
return controller.RequeueOnErrorOrContinue(a.client.Patch(a.ctx, pipelineRun, patch))
}
}

return controller.ContinueProcessing()
Expand Down Expand Up @@ -374,6 +384,20 @@
}

if pipelineRun != nil {
// The finalizer could still exist at this point in the case of the PipelineRun not having succeeded at the time
// of finalizing the Release.
if controllerutil.ContainsFinalizer(pipelineRun, metadata.ReleaseFinalizer) {
patch := client.MergeFrom(pipelineRun.DeepCopy())
removedFinalizer := controllerutil.RemoveFinalizer(pipelineRun, metadata.ReleaseFinalizer)
if !removedFinalizer {
return fmt.Errorf("finalizer not removed")
}

Check warning on line 394 in controllers/release/adapter.go

View check run for this annotation

Codecov / codecov/patch

controllers/release/adapter.go#L393-L394

Added lines #L393 - L394 were not covered by tests
err := a.client.Patch(a.ctx, pipelineRun, patch)
if err != nil {
return err
}

Check warning on line 398 in controllers/release/adapter.go

View check run for this annotation

Codecov / codecov/patch

controllers/release/adapter.go#L397-L398

Added lines #L397 - L398 were not covered by tests
}

err = a.client.Delete(a.ctx, pipelineRun)
if err != nil && !errors.IsNotFound(err) {
return err
Expand Down
52 changes: 40 additions & 12 deletions controllers/release/adapter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,18 @@ import (
"context"
"encoding/json"
"fmt"
"reflect"
"strings"

toolkit "github.com/redhat-appstudio/operator-toolkit/loader"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/operator-framework/operator-lib/handler"
toolkit "github.com/redhat-appstudio/operator-toolkit/loader"
"github.com/redhat-appstudio/release-service/api/v1alpha1"
"github.com/redhat-appstudio/release-service/loader"
"github.com/redhat-appstudio/release-service/metadata"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"reflect"
"strings"

ecapiv1alpha1 "github.com/enterprise-contract/enterprise-contract-controller/api/v1alpha1"
applicationapiv1alpha1 "github.com/redhat-appstudio/application-api/api/v1alpha1"
Expand Down Expand Up @@ -127,7 +124,7 @@ var _ = Describe("Release adapter", Ordered, func() {
Expect(err).NotTo(HaveOccurred())

pipelineRun, err := adapter.loader.GetReleasePipelineRun(adapter.ctx, adapter.client, adapter.release)
Expect(pipelineRun).To(BeNil())
Expect(pipelineRun).To(Or(BeNil(), HaveField("DeletionTimestamp", Not(BeNil()))))
Expect(err).NotTo(HaveOccurred())

_, err = adapter.loader.GetRelease(adapter.ctx, adapter.client, adapter.release.Name, adapter.release.Namespace)
Expand All @@ -151,14 +148,14 @@ var _ = Describe("Release adapter", Ordered, func() {
result, err := adapter.EnsureFinalizerIsAdded()
Expect(!result.RequeueRequest && !result.CancelRequest).To(BeTrue())
Expect(err).NotTo(HaveOccurred())
Expect(adapter.release.Finalizers).To(ContainElement(finalizerName))
Expect(adapter.release.Finalizers).To(ContainElement(metadata.ReleaseFinalizer))
})

It("shouldn't fail if the Release already has the finalizer added", func() {
result, err := adapter.EnsureFinalizerIsAdded()
Expect(!result.RequeueRequest && !result.CancelRequest).To(BeTrue())
Expect(err).NotTo(HaveOccurred())
Expect(adapter.release.Finalizers).To(ContainElement(finalizerName))
Expect(adapter.release.Finalizers).To(ContainElement(metadata.ReleaseFinalizer))

result, err = adapter.EnsureFinalizerIsAdded()
Expect(!result.RequeueRequest && !result.CancelRequest).To(BeTrue())
Expand Down Expand Up @@ -782,6 +779,37 @@ var _ = Describe("Release adapter", Ordered, func() {
Expect(adapter.release.HasProcessingFinished()).To(BeTrue())
})

It("removes the finalizer if present", func() {
adapter.release.MarkProcessing("")

pipelineRun := &v1beta1.PipelineRun{
ObjectMeta: metav1.ObjectMeta{
Name: "pipeline-run",
Namespace: "default",
Finalizers: []string{metadata.ReleaseFinalizer},
},
}
// The resource needs to be created as it will get patched
Expect(adapter.client.Create(adapter.ctx, pipelineRun)).To(Succeed())

pipelineRun.Status.MarkSucceeded("", "")
johnbieren marked this conversation as resolved.
Show resolved Hide resolved

adapter.ctx = toolkit.GetMockedContext(ctx, []toolkit.MockData{
{
ContextKey: loader.ReleasePipelineRunContextKey,
Resource: pipelineRun,
},
})

result, err := adapter.EnsureReleaseProcessingIsTracked()
Expect(!result.RequeueRequest && !result.CancelRequest).To(BeTrue())
Expect(err).NotTo(HaveOccurred())
Expect(pipelineRun.Finalizers).To(BeEmpty())

// Clean up at the end
Expect(adapter.client.Delete(adapter.ctx, pipelineRun)).To(Succeed())
johnbieren marked this conversation as resolved.
Show resolved Hide resolved
})

It("should continue if the PipelineRun doesn't exist", func() {
adapter.release.MarkProcessing("")

Expand Down Expand Up @@ -993,8 +1021,8 @@ var _ = Describe("Release adapter", Ordered, func() {

Expect(adapter.finalizeRelease()).To(Succeed())
pipelineRun, err = adapter.loader.GetReleasePipelineRun(adapter.ctx, adapter.client, adapter.release)
Expect(pipelineRun).To(BeNil())
Expect(err).NotTo(HaveOccurred())
Expect(pipelineRun).To(BeNil())
})
})

Expand Down
4 changes: 4 additions & 0 deletions metadata/finalizers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package metadata

// ReleaseFinalizer is the finalizer name to be added to the Releases
const ReleaseFinalizer string = "appstudio.redhat.com/release-finalizer"
4 changes: 3 additions & 1 deletion tekton/pipeline_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"encoding/json"
"fmt"
"os"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"strings"
"unicode"

Expand Down Expand Up @@ -123,9 +124,10 @@ func (r *ReleasePipelineRun) WithObjectReferences(objects ...client.Object) *Rel
return r
}

// WithOwner set's owner annotations to the release PipelineRun.
// WithOwner sets owner annotations to the release PipelineRun and a finalizer to prevent its deletion.
func (r *ReleasePipelineRun) WithOwner(release *v1alpha1.Release) *ReleasePipelineRun {
_ = libhandler.SetOwnerAnnotations(release, r)
controllerutil.AddFinalizer(r, metadata.ReleaseFinalizer)

return r
}
Expand Down
1 change: 1 addition & 0 deletions tekton/pipeline_run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ var _ = Describe("PipelineRun", func() {
It("can append owner release information to the object as annotations", func() {
releasePipelineRun.WithOwner(release)
Expect(releasePipelineRun.Annotations).NotTo(BeNil())
Expect(releasePipelineRun.Finalizers).NotTo(BeEmpty())
})

It("can append the release Name, Namespace, and Application to a PipelineRun object and that these label key names match the correct label format", func() {
Expand Down
Loading