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

opendefensecloud / solution-arsenal / 21667177506

04 Feb 2026 10:06AM UTC coverage: 66.416% (+0.6%) from 65.813%
21667177506

push

github

trevex
fix linting issues regarding nlreturn

619 of 932 relevant lines covered (66.42%)

6.89 hits per line

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

71.86
/pkg/controller/discovery_controller.go
1
// Copyright 2026 BWI GmbH and Artefact Conduit contributors
2
// SPDX-License-Identifier: Apache-2.0
3

4
package controller
5

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

11
        corev1 "k8s.io/api/core/v1"
12
        apierrors "k8s.io/apimachinery/pkg/api/errors"
13
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14
        "k8s.io/apimachinery/pkg/runtime"
15
        "k8s.io/apimachinery/pkg/util/intstr"
16
        "k8s.io/client-go/kubernetes"
17
        "k8s.io/client-go/tools/record"
18
        ctrl "sigs.k8s.io/controller-runtime"
19
        "sigs.k8s.io/controller-runtime/pkg/client"
20
        "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
21

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

25
const (
26
        discoveryFinalizer = "solar.opendefense.cloud/discovery-finalizer"
27
)
28

29
// DiscoveryReconciler reconciles a Discovery object
30
type DiscoveryReconciler struct {
31
        client.Client
32
        ClientSet     kubernetes.Interface
33
        Scheme        *runtime.Scheme
34
        Recorder      record.EventRecorder
35
        WorkerImage   string
36
        WorkerCommand string
37
        WorkerArgs    []string
38
}
39

40
// nolint:lll
41
// +kubebuilder:rbac:groups=solar.opendefense.cloud,resources=discoveries,verbs=get;list;watch;create;update;patch;delete
42
// +kubebuilder:rbac:groups=solar.opendefense.cloud,resources=discoveries/status,verbs=get;update;patch
43
// +kubebuilder:rbac:groups=solar.opendefense.cloud,resources=discoveries/finalizers,verbs=update
44
// +kubebuilder:rbac:groups="",resources=pods,verbs=get;list;watch;create;update;patch;delete
45
// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch;delete
46
// +kubebuilder:rbac:groups=core,resources=events,verbs=create;patch
47

