251
vendor/k8s.io/apiserver/pkg/endpoints/installer.go
generated
vendored
251
vendor/k8s.io/apiserver/pkg/endpoints/installer.go
generated
vendored
@@ -32,15 +32,21 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/apiserver/pkg/endpoints/deprecation"
|
||||
"k8s.io/apiserver/pkg/endpoints/discovery"
|
||||
"k8s.io/apiserver/pkg/endpoints/handlers"
|
||||
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
|
||||
"k8s.io/apiserver/pkg/endpoints/handlers/negotiation"
|
||||
"k8s.io/apiserver/pkg/endpoints/metrics"
|
||||
utilwarning "k8s.io/apiserver/pkg/endpoints/warning"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
"k8s.io/apiserver/pkg/storageversion"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
versioninfo "k8s.io/component-base/version"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -90,8 +96,9 @@ var toDiscoveryKubeVerb = map[string]string{
|
||||
}
|
||||
|
||||
// Install handlers for API resources.
|
||||
func (a *APIInstaller) Install() ([]metav1.APIResource, *restful.WebService, []error) {
|
||||
func (a *APIInstaller) Install() ([]metav1.APIResource, []*storageversion.ResourceInfo, *restful.WebService, []error) {
|
||||
var apiResources []metav1.APIResource
|
||||
var resourceInfos []*storageversion.ResourceInfo
|
||||
var errors []error
|
||||
ws := a.newWebService()
|
||||
|
||||
@@ -104,15 +111,18 @@ func (a *APIInstaller) Install() ([]metav1.APIResource, *restful.WebService, []e
|
||||
}
|
||||
sort.Strings(paths)
|
||||
for _, path := range paths {
|
||||
apiResource, err := a.registerResourceHandlers(path, a.group.Storage[path], ws)
|
||||
apiResource, resourceInfo, err := a.registerResourceHandlers(path, a.group.Storage[path], ws)
|
||||
if err != nil {
|
||||
errors = append(errors, fmt.Errorf("error in registering resource: %s, %v", path, err))
|
||||
}
|
||||
if apiResource != nil {
|
||||
apiResources = append(apiResources, *apiResource)
|
||||
}
|
||||
if resourceInfo != nil {
|
||||
resourceInfos = append(resourceInfos, resourceInfo)
|
||||
}
|
||||
}
|
||||
return apiResources, ws, errors
|
||||
return apiResources, resourceInfos, ws, errors
|
||||
}
|
||||
|
||||
// newWebService creates a new restful webservice with the api installer's prefix and version.
|
||||
@@ -178,7 +188,7 @@ func GetResourceKind(groupVersion schema.GroupVersion, storage rest.Storage, typ
|
||||
return fqKindToRegister, nil
|
||||
}
|
||||
|
||||
func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storage, ws *restful.WebService) (*metav1.APIResource, error) {
|
||||
func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storage, ws *restful.WebService) (*metav1.APIResource, *storageversion.ResourceInfo, error) {
|
||||
admit := a.group.Admit
|
||||
|
||||
optionsExternalVersion := a.group.GroupVersion
|
||||
@@ -188,19 +198,19 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
|
||||
resource, subresource, err := splitSubresource(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
group, version := a.group.GroupVersion.Group, a.group.GroupVersion.Version
|
||||
|
||||
fqKindToRegister, err := GetResourceKind(a.group.GroupVersion, storage, a.group.Typer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
versionedPtr, err := a.group.Creater.New(fqKindToRegister)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
defaultVersionedObject := indirectArbitraryPointer(versionedPtr)
|
||||
kind := fqKindToRegister.Kind
|
||||
@@ -211,18 +221,18 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
if isSubresource {
|
||||
parentStorage, ok := a.group.Storage[resource]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing parent storage: %q", resource)
|
||||
return nil, nil, fmt.Errorf("missing parent storage: %q", resource)
|
||||
}
|
||||
scoper, ok := parentStorage.(rest.Scoper)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%q must implement scoper", resource)
|
||||
return nil, nil, fmt.Errorf("%q must implement scoper", resource)
|
||||
}
|
||||
namespaceScoped = scoper.NamespaceScoped()
|
||||
|
||||
} else {
|
||||
scoper, ok := storage.(rest.Scoper)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%q must implement scoper", resource)
|
||||
return nil, nil, fmt.Errorf("%q must implement scoper", resource)
|
||||
}
|
||||
namespaceScoped = scoper.NamespaceScoped()
|
||||
}
|
||||
@@ -244,49 +254,47 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
if !isMetadata {
|
||||
storageMeta = defaultStorageMetadata{}
|
||||
}
|
||||
exporter, isExporter := storage.(rest.Exporter)
|
||||
if !isExporter {
|
||||
exporter = nil
|
||||
}
|
||||
|
||||
versionedExportOptions, err := a.group.Creater.New(optionsExternalVersion.WithKind("ExportOptions"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if isNamedCreater {
|
||||
isCreater = true
|
||||
}
|
||||
|
||||
var resetFields map[fieldpath.APIVersion]*fieldpath.Set
|
||||
if a.group.OpenAPIModels != nil && utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) {
|
||||
if resetFieldsStrategy, isResetFieldsStrategy := storage.(rest.ResetFieldsStrategy); isResetFieldsStrategy {
|
||||
resetFields = resetFieldsStrategy.GetResetFields()
|
||||
}
|
||||
}
|
||||
|
||||
var versionedList interface{}
|
||||
if isLister {
|
||||
list := lister.NewList()
|
||||
listGVKs, _, err := a.group.Typer.ObjectKinds(list)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
versionedListPtr, err := a.group.Creater.New(a.group.GroupVersion.WithKind(listGVKs[0].Kind))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
versionedList = indirectArbitraryPointer(versionedListPtr)
|
||||
}
|
||||
|
||||
versionedListOptions, err := a.group.Creater.New(optionsExternalVersion.WithKind("ListOptions"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
versionedCreateOptions, err := a.group.Creater.New(optionsExternalVersion.WithKind("CreateOptions"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
versionedPatchOptions, err := a.group.Creater.New(optionsExternalVersion.WithKind("PatchOptions"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
versionedUpdateOptions, err := a.group.Creater.New(optionsExternalVersion.WithKind("UpdateOptions"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var versionedDeleteOptions runtime.Object
|
||||
@@ -295,7 +303,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
if isGracefulDeleter {
|
||||
versionedDeleteOptions, err = a.group.Creater.New(optionsExternalVersion.WithKind("DeleteOptions"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
versionedDeleterObject = indirectArbitraryPointer(versionedDeleteOptions)
|
||||
|
||||
@@ -306,7 +314,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
|
||||
versionedStatusPtr, err := a.group.Creater.New(optionsExternalVersion.WithKind("Status"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
versionedStatus := indirectArbitraryPointer(versionedStatusPtr)
|
||||
var (
|
||||
@@ -319,14 +327,14 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
getOptions, getSubpath, _ = getterWithOptions.NewGetOptions()
|
||||
getOptionsInternalKinds, _, err := a.group.Typer.ObjectKinds(getOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
getOptionsInternalKind = getOptionsInternalKinds[0]
|
||||
versionedGetOptions, err = a.group.Creater.New(a.group.GroupVersion.WithKind(getOptionsInternalKind.Kind))
|
||||
if err != nil {
|
||||
versionedGetOptions, err = a.group.Creater.New(optionsExternalVersion.WithKind(getOptionsInternalKind.Kind))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
isGetter = true
|
||||
@@ -336,7 +344,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
if isWatcher {
|
||||
versionedWatchEventPtr, err := a.group.Creater.New(a.group.GroupVersion.WithKind("WatchEvent"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
versionedWatchEvent = indirectArbitraryPointer(versionedWatchEventPtr)
|
||||
}
|
||||
@@ -352,7 +360,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
if connectOptions != nil {
|
||||
connectOptionsInternalKinds, _, err := a.group.Typer.ObjectKinds(connectOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
connectOptionsInternalKind = connectOptionsInternalKinds[0]
|
||||
@@ -360,7 +368,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
if err != nil {
|
||||
versionedConnectOptions, err = a.group.Creater.New(optionsExternalVersion.WithKind(connectOptionsInternalKind.Kind))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -381,7 +389,11 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
resourceKind = kind
|
||||
}
|
||||
|
||||
tableProvider, _ := storage.(rest.TableConvertor)
|
||||
tableProvider, isTableProvider := storage.(rest.TableConvertor)
|
||||
if isLister && !isTableProvider {
|
||||
// All listers must implement TableProvider
|
||||
return nil, nil, fmt.Errorf("%q must implement TableConvertor", resource)
|
||||
}
|
||||
|
||||
var apiResource metav1.APIResource
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.StorageVersionHash) &&
|
||||
@@ -390,7 +402,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
versioner := storageVersionProvider.StorageVersion()
|
||||
gvk, err := getStorageVersionKind(versioner, storage, a.group.Typer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
apiResource.StorageVersionHash = discovery.StorageVersionHash(gvk.Group, gvk.Version, gvk.Kind)
|
||||
}
|
||||
@@ -498,6 +510,36 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
}
|
||||
}
|
||||
|
||||
var resourceInfo *storageversion.ResourceInfo
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.StorageVersionAPI) &&
|
||||
utilfeature.DefaultFeatureGate.Enabled(features.APIServerIdentity) &&
|
||||
isStorageVersionProvider &&
|
||||
storageVersionProvider.StorageVersion() != nil {
|
||||
|
||||
versioner := storageVersionProvider.StorageVersion()
|
||||
encodingGVK, err := getStorageVersionKind(versioner, storage, a.group.Typer)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
decodableVersions := []schema.GroupVersion{}
|
||||
if a.group.ConvertabilityChecker != nil {
|
||||
decodableVersions = a.group.ConvertabilityChecker.VersionsForGroupKind(fqKindToRegister.GroupKind())
|
||||
}
|
||||
resourceInfo = &storageversion.ResourceInfo{
|
||||
GroupResource: schema.GroupResource{
|
||||
Group: a.group.GroupVersion.Group,
|
||||
Resource: apiResource.Name,
|
||||
},
|
||||
EncodingVersion: encodingGVK.GroupVersion().String(),
|
||||
// We record EquivalentResourceMapper first instead of calculate
|
||||
// DecodableVersions immediately because API installation must
|
||||
// be completed first for us to know equivalent APIs
|
||||
EquivalentResourceMapper: a.group.EquivalentResourceRegistry,
|
||||
|
||||
DirectlyDecodableVersions: decodableVersions,
|
||||
}
|
||||
}
|
||||
|
||||
// Create Routes for the actions.
|
||||
// TODO: Add status documentation using Returns()
|
||||
// Errors (see api/errors/errors.go as well as go-restful router):
|
||||
@@ -517,7 +559,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
|
||||
for _, s := range a.group.Serializer.SupportedMediaTypes() {
|
||||
if len(s.MediaTypeSubType) == 0 || len(s.MediaTypeType) == 0 {
|
||||
return nil, fmt.Errorf("all serializers in the group Serializer must have MediaTypeType and MediaTypeSubType set: %s", s.MediaType)
|
||||
return nil, nil, fmt.Errorf("all serializers in the group Serializer must have MediaTypeType and MediaTypeSubType set: %s", s.MediaType)
|
||||
}
|
||||
}
|
||||
mediaTypes, streamMediaTypes := negotiation.MediaTypesForSerializer(a.group.Serializer)
|
||||
@@ -556,15 +598,17 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
}
|
||||
if a.group.OpenAPIModels != nil && utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) {
|
||||
reqScope.FieldManager, err = fieldmanager.NewDefaultFieldManager(
|
||||
a.group.OpenAPIModels,
|
||||
a.group.TypeConverter,
|
||||
a.group.UnsafeConvertor,
|
||||
a.group.Defaulter,
|
||||
a.group.Creater,
|
||||
fqKindToRegister,
|
||||
reqScope.HubGroupVersion,
|
||||
isSubresource,
|
||||
resetFields,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create field manager: %v", err)
|
||||
return nil, nil, fmt.Errorf("failed to create field manager: %v", err)
|
||||
}
|
||||
}
|
||||
for _, action := range actions {
|
||||
@@ -585,6 +629,9 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
requestScope = "resource"
|
||||
operationSuffix = operationSuffix + "WithPath"
|
||||
}
|
||||
if strings.Index(action.Path, "/{name}") != -1 || action.Verb == "POST" {
|
||||
requestScope = "resource"
|
||||
}
|
||||
if action.AllNamespaces {
|
||||
requestScope = "cluster"
|
||||
operationSuffix = operationSuffix + "ForAllNamespaces"
|
||||
@@ -596,7 +643,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
kubeVerbs[kubeVerb] = struct{}{}
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("unknown action verb for discovery: %s", action.Verb)
|
||||
return nil, nil, fmt.Errorf("unknown action verb for discovery: %s", action.Verb)
|
||||
}
|
||||
|
||||
routes := []*restful.RouteBuilder{}
|
||||
@@ -605,32 +652,55 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
if isSubresource {
|
||||
parentStorage, ok := a.group.Storage[resource]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing parent storage: %q", resource)
|
||||
return nil, nil, fmt.Errorf("missing parent storage: %q", resource)
|
||||
}
|
||||
|
||||
fqParentKind, err := GetResourceKind(a.group.GroupVersion, parentStorage, a.group.Typer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
kind = fqParentKind.Kind
|
||||
}
|
||||
|
||||
verbOverrider, needOverride := storage.(StorageMetricsOverride)
|
||||
|
||||
// accumulate endpoint-level warnings
|
||||
var (
|
||||
enableWarningHeaders = utilfeature.DefaultFeatureGate.Enabled(features.WarningHeaders)
|
||||
|
||||
warnings []string
|
||||
deprecated bool
|
||||
removedRelease string
|
||||
)
|
||||
|
||||
{
|
||||
versionedPtrWithGVK := versionedPtr.DeepCopyObject()
|
||||
versionedPtrWithGVK.GetObjectKind().SetGroupVersionKind(fqKindToRegister)
|
||||
currentMajor, currentMinor, _ := deprecation.MajorMinor(versioninfo.Get())
|
||||
deprecated = deprecation.IsDeprecated(versionedPtrWithGVK, currentMajor, currentMinor)
|
||||
if deprecated {
|
||||
removedRelease = deprecation.RemovedRelease(versionedPtrWithGVK)
|
||||
warnings = append(warnings, deprecation.WarningMessage(versionedPtrWithGVK))
|
||||
}
|
||||
}
|
||||
|
||||
switch action.Verb {
|
||||
case "GET": // Get a resource.
|
||||
var handler restful.RouteFunction
|
||||
if isGetterWithOptions {
|
||||
handler = restfulGetResourceWithOptions(getterWithOptions, reqScope, isSubresource)
|
||||
} else {
|
||||
handler = restfulGetResource(getter, exporter, reqScope)
|
||||
handler = restfulGetResource(getter, reqScope)
|
||||
}
|
||||
|
||||
if needOverride {
|
||||
// need change the reported verb
|
||||
handler = metrics.InstrumentRouteFunc(verbOverrider.OverrideMetricsVerb(action.Verb), group, version, resource, subresource, requestScope, metrics.APIServerComponent, handler)
|
||||
handler = metrics.InstrumentRouteFunc(verbOverrider.OverrideMetricsVerb(action.Verb), group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, handler)
|
||||
} else {
|
||||
handler = metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, handler)
|
||||
handler = metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, handler)
|
||||
}
|
||||
if enableWarningHeaders {
|
||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||
}
|
||||
|
||||
doc := "read the specified " + kind
|
||||
@@ -646,12 +716,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
Writes(producedObject)
|
||||
if isGetterWithOptions {
|
||||
if err := AddObjectParams(ws, route, versionedGetOptions); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if isExporter {
|
||||
if err := AddObjectParams(ws, route, versionedExportOptions); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
addParams(route, action.Params)
|
||||
@@ -661,7 +726,10 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
if isSubresource {
|
||||
doc = "list " + subresource + " of objects of kind " + kind
|
||||
}
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulListResource(lister, watcher, reqScope, false, a.minRequestTimeout))
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulListResource(lister, watcher, reqScope, false, a.minRequestTimeout))
|
||||
if enableWarningHeaders {
|
||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||
}
|
||||
route := ws.GET(action.Path).To(handler).
|
||||
Doc(doc).
|
||||
Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")).
|
||||
@@ -670,7 +738,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
Returns(http.StatusOK, "OK", versionedList).
|
||||
Writes(versionedList)
|
||||
if err := AddObjectParams(ws, route, versionedListOptions); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
switch {
|
||||
case isLister && isWatcher:
|
||||
@@ -693,7 +761,10 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
if isSubresource {
|
||||
doc = "replace " + subresource + " of the specified " + kind
|
||||
}
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulUpdateResource(updater, reqScope, admit))
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulUpdateResource(updater, reqScope, admit))
|
||||
if enableWarningHeaders {
|
||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||
}
|
||||
route := ws.PUT(action.Path).To(handler).
|
||||
Doc(doc).
|
||||
Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")).
|
||||
@@ -706,7 +777,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
Reads(defaultVersionedObject).
|
||||
Writes(producedObject)
|
||||
if err := AddObjectParams(ws, route, versionedUpdateOptions); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
addParams(route, action.Params)
|
||||
routes = append(routes, route)
|
||||
@@ -723,7 +794,10 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) {
|
||||
supportedTypes = append(supportedTypes, string(types.ApplyPatchType))
|
||||
}
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulPatchResource(patcher, reqScope, admit, supportedTypes))
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulPatchResource(patcher, reqScope, admit, supportedTypes))
|
||||
if enableWarningHeaders {
|
||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||
}
|
||||
route := ws.PATCH(action.Path).To(handler).
|
||||
Doc(doc).
|
||||
Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")).
|
||||
@@ -734,7 +808,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
Reads(metav1.Patch{}).
|
||||
Writes(producedObject)
|
||||
if err := AddObjectParams(ws, route, versionedPatchOptions); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
addParams(route, action.Params)
|
||||
routes = append(routes, route)
|
||||
@@ -745,7 +819,10 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
} else {
|
||||
handler = restfulCreateResource(creater, reqScope, admit)
|
||||
}
|
||||
handler = metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, handler)
|
||||
handler = metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, handler)
|
||||
if enableWarningHeaders {
|
||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||
}
|
||||
article := GetArticleForNoun(kind, " ")
|
||||
doc := "create" + article + kind
|
||||
if isSubresource {
|
||||
@@ -764,7 +841,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
Reads(defaultVersionedObject).
|
||||
Writes(producedObject)
|
||||
if err := AddObjectParams(ws, route, versionedCreateOptions); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
addParams(route, action.Params)
|
||||
routes = append(routes, route)
|
||||
@@ -778,7 +855,10 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
if deleteReturnsDeletedObject {
|
||||
deleteReturnType = producedObject
|
||||
}
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulDeleteResource(gracefulDeleter, isGracefulDeleter, reqScope, admit))
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulDeleteResource(gracefulDeleter, isGracefulDeleter, reqScope, admit))
|
||||
if enableWarningHeaders {
|
||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||
}
|
||||
route := ws.DELETE(action.Path).To(handler).
|
||||
Doc(doc).
|
||||
Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")).
|
||||
@@ -791,7 +871,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
route.Reads(versionedDeleterObject)
|
||||
route.ParameterNamed("body").Required(false)
|
||||
if err := AddObjectParams(ws, route, versionedDeleteOptions); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
addParams(route, action.Params)
|
||||
@@ -801,7 +881,10 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
if isSubresource {
|
||||
doc = "delete collection of " + subresource + " of a " + kind
|
||||
}
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulDeleteCollection(collectionDeleter, isCollectionDeleter, reqScope, admit))
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulDeleteCollection(collectionDeleter, isCollectionDeleter, reqScope, admit))
|
||||
if enableWarningHeaders {
|
||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||
}
|
||||
route := ws.DELETE(action.Path).To(handler).
|
||||
Doc(doc).
|
||||
Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")).
|
||||
@@ -813,11 +896,11 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
route.Reads(versionedDeleterObject)
|
||||
route.ParameterNamed("body").Required(false)
|
||||
if err := AddObjectParams(ws, route, versionedDeleteOptions); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
if err := AddObjectParams(ws, route, versionedListOptions); err != nil {
|
||||
return nil, err
|
||||
if err := AddObjectParams(ws, route, versionedListOptions, "watch", "allowWatchBookmarks"); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
addParams(route, action.Params)
|
||||
routes = append(routes, route)
|
||||
@@ -828,7 +911,10 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
doc = "watch changes to " + subresource + " of an object of kind " + kind
|
||||
}
|
||||
doc += ". deprecated: use the 'watch' parameter with a list operation instead, filtered to a single item with the 'fieldSelector' parameter."
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulListResource(lister, watcher, reqScope, true, a.minRequestTimeout))
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulListResource(lister, watcher, reqScope, true, a.minRequestTimeout))
|
||||
if enableWarningHeaders {
|
||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||
}
|
||||
route := ws.GET(action.Path).To(handler).
|
||||
Doc(doc).
|
||||
Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")).
|
||||
@@ -837,7 +923,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
Returns(http.StatusOK, "OK", versionedWatchEvent).
|
||||
Writes(versionedWatchEvent)
|
||||
if err := AddObjectParams(ws, route, versionedListOptions); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
addParams(route, action.Params)
|
||||
routes = append(routes, route)
|
||||
@@ -848,7 +934,10 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
doc = "watch individual changes to a list of " + subresource + " of " + kind
|
||||
}
|
||||
doc += ". deprecated: use the 'watch' parameter with a list operation instead."
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulListResource(lister, watcher, reqScope, true, a.minRequestTimeout))
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulListResource(lister, watcher, reqScope, true, a.minRequestTimeout))
|
||||
if enableWarningHeaders {
|
||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||
}
|
||||
route := ws.GET(action.Path).To(handler).
|
||||
Doc(doc).
|
||||
Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")).
|
||||
@@ -857,7 +946,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
Returns(http.StatusOK, "OK", versionedWatchEvent).
|
||||
Writes(versionedWatchEvent)
|
||||
if err := AddObjectParams(ws, route, versionedListOptions); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
addParams(route, action.Params)
|
||||
routes = append(routes, route)
|
||||
@@ -871,7 +960,10 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
if isSubresource {
|
||||
doc = "connect " + method + " requests to " + subresource + " of " + kind
|
||||
}
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulConnectResource(connecter, reqScope, admit, path, isSubresource))
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulConnectResource(connecter, reqScope, admit, path, isSubresource))
|
||||
if enableWarningHeaders {
|
||||
handler = utilwarning.AddWarningsHandler(handler, warnings)
|
||||
}
|
||||
route := ws.Method(method).Path(action.Path).
|
||||
To(handler).
|
||||
Doc(doc).
|
||||
@@ -881,7 +973,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
Writes(connectProducedObject)
|
||||
if versionedConnectOptions != nil {
|
||||
if err := AddObjectParams(ws, route, versionedConnectOptions); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
addParams(route, action.Params)
|
||||
@@ -895,7 +987,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
}
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unrecognized action verb: %s", action.Verb)
|
||||
return nil, nil, fmt.Errorf("unrecognized action verb: %s", action.Verb)
|
||||
}
|
||||
for _, route := range routes {
|
||||
route.Metadata(ROUTE_META_GVK, metav1.GroupVersionKind{
|
||||
@@ -931,7 +1023,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
// Record the existence of the GVR and the corresponding GVK
|
||||
a.group.EquivalentResourceRegistry.RegisterKindFor(reqScope.Resource, reqScope.Subresource, fqKindToRegister)
|
||||
|
||||
return &apiResource, nil
|
||||
return &apiResource, resourceInfo, nil
|
||||
}
|
||||
|
||||
// indirectArbitraryPointer returns *ptrToObject for an arbitrary pointer
|
||||
@@ -958,12 +1050,13 @@ func addParams(route *restful.RouteBuilder, params []*restful.Parameter) {
|
||||
// Go JSON behavior for omitting a field) become query parameters. The name of the query parameter is
|
||||
// the JSON field name. If a description struct tag is set on the field, that description is used on the
|
||||
// query parameter. In essence, it converts a standard JSON top level object into a query param schema.
|
||||
func AddObjectParams(ws *restful.WebService, route *restful.RouteBuilder, obj interface{}) error {
|
||||
func AddObjectParams(ws *restful.WebService, route *restful.RouteBuilder, obj interface{}, excludedNames ...string) error {
|
||||
sv, err := conversion.EnforcePtr(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
st := sv.Type()
|
||||
excludedNameSet := sets.NewString(excludedNames...)
|
||||
switch st.Kind() {
|
||||
case reflect.Struct:
|
||||
for i := 0; i < st.NumField(); i++ {
|
||||
@@ -989,7 +1082,9 @@ func AddObjectParams(ws *restful.WebService, route *restful.RouteBuilder, obj in
|
||||
if len(jsonName) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if excludedNameSet.Has(jsonName) {
|
||||
continue
|
||||
}
|
||||
var desc string
|
||||
if docable, ok := obj.(documentable); ok {
|
||||
desc = docable.SwaggerDoc()[jsonName]
|
||||
@@ -1017,6 +1112,10 @@ func typeToJSON(typeName string) string {
|
||||
return "string"
|
||||
case "v1.DeletionPropagation", "*v1.DeletionPropagation":
|
||||
return "string"
|
||||
case "v1.ResourceVersionMatch", "*v1.ResourceVersionMatch":
|
||||
return "string"
|
||||
case "v1.IncludeObjectPolicy", "*v1.IncludeObjectPolicy":
|
||||
return "string"
|
||||
|
||||
// TODO: Fix these when go-restful supports a way to specify an array query param:
|
||||
// https://github.com/emicklei/go-restful/issues/225
|
||||
@@ -1062,7 +1161,7 @@ func splitSubresource(path string) (string, string, error) {
|
||||
|
||||
// GetArticleForNoun returns the article needed for the given noun.
|
||||
func GetArticleForNoun(noun string, padding string) string {
|
||||
if noun[len(noun)-2:] != "ss" && noun[len(noun)-1:] == "s" {
|
||||
if !strings.HasSuffix(noun, "ss") && strings.HasSuffix(noun, "s") {
|
||||
// Plurals don't have an article.
|
||||
// Don't catch words like class
|
||||
return fmt.Sprintf("%v", padding)
|
||||
@@ -1129,9 +1228,9 @@ func restfulPatchResource(r rest.Patcher, scope handlers.RequestScope, admit adm
|
||||
}
|
||||
}
|
||||
|
||||
func restfulGetResource(r rest.Getter, e rest.Exporter, scope handlers.RequestScope) restful.RouteFunction {
|
||||
func restfulGetResource(r rest.Getter, scope handlers.RequestScope) restful.RouteFunction {
|
||||
return func(req *restful.Request, res *restful.Response) {
|
||||
handlers.GetResource(r, e, &scope)(res.ResponseWriter, req.Request)
|
||||
handlers.GetResource(r, &scope)(res.ResponseWriter, req.Request)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user