Skip to content

Commit 12f4b12

Browse files
*: label k8s objects we own
Signed-off-by: Steve Kuznetsov <[email protected]>
1 parent 9e7031f commit 12f4b12

File tree

5 files changed

+345
-6
lines changed

5 files changed

+345
-6
lines changed

pkg/controller/operators/catalog/operator.go

+124
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@ import (
1111
"sync"
1212
"time"
1313

14+
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/internal/alongside"
15+
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/labeller"
1416
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/validatingroundtripper"
1517
errorwrap "github.com/pkg/errors"
1618
"github.com/sirupsen/logrus"
1719
"google.golang.org/grpc/connectivity"
20+
batchv1 "k8s.io/api/batch/v1"
1821
corev1 "k8s.io/api/core/v1"
1922
rbacv1 "k8s.io/api/rbac/v1"
2023
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
@@ -32,6 +35,9 @@ import (
3235
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
3336
"k8s.io/apimachinery/pkg/util/validation/field"
3437
"k8s.io/apimachinery/pkg/util/yaml"
38+
batchv1applyconfigurations "k8s.io/client-go/applyconfigurations/batch/v1"
39+
corev1applyconfigurations "k8s.io/client-go/applyconfigurations/core/v1"
40+
rbacv1applyconfigurations "k8s.io/client-go/applyconfigurations/rbac/v1"
3541
"k8s.io/client-go/dynamic"
3642
"k8s.io/client-go/informers"
3743
"k8s.io/client-go/metadata"
@@ -103,6 +109,7 @@ type Operator struct {
103109
client versioned.Interface
104110
dynamicClient dynamic.Interface
105111
lister operatorlister.OperatorLister
112+
k8sLabelQueueSets map[schema.GroupVersionResource]workqueue.RateLimitingInterface
106113
catsrcQueueSet *queueinformer.ResourceQueueSet
107114
subQueueSet *queueinformer.ResourceQueueSet
108115
ipQueueSet *queueinformer.ResourceQueueSet
@@ -191,6 +198,7 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
191198
lister: lister,
192199
namespace: operatorNamespace,
193200
recorder: eventRecorder,
201+
k8sLabelQueueSets: map[schema.GroupVersionResource]workqueue.RateLimitingInterface{},
194202
catsrcQueueSet: queueinformer.NewEmptyResourceQueueSet(),
195203
subQueueSet: queueinformer.NewEmptyResourceQueueSet(),
196204
ipQueueSet: queueinformer.NewEmptyResourceQueueSet(),
@@ -363,21 +371,85 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
363371
op.lister.RbacV1().RegisterRoleLister(metav1.NamespaceAll, roleInformer.Lister())
364372
sharedIndexInformers = append(sharedIndexInformers, roleInformer.Informer())
365373

374+
labelObjects := func(gvr schema.GroupVersionResource, informer cache.SharedIndexInformer, sync func(obj interface{}) error) error {
375+
op.k8sLabelQueueSets[gvr] = workqueue.NewRateLimitingQueueWithConfig(workqueue.DefaultControllerRateLimiter(), workqueue.RateLimitingQueueConfig{
376+
Name: gvr.String(),
377+
})
378+
queueInformer, err := queueinformer.NewQueueInformer(
379+
ctx,
380+
queueinformer.WithLogger(op.logger),
381+
queueinformer.WithInformer(informer),
382+
queueinformer.WithSyncer(queueinformer.LegacySyncHandler(sync).ToSyncer()),
383+
)
384+
if err != nil {
385+
return err
386+
}
387+
388+
if err := op.RegisterQueueInformer(queueInformer); err != nil {
389+
return err
390+
}
391+
392+
return nil
393+
}
394+
395+
if err := labelObjects(rbacv1.SchemeGroupVersion.WithResource("roles"), roleInformer.Informer(), labeller.ObjectLabeler[*rbacv1.Role, *rbacv1applyconfigurations.RoleApplyConfiguration](
396+
ctx, op.logger, labeller.HasOLMOwnerRef,
397+
rbacv1applyconfigurations.Role,
398+
func(namespace string, ctx context.Context, cfg *rbacv1applyconfigurations.RoleApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.Role, error) {
399+
return op.opClient.KubernetesInterface().RbacV1().Roles(namespace).Apply(ctx, cfg, opts)
400+
},
401+
)); err != nil {
402+
return nil, err
403+
}
404+
366405
// Wire RoleBindings
367406
roleBindingInformer := k8sInformerFactory.Rbac().V1().RoleBindings()
368407
op.lister.RbacV1().RegisterRoleBindingLister(metav1.NamespaceAll, roleBindingInformer.Lister())
369408
sharedIndexInformers = append(sharedIndexInformers, roleBindingInformer.Informer())
370409

410+
if err := labelObjects(rbacv1.SchemeGroupVersion.WithResource("rolebindings"), roleBindingInformer.Informer(), labeller.ObjectLabeler[*rbacv1.RoleBinding, *rbacv1applyconfigurations.RoleBindingApplyConfiguration](
411+
ctx, op.logger, labeller.HasOLMOwnerRef,
412+
rbacv1applyconfigurations.RoleBinding,
413+
func(namespace string, ctx context.Context, cfg *rbacv1applyconfigurations.RoleBindingApplyConfiguration, opts metav1.ApplyOptions) (*rbacv1.RoleBinding, error) {
414+
return op.opClient.KubernetesInterface().RbacV1().RoleBindings(namespace).Apply(ctx, cfg, opts)
415+
},
416+
)); err != nil {
417+
return nil, err
418+
}
419+
371420
// Wire ServiceAccounts
372421
serviceAccountInformer := k8sInformerFactory.Core().V1().ServiceAccounts()
373422
op.lister.CoreV1().RegisterServiceAccountLister(metav1.NamespaceAll, serviceAccountInformer.Lister())
374423
sharedIndexInformers = append(sharedIndexInformers, serviceAccountInformer.Informer())
375424

425+
if err := labelObjects(corev1.SchemeGroupVersion.WithResource("serviceaccounts"), serviceAccountInformer.Informer(), labeller.ObjectLabeler[*corev1.ServiceAccount, *corev1applyconfigurations.ServiceAccountApplyConfiguration](
426+
ctx, op.logger, func(object metav1.Object) bool {
427+
return labeller.HasOLMOwnerRef(object) || labeller.HasOLMLabel(object)
428+
},
429+
corev1applyconfigurations.ServiceAccount,
430+
func(namespace string, ctx context.Context, cfg *corev1applyconfigurations.ServiceAccountApplyConfiguration, opts metav1.ApplyOptions) (*corev1.ServiceAccount, error) {
431+
return op.opClient.KubernetesInterface().CoreV1().ServiceAccounts(namespace).Apply(ctx, cfg, opts)
432+
},
433+
)); err != nil {
434+
return nil, err
435+
}
436+
376437
// Wire Services
377438
serviceInformer := k8sInformerFactory.Core().V1().Services()
378439
op.lister.CoreV1().RegisterServiceLister(metav1.NamespaceAll, serviceInformer.Lister())
379440
sharedIndexInformers = append(sharedIndexInformers, serviceInformer.Informer())
380441

442+
// TODO(skuznets): some services don't seem to have any marker to key off of, but they match the operator name
443+
if err := labelObjects(corev1.SchemeGroupVersion.WithResource("services"), serviceInformer.Informer(), labeller.ObjectLabeler[*corev1.Service, *corev1applyconfigurations.ServiceApplyConfiguration](
444+
ctx, op.logger, labeller.HasOLMOwnerRef,
445+
corev1applyconfigurations.Service,
446+
func(namespace string, ctx context.Context, cfg *corev1applyconfigurations.ServiceApplyConfiguration, opts metav1.ApplyOptions) (*corev1.Service, error) {
447+
return op.opClient.KubernetesInterface().CoreV1().Services(namespace).Apply(ctx, cfg, opts)
448+
},
449+
)); err != nil {
450+
return nil, err
451+
}
452+
381453
// Wire Pods for CatalogSource
382454
catsrcReq, err := labels.NewRequirement(reconciler.CatalogSourceLabelKey, selection.Exists, nil)
383455
if err != nil {
@@ -392,6 +464,23 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
392464
op.lister.CoreV1().RegisterPodLister(metav1.NamespaceAll, csPodInformer.Lister())
393465
sharedIndexInformers = append(sharedIndexInformers, csPodInformer.Informer())
394466

467+
if err := labelObjects(corev1.SchemeGroupVersion.WithResource("pods"), csPodInformer.Informer(), labeller.ObjectLabeler[*corev1.Pod, *corev1applyconfigurations.PodApplyConfiguration](
468+
ctx, op.logger, func(object metav1.Object) bool {
469+
if labels := object.GetLabels(); labels != nil {
470+
if _, ok := labels[reconciler.CatalogSourceLabelKey]; ok {
471+
return true
472+
}
473+
}
474+
return false
475+
},
476+
corev1applyconfigurations.Pod,
477+
func(namespace string, ctx context.Context, cfg *corev1applyconfigurations.PodApplyConfiguration, opts metav1.ApplyOptions) (*corev1.Pod, error) {
478+
return op.opClient.KubernetesInterface().CoreV1().Pods(namespace).Apply(ctx, cfg, opts)
479+
},
480+
)); err != nil {
481+
return nil, err
482+
}
483+
395484
// Wire Pods for BundleUnpack job
396485
buReq, err := labels.NewRequirement(bundle.BundleUnpackPodLabel, selection.Exists, nil)
397486
if err != nil {
@@ -416,6 +505,27 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
416505
jobInformer := k8sInformerFactory.Batch().V1().Jobs()
417506
sharedIndexInformers = append(sharedIndexInformers, jobInformer.Informer())
418507

508+
if err := labelObjects(batchv1.SchemeGroupVersion.WithResource("jobs"), jobInformer.Informer(), labeller.ObjectLabeler[*batchv1.Job, *batchv1applyconfigurations.JobApplyConfiguration](
509+
ctx, op.logger, func(object metav1.Object) bool {
510+
job, ok := object.(*batchv1.Job)
511+
if !ok {
512+
return false
513+
}
514+
for _, container := range job.Spec.Template.Spec.Containers {
515+
if strings.Join(container.Command[0:3], " ") == "opm alpha bundle extract" {
516+
return true
517+
}
518+
}
519+
return false
520+
},
521+
batchv1applyconfigurations.Job,
522+
func(namespace string, ctx context.Context, cfg *batchv1applyconfigurations.JobApplyConfiguration, opts metav1.ApplyOptions) (*batchv1.Job, error) {
523+
return op.opClient.KubernetesInterface().BatchV1().Jobs(namespace).Apply(ctx, cfg, opts)
524+
},
525+
)); err != nil {
526+
return nil, err
527+
}
528+
419529
// Generate and register QueueInformers for k8s resources
420530
k8sSyncer := queueinformer.LegacySyncHandler(op.syncObject).ToSyncerWithDelete(op.handleDeletion)
421531
for _, informer := range sharedIndexInformers {
@@ -480,6 +590,20 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
480590
return nil, err
481591
}
482592

593+
if err := labelObjects(apiextensionsv1.SchemeGroupVersion.WithResource("customresourcedefinitions"), crdInformer, labeller.ObjectPatchLabeler[*apiextensionsv1.CustomResourceDefinition](
594+
ctx, op.logger, func(object metav1.Object) bool {
595+
for key := range object.GetAnnotations() {
596+
if strings.HasPrefix(key, alongside.AnnotationPrefix) {
597+
return true
598+
}
599+
}
600+
return false
601+
},
602+
op.opClient.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Patch,
603+
)); err != nil {
604+
return nil, err
605+
}
606+
483607
// Namespace sync for resolving subscriptions
484608
namespaceInformer := informers.NewSharedInformerFactory(op.opClient.KubernetesInterface(), resyncPeriod()).Core().V1().Namespaces()
485609
op.lister.CoreV1().RegisterNamespaceLister(namespaceInformer.Lister())

pkg/controller/operators/internal/alongside/alongside.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
)
1111

1212
const (
13-
prefix = "operatorframework.io/installed-alongside-"
13+
AnnotationPrefix = "operatorframework.io/installed-alongside-"
1414
)
1515

1616
// NamespacedName is a reference to an object by namespace and name.
@@ -33,7 +33,7 @@ type Annotator struct{}
3333
func (a Annotator) FromObject(o Annotatable) []NamespacedName {
3434
var result []NamespacedName
3535
for k, v := range o.GetAnnotations() {
36-
if !strings.HasPrefix(k, prefix) {
36+
if !strings.HasPrefix(k, AnnotationPrefix) {
3737
continue
3838
}
3939
tokens := strings.Split(v, "/")
@@ -55,7 +55,7 @@ func (a Annotator) ToObject(o Annotatable, nns []NamespacedName) {
5555
annotations := o.GetAnnotations()
5656

5757
for key := range annotations {
58-
if strings.HasPrefix(key, prefix) {
58+
if strings.HasPrefix(key, AnnotationPrefix) {
5959
delete(annotations, key)
6060
}
6161
}
@@ -82,5 +82,5 @@ func key(n NamespacedName) string {
8282
hasher.Write([]byte(n.Namespace))
8383
hasher.Write([]byte{'/'})
8484
hasher.Write([]byte(n.Name))
85-
return fmt.Sprintf("%s%x", prefix, hasher.Sum64())
85+
return fmt.Sprintf("%s%x", AnnotationPrefix, hasher.Sum64())
8686
}

pkg/controller/operators/internal/alongside/alongside_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func TestAnnotatorFromObject(t *testing.T) {
2323
NamespacedNames []NamespacedName
2424
}{
2525
{
26-
Name: "annotation without prefix ignored",
26+
Name: "annotation without AnnotationPrefix ignored",
2727
Object: TestAnnotatable{
2828
"foo": "namespace/name",
2929
},
@@ -66,7 +66,7 @@ func TestAnnotatorToObject(t *testing.T) {
6666
},
6767
},
6868
{
69-
Name: "annotation without prefix ignored",
69+
Name: "annotation without AnnotationPrefix ignored",
7070
Object: TestAnnotatable{
7171
"operatorframework.io/something-else": "",
7272
},

0 commit comments

Comments
 (0)