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

opendefensecloud / solution-arsenal / 24348008499

13 Apr 2026 02:10PM UTC coverage: 72.293% (-2.0%) from 74.334%
24348008499

Pull #395

github

web-flow
Merge 533051a8b into 3bbb809bb
Pull Request #395: feat: split of additional resources from Target and refactor rendering

535 of 713 new or added lines in 8 files covered. (75.04%)

16 existing lines in 3 files now uncovered.

2030 of 2808 relevant lines covered (72.29%)

20.88 hits per line

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

77.78
/pkg/controller/profile_controller.go
1
// Copyright 2026 BWI GmbH and Solution Arsenal contributors
2
// SPDX-License-Identifier: Apache-2.0
3

4
package controller
5

6
import (
7
        "context"
8
        "fmt"
9

10
        corev1 "k8s.io/api/core/v1"
11
        apierrors "k8s.io/apimachinery/pkg/api/errors"
12
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13
        "k8s.io/apimachinery/pkg/labels"
14
        "k8s.io/apimachinery/pkg/runtime"
15
        "k8s.io/client-go/tools/events"
16
        ctrl "sigs.k8s.io/controller-runtime"
17
        "sigs.k8s.io/controller-runtime/pkg/client"
18
        "sigs.k8s.io/controller-runtime/pkg/handler"
19
        "sigs.k8s.io/controller-runtime/pkg/reconcile"
20

21
        solarv1alpha1 "go.opendefense.cloud/solar/api/solar/v1alpha1"
22
)
23

24
// ProfileReconciler reconciles a Profile object.
25
// It evaluates the Profile's TargetSelector against all Targets in the namespace
26
// and creates/deletes ReleaseBindings accordingly.
27
type ProfileReconciler struct {
28
        client.Client
29
        Scheme   *runtime.Scheme
30
        Recorder events.EventRecorder
31
        // WatchNamespace restricts reconciliation to this namespace.
32
        WatchNamespace string
33
}
34

35
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=profiles,verbs=get;list;watch
36
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=profiles/status,verbs=get;update;patch
37
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=releasebindings,verbs=get;list;watch;create;update;patch;delete
38
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=targets,verbs=get;list;watch
39
//+kubebuilder:rbac:groups=core,resources=events,verbs=create;patch
40
//+kubebuilder:rbac:groups=events.k8s.io,resources=events,verbs=create;patch
41

