Skip to content

Commit 98964b3

Browse files
committed
feat(listers): add and use aggregate informer lister
1 parent 9f154cf commit 98964b3

File tree

17 files changed

+1055
-112
lines changed

17 files changed

+1055
-112
lines changed

pkg/controller/operators/olm/apiservices.go

Lines changed: 157 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ import (
55
"strings"
66
"time"
77

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"
812
log "github.com/sirupsen/logrus"
913
appsv1 "k8s.io/api/apps/v1"
1014
corev1 "k8s.io/api/core/v1"
@@ -13,11 +17,6 @@ import (
1317
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1418
"k8s.io/apimachinery/pkg/util/intstr"
1519
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"
2120
)
2221

2322
const (
@@ -63,15 +62,14 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
6362
"apiservice": apiServiceName,
6463
})
6564

66-
// Replace all '.'s with "-"s to convert to a DNS-1035 label
6765
serviceName := APIServiceNameToServiceName(apiServiceName)
68-
service, err := a.OpClient.GetService(csv.GetNamespace(), serviceName)
66+
service, err := a.lister.CoreV1().ServiceLister().Services(csv.GetNamespace()).Get(serviceName)
6967
if k8serrors.IsNotFound(err) || err != nil {
7068
logger.Warnf("generated Service not found")
7169
return err
7270
}
7371

74-
apiService, err := a.OpClient.GetAPIService(apiServiceName)
72+
apiService, err := a.lister.APIRegistrationV1().APIServiceLister().Get(apiServiceName)
7573
if k8serrors.IsNotFound(err) || err != nil {
7674
logger.Warnf("generated APIService not found")
7775
return err
@@ -97,9 +95,9 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
9795

9896
// Check if serving cert is active
9997
secretName := apiServiceName + "-cert"
100-
secret, err := a.OpClient.GetSecret(csv.GetNamespace(), secretName)
98+
secret, err := a.lister.CoreV1().SecretLister().Secrets(csv.GetNamespace()).Get(secretName)
10199
if k8serrors.IsNotFound(err) || err != nil {
102-
logger.Warnf("generated Secret not found")
100+
logger.Warnf("generated Secret %s could not be retrieved", secretName)
103101
return err
104102
}
105103
cert, err := certs.PEMToCert(secret.Data["tls.crt"])
@@ -113,9 +111,10 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
113111
}
114112

115113
// 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)
119118
}
120119

121120
// Check if serving cert is trusted by the CA
@@ -127,7 +126,17 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
127126
if err := certs.VerifyCert(ca, cert, host); err != nil {
128127
return fmt.Errorf("could not verify cert: %s", err.Error())
129128
}
129+
}
130130

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)
131140
}
132141
}
133142

@@ -146,7 +155,7 @@ func (a *Operator) isAPIServiceAvailable(apiService *apiregistrationv1.APIServic
146155
func (a *Operator) areAPIServicesAvailable(descs []v1alpha1.APIServiceDescription) (bool, error) {
147156
for _, desc := range descs {
148157
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)
150159
if err != nil {
151160
return false, err
152161
}
@@ -247,23 +256,32 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
247256
Selector: depSpec.Selector.MatchLabels,
248257
},
249258
}
250-
251-
// Replace all '.'s with "-"s to convert to a DNS-1035 label
252259
service.SetName(APIServiceNameToServiceName(apiServiceName))
253260
service.SetNamespace(csv.GetNamespace())
254261
ownerutil.AddNonBlockingOwner(service, csv)
255262

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
259274
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())
263277
}
264-
} else if err != nil {
278+
}
279+
280+
// Attempt to create the Service
281+
_, err = a.OpClient.CreateService(service)
282+
if err != nil {
265283
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())
267285
}
268286

269287
// Create signed serving cert
@@ -302,17 +320,28 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
302320
}
303321
caHash := certs.PEMSHA256(caPEM)
304322
secret.SetAnnotations(map[string]string{OLMCAHashAnnotationKey: caHash})
305-
ownerutil.AddNonBlockingOwner(secret, csv)
306323

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
310332
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())
312342
return nil, err
313343
}
314-
} else if err != nil {
315-
log.Warnf("could not create Secret %s", secret.GetName())
344+
} else {
316345
return nil, err
317346
}
318347

@@ -329,17 +358,28 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
329358
}
330359
secretRole.SetName(secret.GetName())
331360
secretRole.SetNamespace(csv.GetNamespace())
332-
ownerutil.AddNonBlockingOwner(secretRole, csv)
333361

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
337370
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())
339380
return nil, err
340381
}
341-
} else if err != nil {
342-
log.Warnf("could not create Role %s", secretRole.GetName())
382+
} else {
343383
return nil, err
344384
}
345385

@@ -360,17 +400,28 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
360400
}
361401
secretRoleBinding.SetName(secret.GetName())
362402
secretRoleBinding.SetNamespace(csv.GetNamespace())
363-
ownerutil.AddNonBlockingOwner(secretRoleBinding, csv)
364403

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
368412
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())
370422
return nil, err
371423
}
372-
} else if err != nil {
373-
log.Warnf("could not create RoleBinding %s", secretRoleBinding.GetName())
424+
} else {
374425
return nil, err
375426
}
376427

@@ -391,17 +442,28 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
391442
},
392443
}
393444
authDelegatorClusterRoleBinding.SetName(apiServiceName + "-system:auth-delegator")
394-
ownerutil.AddNonBlockingOwner(authDelegatorClusterRoleBinding, csv)
395445

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
399454
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())
401464
return nil, err
402465
}
403-
} else if err != nil {
404-
log.Warnf("could not create ClusterRoleBinding %s", authDelegatorClusterRoleBinding.GetName())
466+
} else {
405467
return nil, err
406468
}
407469

@@ -423,17 +485,28 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
423485
}
424486
authReaderRoleBinding.SetName(apiServiceName + "-auth-reader")
425487
authReaderRoleBinding.SetNamespace("kube-system")
426-
ownerutil.AddNonBlockingOwner(authReaderRoleBinding, csv)
427488

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
431497
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())
433507
return nil, err
434508
}
435-
} else if err != nil {
436-
log.Warnf("could not create RoleBinding %s", authReaderRoleBinding.GetName())
509+
} else {
437510
return nil, err
438511
}
439512

@@ -469,7 +542,6 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
469542
depSpec.Template.Spec.Volumes = append(depSpec.Template.Spec.Volumes, volume)
470543
}
471544

472-
// TODO(NICK): limit which containers get a volume mount
473545
mount := corev1.VolumeMount{
474546
Name: volume.Name,
475547
MountPath: "/apiserver.local.config/certificates",
@@ -501,7 +573,7 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
501573
depSpec.Template.ObjectMeta.SetAnnotations(map[string]string{OLMCAHashAnnotationKey: caHash})
502574

503575
exists := true
504-
apiService, err := a.OpClient.GetAPIService(apiServiceName)
576+
apiService, err := a.lister.APIRegistrationV1().APIServiceLister().Get(apiServiceName)
505577
if err != nil {
506578
if !k8serrors.IsNotFound(err) {
507579
return nil, err
@@ -556,5 +628,29 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
556628
// APIServiceNameToServiceName returns the result of replacing all
557629
// periods in the given APIService name with hyphens
558630
func APIServiceNameToServiceName(apiServiceName string) string {
631+
// Replace all '.'s with "-"s to convert to a DNS-1035 label
559632
return strings.Replace(apiServiceName, ".", "-", -1)
560633
}
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

Comments
 (0)