Skip to content

Commit 8f4d4f9

Browse files
authored
Merge pull request #323 from justinsb/controllerrestmapper_restmappings
controllerrestmapper: implement RESTMappings
2 parents f36e9e1 + c91c068 commit 8f4d4f9

File tree

2 files changed

+81
-7
lines changed

2 files changed

+81
-7
lines changed

pkg/restmapper/caching.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
apierrors "k8s.io/apimachinery/pkg/api/errors"
1010
"k8s.io/apimachinery/pkg/api/meta"
11+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1112
"k8s.io/apimachinery/pkg/runtime/schema"
1213
"k8s.io/client-go/discovery"
1314
"k8s.io/klog/v2"
@@ -17,6 +18,7 @@ import (
1718
// cache is our cache of schema information.
1819
type cache struct {
1920
mutex sync.Mutex
21+
groups map[string]metav1.APIGroup
2022
groupVersions map[schema.GroupVersion]*cachedGroupVersion
2123
}
2224

@@ -27,6 +29,34 @@ func newCache() *cache {
2729
}
2830
}
2931

32+
// findGroupInfo returns the APIGroup for the specified group, querying discovery if not cached.
33+
// If not found, returns APIGroup{}, false, nil
34+
func (c *cache) findGroupInfo(ctx context.Context, discovery discovery.DiscoveryInterface, groupName string) (metav1.APIGroup, bool, error) {
35+
log := log.FromContext(ctx)
36+
37+
c.mutex.Lock()
38+
defer c.mutex.Unlock()
39+
40+
if c.groups == nil {
41+
log.Info("discovering server groups")
42+
serverGroups, err := discovery.ServerGroups()
43+
if err != nil {
44+
klog.Infof("unexpected error from ServerGroups: %v", err)
45+
return metav1.APIGroup{}, false, fmt.Errorf("error from ServerGroups: %w", err)
46+
}
47+
48+
groups := make(map[string]metav1.APIGroup)
49+
for i := range serverGroups.Groups {
50+
group := &serverGroups.Groups[i]
51+
groups[group.Name] = *group
52+
}
53+
c.groups = groups
54+
}
55+
56+
group, found := c.groups[groupName]
57+
return group, found, nil
58+
}
59+
3060
// cachedGroupVersion caches (all) the resource information for a particular groupversion.
3161
type cachedGroupVersion struct {
3262
gv schema.GroupVersion
@@ -88,7 +118,7 @@ func (c *cachedGroupVersion) fetch(ctx context.Context, discovery discovery.Disc
88118
if meta.IsNoMatchError(err) || apierrors.IsNotFound(err) {
89119
return nil, nil
90120
} else {
91-
klog.Infof("unexpected error from ServerResourcesForGroupVersion(%v): %w", c.gv, err)
121+
klog.Infof("unexpected error from ServerResourcesForGroupVersion(%v): %v", c.gv, err)
92122
return nil, fmt.Errorf("error from ServerResourcesForGroupVersion(%v): %w", c.gv, err)
93123
}
94124
}

pkg/restmapper/controllerrestmapper.go

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,22 +35,22 @@ var _ meta.RESTMapper = &ControllerRESTMapper{}
3535

3636
// KindFor takes a partial resource and returns the single match. Returns an error if there are multiple matches
3737
func (m *ControllerRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
38-
return schema.GroupVersionKind{}, fmt.Errorf("ControllerRESTMaper does not support KindFor operation")
38+
return schema.GroupVersionKind{}, fmt.Errorf("ControllerRESTMapper does not support KindFor operation")
3939
}
4040

4141
// KindsFor takes a partial resource and returns the list of potential kinds in priority order
4242
func (m *ControllerRESTMapper) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) {
43-
return nil, fmt.Errorf("ControllerRESTMaper does not support KindsFor operation")
43+
return nil, fmt.Errorf("ControllerRESTMapper does not support KindsFor operation")
4444
}
4545

4646
// ResourceFor takes a partial resource and returns the single match. Returns an error if there are multiple matches
4747
func (m *ControllerRESTMapper) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) {
48-
return schema.GroupVersionResource{}, fmt.Errorf("ControllerRESTMaper does not support ResourceFor operation")
48+
return schema.GroupVersionResource{}, fmt.Errorf("ControllerRESTMapper does not support ResourceFor operation")
4949
}
5050

5151
// ResourcesFor takes a partial resource and returns the list of potential resource in priority order
5252
func (m *ControllerRESTMapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
53-
return nil, fmt.Errorf("ControllerRESTMaper does not support ResourcesFor operation")
53+
return nil, fmt.Errorf("ControllerRESTMapper does not support ResourcesFor operation")
5454
}
5555

5656
// RESTMapping identifies a preferred resource mapping for the provided group kind.
@@ -75,9 +75,53 @@ func (m *ControllerRESTMapper) RESTMapping(gk schema.GroupKind, versions ...stri
7575
// version search is provided. Otherwise identifies a preferred resource mapping for
7676
// the provided version(s).
7777
func (m *ControllerRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) {
78-
return nil, fmt.Errorf("ControllerRESTMaper does not support RESTMappings operation")
78+
ctx := context.TODO()
79+
80+
if len(versions) != 0 {
81+
return nil, fmt.Errorf("ControllerRESTMapper does not support RESTMappings operation with specified versions")
82+
}
83+
84+
group, found, err := m.cache.findGroupInfo(ctx, m.uncached, gk.Group)
85+
if err != nil {
86+
return nil, err
87+
}
88+
if !found {
89+
return nil, &meta.NoResourceMatchError{PartialResource: schema.GroupVersionResource{Group: gk.Group, Resource: gk.Kind}}
90+
}
91+
92+
var mappings []*meta.RESTMapping
93+
94+
if group.PreferredVersion.Version != "" {
95+
gv := schema.GroupVersion{Group: gk.Group, Version: group.PreferredVersion.Version}
96+
mapping, err := m.cache.findRESTMapping(ctx, m.uncached, gv, gk.Kind)
97+
if err != nil {
98+
return nil, err
99+
}
100+
if mapping != nil {
101+
mappings = append(mappings, mapping)
102+
}
103+
}
104+
105+
for i := range group.Versions {
106+
gv := schema.GroupVersion{Group: gk.Group, Version: group.Versions[i].Version}
107+
if gv.Version == group.PreferredVersion.Version {
108+
continue
109+
}
110+
mapping, err := m.cache.findRESTMapping(ctx, m.uncached, gv, gk.Kind)
111+
if err != nil {
112+
return nil, err
113+
}
114+
if mapping != nil {
115+
mappings = append(mappings, mapping)
116+
}
117+
}
118+
119+
if len(mappings) == 0 {
120+
return nil, &meta.NoResourceMatchError{PartialResource: schema.GroupVersionResource{Group: gk.Group, Resource: gk.Kind}}
121+
}
122+
return mappings, nil
79123
}
80124

81125
func (m *ControllerRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
82-
return "", fmt.Errorf("ControllerRESTMaper does not support ResourceSingularizer operation")
126+
return "", fmt.Errorf("ControllerRESTMapper does not support ResourceSingularizer operation")
83127
}

0 commit comments

Comments
 (0)