@@ -5,6 +5,10 @@ import (
5
5
"strings"
6
6
"time"
7
7
8
+ "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
9
+ "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/certs"
10
+ "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
11
+ "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
8
12
log "github.com/sirupsen/logrus"
9
13
appsv1 "k8s.io/api/apps/v1"
10
14
corev1 "k8s.io/api/core/v1"
@@ -13,11 +17,6 @@ import (
13
17
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14
18
"k8s.io/apimachinery/pkg/util/intstr"
15
19
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
16
-
17
- "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
18
- "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/certs"
19
- "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
20
- "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
21
20
)
22
21
23
22
const (
@@ -63,15 +62,14 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
63
62
"apiservice" : apiServiceName ,
64
63
})
65
64
66
- // Replace all '.'s with "-"s to convert to a DNS-1035 label
67
65
serviceName := APIServiceNameToServiceName (apiServiceName )
68
- service , err := a .OpClient . GetService ( csv .GetNamespace (), serviceName )
66
+ service , err := a .lister . CoreV1 (). ServiceLister (). Services ( csv .GetNamespace ()). Get ( serviceName )
69
67
if k8serrors .IsNotFound (err ) || err != nil {
70
68
logger .Warnf ("generated Service not found" )
71
69
return err
72
70
}
73
71
74
- apiService , err := a .OpClient . GetAPIService (apiServiceName )
72
+ apiService , err := a .lister . APIRegistrationV1 (). APIServiceLister (). Get (apiServiceName )
75
73
if k8serrors .IsNotFound (err ) || err != nil {
76
74
logger .Warnf ("generated APIService not found" )
77
75
return err
@@ -97,9 +95,9 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
97
95
98
96
// Check if serving cert is active
99
97
secretName := apiServiceName + "-cert"
100
- secret , err := a .OpClient . GetSecret ( csv .GetNamespace (), secretName )
98
+ secret , err := a .lister . CoreV1 (). SecretLister (). Secrets ( csv .GetNamespace ()). Get ( secretName )
101
99
if k8serrors .IsNotFound (err ) || err != nil {
102
- logger .Warnf ("generated Secret not found" )
100
+ logger .Warnf ("generated Secret %s could not be retrieved" , secretName )
103
101
return err
104
102
}
105
103
cert , err := certs .PEMToCert (secret .Data ["tls.crt" ])
@@ -113,9 +111,10 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
113
111
}
114
112
115
113
// Check if CA hash matches expected
116
- if secret .Annotations [OLMCAHashAnnotationKey ] != hashFunc (caBundle ) {
117
- logger .Warnf ("CA cert hash does not match expected" )
118
- return fmt .Errorf ("CA cert hash does not match expected" )
114
+ caHash := hashFunc (caBundle )
115
+ if hash , ok := secret .GetAnnotations ()[OLMCAHashAnnotationKey ]; ! ok || hash != caHash {
116
+ logger .Warnf ("secret %s CA cert hash does not match expected" , secretName )
117
+ return fmt .Errorf ("secret %s CA cert hash does not match expected" , secretName )
119
118
}
120
119
121
120
// Check if serving cert is trusted by the CA
@@ -127,7 +126,17 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
127
126
if err := certs .VerifyCert (ca , cert , host ); err != nil {
128
127
return fmt .Errorf ("could not verify cert: %s" , err .Error ())
129
128
}
129
+ }
130
130
131
+ // Ensure the existing deployment has a matching CA hash annotation
132
+ deployment , err := a .lister .AppsV1 ().DeploymentLister ().Deployments (csv .GetNamespace ()).Get (desc .DeploymentName )
133
+ if k8serrors .IsNotFound (err ) || err != nil {
134
+ logger .Warnf ("expected APIService Deployment %s could not be retrieved" , desc .DeploymentName )
135
+ return err
136
+ }
137
+ if hash , ok := deployment .GetAnnotations ()[OLMCAHashAnnotationKey ]; ! ok || hash != caHash {
138
+ logger .Warnf ("Deployment %s CA cert hash does not match expected" , desc .DeploymentName )
139
+ return fmt .Errorf ("Deployment %s CA cert hash does not match expected" , desc .DeploymentName )
131
140
}
132
141
}
133
142
@@ -146,7 +155,7 @@ func (a *Operator) isAPIServiceAvailable(apiService *apiregistrationv1.APIServic
146
155
func (a * Operator ) areAPIServicesAvailable (descs []v1alpha1.APIServiceDescription ) (bool , error ) {
147
156
for _ , desc := range descs {
148
157
apiServiceName := fmt .Sprintf ("%s.%s" , desc .Version , desc .Group )
149
- apiService , err := a .OpClient . GetAPIService (apiServiceName )
158
+ apiService , err := a .lister . APIRegistrationV1 (). APIServiceLister (). Get (apiServiceName )
150
159
if err != nil {
151
160
return false , err
152
161
}
@@ -247,23 +256,32 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
247
256
Selector : depSpec .Selector .MatchLabels ,
248
257
},
249
258
}
250
-
251
- // Replace all '.'s with "-"s to convert to a DNS-1035 label
252
259
service .SetName (APIServiceNameToServiceName (apiServiceName ))
253
260
service .SetNamespace (csv .GetNamespace ())
254
261
ownerutil .AddNonBlockingOwner (service , csv )
255
262
256
- _ , err := a .OpClient .CreateService (service )
257
- if k8serrors .IsAlreadyExists (err ) {
258
- // attempt a replace
263
+ existingService , err := a .lister .CoreV1 ().ServiceLister ().Services (csv .GetNamespace ()).Get (service .GetName ())
264
+ if err == nil {
265
+ // Check if the only owners are this CSV or in this CSV's replacement chain
266
+ if ! ownerutil .Adoptable (csv , existingService .GetOwnerReferences ()) {
267
+ return nil , fmt .Errorf ("service %s not safe to replace: extraneous ownerreferences found" , service .GetName ())
268
+ }
269
+
270
+ // Append previous ownerrefs to the new Service
271
+ service .SetOwnerReferences (append (service .GetOwnerReferences (), existingService .GetOwnerReferences ()... ))
272
+
273
+ // Attempt a replace
259
274
deleteErr := a .OpClient .DeleteService (service .GetNamespace (), service .GetName (), & metav1.DeleteOptions {})
260
- if _ , err := a .OpClient .CreateService (service ); err != nil || deleteErr != nil {
261
- logger .Warnf ("could not replace service %s" , service .GetName ())
262
- return nil , err
275
+ if err != nil && ! k8serrors .IsNotFound (deleteErr ) {
276
+ return nil , fmt .Errorf ("could not delete existing service %s" , service .GetName ())
263
277
}
264
- } else if err != nil {
278
+ }
279
+
280
+ // Attempt to create the Service
281
+ _ , err = a .OpClient .CreateService (service )
282
+ if err != nil {
265
283
logger .Warnf ("could not create service %s" , service .GetName ())
266
- return nil , err
284
+ return nil , fmt . Errorf ( "could not create service %s: %s" , service . GetName (), err . Error ())
267
285
}
268
286
269
287
// Create signed serving cert
@@ -302,17 +320,28 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
302
320
}
303
321
caHash := certs .PEMSHA256 (caPEM )
304
322
secret .SetAnnotations (map [string ]string {OLMCAHashAnnotationKey : caHash })
305
- ownerutil .AddNonBlockingOwner (secret , csv )
306
323
307
- _ , err = a .OpClient .CreateSecret (secret )
308
- if k8serrors .IsAlreadyExists (err ) {
309
- // attempt an update
324
+ existingSecret , err := a .lister .CoreV1 ().SecretLister ().Secrets (csv .GetNamespace ()).Get (secret .GetName ())
325
+ if err == nil {
326
+ // Check if the only owners are this CSV or in this CSV's replacement chain
327
+ if ownerutil .Adoptable (csv , existingSecret .GetOwnerReferences ()) {
328
+ ownerutil .AddNonBlockingOwner (secret , csv )
329
+ }
330
+
331
+ // Attempt an update
310
332
if _ , err := a .OpClient .UpdateSecret (secret ); err != nil {
311
- logger .Warnf ("could not update Secret %s" , secret .GetName ())
333
+ logger .Warnf ("could not update secret %s" , secret .GetName ())
334
+ return nil , err
335
+ }
336
+ } else if k8serrors .IsNotFound (err ) {
337
+ // Create the secret
338
+ ownerutil .AddNonBlockingOwner (secret , csv )
339
+ _ , err = a .OpClient .CreateSecret (secret )
340
+ if err != nil {
341
+ log .Warnf ("could not create secret %s" , secret .GetName ())
312
342
return nil , err
313
343
}
314
- } else if err != nil {
315
- log .Warnf ("could not create Secret %s" , secret .GetName ())
344
+ } else {
316
345
return nil , err
317
346
}
318
347
@@ -329,17 +358,28 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
329
358
}
330
359
secretRole .SetName (secret .GetName ())
331
360
secretRole .SetNamespace (csv .GetNamespace ())
332
- ownerutil .AddNonBlockingOwner (secretRole , csv )
333
361
334
- _ , err = a .OpClient .CreateRole (secretRole )
335
- if k8serrors .IsAlreadyExists (err ) {
336
- // attempt an update
362
+ existingSecretRole , err := a .lister .RbacV1 ().RoleLister ().Roles (csv .GetNamespace ()).Get (secretRole .GetName ())
363
+ if err == nil {
364
+ // Check if the only owners are this CSV or in this CSV's replacement chain
365
+ if ownerutil .Adoptable (csv , existingSecretRole .GetOwnerReferences ()) {
366
+ ownerutil .AddNonBlockingOwner (secretRole , csv )
367
+ }
368
+
369
+ // Attempt an update
337
370
if _ , err := a .OpClient .UpdateRole (secretRole ); err != nil {
338
- logger .Warnf ("could not update Role %s" , secretRole .GetName ())
371
+ logger .Warnf ("could not update secret role %s" , secretRole .GetName ())
372
+ return nil , err
373
+ }
374
+ } else if k8serrors .IsNotFound (err ) {
375
+ // Create the role
376
+ ownerutil .AddNonBlockingOwner (secretRole , csv )
377
+ _ , err = a .OpClient .CreateRole (secretRole )
378
+ if err != nil {
379
+ log .Warnf ("could not create secret role %s" , secretRole .GetName ())
339
380
return nil , err
340
381
}
341
- } else if err != nil {
342
- log .Warnf ("could not create Role %s" , secretRole .GetName ())
382
+ } else {
343
383
return nil , err
344
384
}
345
385
@@ -360,17 +400,28 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
360
400
}
361
401
secretRoleBinding .SetName (secret .GetName ())
362
402
secretRoleBinding .SetNamespace (csv .GetNamespace ())
363
- ownerutil .AddNonBlockingOwner (secretRoleBinding , csv )
364
403
365
- _ , err = a .OpClient .CreateRoleBinding (secretRoleBinding )
366
- if k8serrors .IsAlreadyExists (err ) {
367
- // attempt an update
404
+ existingSecretRoleBinding , err := a .lister .RbacV1 ().RoleBindingLister ().RoleBindings (csv .GetNamespace ()).Get (secretRoleBinding .GetName ())
405
+ if err == nil {
406
+ // Check if the only owners are this CSV or in this CSV's replacement chain
407
+ if ownerutil .Adoptable (csv , existingSecretRoleBinding .GetOwnerReferences ()) {
408
+ ownerutil .AddNonBlockingOwner (secretRoleBinding , csv )
409
+ }
410
+
411
+ // Attempt an update
368
412
if _ , err := a .OpClient .UpdateRoleBinding (secretRoleBinding ); err != nil {
369
- logger .Warnf ("could not update RoleBinding %s" , secretRoleBinding .GetName ())
413
+ logger .Warnf ("could not update secret rolebinding %s" , secretRoleBinding .GetName ())
414
+ return nil , err
415
+ }
416
+ } else if k8serrors .IsNotFound (err ) {
417
+ // Create the role
418
+ ownerutil .AddNonBlockingOwner (secretRoleBinding , csv )
419
+ _ , err = a .OpClient .CreateRoleBinding (secretRoleBinding )
420
+ if err != nil {
421
+ log .Warnf ("could not create secret rolebinding %s" , secretRoleBinding .GetName ())
370
422
return nil , err
371
423
}
372
- } else if err != nil {
373
- log .Warnf ("could not create RoleBinding %s" , secretRoleBinding .GetName ())
424
+ } else {
374
425
return nil , err
375
426
}
376
427
@@ -391,17 +442,28 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
391
442
},
392
443
}
393
444
authDelegatorClusterRoleBinding .SetName (apiServiceName + "-system:auth-delegator" )
394
- ownerutil .AddNonBlockingOwner (authDelegatorClusterRoleBinding , csv )
395
445
396
- _ , err = a .OpClient .CreateClusterRoleBinding (authDelegatorClusterRoleBinding )
397
- if k8serrors .IsAlreadyExists (err ) {
398
- // attempt an update
446
+ existingAuthDelegatorClusterRoleBinding , err := a .lister .RbacV1 ().ClusterRoleBindingLister ().Get (authDelegatorClusterRoleBinding .GetName ())
447
+ if err == nil {
448
+ // Check if the only owners are this CSV or in this CSV's replacement chain
449
+ if ownerutil .Adoptable (csv , existingAuthDelegatorClusterRoleBinding .GetOwnerReferences ()) {
450
+ ownerutil .AddNonBlockingOwner (authDelegatorClusterRoleBinding , csv )
451
+ }
452
+
453
+ // Attempt an update
399
454
if _ , err := a .OpClient .UpdateClusterRoleBinding (authDelegatorClusterRoleBinding ); err != nil {
400
- logger .Warnf ("could not update ClusterRoleBinding %s" , authDelegatorClusterRoleBinding .GetName ())
455
+ logger .Warnf ("could not update auth delegator clusterrolebinding %s" , authDelegatorClusterRoleBinding .GetName ())
456
+ return nil , err
457
+ }
458
+ } else if k8serrors .IsNotFound (err ) {
459
+ // Create the role
460
+ ownerutil .AddNonBlockingOwner (authDelegatorClusterRoleBinding , csv )
461
+ _ , err = a .OpClient .CreateClusterRoleBinding (authDelegatorClusterRoleBinding )
462
+ if err != nil {
463
+ log .Warnf ("could not create auth delegator clusterrolebinding %s" , authDelegatorClusterRoleBinding .GetName ())
401
464
return nil , err
402
465
}
403
- } else if err != nil {
404
- log .Warnf ("could not create ClusterRoleBinding %s" , authDelegatorClusterRoleBinding .GetName ())
466
+ } else {
405
467
return nil , err
406
468
}
407
469
@@ -423,17 +485,28 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
423
485
}
424
486
authReaderRoleBinding .SetName (apiServiceName + "-auth-reader" )
425
487
authReaderRoleBinding .SetNamespace ("kube-system" )
426
- ownerutil .AddNonBlockingOwner (authReaderRoleBinding , csv )
427
488
428
- _ , err = a .OpClient .CreateRoleBinding (authReaderRoleBinding )
429
- if k8serrors .IsAlreadyExists (err ) {
430
- // attempt an update
489
+ existingAuthReaderRoleBinding , err := a .lister .RbacV1 ().RoleBindingLister ().RoleBindings ("kube-system" ).Get (authReaderRoleBinding .GetName ())
490
+ if err == nil {
491
+ // Check if the only owners are this CSV or in this CSV's replacement chain
492
+ if ownerutil .Adoptable (csv , existingAuthReaderRoleBinding .GetOwnerReferences ()) {
493
+ ownerutil .AddNonBlockingOwner (authReaderRoleBinding , csv )
494
+ }
495
+
496
+ // Attempt an update
431
497
if _ , err := a .OpClient .UpdateRoleBinding (authReaderRoleBinding ); err != nil {
432
- logger .Warnf ("could not update RoleBinding %s" , authReaderRoleBinding .GetName ())
498
+ logger .Warnf ("could not update auth reader role binding %s" , authReaderRoleBinding .GetName ())
499
+ return nil , err
500
+ }
501
+ } else if k8serrors .IsNotFound (err ) {
502
+ // Create the role
503
+ ownerutil .AddNonBlockingOwner (authReaderRoleBinding , csv )
504
+ _ , err = a .OpClient .CreateRoleBinding (authReaderRoleBinding )
505
+ if err != nil {
506
+ log .Warnf ("could not create auth reader role binding %s" , authReaderRoleBinding .GetName ())
433
507
return nil , err
434
508
}
435
- } else if err != nil {
436
- log .Warnf ("could not create RoleBinding %s" , authReaderRoleBinding .GetName ())
509
+ } else {
437
510
return nil , err
438
511
}
439
512
@@ -469,7 +542,6 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
469
542
depSpec .Template .Spec .Volumes = append (depSpec .Template .Spec .Volumes , volume )
470
543
}
471
544
472
- // TODO(NICK): limit which containers get a volume mount
473
545
mount := corev1.VolumeMount {
474
546
Name : volume .Name ,
475
547
MountPath : "/apiserver.local.config/certificates" ,
@@ -501,7 +573,7 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
501
573
depSpec .Template .ObjectMeta .SetAnnotations (map [string ]string {OLMCAHashAnnotationKey : caHash })
502
574
503
575
exists := true
504
- apiService , err := a .OpClient . GetAPIService (apiServiceName )
576
+ apiService , err := a .lister . APIRegistrationV1 (). APIServiceLister (). Get (apiServiceName )
505
577
if err != nil {
506
578
if ! k8serrors .IsNotFound (err ) {
507
579
return nil , err
@@ -556,5 +628,29 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
556
628
// APIServiceNameToServiceName returns the result of replacing all
557
629
// periods in the given APIService name with hyphens
558
630
func APIServiceNameToServiceName (apiServiceName string ) string {
631
+ // Replace all '.'s with "-"s to convert to a DNS-1035 label
559
632
return strings .Replace (apiServiceName , "." , "-" , - 1 )
560
633
}
634
+
635
+ // safeToReplace ensures that the given set of OwnerReferences refers to CSVs in the given CSV's replacement chain
636
+ // or the CSV itself
637
+ func (a * Operator ) safeToReplace (csv * v1alpha1.ClusterServiceVersion , owners []metav1.OwnerReference ) bool {
638
+ replaces := map [string ]struct {}{
639
+ csv .GetName (): {},
640
+ }
641
+ for _ , r := range a .findIntermediatesForDeletion (csv ) {
642
+ replaces [r .GetName ()] = struct {}{}
643
+ }
644
+
645
+ for _ , owner := range owners {
646
+ if owner .Kind != v1alpha1 .ClusterServiceVersionKind {
647
+ return false
648
+ }
649
+
650
+ if _ , ok := replaces [owner .Name ]; ! ok {
651
+ return false
652
+ }
653
+ }
654
+
655
+ return true
656
+ }
0 commit comments