Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CustomResources in separate API server #45182

Merged
merged 2 commits into from
May 6, 2017
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions hack/.linted_packages
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ staging/src/k8s.io/kube-apiextensions-server/pkg/client/informers/internalversio
staging/src/k8s.io/kube-apiextensions-server/pkg/client/informers/internalversion/apiextensions/internalversion
staging/src/k8s.io/kube-apiextensions-server/pkg/client/listers/apiextensions/internalversion
staging/src/k8s.io/kube-apiextensions-server/pkg/client/listers/apiextensions/v1alpha1
staging/src/k8s.io/kube-apiextensions-server/test/integration
staging/src/k8s.io/metrics/pkg/apis/custom_metrics/install
staging/src/k8s.io/metrics/pkg/apis/metrics/install
staging/src/k8s.io/sample-apiserver
Expand Down
3 changes: 3 additions & 0 deletions hack/make-rules/test-integration.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ kube::test::find_integration_test_dirs() {
find test/integration/ -name '*_test.go' -print0 \
| xargs -0n1 dirname | sed "s|^|${KUBE_GO_PACKAGE}/|" \
| LC_ALL=C sort -u
find vendor/k8s.io/kube-apiextensions-server/test/integration/ -name '*_test.go' -print0 \
| xargs -0n1 dirname | sed "s|^|${KUBE_GO_PACKAGE}/|" \
| LC_ALL=C sort -u
)
}

