Skip to content

Commit 047e595

Browse files
authored
Merge pull request #1873 from kube-logging/feat/add-finalizer-cleanup
feat: add option to cleanup stuck finalizers
2 parents b097046 + 74418ab commit 047e595

File tree

8 files changed

+86
-22
lines changed

8 files changed

+86
-22
lines changed

Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,14 +144,16 @@ list: ## List all make targets
144144
manager: codegen fmt vet ## Build manager binary
145145
go build -o bin/manager main.go
146146

147+
HELM_MANIFEST_OVERRIDE='s@manager-role@{{ template "logging-operator.fullname" . }}\n annotations:\n {{- if .Values.rbac.retainOnDelete }}\n "helm.sh/resource-policy": keep\n {{- end }}@'
148+
147149
.PHONY: manifests
148150
manifests: ${CONTROLLER_GEN} ## Generate manifests e.g. CRD, RBAC etc.
149151
cd pkg/sdk && $(CONTROLLER_GEN) $(CRD_OPTIONS) webhook paths="./..." output:crd:artifacts:config=../../config/crd/bases output:webhook:artifacts:config=../../config/webhook
150152
$(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role paths="./controllers/..." output:rbac:artifacts:config=./config/rbac
151153
cp config/crd/bases/* charts/logging-operator/crds/
152154
for f in config/crd/bases/*.yaml; do sed '/controller-gen.kubebuilder.io\/version/ r hack/crds.annotations.snippet.txt' $${f} > charts/logging-operator/charts/logging-operator-crds/templates/$${f##*/}; done
153155
echo "{{- if .Values.rbac.enabled }}" > ./charts/logging-operator/templates/clusterrole.yaml
154-
cat config/rbac/role.yaml | sed -e 's@manager-role@{{ template "logging-operator.fullname" . }}@' | sed -e '/creationTimestamp/d' | cat >> ./charts/logging-operator/templates/clusterrole.yaml
156+
cat config/rbac/role.yaml | sed -e $(HELM_MANIFEST_OVERRIDE) | cat >> ./charts/logging-operator/templates/clusterrole.yaml
155157
echo "{{- end }}" >> ./charts/logging-operator/templates/clusterrole.yaml
156158

157159
.PHONY: run

charts/logging-operator/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Use `createCustomResource=false` with Helm v3 to avoid trying to create CRDs fro
5353
| http.port | int | `8080` | HTTP listen port number. |
5454
| http.service | object | `{"annotations":{},"clusterIP":"None","labels":{},"type":"ClusterIP"}` | Service definition for query http service. |
5555
| rbac.enabled | bool | `true` | Create rbac service account and roles. |
56+
| rbac.retainOnDelete | bool | `false` | Keep the operators RBAC resources after the operator is deleted to allow removing pending finalizers. |
5657
| monitoring.serviceMonitor.enabled | bool | `false` | Create a Prometheus Operator ServiceMonitor object. |
5758
| monitoring.serviceMonitor.additionalLabels | object | `{}` | |
5859
| monitoring.serviceMonitor.metricRelabelings | list | `[]` | |

charts/logging-operator/templates/clusterrole.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ apiVersion: rbac.authorization.k8s.io/v1
44
kind: ClusterRole
55
metadata:
66
name: {{ template "logging-operator.fullname" . }}
7+
annotations:
8+
{{- if .Values.rbac.retainOnDelete }}
9+
"helm.sh/resource-policy": keep
10+
{{- end }}
711
rules:
812
- apiGroups:
913
- ""

charts/logging-operator/templates/clusterrolebinding.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ apiVersion: rbac.authorization.k8s.io/v1
44
kind: ClusterRoleBinding
55
metadata:
66
name: {{ template "logging-operator.fullname" . }}
7+
annotations:
8+
{{- if .Values.rbac.retainOnDelete }}
9+
"helm.sh/resource-policy": keep
10+
{{- end }}
711
labels:
812
{{ include "logging-operator.labels" . | indent 4 }}
913
subjects:
@@ -14,5 +18,4 @@ roleRef:
1418
apiGroup: rbac.authorization.k8s.io
1519
kind: ClusterRole
1620
name: {{ template "logging-operator.fullname" . }}
17-
18-
{{- end }}
21+
{{- end }}

