mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-04 01:40:07 +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.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},
|
schema.GroupVersionKind{Group: crd.Spec.Group, Version: crd.Spec.Version, Kind: crd.Spec.Names.ListKind},
|
||||||
apiextensionsserver.UnstructuredCopier{},
|
apiextensionsserver.UnstructuredCopier{},
|
||||||
customresource.NewStrategy(discoveryclient.NewUnstructuredObjectTyper(nil), true),
|
customresource.NewStrategy(discoveryclient.NewUnstructuredObjectTyper(nil), true, gvk),
|
||||||
m.crdRESTOptionsGetter,
|
m.crdRESTOptionsGetter,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ go_library(
|
|||||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema: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:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/json: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/types:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime: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/util/wait:go_default_library",
|
||||||
|
@ -56,6 +56,17 @@ var (
|
|||||||
registry = registered.NewOrDie("")
|
registry = registered.NewOrDie("")
|
||||||
Scheme = runtime.NewScheme()
|
Scheme = runtime.NewScheme()
|
||||||
Codecs = serializer.NewCodecFactory(Scheme)
|
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() {
|
func init() {
|
||||||
@ -64,14 +75,7 @@ func init() {
|
|||||||
// we need to add the options to empty v1
|
// we need to add the options to empty v1
|
||||||
metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Group: "", Version: "v1"})
|
metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Group: "", Version: "v1"})
|
||||||
|
|
||||||
unversioned := schema.GroupVersion{Group: "", Version: "v1"}
|
Scheme.AddUnversionedTypes(unversionedVersion, unversionedTypes...)
|
||||||
Scheme.AddUnversionedTypes(unversioned,
|
|
||||||
&metav1.Status{},
|
|
||||||
&metav1.APIVersions{},
|
|
||||||
&metav1.APIGroupList{},
|
|
||||||
&metav1.APIGroup{},
|
|
||||||
&metav1.APIResourceList{},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -19,6 +19,7 @@ package apiserver
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
"sync"
|
"sync"
|
||||||
@ -33,6 +34,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/serializer/versioning"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"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 {
|
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 {
|
func (s UnstructuredNegotiatedSerializer) DecoderToVersion(serializer runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder {
|
||||||
return unstructured.UnstructuredJSONScheme
|
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{}
|
type UnstructuredCreator struct{}
|
||||||
|
|
||||||
func (UnstructuredCreator) New(kind schema.GroupVersionKind) (runtime.Object, error) {
|
func (UnstructuredCreator) New(kind schema.GroupVersionKind) (runtime.Object, error) {
|
||||||
|
@ -13,6 +13,7 @@ go_test(
|
|||||||
"basic_test.go",
|
"basic_test.go",
|
||||||
"finalization_test.go",
|
"finalization_test.go",
|
||||||
"registration_test.go",
|
"registration_test.go",
|
||||||
|
"validation_test.go",
|
||||||
],
|
],
|
||||||
tags = [
|
tags = [
|
||||||
"automanaged",
|
"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