2017-02-01 00:45:59 +00:00
|
|
|
/*
|
|
|
|
Copyright 2014 The Kubernetes Authors.
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2017-02-03 13:41:32 +00:00
|
|
|
package endpoints
|
2017-02-01 00:45:59 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"path"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/emicklei/go-restful"
|
|
|
|
|
|
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
|
|
"k8s.io/apimachinery/pkg/api/meta"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
|
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
2017-02-03 13:41:32 +00:00
|
|
|
"k8s.io/apiserver/pkg/admission"
|
|
|
|
"k8s.io/apiserver/pkg/endpoints/request"
|
|
|
|
"k8s.io/kubernetes/pkg/genericapiserver/endpoints/handlers"
|
|
|
|
"k8s.io/kubernetes/pkg/genericapiserver/registry/rest"
|
2017-02-01 00:45:59 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// APIGroupVersion is a helper for exposing rest.Storage objects as http.Handlers via go-restful
|
|
|
|
// It handles URLs of the form:
|
|
|
|
// /${storage_key}[/${object_name}]
|
|
|
|
// Where 'storage_key' points to a rest.Storage object stored in storage.
|
|
|
|
// This object should contain all parameterization necessary for running a particular API version
|
|
|
|
type APIGroupVersion struct {
|
|
|
|
Storage map[string]rest.Storage
|
|
|
|
|
|
|
|
Root string
|
|
|
|
|
|
|
|
// GroupVersion is the external group version
|
|
|
|
GroupVersion schema.GroupVersion
|
|
|
|
|
|
|
|
// OptionsExternalVersion controls the Kubernetes APIVersion used for common objects in the apiserver
|
2017-02-03 13:41:32 +00:00
|
|
|
// schema like api.Status, api.DeleteOptions, and metav1.ListOptions. Other implementors may
|
2017-02-01 00:45:59 +00:00
|
|
|
// define a version "v1beta1" but want to use the Kubernetes "v1" internal objects. If
|
|
|
|
// empty, defaults to GroupVersion.
|
|
|
|
OptionsExternalVersion *schema.GroupVersion
|
2017-02-03 13:41:32 +00:00
|
|
|
// MetaGroupVersion defaults to "meta.k8s.io/v1" and is the scheme group version used to decode
|
|
|
|
// common API implementations like ListOptions. Future changes will allow this to vary by group
|
|
|
|
// version (for when the inevitable meta/v2 group emerges).
|
|
|
|
MetaGroupVersion *schema.GroupVersion
|
2017-02-01 00:45:59 +00:00
|
|
|
|
|
|
|
Mapper meta.RESTMapper
|
|
|
|
|
|
|
|
// Serializer is used to determine how to convert responses from API methods into bytes to send over
|
|
|
|
// the wire.
|
|
|
|
Serializer runtime.NegotiatedSerializer
|
|
|
|
ParameterCodec runtime.ParameterCodec
|
|
|
|
|
|
|
|
Typer runtime.ObjectTyper
|
|
|
|
Creater runtime.ObjectCreater
|
|
|
|
Convertor runtime.ObjectConvertor
|
|
|
|
Copier runtime.ObjectCopier
|
|
|
|
Linker runtime.SelfLinker
|
|
|
|
|
|
|
|
Admit admission.Interface
|
|
|
|
Context request.RequestContextMapper
|
|
|
|
|
|
|
|
MinRequestTimeout time.Duration
|
|
|
|
|
|
|
|
// SubresourceGroupVersionKind contains the GroupVersionKind overrides for each subresource that is
|
|
|
|
// accessible from this API group version. The GroupVersionKind is that of the external version of
|
|
|
|
// the subresource. The key of this map should be the path of the subresource. The keys here should
|
|
|
|
// match the keys in the Storage map above for subresources.
|
|
|
|
SubresourceGroupVersionKind map[string]schema.GroupVersionKind
|
|
|
|
|
|
|
|
// ResourceLister is an interface that knows how to list resources
|
|
|
|
// for this API Group.
|
|
|
|
ResourceLister handlers.APIResourceLister
|
|
|
|
}
|
|
|
|
|
|
|
|
// InstallREST registers the REST handlers (storage, watch, proxy and redirect) into a restful Container.
|
|
|
|
// It is expected that the provided path root prefix will serve all operations. Root MUST NOT end
|
|
|
|
// in a slash.
|
|
|
|
func (g *APIGroupVersion) InstallREST(container *restful.Container) error {
|
|
|
|
installer := g.newInstaller()
|
|
|
|
ws := installer.NewWebService()
|
|
|
|
apiResources, registrationErrors := installer.Install(ws)
|
|
|
|
lister := g.ResourceLister
|
|
|
|
if lister == nil {
|
|
|
|
lister = staticLister{apiResources}
|
|
|
|
}
|
|
|
|
AddSupportedResourcesWebService(g.Serializer, ws, g.GroupVersion, lister)
|
|
|
|
container.Add(ws)
|
|
|
|
return utilerrors.NewAggregate(registrationErrors)
|
|
|
|
}
|
|
|
|
|
|
|
|
// UpdateREST registers the REST handlers for this APIGroupVersion to an existing web service
|
|
|
|
// in the restful Container. It will use the prefix (root/version) to find the existing
|
|
|
|
// web service. If a web service does not exist within the container to support the prefix
|
|
|
|
// this method will return an error.
|
|
|
|
func (g *APIGroupVersion) UpdateREST(container *restful.Container) error {
|
|
|
|
installer := g.newInstaller()
|
|
|
|
var ws *restful.WebService = nil
|
|
|
|
|
|
|
|
for i, s := range container.RegisteredWebServices() {
|
|
|
|
if s.RootPath() == installer.prefix {
|
|
|
|
ws = container.RegisteredWebServices()[i]
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ws == nil {
|
|
|
|
return apierrors.NewInternalError(fmt.Errorf("unable to find an existing webservice for prefix %s", installer.prefix))
|
|
|
|
}
|
|
|
|
apiResources, registrationErrors := installer.Install(ws)
|
|
|
|
lister := g.ResourceLister
|
|
|
|
if lister == nil {
|
|
|
|
lister = staticLister{apiResources}
|
|
|
|
}
|
|
|
|
AddSupportedResourcesWebService(g.Serializer, ws, g.GroupVersion, lister)
|
|
|
|
return utilerrors.NewAggregate(registrationErrors)
|
|
|
|
}
|
|
|
|
|
|
|
|
// newInstaller is a helper to create the installer. Used by InstallREST and UpdateREST.
|
|
|
|
func (g *APIGroupVersion) newInstaller() *APIInstaller {
|
|
|
|
prefix := path.Join(g.Root, g.GroupVersion.Group, g.GroupVersion.Version)
|
|
|
|
installer := &APIInstaller{
|
|
|
|
group: g,
|
|
|
|
prefix: prefix,
|
|
|
|
minRequestTimeout: g.MinRequestTimeout,
|
|
|
|
}
|
|
|
|
return installer
|
|
|
|
}
|
|
|
|
|
|
|
|
// staticLister implements the APIResourceLister interface
|
|
|
|
type staticLister struct {
|
|
|
|
list []metav1.APIResource
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s staticLister) ListAPIResources() []metav1.APIResource {
|
|
|
|
return s.list
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ handlers.APIResourceLister = &staticLister{}
|