Skip to content

Commit 404af4b

Browse files
committed
factors out sub-resource interface
1 parent 03806b4 commit 404af4b

File tree

9 files changed

+177
-60
lines changed

9 files changed

+177
-60
lines changed

internal/sample-apiserver/pkg/apiserver/ext.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
genericregistry "k8s.io/apiserver/pkg/registry/generic"
2525
"k8s.io/apiserver/pkg/registry/rest"
2626
pkgserver "k8s.io/apiserver/pkg/server"
27+
"sigs.k8s.io/apiserver-runtime/pkg/builder/resource/resourcestrategy"
2728
)
2829

2930
type StorageProvider func(s *runtime.Scheme, g genericregistry.RESTOptionsGetter) (rest.Storage, error)
@@ -46,16 +47,24 @@ func BuildAPIGroupInfos(s *runtime.Scheme, g genericregistry.RESTOptionsGetter)
4647
apiGroups := []*pkgserver.APIGroupInfo{}
4748
for _, group := range groups.List() {
4849
apis := map[string]map[string]rest.Storage{}
49-
var err error
5050
for gvr, storageProviderFunc := range APIs {
5151
if gvr.Group == group {
5252
if _, found := apis[gvr.Version]; !found {
5353
apis[gvr.Version] = map[string]rest.Storage{}
5454
}
55-
apis[gvr.Version][gvr.Resource], err = storageProviderFunc(s, g)
55+
storage, err := storageProviderFunc(s, g)
5656
if err != nil {
5757
return nil, err
5858
}
59+
apis[gvr.Version][gvr.Resource] = storage
60+
// add the defaulting function for this version to the scheme
61+
if _, ok := storage.(resourcestrategy.Defaulter); ok {
62+
if obj, ok := storage.(runtime.Object); ok {
63+
Scheme.AddTypeDefaultingFunc(obj, func(obj interface{}) {
64+
obj.(resourcestrategy.Defaulter).Default()
65+
})
66+
}
67+
}
5968
}
6069
}
6170
apiGroupInfo := pkgserver.NewDefaultAPIGroupInfo(group, Scheme, metav1.ParameterCodec, Codecs)

pkg/builder/builder_auth.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func (a *Server) WithLocalDebugExtension() *Server {
2626
secureBindingAddr := options.RecommendedOptions.SecureServing.BindAddress.String()
2727
if enablesLocalStandaloneDebugging {
2828
if secureBindingAddr != "127.0.0.1" {
29-
klog.Fatal(`the binding address must be "127.0.0.1" if --standalone-debug-mode is set`)
29+
klog.Fatal(`--bind-address must be "127.0.0.1" if --standalone-debug-mode is set`)
3030
}
3131
options.RecommendedOptions.Authorization = nil
3232
options.RecommendedOptions.CoreAPI = nil

pkg/builder/builder_resource.go

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
117
package builder
218

319
import (
420
"fmt"
521

6-
"k8s.io/apimachinery/pkg/runtime"
722
"k8s.io/apimachinery/pkg/runtime/schema"
823
regsitryrest "k8s.io/apiserver/pkg/registry/rest"
924
"sigs.k8s.io/apiserver-runtime/internal/sample-apiserver/pkg/apiserver"
1025
"sigs.k8s.io/apiserver-runtime/pkg/builder/resource"
1126
"sigs.k8s.io/apiserver-runtime/pkg/builder/resource/resourcerest"
12-
"sigs.k8s.io/apiserver-runtime/pkg/builder/resource/resourcestrategy"
1327
"sigs.k8s.io/apiserver-runtime/pkg/builder/rest"
1428
)
1529

@@ -44,32 +58,32 @@ func (a *Server) WithResource(obj resource.Object) *Server {
4458

4559
// reuse the storage if this resource has already been registered
4660
if s, found := a.storage[gvr.GroupResource()]; found {
47-
_ = a.forGroupVersionResource(gvr, obj, s.Get)
61+
_ = a.forGroupVersionResource(gvr, s.Get)
4862
return a
4963
}
5064

5165
// If the type implements it's own storage, then use that
5266
switch s := obj.(type) {
5367
case resourcerest.Creator:
54-
return a.forGroupVersionResource(gvr, obj, rest.StaticHandlerProvider{Storage: s.(regsitryrest.Storage)}.Get)
68+
return a.forGroupVersionResource(gvr, rest.StaticHandlerProvider{Storage: s.(regsitryrest.Storage)}.Get)
5569
case resourcerest.Updater:
56-
return a.forGroupVersionResource(gvr, obj, rest.StaticHandlerProvider{Storage: s.(regsitryrest.Storage)}.Get)
70+
return a.forGroupVersionResource(gvr, rest.StaticHandlerProvider{Storage: s.(regsitryrest.Storage)}.Get)
5771
case resourcerest.Getter:
58-
return a.forGroupVersionResource(gvr, obj, rest.StaticHandlerProvider{Storage: s.(regsitryrest.Storage)}.Get)
72+
return a.forGroupVersionResource(gvr, rest.StaticHandlerProvider{Storage: s.(regsitryrest.Storage)}.Get)
5973
case resourcerest.Lister:
60-
return a.forGroupVersionResource(gvr, obj, rest.StaticHandlerProvider{Storage: s.(regsitryrest.Storage)}.Get)
74+
return a.forGroupVersionResource(gvr, rest.StaticHandlerProvider{Storage: s.(regsitryrest.Storage)}.Get)
6175
}
6276

63-
_ = a.forGroupVersionResource(gvr, obj, rest.New(obj))
77+
_ = a.forGroupVersionResource(gvr, rest.New(obj))
6478

6579
// automatically create status subresource if the object implements the status interface
6680
if sgs, ok := obj.(resource.ObjectWithStatusSubResource); ok {
6781
st := gvr.GroupVersion().WithResource(gvr.Resource + "/status")
6882
if s, found := a.storage[st.GroupResource()]; found {
69-
_ = a.forGroupVersionResource(st, obj, s.Get)
83+
_ = a.forGroupVersionResource(st, s.Get)
7084
} else {
7185
_, _, _, sp := rest.NewStatus(sgs)
72-
_ = a.forGroupVersionResource(st, obj, sp)
86+
_ = a.forGroupVersionResource(st, sp)
7387
}
7488
}
7589
return a
@@ -85,12 +99,12 @@ func (a *Server) WithResourceAndStrategy(obj resource.Object, strategy rest.Stra
8599
gvr := obj.GetGroupVersionResource()
86100
a.schemeBuilder.Register(resource.AddToScheme(obj))
87101

88-
_ = a.forGroupVersionResource(gvr, obj, rest.NewWithStrategy(obj, strategy))
102+
_ = a.forGroupVersionResource(gvr, rest.NewWithStrategy(obj, strategy))
89103

90104
// automatically create status subresource if the object implements the status interface
91105
if _, ok := obj.(resource.ObjectWithStatusSubResource); ok {
92106
st := gvr.GroupVersion().WithResource(gvr.Resource + "/status")
93-
_ = a.forGroupVersionResource(st, obj, rest.NewStatusWithStrategy(obj, strategy))
107+
_ = a.forGroupVersionResource(st, rest.NewStatusWithStrategy(obj, strategy))
94108
}
95109
return a
96110
}
@@ -105,7 +119,7 @@ func (a *Server) WithResourceAndStrategy(obj resource.Object, strategy rest.Stra
105119
func (a *Server) WithResourceAndHandler(obj resource.Object, sp rest.ResourceHandlerProvider) *Server {
106120
gvr := obj.GetGroupVersionResource()
107121
a.schemeBuilder.Register(resource.AddToScheme(obj))
108-
return a.forGroupVersionResource(gvr, obj, sp)
122+
return a.forGroupVersionResource(gvr, sp)
109123
}
110124

111125
// WithResourceAndStorage registers the resource with the apiserver, applying fn to the storage for the resource
@@ -120,19 +134,19 @@ func (a *Server) WithResourceAndStorage(obj resource.Object, fn rest.StoreFn) *S
120134
gvr := obj.GetGroupVersionResource()
121135
a.schemeBuilder.Register(resource.AddToScheme(obj))
122136

123-
_ = a.forGroupVersionResource(gvr, obj, rest.NewWithFn(obj, fn))
137+
_ = a.forGroupVersionResource(gvr, rest.NewWithFn(obj, fn))
124138

125139
// automatically create status subresource if the object implements the status interface
126140
if _, ok := obj.(resource.ObjectWithStatusSubResource); ok {
127141
st := gvr.GroupVersion().WithResource(gvr.Resource + "/status")
128-
_ = a.forGroupVersionResource(st, obj, rest.NewStatusWithFn(obj, fn))
142+
_ = a.forGroupVersionResource(st, rest.NewStatusWithFn(obj, fn))
129143
}
130144
return a
131145
}
132146

133147
// forGroupVersionResource manually registers storage for a specific resource or subresource version.
134148
func (a *Server) forGroupVersionResource(
135-
gvr schema.GroupVersionResource, obj runtime.Object, sp rest.ResourceHandlerProvider) *Server {
149+
gvr schema.GroupVersionResource, sp rest.ResourceHandlerProvider) *Server {
136150
// register the group version
137151
a.withGroupVersions(gvr.GroupVersion())
138152

@@ -142,14 +156,6 @@ func (a *Server) forGroupVersionResource(
142156
if _, found := a.storage[gvr.GroupResource()]; !found {
143157
a.storage[gvr.GroupResource()] = &singletonProvider{Provider: sp}
144158
}
145-
146-
// add the defaulting function for this version to the scheme
147-
if _, ok := obj.(resourcestrategy.Defaulter); ok {
148-
apiserver.Scheme.AddTypeDefaultingFunc(obj, func(obj interface{}) {
149-
obj.(resourcestrategy.Defaulter).Default()
150-
})
151-
}
152-
153159
// add the API with its storage
154160
apiserver.APIs[gvr] = sp
155161
return a
@@ -161,13 +167,13 @@ func (a *Server) forGroupVersionResource(
161167
// Note: WithSubResource does NOT register the request or parent with the SchemeBuilder. If they were not registered
162168
// through a WithResource call, then this must be done manually with WithAdditionalSchemeInstallers.
163169
func (a *Server) WithSubResource(
164-
parent resource.Object, subResourcePath string, request runtime.Object) *Server {
170+
parent resource.Object, subResource resource.SubResource) *Server {
165171
gvr := parent.GetGroupVersionResource()
166-
gvr.Resource = gvr.Resource + "/" + subResourcePath
167172

168173
// reuse the storage if this resource has already been registered
169174
if s, found := a.storage[gvr.GroupResource()]; found {
170-
_ = a.forGroupVersionResource(gvr, request, s.Get)
175+
subResourceGVR := gvr.GroupVersion().WithResource(gvr.Resource + "/" + subResource.SubResourceName())
176+
_ = a.forGroupVersionResource(subResourceGVR, s.Get)
171177
} else {
172178
a.errs = append(a.errs, fmt.Errorf(
173179
"subresources must be registered with a strategy or handler the first time they are registered"))
@@ -181,10 +187,10 @@ func (a *Server) WithSubResource(
181187
// Note: WithSubResource does NOT register the request or parent with the SchemeBuilder. If they were not registered
182188
// through a WithResource call, then this must be done manually with WithAdditionalSchemeInstallers.
183189
func (a *Server) WithSubResourceAndStrategy(
184-
parent resource.Object, subResourcePath string, request resource.Object, strategy rest.Strategy) *Server {
190+
parent resource.Object, subResource resource.SubResource, strategy rest.Strategy) *Server {
185191
gvr := parent.GetGroupVersionResource()
186-
gvr.Resource = gvr.Resource + "/" + subResourcePath
187-
return a.forGroupVersionResource(gvr, request, rest.NewWithStrategy(request, strategy))
192+
gvr.Resource = gvr.Resource + "/" + subResource.SubResourceName()
193+
return a.forGroupVersionResource(gvr, rest.NewSubResourceWithStrategy(parent, subResource, strategy))
188194
}
189195

190196
// WithSubResourceAndHandler registers a request handler for the subresource rather than the default
@@ -193,11 +199,11 @@ func (a *Server) WithSubResourceAndStrategy(
193199
// Note: WithSubResource does NOT register the request or parent with the SchemeBuilder. If they were not registered
194200
// through a WithResource call, then this must be done manually with WithAdditionalSchemeInstallers.
195201
func (a *Server) WithSubResourceAndHandler(
196-
parent resource.Object, subResourcePath string, request runtime.Object, sp rest.ResourceHandlerProvider) *Server {
202+
parent resource.Object, subResource resource.SubResource, sp rest.ResourceHandlerProvider) *Server {
197203
gvr := parent.GetGroupVersionResource()
198204
// add the subresource path
199-
gvr.Resource = gvr.Resource + "/" + subResourcePath
200-
return a.forGroupVersionResource(gvr, request, sp)
205+
gvr.Resource = gvr.Resource + "/" + subResource.SubResourceName()
206+
return a.forGroupVersionResource(gvr, sp)
201207
}
202208

203209
// WithSchemeInstallers registers functions to install resource types into the Scheme.

pkg/builder/resource/resourcerest/interface.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ limitations under the License.
1616

1717
package resourcerest
1818

19-
import "k8s.io/apiserver/pkg/registry/rest"
19+
import (
20+
"k8s.io/apiserver/pkg/registry/rest"
21+
)
2022

2123
// CategoriesProvider allows a resource to specify which groups of resources (categories) it's part of. Categories can
2224
// be used by API clients to refer to a batch of resources by using a single name (e.g. "all" could translate to "pod,rc,svc,...").

pkg/builder/resource/types.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,14 @@ type MultiVersionObject interface {
8484

8585
// StatusSubResource defines interface for registering status subresource to a parent resource.
8686
type StatusSubResource interface {
87+
SubResource
8788
// CopyTo copies the content of the status subresource to a parent resource.
8889
CopyTo(parent ObjectWithStatusSubResource)
8990
}
9091

91-
// ArbitrarySubResource defines interface for registering arbitrary subresource to the parent resource.
92-
type ArbitrarySubResource interface {
93-
Name() string
92+
// SubResource defines interface for registering arbitrary subresource to the parent resource.
93+
type SubResource interface {
94+
SubResourceName() string
9495
// TODO: fill the details for this interface.
9596
}
9697

@@ -107,12 +108,6 @@ type ObjectWithScaleSubResource interface {
107108
GetScale() (scaleSubResource *autoscalingv1.Scale)
108109
}
109110

110-
// ObjectWithArbitrarySubResource adds arbitrary subresources to the resource.
111-
type ObjectWithArbitrarySubResource interface {
112-
Object
113-
ArbitrarySubResources() []ArbitrarySubResource
114-
}
115-
116111
// AddToScheme returns a function to add the Objects to the scheme.
117112
//
118113
// AddToScheme will register the objects returned by New and NewList under the GroupVersion for each object.

pkg/builder/rest/provider.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package rest
18+
19+
import (
20+
"k8s.io/apimachinery/pkg/runtime"
21+
"k8s.io/apiserver/pkg/registry/generic"
22+
"k8s.io/apiserver/pkg/registry/rest"
23+
"sigs.k8s.io/apiserver-runtime/internal/sample-apiserver/pkg/apiserver"
24+
)
25+
26+
// ResourceHandlerProvider provides a request handler for a resource
27+
type ResourceHandlerProvider = apiserver.StorageProvider
28+
29+
// StaticHandlerProvider returns itself as the request handler.
30+
type StaticHandlerProvider struct {
31+
rest.Storage
32+
}
33+
34+
// Get returns itself as the handler
35+
func (p StaticHandlerProvider) Get(s *runtime.Scheme, g generic.RESTOptionsGetter) (rest.Storage, error) {
36+
return p.Storage, nil
37+
}

pkg/builder/rest/rest.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,9 @@ import (
2727
"k8s.io/apiserver/pkg/registry/generic"
2828
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
2929
"k8s.io/apiserver/pkg/registry/rest"
30-
"sigs.k8s.io/apiserver-runtime/internal/sample-apiserver/pkg/apiserver"
3130
"sigs.k8s.io/apiserver-runtime/pkg/builder/resource"
3231
)
3332

34-
// ResourceHandlerProvider provides a request handler for a resource
35-
type ResourceHandlerProvider = apiserver.StorageProvider
36-
37-
// StaticHandlerProvider returns itself as the request handler.
38-
type StaticHandlerProvider struct {
39-
rest.Storage
40-
}
41-
42-
// Get returns itself as the handler
43-
func (p StaticHandlerProvider) Get(s *runtime.Scheme, g generic.RESTOptionsGetter) (rest.Storage, error) {
44-
return p.Storage, nil
45-
}
46-
4733
// New returns a new etcd backed request handler for the resource.
4834
func New(obj resource.Object) ResourceHandlerProvider {
4935
return func(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) (rest.Storage, error) {

pkg/builder/rest/rest_subresource.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package rest
18+
19+
import (
20+
"k8s.io/apimachinery/pkg/runtime"
21+
"k8s.io/apiserver/pkg/registry/generic"
22+
"k8s.io/apiserver/pkg/registry/rest"
23+
"sigs.k8s.io/apiserver-runtime/pkg/builder/resource"
24+
)
25+
26+
// NewSubResourceWithStrategy returns a new etcd backed request handler for subresource using the provided Strategy.
27+
func NewSubResourceWithStrategy(parent resource.Object, subResource resource.SubResource, s Strategy) ResourceHandlerProvider {
28+
return func(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) (rest.Storage, error) {
29+
fullResourceName := parent.GetGroupVersionResource().Resource + "/" + subResource.SubResourceName()
30+
gvr := parent.GetGroupVersionResource().GroupVersion().WithResource(fullResourceName)
31+
return newStore(
32+
parent.New,
33+
parent.NewList,
34+
gvr,
35+
s,
36+
optsGetter,
37+
nil)
38+
}
39+
}

0 commit comments

Comments
 (0)