48
// Reconcile moves the current state of the cluster closer to the desired state
49
func (r *DiscoveryReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
5✔
50
        log := ctrl.LoggerFrom(ctx)
5✔
51
        ctrlResult := ctrl.Result{}
5✔
52

5✔
53
        log.V(1).Info("Discovery is being reconciled", "req", req)
5✔
54

5✔
55
        // Fetch the Order instance
5✔
56
        res := &solarv1alpha1.Discovery{}
5✔
57
        if err := r.Get(ctx, req.NamespacedName, res); err != nil {
5✔
58
                if apierrors.IsNotFound(err) {
×
59
                        // Object not found, return. Created objects are automatically garbage collected.
×
60
                        return ctrlResult, nil
×
61
                }
×
62

63
                return ctrlResult, errLogAndWrap(log, err, "failed to get object")
×
64
        }
65

66
        // Handle deletion: cleanup artifact workflows, then remove finalizer
67
        if !res.DeletionTimestamp.IsZero() {
5✔
68
                log.V(1).Info("Discovery is being deleted")
×
69
                r.Recorder.Event(res, corev1.EventTypeWarning, "Deleting", "Discovery is being deleted, cleaning up worker")
×
70

×
71
                // Cleanup worker resources, if exists
×
72
                if err := r.deleteWorkerResources(ctx, res); err != nil {
×
73
                        return ctrlResult, errLogAndWrap(log, err, "failed to clean up worker resources")
×
74
                }
×
75

76
                // Remove finalizer
77
                if slices.Contains(res.Finalizers, discoveryFinalizer) {
×
78
                        log.V(1).Info("Removing finalizer from resource")
×
79
                        res.Finalizers = slices.DeleteFunc(res.Finalizers, func(f string) bool {
×
80
                                return f == discoveryFinalizer
×
81
                        })
×
82
                        if err := r.Update(ctx, res); err != nil {
×
83
                                return ctrlResult, errLogAndWrap(log, err, "failed to remove finalizer")
×
84
                        }
×
85
                }
86

87
                return ctrlResult, nil
×
88
        }
89

90
        // Add finalizer if not present and not deleting
91
        if res.DeletionTimestamp.IsZero() {
10✔
92
                if !slices.Contains(res.Finalizers, discoveryFinalizer) {
6✔
93
                        log.V(1).Info("Adding finalizer to resource")
1✔
94
                        res.Finalizers = append(res.Finalizers, discoveryFinalizer)
1✔
95
                        if err := r.Update(ctx, res); err != nil {
1✔
96
                                return ctrlResult, errLogAndWrap(log, err, "failed to add finalizer")
×
97
                        }
×
98
                        // Return without requeue; the Update event will trigger reconciliation again
99
                        return ctrlResult, nil
1✔
100
                }
101
        }
102

103
        pod, err := r.ClientSet.CoreV1().Pods(res.Namespace).Get(ctx, discoveryPrefixed(res.Name), metav1.GetOptions{})
4✔
104
        if err != nil && !apierrors.IsNotFound(err) {
4✔
105
                r.Recorder.Eventf(res, corev1.EventTypeWarning, "Reconcile", "Failed to get pod", err)
×
106
                return ctrlResult, errLogAndWrap(log, err, "failed to get pod information")
×
107
        }
×
108

109
        // No pod yet, create it.
110
        if pod == nil || pod.Name == "" {
5✔
111
                if err := r.createWorkerResources(ctx, res); err != nil {
1✔
112
                        return ctrlResult, errLogAndWrap(log, err, "failed to create pod")
×
113
                }
×
114

115
                return ctrlResult, nil
1✔
116
        }
117

118
        // Pod exists, check if it's up to date with our configuration and if it is healthy.
119
        if res.Status.PodGeneration != res.GetGeneration() {
4✔
120
                // Recreate pod, configuration mismatch
1✔
121
                r.Recorder.Eventf(res, corev1.EventTypeNormal, "Reconcile", "Configuration changed. Replacing pod.")
1✔
122
                if err := r.deleteWorkerResources(ctx, res); err != nil {
1✔
123
                        return ctrlResult, errLogAndWrap(log, err, "failed to clean up worker resources")
×
124
                }
×
125

126
                if err := r.createWorkerResources(ctx, res); err != nil {
1✔
127
                        return ctrlResult, errLogAndWrap(log, err, "failed to create pod")
×
128
                }
×
129

130
                return ctrlResult, nil
1✔
131
        } else {
2✔
132
                log.V(1).Info("Configuration hasn't changed", "podGen", res.Status.PodGeneration, "gen", res.GetGeneration())
2✔
133
        }
2✔
134

135
        return ctrlResult, nil
2✔
136
}
137

138
// deleteWorkerResources deletes the resources of the worker pod
139
func (r *DiscoveryReconciler) deleteWorkerResources(ctx context.Context, res *solarv1alpha1.Discovery) error {
1✔
140
        log := ctrl.LoggerFrom(ctx)
1✔
141

1✔
142
        if err := r.ClientSet.CoreV1().Services(res.Namespace).Delete(ctx, discoveryPrefixed(res.Name), metav1.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) {
1✔
143
                r.Recorder.Eventf(res, corev1.EventTypeWarning, "DeletionFailed", "Failed to delete service", err)
×
144
                return errLogAndWrap(log, err, "service deletion failed")
×
145
        }
×
146

147
        if err := r.ClientSet.CoreV1().Secrets(res.Namespace).Delete(ctx, discoveryPrefixed(res.Name), metav1.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) {
1✔
148
                r.Recorder.Eventf(res, corev1.EventTypeWarning, "DeletionFailed", "Failed to delete secret", err)
×
149
                return errLogAndWrap(log, err, "secret deletion failed")
×
150
        }
×
151
        if err := r.ClientSet.CoreV1().Pods(res.Namespace).Delete(ctx, discoveryPrefixed(res.Name), metav1.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) {
1✔
152
                r.Recorder.Eventf(res, corev1.EventTypeWarning, "DeletionFailed", "Failed to delete pod", err)
×
153
                return errLogAndWrap(log, err, "pod deletion failed")
×
154
        }
×
155

156
        return nil
1✔
157
}
158