charts/logging-operator/templates/serviceaccount.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ metadata:
77
namespace: {{ include "logging-operator.namespace" . }}
88
labels:
99
{{ include "logging-operator.labels" . | indent 4 }}
10-
{{- with .Values.serviceAccount.annotations }}
1110
annotations:
11+
{{- if .Values.rbac.retainOnDelete }}
12+
"helm.sh/resource-policy": keep
13+
{{- end }}
14+
{{- with .Values.serviceAccount.annotations }}
1215
{{ toYaml . | indent 4 }}
13-
{{- end }}
16+
{{- end }}
1417
{{- end }}

charts/logging-operator/values.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ http:
6060
rbac:
6161
# -- Create rbac service account and roles.
6262
enabled: true
63+
# -- Keep the operators RBAC resources after the operator is deleted to allow removing pending finalizers.
64+
retainOnDelete: false
6365

6466
# specify service account manually
6567
# serviceAccountName: custom

controllers/logging/logging_controller.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,14 @@ import (
5151
syslogngconfig "github.com/kube-logging/logging-operator/pkg/sdk/logging/model/syslogng/config"
5252
loggingmodeltypes "github.com/kube-logging/logging-operator/pkg/sdk/logging/model/types"
5353

54-
"github.com/kube-logging/logging-operator/pkg/sdk/logging/api/v1beta1"
5554
loggingv1beta1 "github.com/kube-logging/logging-operator/pkg/sdk/logging/api/v1beta1"
5655
)
5756

57+
const (
58+
SyslogNGConfigFinalizer = "syslogngconfig.logging.banzaicloud.io/finalizer"
59+
FluentdConfigFinalizer = "fluentdconfig.logging.banzaicloud.io/finalizer"
60+
)
61+
5862
var fluentbitWarning sync.Once
5963
var promCrdWarning sync.Once
6064

@@ -323,12 +327,10 @@ func (r *LoggingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
323327
}
324328