42
// Reconcile evaluates the Profile's TargetSelector and ensures matching ReleaseBindings exist.
43
func (r *ProfileReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
24✔
44
        log := ctrl.LoggerFrom(ctx)
24✔
45

24✔
46
        log.V(1).Info("Profile is being reconciled", "req", req)
24✔
47

24✔
48
        if r.WatchNamespace != "" && req.Namespace != r.WatchNamespace {
35✔
49
                return ctrl.Result{}, nil
11✔
50
        }
11✔
51

52
        // Fetch Profile
53
        profile := &solarv1alpha1.Profile{}
13✔
54
        if err := r.Get(ctx, req.NamespacedName, profile); err != nil {
13✔
NEW
55
                if apierrors.IsNotFound(err) {
×
NEW
56
                        return ctrl.Result{}, nil
×
NEW
57
                }
×
58

NEW
59
                return ctrl.Result{}, errLogAndWrap(log, err, "failed to get Profile")
×
60
        }
61

62
        // Evaluate TargetSelector against all Targets
63
        selector, err := metav1.LabelSelectorAsSelector(&profile.Spec.TargetSelector)
13✔
64
        if err != nil {
13✔
NEW
65
                log.Error(err, "invalid targetSelector in Profile")
×
NEW
66

×
NEW
67
                return ctrl.Result{}, nil
×
NEW
68
        }
×
69

70
        targetList := &solarv1alpha1.TargetList{}
13✔
71
        if err := r.List(ctx, targetList,
13✔
72
                client.InNamespace(profile.Namespace),
13✔
73
                client.MatchingLabelsSelector{Selector: selector},
13✔
74
        ); err != nil {
13✔
NEW
75
                return ctrl.Result{}, errLogAndWrap(log, err, "failed to list Targets")
×
NEW
76
        }
×
77

78
        // Build set of desired ReleaseBindings (one per matching target)
79
        desiredTargets := map[string]bool{}
13✔
80
        for _, target := range targetList.Items {
27✔
81
                desiredTargets[target.Name] = true
14✔
82
        }
14✔
83

84
        // List existing ReleaseBindings owned by this Profile
85
        existingBindings := &solarv1alpha1.ReleaseBindingList{}
13✔
86
        if err := r.List(ctx, existingBindings,
13✔
87
                client.InNamespace(profile.Namespace),
13✔
88
                client.MatchingFields{"metadata.ownerReferences.name": profile.Name},
13✔
89
        ); err != nil {
26✔
90
                // Field index may not be available; fall back to listing all and filtering
13✔
91
                allBindings := &solarv1alpha1.ReleaseBindingList{}
13✔
92
                if err := r.List(ctx, allBindings, client.InNamespace(profile.Namespace)); err != nil {
13✔
NEW
93
                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to list ReleaseBindings")
×
NEW
94
                }
×
95

96
                existingBindings = &solarv1alpha1.ReleaseBindingList{}
13✔
97

13✔
98
                for i := range allBindings.Items {
22✔
99
                        if metav1.IsControlledBy(&allBindings.Items[i], profile) {
18✔
100
                                existingBindings.Items = append(existingBindings.Items, allBindings.Items[i])
9✔
101
                        }
9✔
102
                }
103
        }
104

105
        // Delete ReleaseBindings for targets that no longer match
106
        existingTargets := map[string]*solarv1alpha1.ReleaseBinding{}
13✔
107
        for i := range existingBindings.Items {
22✔
108
                rb := &existingBindings.Items[i]
9✔
109
                existingTargets[rb.Spec.TargetRef.Name] = rb
9✔
110

9✔
111
                if !desiredTargets[rb.Spec.TargetRef.Name] {
10✔
112
                        log.V(1).Info("Deleting ReleaseBinding for unmatched target", "target", rb.Spec.TargetRef.Name)
1✔
113
                        if err := r.Delete(ctx, rb); err != nil && !apierrors.IsNotFound(err) {
1✔
NEW
114
                                return ctrl.Result{}, errLogAndWrap(log, err, "failed to delete ReleaseBinding")
×
NEW
115
                        }
×
116

117
                        r.Recorder.Eventf(profile, nil, corev1.EventTypeNormal, "Deleted", "Delete",
1✔
118
                                "Deleted ReleaseBinding for target %s", rb.Spec.TargetRef.Name)
1✔
119
                }
120
        }
121

122
        // Create ReleaseBindings for new matching targets
123
        for _, target := range targetList.Items {
27✔
124
                if _, exists := existingTargets[target.Name]; exists {
22✔
125
                        continue
8✔
126
                }
127

128
                rb := &solarv1alpha1.ReleaseBinding{
6✔
129
                        ObjectMeta: metav1.ObjectMeta{
6✔
130
                                // We need to truncated the name: 57 (input) + 1 (-) + 5 (appended by generated) = 63 (max chars allowed)
6✔
131
                                GenerateName: truncateName(fmt.Sprintf("%s-%s", profile.Name, target.Name), 57) + "-",
6✔
132
                                Namespace:    profile.Namespace,
6✔
133
                        },
6✔
134
                        Spec: solarv1alpha1.ReleaseBindingSpec{
6✔
135
                                TargetRef:  corev1.LocalObjectReference{Name: target.Name},
6✔
136
                                ReleaseRef: profile.Spec.ReleaseRef,
6✔
137
                        },
6✔
138
                }
6✔
139
                if err := ctrl.SetControllerReference(profile, rb, r.Scheme); err != nil {
6✔
NEW
140
                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to set controller reference on ReleaseBinding")
×
NEW
141
                }
×
142

143
                if err := r.Create(ctx, rb); err != nil {
6✔
NEW
144
                        if apierrors.IsAlreadyExists(err) {
×
NEW
145
                                continue
×
146
                        }
147

NEW
148
                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to create ReleaseBinding")
×
149
                }
150

151
                log.V(1).Info("Created ReleaseBinding for target", "target", target.Name)
6✔
152
                r.Recorder.Eventf(profile, nil, corev1.EventTypeNormal, "Created", "Create",
6✔
153
                        "Created ReleaseBinding for target %s", target.Name)
6✔
154
        }
155

156
        // Update status
157
        original := profile.DeepCopy()
13✔
158
        profile.Status.MatchedTargets = len(targetList.Items)
13✔
159
        if profile.Status.MatchedTargets != original.Status.MatchedTargets {
19✔
160
                if err := r.Status().Update(ctx, profile); err != nil {
6✔
NEW
161
                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to update Profile status")
×
NEW
162
                }
×
163
        }
164

165
        return ctrl.Result{}, nil
13✔
166
}
167

168
// SetupWithManager sets up the controller with the Manager.
169
func (r *ProfileReconciler) SetupWithManager(mgr ctrl.Manager) error {
1✔
170
        return ctrl.NewControllerManagedBy(mgr).
1✔
171
                For(&solarv1alpha1.Profile{}).
1✔
172
                Owns(&solarv1alpha1.ReleaseBinding{}).
1✔
173
                Watches(
1✔
174
                        &solarv1alpha1.Target{},
1✔
175
                        handler.EnqueueRequestsFromMapFunc(r.mapTargetToProfiles),
1✔
176
                ).
1✔
177
                Complete(r)
1✔
178
}
1✔
179

180
// mapTargetToProfiles maps a Target to all Profiles in the same namespace that might match it.
181
func (r *ProfileReconciler) mapTargetToProfiles(ctx context.Context, obj client.Object) []reconcile.Request {
136✔
182
        log := ctrl.LoggerFrom(ctx)
136✔
183

136✔
184
        target, ok := obj.(*solarv1alpha1.Target)
136✔
185
        if !ok {
136✔
NEW
186
                return nil
×
NEW
187
        }
×
188

189
        profileList := &solarv1alpha1.ProfileList{}
136✔
190
        if err := r.List(ctx, profileList, client.InNamespace(target.Namespace)); err != nil {
136✔
NEW
191
                log.Error(err, "failed to list Profiles for Target mapping")
×
NEW
192

×
NEW
193
                return nil
×
NEW
194
        }
×
195

196
        targetLabels := labels.Set(target.Labels)
136✔
197
        var requests []reconcile.Request
136✔
198

136✔
199
        for _, profile := range profileList.Items {
181✔
200
                selector, err := metav1.LabelSelectorAsSelector(&profile.Spec.TargetSelector)
45✔
201
                if err != nil {
45✔
NEW
202
                        continue
×
203
                }
204

205
                if selector.Matches(targetLabels) {
78✔
206
                        requests = append(requests, reconcile.Request{
33✔
207
                                NamespacedName: client.ObjectKeyFromObject(&profile),
33✔
208
                        })
33✔
209
                }
33✔
210
        }
211

212
        return requests
136✔
213
}
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