Expand Down
6 changes: 5 additions & 1 deletion hack/make-rules/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,11 @@ kube::test::find_dirs() {
find ./staging/src/k8s.io/kube-aggregator -name '*_test.go' \
-name '*_test.go' -print0 | xargs -0n1 dirname | sed 's|^\./staging/src/|./vendor/|' | LC_ALL=C sort -u

find ./staging/src/k8s.io/kube-apiextensions-server -name '*_test.go' \
find ./staging/src/k8s.io/kube-apiextensions-server -not \( \
\( \
-o -path './test/integration/*' \
\) -prune \
\) -name '*_test.go' \
-name '*_test.go' -print0 | xargs -0n1 dirname | sed 's|^\./staging/src/|./vendor/|' | LC_ALL=C sort -u

find ./staging/src/k8s.io/sample-apiserver -name '*_test.go' \
Expand Down
18 changes: 11 additions & 7 deletions staging/src/k8s.io/apiserver/pkg/endpoints/discovery/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,29 @@ import (
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
)

// apiGroupHandler creates a webservice serving the supported versions, preferred version, and name
// APIGroupHandler creates a webservice serving the supported versions, preferred version, and name
// of a group. E.g., such a web service will be registered at /apis/extensions.
type apiGroupHandler struct {
type APIGroupHandler struct {
serializer runtime.NegotiatedSerializer

group metav1.APIGroup
}

func NewAPIGroupHandler(serializer runtime.NegotiatedSerializer, group metav1.APIGroup) *apiGroupHandler {
func NewAPIGroupHandler(serializer runtime.NegotiatedSerializer, group metav1.APIGroup) *APIGroupHandler {
if keepUnversioned(group.Name) {
// Because in release 1.1, /apis/extensions returns response with empty
// APIVersion, we use stripVersionNegotiatedSerializer to keep the
// response backwards compatible.
serializer = stripVersionNegotiatedSerializer{serializer}
}

return &apiGroupHandler{
return &APIGroupHandler{
serializer: serializer,
group: group,
}
}

func (s *apiGroupHandler) WebService() *restful.WebService {
func (s *APIGroupHandler) WebService() *restful.WebService {
mediaTypes, _ := negotiation.MediaTypesForSerializer(s.serializer)
ws := new(restful.WebService)
ws.Path(APIGroupPrefix + "/" + s.group.Name)
Expand All @@ -65,6 +65,10 @@ func (s *apiGroupHandler) WebService() *restful.WebService {
}

// handle returns a handler which will return the api.GroupAndVersion of the group.
func (s *apiGroupHandler) handle(req *restful.Request, resp *restful.Response) {
responsewriters.WriteObjectNegotiated(s.serializer, schema.GroupVersion{}, resp.ResponseWriter, req.Request, http.StatusOK, &s.group)
func (s *APIGroupHandler) handle(req *restful.Request, resp *restful.Response) {
s.ServeHTTP(resp.ResponseWriter, req.Request)
}

func (s *APIGroupHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
responsewriters.WriteObjectNegotiated(s.serializer, schema.GroupVersion{}, w, req, http.StatusOK, &s.group)
}
24 changes: 17 additions & 7 deletions staging/src/k8s.io/apiserver/pkg/endpoints/discovery/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,31 +32,37 @@ type APIResourceLister interface {
ListAPIResources() []metav1.APIResource
}

// apiVersionHandler creates a webservice serving the supported resources for the version
type APIResourceListerFunc func() []metav1.APIResource

func (f APIResourceListerFunc) ListAPIResources() []metav1.APIResource {
return f()
}

// APIVersionHandler creates a webservice serving the supported resources for the version
// E.g., such a web service will be registered at /apis/extensions/v1beta1.
type apiVersionHandler struct {
type APIVersionHandler struct {
serializer runtime.NegotiatedSerializer

groupVersion schema.GroupVersion
apiResourceLister APIResourceLister
}

func NewAPIVersionHandler(serializer runtime.NegotiatedSerializer, groupVersion schema.GroupVersion, apiResourceLister APIResourceLister) *apiVersionHandler {
func NewAPIVersionHandler(serializer runtime.NegotiatedSerializer, groupVersion schema.GroupVersion, apiResourceLister APIResourceLister) *APIVersionHandler {
if keepUnversioned(groupVersion.Group) {
// Because in release 1.1, /apis/extensions returns response with empty
// APIVersion, we use stripVersionNegotiatedSerializer to keep the
// response backwards compatible.
serializer = stripVersionNegotiatedSerializer{serializer}
}

return &apiVersionHandler{
return &APIVersionHandler{
serializer: serializer,
groupVersion: groupVersion,
apiResourceLister: apiResourceLister,
}
}

func (s *apiVersionHandler) AddToWebService(ws *restful.WebService) {
func (s *APIVersionHandler) AddToWebService(ws *restful.WebService) {
mediaTypes, _ := negotiation.MediaTypesForSerializer(s.serializer)
ws.Route(ws.GET("/").To(s.handle).
Doc("get available resources").
Expand All @@ -67,7 +73,11 @@ func (s *apiVersionHandler) AddToWebService(ws *restful.WebService) {
}

// handle returns a handler which will return the api.VersionAndVersion of the group.
func (s *apiVersionHandler) handle(req *restful.Request, resp *restful.Response) {
responsewriters.WriteObjectNegotiated(s.serializer, schema.GroupVersion{}, resp.ResponseWriter, req.Request, http.StatusOK,
func (s *APIVersionHandler) handle(req *restful.Request, resp *restful.Response) {
s.ServeHTTP(resp.ResponseWriter, req.Request)
}

func (s *APIVersionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
responsewriters.WriteObjectNegotiated(s.serializer, schema.GroupVersion{}, w, req, http.StatusOK,
&metav1.APIResourceList{GroupVersion: s.groupVersion.String(), APIResources: s.apiResourceLister.ListAPIResources()})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: apiregistration.k8s.io/v1alpha1
kind: APIService
metadata:
name: v1alpha1.mygroup.example.com
spec:
insecureSkipTLSVerify: true
group: mygroup.example.com
priority: 500
service:
name: api
namespace: kube-apiextensions
version: v1alpha1
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ metadata:
spec:
group: mygroup.example.com
version: v1alpha1
scope: Namespaced
names:
name: noxus
singular: noxu
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: mygroup.example.com/v1alpha1
kind: Noxu
metadata:
name: alfa-noxu
spec:
key: value
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type CustomResourceSpec struct {

// CustomResourceNames indicates the names to serve this CustomResource
type CustomResourceNames struct {
// Plural is the plural name of the resource to serve. It must match the name of the TPR-registration
// Plural is the plural name of the resource to serve. It must match the name of the CustomResource-registration
// too: plural.group and it must be all lowercase.
Plural string
// Singular is the singular name of the resource. It must be all lowercase Defaults to lowercased <kind>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type CustomResourceSpec struct {

// CustomResourceNames indicates the names to serve this CustomResource
type CustomResourceNames struct {
// Plural is the plural name of the resource to serve. It must match the name of the TPR-registration
// Plural is the plural name of the resource to serve. It must match the name of the CustomResource-registration
// too: plural.group and it must be all lowercase.
Plural string `json:"plural" protobuf:"bytes,1,opt,name=plural"`
// Singular is the singular name of the resource. It must be all lowercase Defaults to lowercased <kind>
Expand Down
29 changes: 28 additions & 1 deletion staging/src/k8s.io/kube-apiextensions-server/pkg/apiserver/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,52 @@ load(

go_library(
name = "go_default_library",
srcs = ["apiserver.go"],
srcs = [
"apiserver.go",
"customresource_discovery.go",
"customresource_discovery_controller.go",
"customresource_handler.go",
],
tags = ["automanaged"],
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery/announced:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/version:go_default_library",
"//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/discovery:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/handlers:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/generic/registry:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library",
"//vendor/k8s.io/apiserver/pkg/server:go_default_library",
"//vendor/k8s.io/apiserver/pkg/storage/storagebackend:go_default_library",
"//vendor/k8s.io/client-go/discovery:go_default_library",
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
"//vendor/k8s.io/client-go/util/workqueue:go_default_library",
"//vendor/k8s.io/kube-apiextensions-server/pkg/apis/apiextensions:go_default_library",
"//vendor/k8s.io/kube-apiextensions-server/pkg/apis/apiextensions/install:go_default_library",
"//vendor/k8s.io/kube-apiextensions-server/pkg/apis/apiextensions/v1alpha1:go_default_library",
"//vendor/k8s.io/kube-apiextensions-server/pkg/client/clientset/clientset:go_default_library",
"//vendor/k8s.io/kube-apiextensions-server/pkg/client/clientset/internalclientset:go_default_library",
"//vendor/k8s.io/kube-apiextensions-server/pkg/client/informers/externalversions:go_default_library",
"//vendor/k8s.io/kube-apiextensions-server/pkg/client/informers/internalversion:go_default_library",
"//vendor/k8s.io/kube-apiextensions-server/pkg/client/informers/internalversion/apiextensions/internalversion:go_default_library",
"//vendor/k8s.io/kube-apiextensions-server/pkg/client/listers/apiextensions/internalversion:go_default_library",
"//vendor/k8s.io/kube-apiextensions-server/pkg/registry/customresource:go_default_library",
"//vendor/k8s.io/kube-apiextensions-server/pkg/registry/customresourcestorage:go_default_library",
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,30 @@ limitations under the License.
package apiserver

import (
"net/http"
"time"

"k8s.io/apimachinery/pkg/apimachinery/announced"
"k8s.io/apimachinery/pkg/apimachinery/registered"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/version"
"k8s.io/apiserver/pkg/endpoints/discovery"
genericregistry "k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest"
genericapiserver "k8s.io/apiserver/pkg/server"

"k8s.io/kube-apiextensions-server/pkg/apis/apiextensions"
"k8s.io/kube-apiextensions-server/pkg/apis/apiextensions/install"
"k8s.io/kube-apiextensions-server/pkg/apis/apiextensions/v1alpha1"
"k8s.io/kube-apiextensions-server/pkg/client/clientset/internalclientset"
internalinformers "k8s.io/kube-apiextensions-server/pkg/client/informers/internalversion"
"k8s.io/kube-apiextensions-server/pkg/registry/customresource"

// make sure the generated client works
_ "k8s.io/kube-apiextensions-server/pkg/client/clientset/clientset"
_ "k8s.io/kube-apiextensions-server/pkg/client/clientset/internalclientset"
_ "k8s.io/kube-apiextensions-server/pkg/client/informers/externalversions"
_ "k8s.io/kube-apiextensions-server/pkg/client/informers/internalversion"
)
Expand Down Expand Up @@ -64,6 +70,8 @@ func init() {

type Config struct {
GenericConfig *genericapiserver.Config

CustomResourceRESTOptionsGetter genericregistry.RESTOptionsGetter
}

type CustomResources struct {
Expand All @@ -76,6 +84,7 @@ type completedConfig struct {

// Complete fills in any fields not set that are required to have valid data. It's mutating the receiver.
func (c *Config) Complete() completedConfig {
c.GenericConfig.EnableDiscovery = false
c.GenericConfig.Complete()

c.GenericConfig.Version = &version.Info{
Expand All @@ -92,7 +101,7 @@ func (c *Config) SkipComplete() completedConfig {
}

// New returns a new instance of CustomResources from the given config.
func (c completedConfig) New() (*CustomResources, error) {
func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget, stopCh <-chan struct{}) (*CustomResources, error) {
genericServer, err := c.Config.GenericConfig.SkipComplete().New() // completion is done in Complete, no need for a second time
if err != nil {
return nil, err
Expand All @@ -112,5 +121,47 @@ func (c completedConfig) New() (*CustomResources, error) {
return nil, err
}

customResourceClient, err := internalclientset.NewForConfig(s.GenericAPIServer.LoopbackClientConfig)
if err != nil {
return nil, err
}
customResourceInformers := internalinformers.NewSharedInformerFactory(customResourceClient, 5*time.Minute)

delegateHandler := delegationTarget.UnprotectedHandler()
if delegateHandler == nil {
delegateHandler = http.NotFoundHandler()
}

versionDiscoveryHandler := &versionDiscoveryHandler{
discovery: map[schema.GroupVersion]*discovery.APIVersionHandler{},
delegate: delegateHandler,
}
groupDiscoveryHandler := &groupDiscoveryHandler{
discovery: map[string]*discovery.APIGroupHandler{},
delegate: delegateHandler,
}
customResourceHandler := NewCustomResourceHandler(
versionDiscoveryHandler,
groupDiscoveryHandler,
s.GenericAPIServer.RequestContextMapper(),
customResourceInformers.Apiextensions().InternalVersion().CustomResources().Lister(),
delegationTarget.UnprotectedHandler(),
c.CustomResourceRESTOptionsGetter,
c.GenericConfig.AdmissionControl,
)
s.GenericAPIServer.FallThroughHandler.Handle("/apis", customResourceHandler)
s.GenericAPIServer.FallThroughHandler.HandlePrefix("/apis/", customResourceHandler)

customResourceController := NewDiscoveryController(customResourceInformers.Apiextensions().InternalVersion().CustomResources(), versionDiscoveryHandler, groupDiscoveryHandler)

s.GenericAPIServer.AddPostStartHook("start-apiextensions-informers", func(context genericapiserver.PostStartHookContext) error {
customResourceInformers.Start(stopCh)
return nil
})
s.GenericAPIServer.AddPostStartHook("start-apiextensions-controllers", func(context genericapiserver.PostStartHookContext) error {
go customResourceController.Run(stopCh)
return nil
})

return s, nil
}