Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/apiexport/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func main() {
return reconcile.Result{}, fmt.Errorf("failed to get configmap: %w", err)
}

log.Info("Reconciling configmap", "name", s.Name, "uuid", s.UID)
log.Info("Reconciling ConfigMap", "name", s.Name, "uuid", s.UID)

return reconcile.Result{}, nil
},
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/kcp-dev/apimachinery/v2 v2.0.1-0.20240817110845-a9eb9752bfeb
github.com/kcp-dev/kcp/sdk v0.26.1
github.com/kcp-dev/logicalcluster/v3 v3.0.5
github.com/multicluster-runtime/multicluster-runtime v0.20.0-alpha.3
github.com/multicluster-runtime/multicluster-runtime v0.20.0-alpha.5
github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace
github.com/stretchr/testify v1.9.0
golang.org/x/sync v0.10.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/multicluster-runtime/multicluster-runtime v0.20.0-alpha.3 h1:GLVW6WCrHbuyrSOcMpXUd/svnW32YLRMJPwRwAiR8zI=
github.com/multicluster-runtime/multicluster-runtime v0.20.0-alpha.3/go.mod h1:6ZuT8VoTSr8nYyToyhnhAepyZoHAaCQzzabzbSFwAKc=
github.com/multicluster-runtime/multicluster-runtime v0.20.0-alpha.5 h1:aoDDYIbqFXbRfWVbQEl5l5KktEVWntuwD2gpPMEIr4A=
github.com/multicluster-runtime/multicluster-runtime v0.20.0-alpha.5/go.mod h1:6ZuT8VoTSr8nYyToyhnhAepyZoHAaCQzzabzbSFwAKc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
Expand Down
10 changes: 2 additions & 8 deletions virtualworkspace/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,10 @@ func (c *scopedCache) IndexField(ctx context.Context, obj client.Object, field s

// Get returns a single object from the cache.
func (c *scopedCache) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
inf, gvk, scope, found, err := c.base.getSharedInformer(obj)
inf, gvk, scope, err := c.base.getSharedInformer(obj)
if err != nil {
return fmt.Errorf("failed to get informer for %T %s: %w", obj, obj.GetObjectKind().GroupVersionKind(), err)
}
if !found {
return fmt.Errorf("no informer found for %T %s", obj, obj.GetObjectKind().GroupVersionKind())
}

cr := cacheReader{
indexer: inf.GetIndexer(),
Expand All @@ -73,13 +70,10 @@ func (c *scopedCache) Get(ctx context.Context, key client.ObjectKey, obj client.

// List returns a list of objects from the cache.
func (c *scopedCache) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
inf, gvk, scope, found, err := c.base.getSharedInformer(list)
inf, gvk, scope, err := c.base.getSharedInformer(list)
if err != nil {
return fmt.Errorf("failed to get informer for %T %s: %w", list, list.GetObjectKind().GroupVersionKind(), err)
}
if !found {
return fmt.Errorf("no informer found for %T %s", list, list.GetObjectKind().GroupVersionKind())
}

cr := cacheReader{
indexer: inf.GetIndexer(),
Expand Down
7 changes: 6 additions & 1 deletion virtualworkspace/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func (p *Provider) Run(ctx context.Context, mgr mcmanager.Manager) error {
if err != nil {
return fmt.Errorf("failed to get logical cluster informer: %w", err)
}
shInf, _, _, _, err := p.cache.getSharedInformer(p.object)
shInf, _, _, err := p.cache.getSharedInformer(p.object)
if err != nil {
return fmt.Errorf("failed to get shared informer: %w", err)
}
Expand Down Expand Up @@ -227,3 +227,8 @@ func (p *Provider) Get(_ context.Context, name string) (cluster.Cluster, error)
func (p *Provider) GetWildcard() cache.Cache {
return p.cache
}

// IndexField indexes the given object by the given field on all engaged clusters, current and future.
func (p *Provider) IndexField(ctx context.Context, obj client.Object, field string, extractValue client.IndexerFunc) error {
return p.cache.IndexField(ctx, obj, field, extractValue)
}
47 changes: 42 additions & 5 deletions virtualworkspace/wildcard.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import (
// WildcardCache is a cache that operates on a /clusters/* endpoint.
type WildcardCache interface {
cache.Cache
getSharedInformer(obj runtime.Object) (k8scache.SharedIndexInformer, schema.GroupVersionKind, apimeta.RESTScopeName, bool, error)
getSharedInformer(obj runtime.Object) (k8scache.SharedIndexInformer, schema.GroupVersionKind, apimeta.RESTScopeName, error)
}

// NewWildcardCache returns a cache.Cache that handles multi-cluster watches
Expand Down Expand Up @@ -80,6 +80,8 @@ func NewWildcardCache(config *rest.Config, opts cache.Options) (WildcardCache, e
Unstructured: make(map[schema.GroupVersionKind]k8scache.SharedIndexInformer),
Metadata: make(map[schema.GroupVersionKind]k8scache.SharedIndexInformer),
},

readerFailOnMissingInformer: opts.ReaderFailOnMissingInformer,
}

opts.NewInformer = func(watcher k8scache.ListerWatcher, obj runtime.Object, duration time.Duration, indexers k8scache.Indexers) k8scache.SharedIndexInformer {
Expand Down Expand Up @@ -121,25 +123,60 @@ type wildcardCache struct {
scheme *runtime.Scheme
mapper apimeta.RESTMapper
tracker informerTracker

readerFailOnMissingInformer bool
}

func (c *wildcardCache) getSharedInformer(obj runtime.Object) (k8scache.SharedIndexInformer, schema.GroupVersionKind, apimeta.RESTScopeName, bool, error) {
func (c *wildcardCache) getSharedInformer(obj runtime.Object) (k8scache.SharedIndexInformer, schema.GroupVersionKind, apimeta.RESTScopeName, error) {
gvk, err := apiutil.GVKForObject(obj, c.scheme)
if err != nil {
return nil, gvk, "", false, err
return nil, gvk, "", fmt.Errorf("failed to get GVK for object: %w", err)
}

// We need the non-list GVK, so chop off the "List" from the end of the kind.
gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")

mapping, err := c.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil {
return nil, gvk, "", false, err
return nil, gvk, "", fmt.Errorf("failed to get REST mapping: %w", err)
}

infs := c.tracker.informersByType(obj)
c.tracker.lock.RLock()
inf, ok := infs[gvk]
c.tracker.lock.RUnlock()

return inf, gvk, mapping.Scope.Name(), ok, nil
// we need to create a new informer here.
if !ok {
// we have been instructed to fail if the informer is missing.
if c.readerFailOnMissingInformer {
return nil, gvk, "", &cache.ErrResourceNotCached{}
}

// Let's generate a new object from the chopped GVK, since the original obj might be of *List type.
o, err := c.scheme.New(gvk)
if err != nil {
return nil, gvk, "", fmt.Errorf("failed to create object for GVK: %w", err)
}

// Call GetInformer, but we don't care about the output. We just need to make sure that our NewInformer
// func has been called, which registers the new informer in our tracker.
if _, err := c.Cache.GetInformer(context.TODO(), o.(client.Object)); err != nil {
return nil, gvk, "", fmt.Errorf("failed to create informer: %w", err)
}

// Now we should be able to find the informer.
infs := c.tracker.informersByType(obj)
c.tracker.lock.RLock()
inf, ok = infs[gvk]
c.tracker.lock.RUnlock()

if !ok {
return nil, gvk, "", fmt.Errorf("failed to find newly started informer for %v", gvk)
}
}

return inf, gvk, mapping.Scope.Name(), nil
}

// IndexField adds an index for the given object kind.
Expand Down