159
// createWorkerResources creates the necessary resources for the worker pod
160
func (r *DiscoveryReconciler) createWorkerResources(ctx context.Context, res *solarv1alpha1.Discovery) error {
2✔
161
        log := ctrl.LoggerFrom(ctx)
2✔
162

2✔
163
        // Create secret
2✔
164
        // TODO: Use the actual configuration file instead of a dummy one
2✔
165
        secret := &corev1.Secret{
2✔
166
                ObjectMeta: objectMeta(res),
2✔
167
                StringData: map[string]string{
2✔
168
                        "config.yaml": "not implemented",
2✔
169
                },
2✔
170
        }
2✔
171
        _, err := r.ClientSet.CoreV1().Secrets(res.Namespace).Create(ctx, secret, metav1.CreateOptions{})
2✔
172
        if err != nil {
2✔
173
                r.Recorder.Eventf(res, corev1.EventTypeWarning, "CreationFailed", "Failed to create secret", err)
×
174
                return errLogAndWrap(log, err, "failed to create secret")
×
175
        }
×
176
        r.Recorder.Eventf(res, corev1.EventTypeNormal, "PodCreate", "Secret created")
2✔
177

2✔
178
        // Set owner references
2✔
179
        if err := controllerutil.SetControllerReference(res, secret, r.Scheme); err != nil {
2✔
180
                return errLogAndWrap(log, err, "failed to set controller reference")
×
181
        }
×
182

183
        // Create pod
184
        var args = r.WorkerArgs
2✔
185
        args = append(args, "--config", "/etc/worker/config.yaml")
2✔
186
        pod := &corev1.Pod{
2✔
187
                ObjectMeta: objectMeta(res),
2✔
188
                Spec: corev1.PodSpec{
2✔
189
                        Containers: []corev1.Container{
2✔
190
                                {
2✔
191
                                        Name:    "worker",
2✔
192
                                        Image:   r.WorkerImage,
2✔
193
                                        Command: []string{r.WorkerCommand},
2✔
194
                                        Args:    args,
2✔
195
                                        VolumeMounts: []corev1.VolumeMount{
2✔
196
                                                {
2✔
197
                                                        Name:      "config",
2✔
198
                                                        ReadOnly:  true,
2✔
199
                                                        MountPath: "/etc/worker"},
2✔
200
                                        },
2✔
201
                                        Ports: []corev1.ContainerPort{
2✔
202
                                                {
2✔
203
                                                        Name:          "webhook",
2✔
204
                                                        ContainerPort: 8080,
2✔
205
                                                },
2✔
206
                                        },
2✔
207
                                },
2✔
208
                        },
2✔
209
                        Volumes: []corev1.Volume{
2✔
210
                                {
2✔
211
                                        Name: "config",
2✔
212
                                        VolumeSource: corev1.VolumeSource{
2✔
213
                                                Secret: &corev1.SecretVolumeSource{
2✔
214
                                                        SecretName: res.Name,
2✔
215
                                                },
2✔
216
                                        },
2✔
217
                                },
2✔
218
                        },
2✔
219
                },
2✔
220
        }
2✔
221

2✔
222
        // Set owner references
2✔
223
        if err := controllerutil.SetControllerReference(res, pod, r.Scheme); err != nil {
2✔
224
                return errLogAndWrap(log, err, "failed to set controller reference")
×
225
        }
×
226

227
        _, err = r.ClientSet.CoreV1().Pods(res.Namespace).Create(ctx, pod, metav1.CreateOptions{})
2✔
228
        if err != nil {
2✔
229
                r.Recorder.Eventf(res, corev1.EventTypeWarning, "PodCreate", "Failed to create pod", err)
×
230
                return errLogAndWrap(log, err, "failed to create pod")
×
231
        }
×
232
        r.Recorder.Eventf(res, corev1.EventTypeNormal, "PodCreate", "Worker pod created")
2✔
233
        log.V(1).Info("Pod created", "podGen", res.GetGeneration())
2✔
234

2✔
235
        // Create service
2✔
236
        svc := &corev1.Service{
2✔
237
                ObjectMeta: objectMeta(res),
2✔
238
                Spec: corev1.ServiceSpec{
2✔
239
                        Type:     corev1.ServiceTypeClusterIP,
2✔
240
                        Ports:    []corev1.ServicePort{{Name: "webhook", Port: 8080, TargetPort: intstr.FromString("webhook")}},
2✔
241
                        Selector: map[string]string{"app.kubernetes.io/name": discoveryPrefixed(res.Name)},
2✔
242
                },
2✔
243
        }
2✔
244
        _, err = r.ClientSet.CoreV1().Services(res.Namespace).Create(ctx, svc, metav1.CreateOptions{})
2✔
245
        if err != nil {
2✔
246
                r.Recorder.Eventf(res, corev1.EventTypeWarning, "CreationFailed", "Failed to create service", err)
×
247
                return errLogAndWrap(log, err, "failed to create service")
×
248
        }
×
249
        r.Recorder.Eventf(res, corev1.EventTypeNormal, "ServiceCreate", "Service created")
2✔
250

2✔
251
        // Update discovery version in status
2✔
252
        res.Status.PodGeneration = res.GetGeneration()
2✔
253
        if err := r.Status().Update(ctx, res); err != nil {
2✔
254
                return errLogAndWrap(log, err, "failed to update status")
×
255
        }
×
256

257
        return nil
2✔
258
}
259

