Skip to content

Commit f4cf484

Browse files
author
Kubernetes Submit Queue
authored
Merge pull request kubernetes#65298 from nikhita/cherrypick-jsoniter-bump-1.9
Automatic merge from submit-queue. Manual cherrypick of kubernetes#65034 to 1.9: make json serializer case sensitive fixes partially kubernetes#64612 This PR imports the latest jsoniterator library so that case sensitivity during unmarshalling is optional. The PR also sets Kubernetes json serializer to be case sensitive. **Release note**: ```release-note ACTION REQUIRED: Kubernetes JSON deserializer is now case-sensitive to restore compatibility with pre-1.8 servers. If your config files contains fields with wrong case, the config files will be now invalid. ``` /sig api-machinery /kind bug /assign caesarxuchao liggitt thockin sttts mbohlool
2 parents 2068255 + 55543f1 commit f4cf484

File tree

126 files changed

+6851
-3312
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

126 files changed

+6851
-3312
lines changed

Godeps/Godeps.json

Lines changed: 93 additions & 83 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Godeps/LICENSES

Lines changed: 418 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/api/testing/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ go_test(
9999
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
100100
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
101101
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
102+
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
102103
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf:go_default_library",
103104
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming:go_default_library",
104105
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",

pkg/api/testing/serialization_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
"k8s.io/apimachinery/pkg/conversion"
4040
"k8s.io/apimachinery/pkg/runtime"
4141
"k8s.io/apimachinery/pkg/runtime/schema"
42+
k8s_json "k8s.io/apimachinery/pkg/runtime/serializer/json"
4243
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
4344
"k8s.io/apimachinery/pkg/util/diff"
4445
"k8s.io/apimachinery/pkg/util/sets"
@@ -568,3 +569,31 @@ func BenchmarkDecodeIntoJSONCodecGen(b *testing.B) {
568569
}
569570
b.StopTimer()
570571
}
572+
573+
// BenchmarkDecodeIntoJSONCodecGenConfigCompatibleWithStandardLibrary provides a
574+
// baseline for JSON decode performance with
575+
// jsoniter.ConfigCompatibleWithStandardLibrary, but with case sensitivity set
576+
// to true
577+
func BenchmarkDecodeIntoJSONCodecGenConfigCompatibleWithStandardLibrary(b *testing.B) {
578+
kcodec := testapi.Default.Codec()
579+
items := benchmarkItems(b)
580+
width := len(items)
581+
encoded := make([][]byte, width)
582+
for i := range items {
583+
data, err := runtime.Encode(kcodec, &items[i])
584+
if err != nil {
585+
b.Fatal(err)
586+
}
587+
encoded[i] = data
588+
}
589+
590+
b.ResetTimer()
591+
iter := k8s_json.CaseSensitiveJsonIterator()
592+
for i := 0; i < b.N; i++ {
593+
obj := v1.Pod{}
594+
if err := iter.Unmarshal(encoded[i%width], &obj); err != nil {
595+
b.Fatal(err)
596+
}
597+
}
598+
b.StopTimer()
599+
}

staging/src/k8s.io/apiextensions-apiserver/Godeps/Godeps.json

Lines changed: 9 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

staging/src/k8s.io/apimachinery/Godeps/Godeps.json

Lines changed: 9 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ go_test(
2222
library = ":go_default_library",
2323
deps = [
2424
"//vendor/github.com/ghodss/yaml:go_default_library",
25-
"//vendor/github.com/json-iterator/go:go_default_library",
2625
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
2726
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
27+
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
2828
],
2929
)
3030

staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/group_version_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import (
2121
"reflect"
2222
"testing"
2323

24-
jsoniter "github.com/json-iterator/go"
24+
k8s_json "k8s.io/apimachinery/pkg/runtime/serializer/json"
2525
)
2626

2727
type GroupVersionHolder struct {
@@ -47,7 +47,8 @@ func TestGroupVersionUnmarshalJSON(t *testing.T) {
4747
t.Errorf("JSON codec failed to unmarshal input '%s': expected %+v, got %+v", c.input, c.expect, result.GV)
4848
}
4949
// test the json-iterator codec
50-
if err := jsoniter.ConfigFastest.Unmarshal(c.input, &result); err != nil {
50+
iter := k8s_json.CaseSensitiveJsonIterator()
51+
if err := iter.Unmarshal(c.input, &result); err != nil {
5152
t.Errorf("json-iterator codec failed to unmarshal input '%v': %v", c.input, err)
5253
}
5354
if !reflect.DeepEqual(result.GV, c.expect) {

staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/types_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import (
2121
"reflect"
2222
"testing"
2323

24-
jsoniter "github.com/json-iterator/go"
24+
k8s_json "k8s.io/apimachinery/pkg/runtime/serializer/json"
2525
)
2626

2727
func TestVerbsUgorjiMarshalJSON(t *testing.T) {
@@ -45,7 +45,7 @@ func TestVerbsUgorjiMarshalJSON(t *testing.T) {
4545
}
4646
}
4747

48-
func TestVerbsUgorjiUnmarshalJSON(t *testing.T) {
48+
func TestVerbsUJsonIterUnmarshalJSON(t *testing.T) {
4949
cases := []struct {
5050
input string
5151
result APIResource
@@ -56,9 +56,10 @@ func TestVerbsUgorjiUnmarshalJSON(t *testing.T) {
5656
{`{"verbs":["delete"]}`, APIResource{Verbs: Verbs([]string{"delete"})}},
5757
}
5858

59+
iter := k8s_json.CaseSensitiveJsonIterator()
5960
for i, c := range cases {
6061
var result APIResource
61-
if err := jsoniter.ConfigFastest.Unmarshal([]byte(c.input), &result); err != nil {
62+
if err := iter.Unmarshal([]byte(c.input), &result); err != nil {
6263
t.Errorf("[%d] Failed to unmarshal input '%v': %v", i, c.input, err)
6364
}
6465
if !reflect.DeepEqual(result, c.result) {

staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json/json.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,20 @@ func init() {
9898
jsoniter.RegisterTypeDecoderFunc("interface {}", decodeNumberAsInt64IfPossible)
9999
}
100100

101+
// CaseSensitiveJsonIterator returns a jsoniterator API that's configured to be
102+
// case-sensitive when unmarshalling, and otherwise compatible with
103+
// the encoding/json standard library.
104+
func CaseSensitiveJsonIterator() jsoniter.API {
105+
return jsoniter.Config{
106+
EscapeHTML: true,
107+
SortMapKeys: true,
108+
ValidateJsonRawMessage: true,
109+
CaseSensitive: true,
110+
}.Froze()
111+
}
112+
113+
var caseSensitiveJsonIterator = CaseSensitiveJsonIterator()
114+
101115
// Decode attempts to convert the provided data into YAML or JSON, extract the stored schema kind, apply the provided default gvk, and then
102116
// load that data into an object matching the desired schema kind or the provided into. If into is *runtime.Unknown, the raw data will be
103117
// extracted and no decoding will be performed. If into is not registered with the typer, then the object will be straight decoded using
@@ -154,7 +168,7 @@ func (s *Serializer) Decode(originalData []byte, gvk *schema.GroupVersionKind, i
154168
types, _, err := s.typer.ObjectKinds(into)
155169
switch {
156170
case runtime.IsNotRegisteredError(err), isUnstructured:
157-
if err := jsoniter.ConfigFastest.Unmarshal(data, into); err != nil {
171+
if err := caseSensitiveJsonIterator.Unmarshal(data, into); err != nil {
158172
return nil, actual, err
159173
}
160174
return into, actual, nil
@@ -188,7 +202,7 @@ func (s *Serializer) Decode(originalData []byte, gvk *schema.GroupVersionKind, i
188202
return nil, actual, err
189203
}
190204

191-
if err := jsoniter.ConfigFastest.Unmarshal(data, obj); err != nil {
205+
if err := caseSensitiveJsonIterator.Unmarshal(data, obj); err != nil {
192206
return nil, actual, err
193207
}
194208
return obj, actual, nil
@@ -197,7 +211,7 @@ func (s *Serializer) Decode(originalData []byte, gvk *schema.GroupVersionKind, i
197211
// Encode serializes the provided object to the given writer.
198212
func (s *Serializer) Encode(obj runtime.Object, w io.Writer) error {
199213
if s.yaml {
200-
json, err := jsoniter.ConfigFastest.Marshal(obj)
214+
json, err := caseSensitiveJsonIterator.Marshal(obj)
201215
if err != nil {
202216
return err
203217
}
@@ -210,7 +224,7 @@ func (s *Serializer) Encode(obj runtime.Object, w io.Writer) error {
210224
}
211225

212226
if s.pretty {
213-
data, err := jsoniter.ConfigFastest.MarshalIndent(obj, "", " ")
227+
data, err := caseSensitiveJsonIterator.MarshalIndent(obj, "", " ")
214228
if err != nil {
215229
return err
216230
}

staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json/json_test.go

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,31 @@ import (
3030

3131
type testDecodable struct {
3232
Other string
33-
Value int `json:"value"`
33+
Value int `json:"value"`
34+
Spec DecodableSpec `json:"spec"`
3435
gvk schema.GroupVersionKind
3536
}
3637

38+
// DecodableSpec has 15 fields. json-iterator treats struct with more than 10
39+
// fields differently from struct that has less than 10 fields.
40+
type DecodableSpec struct {
41+
A int `json:"A"`
42+
B int `json:"B"`
43+
C int `json:"C"`
44+
D int `json:"D"`
45+
E int `json:"E"`
46+
F int `json:"F"`
47+
G int `json:"G"`
48+
H int `json:"h"`
49+
I int `json:"i"`
50+
J int `json:"j"`
51+
K int `json:"k"`
52+
L int `json:"l"`
53+
M int `json:"m"`
54+
N int `json:"n"`
55+
O int `json:"o"`
56+
}
57+
3758
func (d *testDecodable) GetObjectKind() schema.ObjectKind { return d }
3859
func (d *testDecodable) SetGroupVersionKind(gvk schema.GroupVersionKind) { d.gvk = gvk }
3960
func (d *testDecodable) GroupVersionKind() schema.GroupVersionKind { return d.gvk }
@@ -195,6 +216,28 @@ func TestDecode(t *testing.T) {
195216
},
196217
},
197218
},
219+
// Unmarshalling is case-sensitive
220+
{
221+
// "VaLue" should have been "value"
222+
data: []byte(`{"kind":"Test","apiVersion":"other/blah","VaLue":1,"Other":"test"}`),
223+
into: &testDecodable{},
224+
typer: &mockTyper{err: runtime.NewNotRegisteredErrForKind(schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"})},
225+
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
226+
expectedObject: &testDecodable{
227+
Other: "test",
228+
},
229+
},
230+
// Unmarshalling is case-sensitive for big struct.
231+
{
232+
// "b" should have been "B", "I" should have been "i"
233+
data: []byte(`{"kind":"Test","apiVersion":"other/blah","spec": {"A": 1, "b": 2, "h": 3, "I": 4}}`),
234+
into: &testDecodable{},
235+
typer: &mockTyper{err: runtime.NewNotRegisteredErrForKind(schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"})},
236+
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
237+
expectedObject: &testDecodable{
238+
Spec: DecodableSpec{A: 1, H: 3},
239+
},
240+
},
198241
}
199242

200243
for i, test := range testCases {

staging/src/k8s.io/apiserver/Godeps/Godeps.json

Lines changed: 9 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

staging/src/k8s.io/client-go/Godeps/Godeps.json

Lines changed: 9 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

staging/src/k8s.io/kube-aggregator/Godeps/Godeps.json

Lines changed: 9 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

staging/src/k8s.io/metrics/Godeps/Godeps.json

Lines changed: 9 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

staging/src/k8s.io/sample-apiserver/Godeps/Godeps.json

Lines changed: 9 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)