Skip to content

Commit 0767e23

Browse files
committed
Add finalize logic
1 parent b6e0974 commit 0767e23

5 files changed

Lines changed: 139 additions & 3 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
github.com/go-logr/logr v1.4.3
88
github.com/onsi/ginkgo/v2 v2.23.3
99
github.com/onsi/gomega v1.37.0
10+
github.com/prometheus/client_golang v1.23.2
1011
github.com/stretchr/testify v1.11.1
1112
gopkg.in/yaml.v3 v3.0.1
1213
k8s.io/api v0.34.3
@@ -82,7 +83,6 @@ require (
8283
github.com/pjbgf/sha1cd v0.5.0 // indirect
8384
github.com/pkg/errors v0.9.1 // indirect
8485
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
85-
github.com/prometheus/client_golang v1.23.2 // indirect
8686
github.com/prometheus/client_model v0.6.2 // indirect
8787
github.com/prometheus/common v0.67.4 // indirect
8888
github.com/prometheus/procfs v0.19.2 // indirect

internal/controller/function_controller.go

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
ctrl "sigs.k8s.io/controller-runtime"
3737
"sigs.k8s.io/controller-runtime/pkg/client"
3838
"sigs.k8s.io/controller-runtime/pkg/controller"
39+
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
3940
logf "sigs.k8s.io/controller-runtime/pkg/log"
4041
"sigs.k8s.io/controller-runtime/pkg/predicate"
4142

@@ -44,6 +45,8 @@ import (
4445
apierrors "k8s.io/apimachinery/pkg/api/errors"
4546
)
4647

48+
const functionFinalizer = "function.functions.dev/finalizer"
49+
4750
// FunctionReconciler reconciles a Function object
4851
type FunctionReconciler struct {
4952
client.Client
@@ -82,8 +85,6 @@ func (r *FunctionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
8285
return ctrl.Result{}, err
8386
}
8487

85-
logger.Info("Reconciling Function", "function", req.NamespacedName)
86-
8788
// checkout repo
8889
branchReference := "main"
8990
if function.Spec.Source.Reference != "" {
@@ -101,6 +102,45 @@ func (r *FunctionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
101102
return ctrl.Result{}, fmt.Errorf("failed to get function metadata: %w", err)
102103
}
103104

105+
if !controllerutil.ContainsFinalizer(function, functionFinalizer) {
106+
logger.Info("Adding Finalizer for Function")
107+
if ok := controllerutil.AddFinalizer(function, functionFinalizer); !ok {
108+
return ctrl.Result{}, fmt.Errorf("failed to add finalizer for function: %w", err)
109+
}
110+
111+
if err = r.Update(ctx, function); err != nil {
112+
return ctrl.Result{}, fmt.Errorf("failed to add finalizer for function: %w", err)
113+
}
114+
}
115+
116+
// Check if the Function instance is marked to be deleted, which is
117+
// indicated by the deletion timestamp being set.
118+
if function.GetDeletionTimestamp() != nil {
119+
if controllerutil.ContainsFinalizer(function, functionFinalizer) {
120+
logger.Info("Performing Finalizer Operations for Function before delete CR")
121+
122+
//TODO: maybe set some status conditions marking the function as degraded
123+
124+
// Perform all operations required before removing the finalizer and allow
125+
// the Kubernetes API to remove the custom resource.
126+
if err := r.Finalize(ctx, metadata.Name, function.Namespace); err != nil {
127+
return ctrl.Result{}, fmt.Errorf("failed to perform finalizer for function: %w", err)
128+
}
129+
130+
logger.Info("Removing Finalizer for Function after successfully perform the operations")
131+
if ok := controllerutil.RemoveFinalizer(function, functionFinalizer); !ok {
132+
return ctrl.Result{}, fmt.Errorf("failed to remove finalizer for function")
133+
}
134+
135+
if err := r.Update(ctx, function); err != nil {
136+
return ctrl.Result{}, fmt.Errorf("failed to remove finalizer for function: %w", err)
137+
}
138+
}
139+
return ctrl.Result{}, nil
140+
}
141+
142+
logger.Info("Reconciling Function", "function", req.NamespacedName)
143+
104144
// deploy if needed
105145
deployed, err := r.isDeployed(ctx, metadata.Name, function.Namespace)
106146
if err != nil {
@@ -336,3 +376,12 @@ func (r *FunctionReconciler) isMiddlewareLatest(ctx context.Context, metadata fu
336376

337377
return latestMiddleware == functionMiddleware, nil
338378
}
379+
380+
func (r *FunctionReconciler) Finalize(ctx context.Context, name, namespace string) error {
381+
err := r.FuncCliManager.Delete(ctx, name, namespace)
382+
if err != nil {
383+
return fmt.Errorf("failed to finalize function: %w", err)
384+
}
385+
386+
return nil
387+
}

internal/controller/function_controller_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ import (
2727
. "github.com/onsi/gomega"
2828
"github.com/stretchr/testify/mock"
2929
"gopkg.in/yaml.v3"
30+
"k8s.io/apimachinery/pkg/api/errors"
3031
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3132
"k8s.io/apimachinery/pkg/types"
3233
"k8s.io/client-go/tools/record"
3334
"knative.dev/func/pkg/functions"
35+
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
3436
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3537

3638
functionsdevv1alpha1 "github.com/creydr/func-operator/api/v1alpha1"
@@ -64,8 +66,20 @@ var _ = Describe("Function Controller", func() {
6466
err := k8sClient.Get(ctx, typeNamespacedName, resource)
6567
Expect(err).NotTo(HaveOccurred())
6668

69+
By("Remove finalizer to allow deletion")
70+
if controllerutil.ContainsFinalizer(resource, functionFinalizer) {
71+
controllerutil.RemoveFinalizer(resource, functionFinalizer)
72+
Expect(k8sClient.Update(ctx, resource)).To(Succeed())
73+
}
74+
6775
By("Cleanup the specific resource instance Function")
6876
Expect(k8sClient.Delete(ctx, resource)).To(Succeed())
77+
78+
By("Wait for resource to be deleted")
79+
Eventually(func() bool {
80+
err := k8sClient.Get(ctx, typeNamespacedName, resource)
81+
return errors.IsNotFound(err)
82+
}).Should(BeTrue())
6983
})
7084

7185
type reconcileTestCase struct {

internal/funccli/Manager_mock.go

Lines changed: 63 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/funccli/manager.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ type Manager interface {
3131

3232
Describe(ctx context.Context, name, namespace string) (funcfn.Instance, error)
3333
Deploy(ctx context.Context, repoPath string, namespace string, opts DeployOptions) error
34+
Delete(ctx context.Context, name, namespace string) error
3435

3536
GetCurrentVersion(ctx context.Context) (string, error)
3637
GetLatestMiddlewareVersion(ctx context.Context, runtime, invoke string) (string, error)
@@ -234,6 +235,15 @@ func (m *managerImpl) Deploy(ctx context.Context, repoPath string, namespace str
234235
return nil
235236
}
236237

238+
func (m *managerImpl) Delete(ctx context.Context, name, namespace string) error {
239+
out, err := m.Run(ctx, "", "delete", "--namespace", namespace, name)
240+
if err != nil {
241+
return fmt.Errorf("failed to delete function: %q. %w", out, err)
242+
}
243+
244+
return nil
245+
}
246+
237247
func (m *managerImpl) GetLatestMiddlewareVersion(ctx context.Context, runtime string, invoke string) (string, error) {
238248
versions := struct {
239249
MiddlewareVersions map[string]map[string]string `json:"middlewareVersions,omitempty"`

0 commit comments

Comments
 (0)