package hierarchy12import (3"context"4"fmt"56corev1 "k8s.io/api/core/v1"7"k8s.io/apimachinery/pkg/labels"8"sigs.k8s.io/controller-runtime/pkg/client"9)1011// Selector finding objects within the resource hierarchy.12type Selector interface {13// ListOption can be passed to List to perform initial filtering of returned14// objects.15client.ListOption1617// Matches returns true if the Selector matches the provided Object. The18// provided Client may be used to perform extra searches.19Matches(context.Context, client.Client, client.Object) (bool, error)20}2122// LabelsSelector is used for discovering a set of objects in a hierarchy based23// on labels.24type LabelsSelector struct {25// NamespaceName is the default namespace to search for objects in when26// NamespaceSelector is nil.27NamespaceName string2829// NamespaceLabels causes all namespaces whose labels match NamespaceLabels30// to be searched. When nil, only the namespace specified by NamespaceName31// will be searched.32NamespaceLabels labels.Selector3334// Labels discovers all objects whose labels match the selector. If nil,35// no objects will be discovered.36Labels labels.Selector37}3839var _ Selector = (*LabelsSelector)(nil)4041// ApplyToList implements Selector.42func (ls *LabelsSelector) ApplyToList(lo *client.ListOptions) {43if ls.NamespaceLabels == nil {44lo.Namespace = ls.NamespaceName45}46lo.LabelSelector = ls.Labels47}4849// Matches implements Selector.50func (ls *LabelsSelector) Matches(ctx context.Context, cli client.Client, o client.Object) (bool, error) {51if !ls.Labels.Matches(labels.Set(o.GetLabels())) {52return false, nil53}5455// Fast path: we don't need to retrieve the labels of the namespace.56if ls.NamespaceLabels == nil {57return o.GetNamespace() == ls.NamespaceName, nil58}5960// Slow path: we need to look up the namespace to see if its labels match. As61// long as cli implements caching, this won't be too bad.62var ns corev1.Namespace63if err := cli.Get(ctx, client.ObjectKey{Name: o.GetNamespace()}, &ns); err != nil {64return false, fmt.Errorf("error looking up namespace %q: %w", o.GetNamespace(), err)65}66return ls.NamespaceLabels.Matches(labels.Set(ns.GetLabels())), nil67}6869// KeySelector is used for discovering a single object based on namespace and70// name.71type KeySelector struct {72Namespace, Name string73}7475var _ Selector = (*KeySelector)(nil)7677// ApplyToList implements Selector.78func (ks *KeySelector) ApplyToList(lo *client.ListOptions) {79lo.Namespace = ks.Namespace80}8182// Matches implements Selector.83func (ks *KeySelector) Matches(ctx context.Context, cli client.Client, o client.Object) (bool, error) {84return ks.Name == o.GetName() && ks.Namespace == o.GetNamespace(), nil85}868788