• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SAP / sap-btp-service-operator / 22057017061

16 Feb 2026 09:23AM UTC coverage: 78.407% (+0.01%) from 78.394%
22057017061

Pull #610

github

kerenlahav
fix test and bump go
Pull Request #610: BUG fix - OOM crash when cluster contains a lot of secrets

45 of 64 new or added lines in 3 files covered. (70.31%)

7 existing lines in 3 files now uncovered.

2825 of 3603 relevant lines covered (78.41%)

0.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.19
/controllers/secret_controller.go
1
package controllers
2

3
import (
4
        "context"
5
        "fmt"
6
        "reflect"
7

8
        "github.com/SAP/sap-btp-service-operator/internal/utils/logutils"
9
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10
        "sigs.k8s.io/controller-runtime/pkg/builder"
11
        "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
12
        "sigs.k8s.io/controller-runtime/pkg/event"
13
        "sigs.k8s.io/controller-runtime/pkg/predicate"
14

15
        "github.com/SAP/sap-btp-service-operator/api/common"
16
        v1 "github.com/SAP/sap-btp-service-operator/api/v1"
17
        "github.com/SAP/sap-btp-service-operator/internal/utils"
18
        "github.com/go-logr/logr"
19
        "github.com/google/uuid"
20
        corev1 "k8s.io/api/core/v1"
21
        apierrors "k8s.io/apimachinery/pkg/api/errors"
22
        "k8s.io/apimachinery/pkg/runtime"
23
        ctrl "sigs.k8s.io/controller-runtime"
24
        "sigs.k8s.io/controller-runtime/pkg/client"
25
        "sigs.k8s.io/controller-runtime/pkg/controller"
26
        "sigs.k8s.io/controller-runtime/pkg/reconcile"
27
)
28

29
type SecretReconciler struct {
30
        client.Client
31
        Scheme *runtime.Scheme
32
        Log    logr.Logger
33
}
34

35
// +kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch;create;update;patch;delete
36
// +kubebuilder:rbac:groups=core,resources=events,verbs=get;list;watch;create;update;patch;delete
37
// +kubebuilder:rbac:groups=coordination.k8s.io,resources=leases,verbs=get;list;create;update
38

39
func (r *SecretReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
1✔
40
        log := r.Log.WithValues("secret", req.NamespacedName).WithValues("correlation_id", uuid.New().String())
1✔
41
        ctx = context.WithValue(ctx, logutils.LogKey, log)
1✔
42
        log.Info(fmt.Sprintf("reconciling params secret %s", req.NamespacedName))
1✔
43
        // Fetch the Secret
1✔
44
        secret := &corev1.Secret{}
1✔
45
        if err := r.Client.Get(ctx, req.NamespacedName, secret); err != nil {
2✔
46
                if !apierrors.IsNotFound(err) {
1✔
47
                        log.Error(err, "unable to fetch Secret")
×
48
                }
×
49
                // we'll ignore not-found errors, since they can't be fixed by an immediate
50
                // requeue (we'll need to wait for a new notification), and we can get them
51
                // on deleted requests.
52
                return ctrl.Result{}, client.IgnoreNotFound(err)
1✔
53
        }
54

55
        instances := &v1.ServiceInstanceList{}
1✔
56
        labelSelector := client.MatchingLabels{utils.GetLabelKeyForInstanceSecret(secret.Name): secret.Name}
1✔
57
        if err := r.Client.List(ctx, instances, client.InNamespace(secret.Namespace), labelSelector); err != nil {
1✔
58
                log.Error(err, "failed to list service instances")
×
59
                return ctrl.Result{}, err
×
60
        }
×
61

62
        for _, instance := range instances.Items {
2✔
63
                log.Info(fmt.Sprintf("waking up referencing instance %s", instance.Name))
1✔
64
                instance.Status.ForceReconcile = true
1✔
65
                err := utils.UpdateStatus(ctx, r.Client, &instance)
1✔
66
                if err != nil {
1✔
67
                        return reconcile.Result{}, err
×
68
                }
×
69
        }
70

71
        if utils.IsMarkedForDeletion(secret.ObjectMeta) {
2✔
72
                log.Info("secret is marked for deletion, removing finalizer")
1✔
73
                return ctrl.Result{}, utils.RemoveFinalizer(ctx, r.Client, secret, common.FinalizerName)
1✔
74
        }
1✔
75

76
        log.Info("finished reconciling params secret")
1✔
77
        return reconcile.Result{}, nil
1✔
78
}
79

80
// SetupWithManager sets up the controller with the Manager.
81
func (r *SecretReconciler) SetupWithManager(mgr ctrl.Manager) error {
1✔
82
        labelSelector := metav1.LabelSelector{
1✔
83
                MatchLabels: map[string]string{common.WatchSecretLabel: "true"},
1✔
84
        }
1✔
85
        selectorPredicate, err := predicate.LabelSelectorPredicate(labelSelector)
1✔
86
        if err != nil {
1✔
NEW
87
                return err
×
NEW
88
        }
×
89

90
        dataChangedPredicate := predicate.Funcs{
1✔
91
                UpdateFunc: func(e event.UpdateEvent) bool {
2✔
92
                        oldSecret := e.ObjectOld.(*corev1.Secret)
1✔
93
                        newSecret := e.ObjectNew.(*corev1.Secret)
1✔
94
                        return (utils.IsSecretWatched(newSecret) && isSecretDataChanged(oldSecret, newSecret)) || isSecretInDelete(newSecret)
1✔
95
                },
1✔
UNCOV
96
                CreateFunc: func(e event.CreateEvent) bool {
×
NEW
97
                        return utils.IsSecretWatched(e.Object)
×
UNCOV
98
                },
×
99
                DeleteFunc: func(e event.DeleteEvent) bool {
1✔
100
                        return utils.IsSecretWatched(e.Object)
1✔
101
                },
1✔
102
                GenericFunc: func(e event.GenericEvent) bool {
×
NEW
103
                        return utils.IsSecretWatched(e.Object)
×
104
                },
×
105
        }
106

107
        return ctrl.NewControllerManagedBy(mgr).
1✔
108
                For(&corev1.Secret{}, builder.WithPredicates(selectorPredicate, dataChangedPredicate)).
1✔
109
                WithOptions(controller.Options{MaxConcurrentReconciles: 1}).
1✔
110
                Complete(r)
1✔
111
}
112

113
func isSecretDataChanged(oldSecret, newSecret *corev1.Secret) bool {
1✔
114
        return !reflect.DeepEqual(oldSecret.Data, newSecret.Data) || !reflect.DeepEqual(oldSecret.StringData, newSecret.StringData)
1✔
115
}
1✔
116

117
func isSecretInDelete(secret *corev1.Secret) bool {
1✔
118
        return !secret.GetDeletionTimestamp().IsZero() && controllerutil.ContainsFinalizer(secret, common.FinalizerName)
1✔
119
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc