mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 12:43:23 +00:00
make json serializer case sensitive
This commit is contained in:
parent
dd69be30a5
commit
7b0ffb8410
@ -58,7 +58,6 @@ go_library(
|
|||||||
"//pkg/proxy/apis/kubeproxyconfig/scheme:go_default_library",
|
"//pkg/proxy/apis/kubeproxyconfig/scheme:go_default_library",
|
||||||
"//pkg/proxy/apis/kubeproxyconfig/v1alpha1:go_default_library",
|
"//pkg/proxy/apis/kubeproxyconfig/v1alpha1:go_default_library",
|
||||||
"//pkg/util/pointer:go_default_library",
|
"//pkg/util/pointer:go_default_library",
|
||||||
"//vendor/github.com/json-iterator/go:go_default_library",
|
|
||||||
"//vendor/github.com/ugorji/go/codec:go_default_library",
|
"//vendor/github.com/ugorji/go/codec:go_default_library",
|
||||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
|
||||||
"github.com/ugorji/go/codec"
|
"github.com/ugorji/go/codec"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
@ -31,8 +30,6 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
)
|
)
|
||||||
|
|
||||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
|
||||||
|
|
||||||
type configMutationFunc func(map[string]interface{}) error
|
type configMutationFunc func(map[string]interface{}) error
|
||||||
|
|
||||||
// These migrations are a stop-gap until we get a properly-versioned configuration file for MasterConfiguration.
|
// These migrations are a stop-gap until we get a properly-versioned configuration file for MasterConfiguration.
|
||||||
|
@ -96,6 +96,7 @@ go_test(
|
|||||||
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_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/json:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||||
|
@ -37,6 +37,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/conversion"
|
"k8s.io/apimachinery/pkg/conversion"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
k8s_json "k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||||
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
|
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
|
||||||
"k8s.io/apimachinery/pkg/util/diff"
|
"k8s.io/apimachinery/pkg/util/diff"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
@ -560,9 +561,10 @@ func BenchmarkDecodeIntoJSONCodecGenConfigFast(b *testing.B) {
|
|||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
}
|
}
|
||||||
|
|
||||||
// BenchmarkDecodeIntoJSONCodecGenConfigCompatibleWithStandardLibrary
|
// BenchmarkDecodeIntoJSONCodecGenConfigCompatibleWithStandardLibrary provides a
|
||||||
// provides a baseline for JSON decode performance
|
// baseline for JSON decode performance with
|
||||||
// with jsoniter.ConfigCompatibleWithStandardLibrary
|
// jsoniter.ConfigCompatibleWithStandardLibrary, but with case sensitivity set
|
||||||
|
// to true
|
||||||
func BenchmarkDecodeIntoJSONCodecGenConfigCompatibleWithStandardLibrary(b *testing.B) {
|
func BenchmarkDecodeIntoJSONCodecGenConfigCompatibleWithStandardLibrary(b *testing.B) {
|
||||||
kcodec := testapi.Default.Codec()
|
kcodec := testapi.Default.Codec()
|
||||||
items := benchmarkItems(b)
|
items := benchmarkItems(b)
|
||||||
@ -577,9 +579,10 @@ func BenchmarkDecodeIntoJSONCodecGenConfigCompatibleWithStandardLibrary(b *testi
|
|||||||
}
|
}
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
iter := k8s_json.CaseSensitiveJsonIterator()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
obj := v1.Pod{}
|
obj := v1.Pod{}
|
||||||
if err := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(encoded[i%width], &obj); err != nil {
|
if err := iter.Unmarshal(encoded[i%width], &obj); err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,9 @@ go_test(
|
|||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
deps = [
|
deps = [
|
||||||
"//vendor/github.com/ghodss/yaml:go_default_library",
|
"//vendor/github.com/ghodss/yaml:go_default_library",
|
||||||
"//vendor/github.com/json-iterator/go:go_default_library",
|
|
||||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_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/json:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
k8s_json "k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GroupVersionHolder struct {
|
type GroupVersionHolder struct {
|
||||||
@ -47,7 +47,8 @@ func TestGroupVersionUnmarshalJSON(t *testing.T) {
|
|||||||
t.Errorf("JSON codec failed to unmarshal input '%s': expected %+v, got %+v", c.input, c.expect, result.GV)
|
t.Errorf("JSON codec failed to unmarshal input '%s': expected %+v, got %+v", c.input, c.expect, result.GV)
|
||||||
}
|
}
|
||||||
// test the json-iterator codec
|
// test the json-iterator codec
|
||||||
if err := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(c.input, &result); err != nil {
|
iter := k8s_json.CaseSensitiveJsonIterator()
|
||||||
|
if err := iter.Unmarshal(c.input, &result); err != nil {
|
||||||
t.Errorf("json-iterator codec failed to unmarshal input '%v': %v", c.input, err)
|
t.Errorf("json-iterator codec failed to unmarshal input '%v': %v", c.input, err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(result.GV, c.expect) {
|
if !reflect.DeepEqual(result.GV, c.expect) {
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
k8s_json "k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestVerbsUgorjiMarshalJSON(t *testing.T) {
|
func TestVerbsUgorjiMarshalJSON(t *testing.T) {
|
||||||
@ -45,7 +45,7 @@ func TestVerbsUgorjiMarshalJSON(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVerbsUgorjiUnmarshalJSON(t *testing.T) {
|
func TestVerbsUJsonIterUnmarshalJSON(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
input string
|
input string
|
||||||
result APIResource
|
result APIResource
|
||||||
@ -56,9 +56,10 @@ func TestVerbsUgorjiUnmarshalJSON(t *testing.T) {
|
|||||||
{`{"verbs":["delete"]}`, APIResource{Verbs: Verbs([]string{"delete"})}},
|
{`{"verbs":["delete"]}`, APIResource{Verbs: Verbs([]string{"delete"})}},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iter := k8s_json.CaseSensitiveJsonIterator()
|
||||||
for i, c := range cases {
|
for i, c := range cases {
|
||||||
var result APIResource
|
var result APIResource
|
||||||
if err := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal([]byte(c.input), &result); err != nil {
|
if err := iter.Unmarshal([]byte(c.input), &result); err != nil {
|
||||||
t.Errorf("[%d] Failed to unmarshal input '%v': %v", i, c.input, err)
|
t.Errorf("[%d] Failed to unmarshal input '%v': %v", i, c.input, err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(result, c.result) {
|
if !reflect.DeepEqual(result, c.result) {
|
||||||
|
@ -93,6 +93,20 @@ func init() {
|
|||||||
jsoniter.RegisterTypeDecoderFunc("interface {}", decodeNumberAsInt64IfPossible)
|
jsoniter.RegisterTypeDecoderFunc("interface {}", decodeNumberAsInt64IfPossible)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CaseSensitiveJsonIterator returns a jsoniterator API that's configured to be
|
||||||
|
// case-sensitive when unmarshalling, and otherwise compatible with
|
||||||
|
// the encoding/json standard library.
|
||||||
|
func CaseSensitiveJsonIterator() jsoniter.API {
|
||||||
|
return jsoniter.Config{
|
||||||
|
EscapeHTML: true,
|
||||||
|
SortMapKeys: true,
|
||||||
|
ValidateJsonRawMessage: true,
|
||||||
|
CaseSensitive: true,
|
||||||
|
}.Froze()
|
||||||
|
}
|
||||||
|
|
||||||
|
var caseSensitiveJsonIterator = CaseSensitiveJsonIterator()
|
||||||
|
|
||||||
// gvkWithDefaults returns group kind and version defaulting from provided default
|
// gvkWithDefaults returns group kind and version defaulting from provided default
|
||||||
func gvkWithDefaults(actual, defaultGVK schema.GroupVersionKind) schema.GroupVersionKind {
|
func gvkWithDefaults(actual, defaultGVK schema.GroupVersionKind) schema.GroupVersionKind {
|
||||||
if len(actual.Kind) == 0 {
|
if len(actual.Kind) == 0 {
|
||||||
@ -157,7 +171,7 @@ func (s *Serializer) Decode(originalData []byte, gvk *schema.GroupVersionKind, i
|
|||||||
types, _, err := s.typer.ObjectKinds(into)
|
types, _, err := s.typer.ObjectKinds(into)
|
||||||
switch {
|
switch {
|
||||||
case runtime.IsNotRegisteredError(err), isUnstructured:
|
case runtime.IsNotRegisteredError(err), isUnstructured:
|
||||||
if err := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(data, into); err != nil {
|
if err := caseSensitiveJsonIterator.Unmarshal(data, into); err != nil {
|
||||||
return nil, actual, err
|
return nil, actual, err
|
||||||
}
|
}
|
||||||
return into, actual, nil
|
return into, actual, nil
|
||||||
@ -181,7 +195,7 @@ func (s *Serializer) Decode(originalData []byte, gvk *schema.GroupVersionKind, i
|
|||||||
return nil, actual, err
|
return nil, actual, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(data, obj); err != nil {
|
if err := caseSensitiveJsonIterator.Unmarshal(data, obj); err != nil {
|
||||||
return nil, actual, err
|
return nil, actual, err
|
||||||
}
|
}
|
||||||
return obj, actual, nil
|
return obj, actual, nil
|
||||||
@ -190,7 +204,7 @@ func (s *Serializer) Decode(originalData []byte, gvk *schema.GroupVersionKind, i
|
|||||||
// Encode serializes the provided object to the given writer.
|
// Encode serializes the provided object to the given writer.
|
||||||
func (s *Serializer) Encode(obj runtime.Object, w io.Writer) error {
|
func (s *Serializer) Encode(obj runtime.Object, w io.Writer) error {
|
||||||
if s.yaml {
|
if s.yaml {
|
||||||
json, err := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(obj)
|
json, err := caseSensitiveJsonIterator.Marshal(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -203,7 +217,7 @@ func (s *Serializer) Encode(obj runtime.Object, w io.Writer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if s.pretty {
|
if s.pretty {
|
||||||
data, err := jsoniter.ConfigCompatibleWithStandardLibrary.MarshalIndent(obj, "", " ")
|
data, err := caseSensitiveJsonIterator.MarshalIndent(obj, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -30,10 +30,31 @@ import (
|
|||||||
|
|
||||||
type testDecodable struct {
|
type testDecodable struct {
|
||||||
Other string
|
Other string
|
||||||
Value int `json:"value"`
|
Value int `json:"value"`
|
||||||
|
Spec DecodableSpec `json:"spec"`
|
||||||
gvk schema.GroupVersionKind
|
gvk schema.GroupVersionKind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DecodableSpec has 15 fields. json-iterator treats struct with more than 10
|
||||||
|
// fields differently from struct that has less than 10 fields.
|
||||||
|
type DecodableSpec struct {
|
||||||
|
A int `json:"A"`
|
||||||
|
B int `json:"B"`
|
||||||
|
C int `json:"C"`
|
||||||
|
D int `json:"D"`
|
||||||
|
E int `json:"E"`
|
||||||
|
F int `json:"F"`
|
||||||
|
G int `json:"G"`
|
||||||
|
H int `json:"h"`
|
||||||
|
I int `json:"i"`
|
||||||
|
J int `json:"j"`
|
||||||
|
K int `json:"k"`
|
||||||
|
L int `json:"l"`
|
||||||
|
M int `json:"m"`
|
||||||
|
N int `json:"n"`
|
||||||
|
O int `json:"o"`
|
||||||
|
}
|
||||||
|
|
||||||
func (d *testDecodable) GetObjectKind() schema.ObjectKind { return d }
|
func (d *testDecodable) GetObjectKind() schema.ObjectKind { return d }
|
||||||
func (d *testDecodable) SetGroupVersionKind(gvk schema.GroupVersionKind) { d.gvk = gvk }
|
func (d *testDecodable) SetGroupVersionKind(gvk schema.GroupVersionKind) { d.gvk = gvk }
|
||||||
func (d *testDecodable) GroupVersionKind() schema.GroupVersionKind { return d.gvk }
|
func (d *testDecodable) GroupVersionKind() schema.GroupVersionKind { return d.gvk }
|
||||||
@ -221,6 +242,28 @@ func TestDecode(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// Unmarshalling is case-sensitive
|
||||||
|
{
|
||||||
|
// "VaLue" should have been "value"
|
||||||
|
data: []byte(`{"kind":"Test","apiVersion":"other/blah","VaLue":1,"Other":"test"}`),
|
||||||
|
into: &testDecodable{},
|
||||||
|
typer: &mockTyper{err: runtime.NewNotRegisteredErrForKind(schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"})},
|
||||||
|
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||||
|
expectedObject: &testDecodable{
|
||||||
|
Other: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Unmarshalling is case-sensitive for big struct.
|
||||||
|
{
|
||||||
|
// "b" should have been "B", "I" should have been "i"
|
||||||
|
data: []byte(`{"kind":"Test","apiVersion":"other/blah","spec": {"A": 1, "b": 2, "h": 3, "I": 4}}`),
|
||||||
|
into: &testDecodable{},
|
||||||
|
typer: &mockTyper{err: runtime.NewNotRegisteredErrForKind(schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"})},
|
||||||
|
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||||
|
expectedObject: &testDecodable{
|
||||||
|
Spec: DecodableSpec{A: 1, H: 3},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, test := range testCases {
|
for i, test := range testCases {
|
||||||
|
Loading…
Reference in New Issue
Block a user