260
func objectMeta(res *solarv1alpha1.Discovery) metav1.ObjectMeta {
6✔
261
        labels := res.Labels
6✔
262
        if labels == nil {
12✔
263
                labels = make(map[string]string)
6✔
264
        }
6✔
265
        labels["app.kubernetes.io/managed-by"] = "solar-discovery-controller"
6✔
266
        labels["app.kubernetes.io/component"] = "discovery-worker"
6✔
267
        labels["app.kubernetes.io/instance"] = res.Name
6✔
268
        labels["app.kubernetes.io/name"] = discoveryPrefixed(res.Name)
6✔
269

6✔
270
        return metav1.ObjectMeta{
6✔
271
                Name:        discoveryPrefixed(res.Name),
6✔
272
                Namespace:   res.Namespace,
6✔
273
                Labels:      labels,
6✔
274
                Annotations: res.Annotations,
6✔
275
        }
6✔
276
}
277

278
// discoveryPrefixed returns the name of the discovery prefixed resource
279
func discoveryPrefixed(discoveryName string) string {
27✔
280
        return fmt.Sprintf("discovery-%s", discoveryName)
27✔
281
}
27✔
282

283
// SetupWithManager sets up the controller with the Manager.
284
func (r *DiscoveryReconciler) SetupWithManager(mgr ctrl.Manager) error {
1✔
285
        return ctrl.NewControllerManagedBy(mgr).
1✔
286
                For(&solarv1alpha1.Discovery{}).
1✔
287
                Owns(&corev1.Pod{}).
1✔
288
                Owns(&corev1.Secret{}).
1✔
289
                Complete(r)
1✔
290
}
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