mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 22:46:12 +00:00
handle unversioned objects for encoding for CRs
This commit is contained in:
parent
c0aaf94159
commit
6c391607de
2
pkg/master/thirdparty/thirdparty.go
vendored
2
pkg/master/thirdparty/thirdparty.go
vendored
@ -261,7 +261,7 @@ func (m *ThirdPartyResourceServer) migrateThirdPartyResourceData(gvk schema.Grou
|
||||
schema.GroupResource{Group: crd.Spec.Group, Resource: crd.Spec.Names.Plural},
|
||||
schema.GroupVersionKind{Group: crd.Spec.Group, Version: crd.Spec.Version, Kind: crd.Spec.Names.ListKind},
|
||||
apiextensionsserver.UnstructuredCopier{},
|
||||
customresource.NewStrategy(discoveryclient.NewUnstructuredObjectTyper(nil), true),
|
||||
customresource.NewStrategy(discoveryclient.NewUnstructuredObjectTyper(nil), true, gvk),
|
||||
m.crdRESTOptionsGetter,
|
||||
)
|
||||
|
||||
|
@ -42,6 +42,7 @@ go_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/runtime/serializer/versioning: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",
|
||||
|
@ -56,6 +56,17 @@ var (
|
||||
registry = registered.NewOrDie("")
|
||||
Scheme = runtime.NewScheme()
|
||||
Codecs = serializer.NewCodecFactory(Scheme)
|
||||
|
||||
// if you modify this, make sure you update the crEncoder
|
||||
unversionedVersion = schema.GroupVersion{Group: "", Version: "v1"}
|
||||
unversionedTypes = []runtime.Object{
|
||||
&metav1.Status{},
|
||||
&metav1.WatchEvent{},
|
||||
&metav1.APIVersions{},
|
||||
&metav1.APIGroupList{},
|
||||
&metav1.APIGroup{},
|
||||
&metav1.APIResourceList{},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -64,14 +75,7 @@ func init() {
|
||||
// we need to add the options to empty v1
|
||||
metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Group: "", Version: "v1"})
|
||||
|
||||
unversioned := schema.GroupVersion{Group: "", Version: "v1"}
|
||||
Scheme.AddUnversionedTypes(unversioned,
|
||||
&metav1.Status{},
|
||||
&metav1.APIVersions{},
|
||||
&metav1.APIGroupList{},
|
||||
&metav1.APIGroup{},
|
||||
&metav1.APIResourceList{},
|
||||
)
|
||||
Scheme.AddUnversionedTypes(unversionedVersion, unversionedTypes...)
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
|
@ -19,6 +19,7 @@ package apiserver
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"path"
|
||||
"sync"
|
||||
@ -33,6 +34,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/versioning"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
@ -358,13 +360,36 @@ func (s UnstructuredNegotiatedSerializer) SupportedMediaTypes() []runtime.Serial
|
||||
}
|
||||
|
||||
func (s UnstructuredNegotiatedSerializer) EncoderForVersion(serializer runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder {
|
||||
return unstructured.UnstructuredJSONScheme
|
||||
return versioning.NewDefaultingCodecForScheme(Scheme, crEncoderInstance, nil, gv, nil)
|
||||
}
|
||||
|
||||
func (s UnstructuredNegotiatedSerializer) DecoderToVersion(serializer runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder {
|
||||
return unstructured.UnstructuredJSONScheme
|
||||
}
|
||||
|
||||
var crEncoderInstance = crEncoder{}
|
||||
|
||||
// crEncoder *usually* encodes using the unstructured.UnstructuredJSONScheme, but if the type is Status or WatchEvent
|
||||
// it will serialize them out using the converting codec.
|
||||
type crEncoder struct{}
|
||||
|
||||
func (crEncoder) Encode(obj runtime.Object, w io.Writer) error {
|
||||
switch t := obj.(type) {
|
||||
case *metav1.Status, *metav1.WatchEvent:
|
||||
for _, info := range Codecs.SupportedMediaTypes() {
|
||||
// we are always json
|
||||
if info.MediaType == "application/json" {
|
||||
return info.Serializer.Encode(obj, w)
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("unable to find json serializer for %T", t)
|
||||
|
||||
default:
|
||||
return unstructured.UnstructuredJSONScheme.Encode(obj, w)
|
||||
}
|
||||
}
|
||||
|
||||
type UnstructuredCreator struct{}
|
||||
|
||||
func (UnstructuredCreator) New(kind schema.GroupVersionKind) (runtime.Object, error) {
|
||||
|
@ -13,6 +13,7 @@ go_test(
|
||||
"basic_test.go",
|
||||
"finalization_test.go",
|
||||
"registration_test.go",
|
||||
"validation_test.go",
|
||||
],
|
||||
tags = [
|
||||
"automanaged",
|
||||
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
Copyright 2017 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.
|
||||
*/
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
"k8s.io/apiextensions-apiserver/test/integration/testserver"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func TestForProperValidationErrors(t *testing.T) {
|
||||
stopCh, apiExtensionClient, clientPool, err := testserver.StartDefaultServer()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer close(stopCh)
|
||||
|
||||
noxuDefinition := testserver.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
|
||||
noxuVersionClient, err := testserver.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, clientPool)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ns := "not-the-default"
|
||||
noxuResourceClient := NewNamespacedCustomResourceClient(ns, noxuVersionClient, noxuDefinition)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
instanceFn func() *unstructured.Unstructured
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "bad version",
|
||||
instanceFn: func() *unstructured.Unstructured {
|
||||
instance := testserver.NewNoxuInstance(ns, "foo")
|
||||
instance.Object["apiVersion"] = "mygroup.example.com/v2"
|
||||
return instance
|
||||
},
|
||||
expectedError: "the API version in the data (mygroup.example.com/v2) does not match the expected API version (mygroup.example.com/v1beta1)",
|
||||
},
|
||||
{
|
||||
name: "bad kind",
|
||||
instanceFn: func() *unstructured.Unstructured {
|
||||
instance := testserver.NewNoxuInstance(ns, "foo")
|
||||
instance.Object["kind"] = "SomethingElse"
|
||||
return instance
|
||||
},
|
||||
expectedError: `SomethingElse.mygroup.example.com "foo" is invalid: kind: Invalid value: "SomethingElse": must be WishIHadChosenNoxu`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
_, err := noxuResourceClient.Create(tc.instanceFn())
|
||||
if err == nil {
|
||||
t.Errorf("%v: expected %v", tc.name, tc.expectedError)
|
||||
continue
|
||||
}
|
||||
// this only works when status errors contain the expect kind and version, so this effectively tests serializations too
|
||||
if !strings.Contains(err.Error(), tc.expectedError) {
|
||||
t.Errorf("%v: expected %v, got %v", tc.name, tc.expectedError, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user