Merge pull request #58260 from liggitt/crd-yaml

Automatic merge from submit-queue (batch tested with PRs 58260, 58326). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Add support for submitting/receiving CRD objects as yaml

Fixes #37455

```release-note
Custom resources can now be submitted to and received from the API server in application/yaml format.
```

Kubernetes-commit: a7c65d29e6e4fabd9ce24f8373ad6c26bfa948d5
This commit is contained in:
Kubernetes Publisher 2018-01-16 06:42:30 -08:00
commit 74bf920708
5 changed files with 87 additions and 72 deletions

116
Godeps/Godeps.json generated
View File

@ -968,235 +968,235 @@
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/equality",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/errors",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/meta",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/resource",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/testing",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/testing/fuzzer",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/testing/roundtrip",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/validation",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/validation/path",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apimachinery",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apimachinery/announced",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apimachinery/registered",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/fuzzer",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/internalversion",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/validation",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1alpha1",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/fields",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/labels",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/schema",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/selection",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/types",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/cache",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/clock",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/diff",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/errors",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/framer",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/httpstream",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/intstr",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/json",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/mergepatch",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/net",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/proxy",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/rand",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/runtime",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/sets",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/strategicpatch",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/uuid",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation/field",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/wait",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/waitgroup",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/yaml",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/version",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/watch",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/json",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/netutil",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect",
"Rev": "d0c8c1c78cacdef77dfcc0ff70d9b7b01faeaf08"
"Rev": "bc918d4f73e11cb3110730ec8e8ee02c58d6267c"
},
{
"ImportPath": "k8s.io/client-go/discovery",

View File

@ -71,6 +71,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/proxy:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
"//vendor/k8s.io/apiserver/pkg/admission:go_default_library",

View File

@ -41,7 +41,7 @@ func (e errNotAcceptable) Status() metav1.Status {
return metav1.Status{
Status: metav1.StatusFailure,
Code: http.StatusNotAcceptable,
Reason: metav1.StatusReason("NotAcceptable"),
Reason: metav1.StatusReasonNotAcceptable,
Message: e.Error(),
}
}
@ -63,7 +63,7 @@ func (e errUnsupportedMediaType) Status() metav1.Status {
return metav1.Status{
Status: metav1.StatusFailure,
Code: http.StatusUnsupportedMediaType,
Reason: metav1.StatusReason("UnsupportedMediaType"),
Reason: metav1.StatusReasonUnsupportedMediaType,
Message: e.Error(),
}
}

View File

@ -32,17 +32,34 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/apimachinery/pkg/util/mergepatch"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/audit"
"k8s.io/apiserver/pkg/endpoints/handlers/negotiation"
"k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
)
// PatchResource returns a function that will handle a resource patch
// TODO: Eventually PatchResource should just use GuaranteedUpdate and this routine should be a bit cleaner
func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface, converter runtime.ObjectConvertor) http.HandlerFunc {
func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface, converter runtime.ObjectConvertor, patchTypes []string) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
// Do this first, otherwise name extraction can fail for unrecognized content types
// TODO: handle this in negotiation
contentType := req.Header.Get("Content-Type")
// Remove "; charset=" if included in header.
if idx := strings.Index(contentType, ";"); idx > 0 {
contentType = contentType[:idx]
}
patchType := types.PatchType(contentType)
// Ensure the patchType is one we support
if !sets.NewString(patchTypes...).Has(contentType) {
scope.err(negotiation.NewUnsupportedMediaTypeError(patchTypes), w, req)
return
}
// TODO: we either want to remove timeout or document it (if we
// document, move timeout out of this function and declare it in
// api_installer)
@ -63,14 +80,6 @@ func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface
return
}
// TODO: handle this in negotiation
contentType := req.Header.Get("Content-Type")
// Remove "; charset=" if included in header.
if idx := strings.Index(contentType, ";"); idx > 0 {
contentType = contentType[:idx]
}
patchType := types.PatchType(contentType)
patchJS, err := readBody(req)
if err != nil {
scope.err(err, w, req)

View File

@ -690,7 +690,12 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
if hasSubresource {
doc = "partially update " + subresource + " of the specified " + kind
}
handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulPatchResource(patcher, reqScope, admit, mapping.ObjectConvertor))
supportedTypes := []string{
string(types.JSONPatchType),
string(types.MergePatchType),
string(types.StrategicMergePatchType),
}
handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulPatchResource(patcher, reqScope, admit, mapping.ObjectConvertor, supportedTypes))
route := ws.PATCH(action.Path).To(handler).
Doc(doc).
Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")).
@ -1099,9 +1104,9 @@ func restfulUpdateResource(r rest.Updater, scope handlers.RequestScope, typer ru
}
}
func restfulPatchResource(r rest.Patcher, scope handlers.RequestScope, admit admission.Interface, converter runtime.ObjectConvertor) restful.RouteFunction {
func restfulPatchResource(r rest.Patcher, scope handlers.RequestScope, admit admission.Interface, converter runtime.ObjectConvertor, supportedTypes []string) restful.RouteFunction {
return func(req *restful.Request, res *restful.Response) {
handlers.PatchResource(r, scope, admit, converter)(res.ResponseWriter, req.Request)
handlers.PatchResource(r, scope, admit, converter, supportedTypes)(res.ResponseWriter, req.Request)
}
}