@@ -19,13 +19,21 @@ package controllers
19
19
import (
20
20
"context"
21
21
"fmt"
22
+ "regexp"
22
23
"strings"
23
24
"sync"
24
25
"time"
25
26
27
+ "k8s.io/client-go/kubernetes"
28
+
29
+ "sigs.k8s.io/controller-runtime/pkg/manager"
30
+
31
+ "k8s.io/client-go/tools/record"
32
+
26
33
log "github.com/sirupsen/logrus"
27
34
28
35
"sigs.k8s.io/secrets-store-csi-driver/apis/v1alpha1"
36
+ "sigs.k8s.io/secrets-store-csi-driver/pkg/client/clientset/versioned/scheme"
29
37
"sigs.k8s.io/secrets-store-csi-driver/pkg/util/fileutil"
30
38
"sigs.k8s.io/secrets-store-csi-driver/pkg/util/secretutil"
31
39
@@ -35,27 +43,48 @@ import (
35
43
36
44
corev1 "k8s.io/api/core/v1"
37
45
v1 "k8s.io/api/core/v1"
38
- "k8s.io/apimachinery/pkg/api/errors"
39
46
apierrors "k8s.io/apimachinery/pkg/api/errors"
40
47
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
41
48
"k8s.io/apimachinery/pkg/runtime"
49
+ apiruntime "k8s.io/apimachinery/pkg/runtime"
42
50
"k8s.io/apimachinery/pkg/types"
43
51
"k8s.io/apimachinery/pkg/util/wait"
52
+ clientcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
44
53
)
45
54
46
55
const (
47
- secretManagedLabel = "secrets-store.csi.k8s.io/managed"
56
+ secretManagedLabel = "secrets-store.csi.k8s.io/managed"
57
+ secretCreationFailedReason = "FailedToCreateSecret"
48
58
)
49
59
50
60
// SecretProviderClassPodStatusReconciler reconciles a SecretProviderClassPodStatus object
51
61
type SecretProviderClassPodStatusReconciler struct {
52
62
client.Client
53
- Mutex * sync.Mutex
54
- Log * log.Logger
55
- Scheme * runtime.Scheme
56
- NodeID string
57
- Reader client.Reader
58
- Writer client.Writer
63
+ mutex * sync.Mutex
64
+ log * log.Logger
65
+ scheme * apiruntime.Scheme
66
+ nodeID string
67
+ reader client.Reader
68
+ writer client.Writer
69
+ eventRecorder record.EventRecorder
70
+ }
71
+
72
+ // New creates a new SecretProviderClassPodStatusReconciler
73
+ func New (mgr manager.Manager , nodeID string ) (* SecretProviderClassPodStatusReconciler , error ) {
74
+ eventBroadcaster := record .NewBroadcaster ()
75
+ kubeClient := kubernetes .NewForConfigOrDie (mgr .GetConfig ())
76
+ eventBroadcaster .StartRecordingToSink (& clientcorev1.EventSinkImpl {Interface : kubeClient .CoreV1 ().Events ("" )})
77
+ recorder := eventBroadcaster .NewRecorder (scheme .Scheme , corev1.EventSource {Component : "csi-secrets-store-controller" })
78
+
79
+ return & SecretProviderClassPodStatusReconciler {
80
+ Client : mgr .GetClient (),
81
+ mutex : & sync.Mutex {},
82
+ scheme : mgr .GetScheme (),
83
+ nodeID : nodeID ,
84
+ reader : mgr .GetCache (),
85
+ writer : mgr .GetClient (),
86
+ eventRecorder : recorder ,
87
+ }, nil
59
88
}
60
89
61
90
func (r * SecretProviderClassPodStatusReconciler ) RunPatcher (stopCh <- chan struct {}) {
@@ -76,15 +105,15 @@ func (r *SecretProviderClassPodStatusReconciler) RunPatcher(stopCh <-chan struct
76
105
77
106
func (r * SecretProviderClassPodStatusReconciler ) Patcher () error {
78
107
log .Debugf ("patcher started" )
79
- r .Mutex .Lock ()
80
- defer r .Mutex .Unlock ()
108
+ r .mutex .Lock ()
109
+ defer r .mutex .Unlock ()
81
110
82
111
ctx := context .Background ()
83
112
spcPodStatusList := & v1alpha1.SecretProviderClassPodStatusList {}
84
113
spcMap := make (map [string ]v1alpha1.SecretProviderClass )
85
114
secretOwnerMap := make (map [types.NamespacedName ][]* v1alpha1.SecretProviderClassPodStatus )
86
115
// get a list of all spc pod status that belong to the node
87
- err := r .Reader .List (ctx , spcPodStatusList , r .ListOptionsLabelSelector ())
116
+ err := r .reader .List (ctx , spcPodStatusList , r .ListOptionsLabelSelector ())
88
117
if err != nil {
89
118
return fmt .Errorf ("failed to list secret provider class pod status, err: %+v" , err )
90
119
}
@@ -96,7 +125,7 @@ func (r *SecretProviderClassPodStatusReconciler) Patcher() error {
96
125
if val , exists := spcMap [spcPodStatuses [i ].Namespace + "/" + spcName ]; exists {
97
126
spc = & val
98
127
} else {
99
- if err := r .Reader .Get (ctx , client.ObjectKey {Namespace : spcPodStatuses [i ].Namespace , Name : spcName }, spc ); err != nil {
128
+ if err := r .reader .Get (ctx , client.ObjectKey {Namespace : spcPodStatuses [i ].Namespace , Name : spcName }, spc ); err != nil {
100
129
log .Errorf ("failed to get spc %s, err: %+v" , spcName , err )
101
130
return err
102
131
}
@@ -140,25 +169,26 @@ func (r *SecretProviderClassPodStatusReconciler) Patcher() error {
140
169
// ListOptionsLabelSelector returns a ListOptions with a label selector for node name.
141
170
func (r * SecretProviderClassPodStatusReconciler ) ListOptionsLabelSelector () client.ListOption {
142
171
return client .MatchingLabels (map [string ]string {
143
- v1alpha1 .InternalNodeLabel : r .NodeID ,
172
+ v1alpha1 .InternalNodeLabel : r .nodeID ,
144
173
})
145
174
}
146
175
147
176
// +kubebuilder:rbac:groups=secrets-store.csi.x-k8s.io,resources=secretproviderclasspodstatuses,verbs=get;list;watch;create;update;patch;delete
148
177
// +kubebuilder:rbac:groups=secrets-store.csi.x-k8s.io,resources=secretproviderclasspodstatuses/status,verbs=get;update;patch
149
178
// +kubebuilder:rbac:groups=secrets-store.csi.x-k8s.io,resources=secretproviderclasses,verbs=get;list;watch
150
179
// +kubebuilder:rbac:groups="",resources=pods,verbs=get;list;watch
180
+ // +kubebuilder:rbac:groups="",resources=events,verbs=create;patch
151
181
152
182
func (r * SecretProviderClassPodStatusReconciler ) Reconcile (req ctrl.Request ) (ctrl.Result , error ) {
153
- r .Mutex .Lock ()
154
- defer r .Mutex .Unlock ()
183
+ r .mutex .Lock ()
184
+ defer r .mutex .Unlock ()
155
185
156
186
ctx := context .Background ()
157
- logger := log .WithFields (log.Fields {"secretproviderclasspodstatus" : req .NamespacedName , "node" : r .NodeID })
187
+ logger := log .WithFields (log.Fields {"secretproviderclasspodstatus" : req .NamespacedName , "node" : r .nodeID })
158
188
logger .Info ("reconcile started" )
159
189
160
190
var spcPodStatus v1alpha1.SecretProviderClassPodStatus
161
- if err := r .Get (ctx , req .NamespacedName , & spcPodStatus ); err != nil {
191
+ if err := r .reader . Get (ctx , req .NamespacedName , & spcPodStatus ); err != nil {
162
192
if apierrors .IsNotFound (err ) {
163
193
return ctrl.Result {}, nil
164
194
}
@@ -177,14 +207,14 @@ func (r *SecretProviderClassPodStatusReconciler) Reconcile(req ctrl.Request) (ct
177
207
logger .Info ("node label not found, ignoring this spc pod status" )
178
208
return ctrl.Result {}, nil
179
209
}
180
- if ! strings .EqualFold (node , r .NodeID ) {
210
+ if ! strings .EqualFold (node , r .nodeID ) {
181
211
logger .Infof ("ignoring as spc pod status belongs to node %s" , node )
182
212
return ctrl.Result {}, nil
183
213
}
184
214
185
215
spcName := spcPodStatus .Status .SecretProviderClassName
186
216
spc := & v1alpha1.SecretProviderClass {}
187
- if err := r .Reader .Get (ctx , client.ObjectKey {Namespace : req .Namespace , Name : spcName }, spc ); err != nil {
217
+ if err := r .reader .Get (ctx , client.ObjectKey {Namespace : req .Namespace , Name : spcName }, spc ); err != nil {
188
218
logger .Errorf ("failed to get spc %s, err: %+v" , spcName , err )
189
219
if apierrors .IsNotFound (err ) {
190
220
return ctrl.Result {RequeueAfter : 5 * time .Second }, nil
@@ -197,8 +227,18 @@ func (r *SecretProviderClassPodStatusReconciler) Reconcile(req ctrl.Request) (ct
197
227
return ctrl.Result {}, nil
198
228
}
199
229
230
+ // podObjectReference is an object reference to the pod that spc pod status
231
+ // is created for. The object reference is created with minimal required fields
232
+ // name, namespace and UID. By doing this we can skip an additional client call
233
+ // to fetch the pod object
234
+ podObjectReference , err := getPodObjectReference (spcPodStatus )
235
+ if err != nil {
236
+ logger .Errorf ("failed to get pod object reference, error: %+v" , err )
237
+ }
238
+
200
239
files , err := fileutil .GetMountedFiles (spcPodStatus .Status .TargetPath )
201
240
if err != nil {
241
+ r .generateEvent (podObjectReference , corev1 .EventTypeWarning , secretCreationFailedReason , fmt .Sprintf ("failed to get mounted files, err: %+v" , err ))
202
242
logger .Errorf ("failed to get mounted files, err: %+v" , err )
203
243
return ctrl.Result {RequeueAfter : 10 * time .Second }, err
204
244
}
@@ -225,6 +265,7 @@ func (r *SecretProviderClassPodStatusReconciler) Reconcile(req ctrl.Request) (ct
225
265
226
266
datamap := make (map [string ][]byte )
227
267
if datamap , err = secretutil .GetSecretData (secretObj .Data , secretType , files ); err != nil {
268
+ r .generateEvent (podObjectReference , corev1 .EventTypeWarning , secretCreationFailedReason , fmt .Sprintf ("failed to get data in spc %s/%s for secret %s, err: %+v" , req .Namespace , spcName , secretName , err ))
228
269
log .Errorf ("failed to get data in spc %s/%s for secret %s, err: %+v" , req .Namespace , spcName , secretName , err )
229
270
errs = append (errs , fmt .Errorf ("failed to get data in spc %s/%s for secret %s, err: %+v" , req .Namespace , spcName , secretName , err ))
230
271
continue
@@ -256,6 +297,7 @@ func (r *SecretProviderClassPodStatusReconciler) Reconcile(req ctrl.Request) (ct
256
297
Factor : 1.0 ,
257
298
Jitter : 0.1 ,
258
299
}, f ); err != nil {
300
+ r .generateEvent (podObjectReference , corev1 .EventTypeWarning , secretCreationFailedReason , err .Error ())
259
301
return ctrl.Result {RequeueAfter : 5 * time .Second }, err
260
302
}
261
303
}
@@ -291,7 +333,7 @@ func (r *SecretProviderClassPodStatusReconciler) createK8sSecret(ctx context.Con
291
333
Data : datamap ,
292
334
}
293
335
294
- err := r .Writer .Create (ctx , secret )
336
+ err := r .writer .Create (ctx , secret )
295
337
if err == nil {
296
338
log .Infof ("created k8s secret: %s/%s" , namespace , name )
297
339
return nil
@@ -309,8 +351,11 @@ func (r *SecretProviderClassPodStatusReconciler) patchSecretWithOwnerRef(ctx con
309
351
Namespace : namespace ,
310
352
Name : name ,
311
353
}
312
- err := r .Client .Get (ctx , secretKey , secret )
313
- if err != nil && ! errors .IsNotFound (err ) {
354
+ if err := r .Client .Get (ctx , secretKey , secret ); err != nil {
355
+ if apierrors .IsNotFound (err ) {
356
+ log .Debugf ("secret %s/%s not found for patching" , namespace , name )
357
+ return nil
358
+ }
314
359
return err
315
360
}
316
361
@@ -327,14 +372,14 @@ func (r *SecretProviderClassPodStatusReconciler) patchSecretWithOwnerRef(ctx con
327
372
continue
328
373
}
329
374
needsPatch = true
330
- err = controllerutil .SetOwnerReference (spcPodStatus [i ], secret , r .Scheme )
375
+ err : = controllerutil .SetOwnerReference (spcPodStatus [i ], secret , r .scheme )
331
376
if err != nil {
332
377
return err
333
378
}
334
379
}
335
380
336
381
if needsPatch {
337
- return r .Writer .Patch (ctx , secret , patch )
382
+ return r .writer .Patch (ctx , secret , patch )
338
383
}
339
384
return nil
340
385
}
@@ -355,3 +400,35 @@ func (r *SecretProviderClassPodStatusReconciler) secretExists(ctx context.Contex
355
400
}
356
401
return false , err
357
402
}
403
+
404
+ // getPodObjectReference returns a v1.ObjectReference for the pod object
405
+ func getPodObjectReference (spcPodStatus v1alpha1.SecretProviderClassPodStatus ) (* v1.ObjectReference , error ) {
406
+ podName := spcPodStatus .Status .PodName
407
+ podNamespace := spcPodStatus .Namespace
408
+ podUID := getPodUIDFromTargetPath (spcPodStatus .Status .TargetPath )
409
+ if podUID == "" {
410
+ return nil , fmt .Errorf ("failed to get pod UID from target path" )
411
+ }
412
+ return & v1.ObjectReference {
413
+ Name : podName ,
414
+ Namespace : podNamespace ,
415
+ UID : types .UID (podUID ),
416
+ }, nil
417
+ }
418
+
419
+ // getPodUIDFromTargetPath returns podUID from targetPath
420
+ func getPodUIDFromTargetPath (targetPath string ) string {
421
+ re := regexp .MustCompile (`[\\|\/]+pods[\\|\/]+(.+?)[\\|\/]+volumes` )
422
+ match := re .FindStringSubmatch (targetPath )
423
+ if len (match ) < 2 {
424
+ return ""
425
+ }
426
+ return match [1 ]
427
+ }
428
+
429
+ // generateEvent generates an event
430
+ func (r * SecretProviderClassPodStatusReconciler ) generateEvent (obj runtime.Object , eventType , reason , message string ) {
431
+ if obj != nil {
432
+ r .eventRecorder .Eventf (obj , eventType , reason , message )
433
+ }
434
+ }
0 commit comments