325329
func (r *LoggingReconciler) fluentdConfigFinalizer(ctx context.Context, logging *loggingv1beta1.Logging, externalFluentd *loggingv1beta1.FluentdConfig) (bool, error) {
326-
fluentdConfigFinalizer := "fluentdconfig.logging.banzaicloud.io/finalizer"
327-
328330
if logging.DeletionTimestamp.IsZero() {
329-
if externalFluentd != nil && !controllerutil.ContainsFinalizer(logging, fluentdConfigFinalizer) {
331+
if externalFluentd != nil && !controllerutil.ContainsFinalizer(logging, FluentdConfigFinalizer) {
330332
r.Log.Info("adding fluentdconfig finalizer")
331-
controllerutil.AddFinalizer(logging, fluentdConfigFinalizer)
333+
controllerutil.AddFinalizer(logging, FluentdConfigFinalizer)
332334
if err := r.Update(ctx, logging); err != nil {
333335
return true, err
334336
}
@@ -339,9 +341,9 @@ func (r *LoggingReconciler) fluentdConfigFinalizer(ctx context.Context, logging
339341
return false, errors.New(msg)
340342
}
341343

342-
if controllerutil.ContainsFinalizer(logging, fluentdConfigFinalizer) && externalFluentd == nil {
344+
if controllerutil.ContainsFinalizer(logging, FluentdConfigFinalizer) && externalFluentd == nil {
343345
r.Log.Info("removing fluentdconfig finalizer")
344-
controllerutil.RemoveFinalizer(logging, fluentdConfigFinalizer)
346+
controllerutil.RemoveFinalizer(logging, FluentdConfigFinalizer)
345347
if err := r.Update(ctx, logging); err != nil {
346348
return true, err
347349
}
@@ -351,12 +353,10 @@ func (r *LoggingReconciler) fluentdConfigFinalizer(ctx context.Context, logging
351353
}
352354

353355
func (r *LoggingReconciler) syslogNGConfigFinalizer(ctx context.Context, logging *loggingv1beta1.Logging, externalSyslogNG *loggingv1beta1.SyslogNGConfig) (bool, error) {
354-
syslogNGConfigFinalizer := "syslogngconfig.logging.banzaicloud.io/finalizer"
355-
356356
if logging.DeletionTimestamp.IsZero() {
357-
if externalSyslogNG != nil && !controllerutil.ContainsFinalizer(logging, syslogNGConfigFinalizer) {
357+
if externalSyslogNG != nil && !controllerutil.ContainsFinalizer(logging, SyslogNGConfigFinalizer) {
358358
r.Log.Info("adding syslogngconfig finalizer")
359-
controllerutil.AddFinalizer(logging, syslogNGConfigFinalizer)
359+
controllerutil.AddFinalizer(logging, SyslogNGConfigFinalizer)
360360
if err := r.Update(ctx, logging); err != nil {
361361
return true, err
362362
}
@@ -367,9 +367,9 @@ func (r *LoggingReconciler) syslogNGConfigFinalizer(ctx context.Context, logging
367367
return false, errors.New(msg)
368368
}
369369

370-
if controllerutil.ContainsFinalizer(logging, syslogNGConfigFinalizer) && externalSyslogNG == nil {
370+
if controllerutil.ContainsFinalizer(logging, SyslogNGConfigFinalizer) && externalSyslogNG == nil {
371371
r.Log.Info("removing syslogngconfig finalizer")
372-
controllerutil.RemoveFinalizer(logging, syslogNGConfigFinalizer)
372+
controllerutil.RemoveFinalizer(logging, SyslogNGConfigFinalizer)
373373
if err := r.Update(ctx, logging); err != nil {
374374
return true, err
375375
}
@@ -378,7 +378,7 @@ func (r *LoggingReconciler) syslogNGConfigFinalizer(ctx context.Context, logging
378378
return false, nil
379379
}
380380

381-
func (r *LoggingReconciler) dynamicDefaults(ctx context.Context, log logr.Logger, syslogNGSpec *v1beta1.SyslogNGSpec) {
381+
func (r *LoggingReconciler) dynamicDefaults(ctx context.Context, log logr.Logger, syslogNGSpec *loggingv1beta1.SyslogNGSpec) {
382382
nodes := corev1.NodeList{}
383383
if err := r.Client.List(ctx, &nodes); err != nil {
384384
log.Error(err, "listing nodes")

main.go

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"runtime/coverage"
2626
"strings"
2727
"syscall"
28+
"time"
2829

2930
"emperror.dev/errors"
3031
prometheusOperator "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
@@ -41,6 +42,7 @@ import (
4142
ctrl "sigs.k8s.io/controller-runtime"
4243
"sigs.k8s.io/controller-runtime/pkg/cache"
4344
"sigs.k8s.io/controller-runtime/pkg/client"
45+
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
4446
"sigs.k8s.io/controller-runtime/pkg/log/zap"
4547
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
4648
"sigs.k8s.io/controller-runtime/pkg/webhook"
@@ -80,6 +82,7 @@ func main() {
8082
var enableprofile bool
8183
var namespace string
8284
var loggingRef string
85+
var finalizerCleanup bool
8386
var klogLevel int
8487

8588
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
@@ -91,6 +94,7 @@ func main() {
9194
flag.BoolVar(&enableprofile, "pprof", false, "Enable pprof")
9295
flag.StringVar(&namespace, "watch-namespace", "", "Namespace to filter the list of watched objects")
9396
flag.StringVar(&loggingRef, "watch-logging-name", "", "Logging resource name to optionally filter the list of watched objects based on which logging they belong to by checking the app.kubernetes.io/managed-by label")
97+
flag.BoolVar(&finalizerCleanup, "finalizer-cleanup", false, "Remove finalizers from Logging resources during operator shutdown, useful for Helm uninstallation")
9498
flag.Parse()
9599

96100
ctx := context.Background()
@@ -220,7 +224,7 @@ func main() {
220224
// +kubebuilder:scaffold:builder
221225
setupLog.Info("starting manager")
222226

223-
if err := mgr.Start(setupSignalHandler()); err != nil {
227+
if err := mgr.Start(setupSignalHandler(mgr, finalizerCleanup)); err != nil {
224228
setupLog.Error(err, "problem running manager")
225229
os.Exit(1)
226230
}
@@ -231,7 +235,7 @@ func main() {
231235
// SIGUSR1 handler for saving test coverage files
232236
var onlyOneSignalHandler = make(chan struct{})
233237

234-
func setupSignalHandler() context.Context {
238+
func setupSignalHandler(mgr ctrl.Manager, finalizerCleanup bool) context.Context {
235239
close(onlyOneSignalHandler) // panics when called twice
236240

237241
ctx, cancel := context.WithCancel(context.Background())
@@ -241,7 +245,16 @@ func setupSignalHandler() context.Context {
241245
go func() {
242246
<-c
243247
cancel()
244-
<-c
248+
249+
// Due to the way Helm handles uninstallation,
250+
// the operator might be terminated before the finalizers are removed.
251+
if finalizerCleanup {
252+
cleanupCtx, cleanupCancel := context.WithTimeout(context.Background(), 60*time.Second)
253+
defer cleanupCancel()
254+
255+
cleanupFinalizers(cleanupCtx, mgr.GetClient())
256+
}
257+
245258
os.Exit(1) // second signal. Exit directly.
246259
}()
247260

@@ -267,6 +280,7 @@ func setupSignalHandler() context.Context {
267280

268281
return ctx
269282
}
283+
270284
func detectContainerRuntime(ctx context.Context, c client.Reader) error {
271285
var nodeList corev1.NodeList
272286
if err := c.List(ctx, &nodeList, client.Limit(1)); err != nil {
@@ -326,3 +340,38 @@ func setupCustomCache(mgrOptions *ctrl.Options, namespace string, loggingRef str
326340

327341
return mgrOptions, nil
328342
}
343+
344+
func cleanupFinalizers(ctx context.Context, client client.Client) {
345+
log := ctrl.Log.WithName("finalizer-cleanup")
346+
log.Info("Removing finalizers during operator shutdown")
347+
348+
// List all Logging resources
349+
loggingList := &loggingv1beta1.LoggingList{}
350+
if err := client.List(ctx, loggingList); err != nil {
351+
log.Error(err, "Failed to list Logging resources")
352+
return
353+
}
354+
355+
finalizers := []string{
356+
"fluentdconfig.logging.banzaicloud.io/finalizer",
357+
"syslogngconfig.logging.banzaicloud.io/finalizer",
358+
}
359+
for _, logging := range loggingList.Items {
360+
for _, finalizer := range finalizers {
361+
if controllerutil.ContainsFinalizer(&logging, finalizer) {
362+
log.Info(fmt.Sprintf("Removing finalizer: %s from: %s during operator shutdown",
363+
finalizer,
364+
logging.Name))
365+
366+
controllerutil.RemoveFinalizer(&logging, finalizer)
367+
if err := client.Update(ctx, &logging); err != nil {
368+
log.Error(err, fmt.Sprintf("Failed to remove finalizer: %s from: %s during operator shutdown",
369+
finalizer,
370+
logging.Name))
371+
// continue trying to remove finalizers for other resources
372+
continue
373+
}
374+
}
375+
}
376+
}
377+
}

0 commit comments

Comments
 (0)