Skip to content

Commit 2624a4a

Browse files
authored
Merge pull request kubernetes#80943 from obitech/yaml_meta
Add a YAML MetaFactory
2 parents b17ddac + b46e541 commit 2624a4a

File tree

6 files changed

+232
-22
lines changed

6 files changed

+232
-22
lines changed

cmd/kubeadm/app/util/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ go_library(
2525
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
2626
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
2727
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
28+
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer/yaml:go_default_library",
2829
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
2930
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
3031
"//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library",
@@ -35,7 +36,6 @@ go_library(
3536
"//vendor/github.com/pkg/errors:go_default_library",
3637
"//vendor/k8s.io/klog:go_default_library",
3738
"//vendor/k8s.io/utils/exec:go_default_library",
38-
"//vendor/sigs.k8s.io/yaml:go_default_library",
3939
],
4040
)
4141

cmd/kubeadm/app/util/marshal.go

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ import (
2222
"io"
2323

2424
"github.com/pkg/errors"
25-
"sigs.k8s.io/yaml"
2625

2726
"k8s.io/apimachinery/pkg/runtime"
2827
"k8s.io/apimachinery/pkg/runtime/schema"
2928
"k8s.io/apimachinery/pkg/runtime/serializer"
29+
yamlserializer "k8s.io/apimachinery/pkg/runtime/serializer/yaml"
3030
errorsutil "k8s.io/apimachinery/pkg/util/errors"
3131
utilyaml "k8s.io/apimachinery/pkg/util/yaml"
3232
clientsetscheme "k8s.io/client-go/kubernetes/scheme"
@@ -81,7 +81,6 @@ func SplitYAMLDocuments(yamlBytes []byte) (kubeadmapi.DocumentMap, error) {
8181
buf := bytes.NewBuffer(yamlBytes)
8282
reader := utilyaml.NewYAMLReader(bufio.NewReader(buf))
8383
for {
84-
typeMetaInfo := runtime.TypeMeta{}
8584
// Read one YAML document at a time, until io.EOF is returned
8685
b, err := reader.Read()
8786
if err == io.EOF {
@@ -93,31 +92,23 @@ func SplitYAMLDocuments(yamlBytes []byte) (kubeadmapi.DocumentMap, error) {
9392
break
9493
}
9594
// Deserialize the TypeMeta information of this byte slice
96-
if err := yaml.Unmarshal(b, &typeMetaInfo); err != nil {
95+
gvk, err := yamlserializer.DefaultMetaFactory.Interpret(b)
96+
if err != nil {
9797
return nil, err
9898
}
99-
// Require TypeMeta information to be present
100-
if len(typeMetaInfo.APIVersion) == 0 || len(typeMetaInfo.Kind) == 0 {
101-
errs = append(errs, errors.New("invalid configuration: kind and apiVersion is mandatory information that needs to be specified in all YAML documents"))
102-
continue
99+
if len(gvk.Group) == 0 || len(gvk.Version) == 0 || len(gvk.Kind) == 0 {
100+
return nil, errors.New("invalid configuration: kind and apiVersion is mandatory information that needs to be specified")
103101
}
104-
// Check whether the kind has been registered before. If it has, throw an error
105-
if known := knownKinds[typeMetaInfo.Kind]; known {
106-
errs = append(errs, errors.Errorf("invalid configuration: kind %q is specified twice in YAML file", typeMetaInfo.Kind))
107-
continue
108-
}
109-
knownKinds[typeMetaInfo.Kind] = true
110102

111-
// Build a GroupVersionKind object from the deserialized TypeMeta object
112-
gv, err := schema.ParseGroupVersion(typeMetaInfo.APIVersion)
113-
if err != nil {
114-
errs = append(errs, errors.Wrap(err, "unable to parse apiVersion"))
103+
// Check whether the kind has been registered before. If it has, throw an error
104+
if known := knownKinds[gvk.Kind]; known {
105+
errs = append(errs, errors.Errorf("invalid configuration: kind %q is specified twice in YAML file", gvk.Kind))
115106
continue
116107
}
117-
gvk := gv.WithKind(typeMetaInfo.Kind)
108+
knownKinds[gvk.Kind] = true
118109

119110
// Save the mapping between the gvk and the bytes that object consists of
120-
gvkmap[gvk] = b
111+
gvkmap[*gvk] = b
121112
}
122113
if err := errorsutil.NewAggregate(errs); err != nil {
123114
return nil, err

staging/src/k8s.io/apimachinery/pkg/runtime/serializer/yaml/BUILD

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
44

55
go_library(
66
name = "go_default_library",
7-
srcs = ["yaml.go"],
7+
srcs = [
8+
"meta.go",
9+
"yaml.go",
10+
],
811
importmap = "k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/runtime/serializer/yaml",
912
importpath = "k8s.io/apimachinery/pkg/runtime/serializer/yaml",
1013
deps = [
1114
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
1215
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
1316
"//staging/src/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
17+
"//vendor/sigs.k8s.io/yaml:go_default_library",
1418
],
1519
)
1620

@@ -29,10 +33,14 @@ filegroup(
2933

3034
go_test(
3135
name = "go_default_test",
32-
srcs = ["yaml_test.go"],
36+
srcs = [
37+
"meta_test.go",
38+
"yaml_test.go",
39+
],
3340
data = glob(["testdata/**"]),
3441
embed = [":go_default_library"],
3542
deps = [
43+
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
3644
"//staging/src/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
3745
"//vendor/sigs.k8s.io/yaml:go_default_library",
3846
],
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
Copyright 2019 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package yaml
18+
19+
import (
20+
"fmt"
21+
22+
"k8s.io/apimachinery/pkg/runtime"
23+
"k8s.io/apimachinery/pkg/runtime/schema"
24+
"sigs.k8s.io/yaml"
25+
)
26+
27+
// DefaultMetaFactory is a default factory for versioning objects in JSON or
28+
// YAML. The object in memory and in the default serialization will use the
29+
// "kind" and "apiVersion" fields.
30+
var DefaultMetaFactory = SimpleMetaFactory{}
31+
32+
// SimpleMetaFactory provides default methods for retrieving the type and version of objects
33+
// that are identified with an "apiVersion" and "kind" fields in their JSON
34+
// serialization. It may be parameterized with the names of the fields in memory, or an
35+
// optional list of base structs to search for those fields in memory.
36+
type SimpleMetaFactory struct{}
37+
38+
// Interpret will return the APIVersion and Kind of the JSON wire-format
39+
// encoding of an object, or an error.
40+
func (SimpleMetaFactory) Interpret(data []byte) (*schema.GroupVersionKind, error) {
41+
gvk := runtime.TypeMeta{}
42+
if err := yaml.Unmarshal(data, &gvk); err != nil {
43+
return nil, fmt.Errorf("could not interpret GroupVersionKind; unmarshal error: %v", err)
44+
}
45+
gv, err := schema.ParseGroupVersion(gvk.APIVersion)
46+
if err != nil {
47+
return nil, err
48+
}
49+
return &schema.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: gvk.Kind}, nil
50+
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/*
2+
Copyright 2019 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package yaml
18+
19+
import (
20+
"reflect"
21+
"testing"
22+
23+
"k8s.io/apimachinery/pkg/runtime/schema"
24+
)
25+
26+
func TestInterpret(t *testing.T) {
27+
testCases := []struct {
28+
name string
29+
input string
30+
expected *schema.GroupVersionKind
31+
errFn func(error) bool
32+
}{
33+
{
34+
name: "YAMLSuccessfullyInterpretVK",
35+
input: `apiVersion: v1
36+
kind: Service`,
37+
expected: &schema.GroupVersionKind{Version: "v1", Kind: "Service"},
38+
},
39+
{
40+
name: "YAMLSuccessfullyInterpretGVK",
41+
input: `apiVersion: core/v2
42+
kind: Deployment`,
43+
expected: &schema.GroupVersionKind{Group: "core", Version: "v2", Kind: "Deployment"},
44+
},
45+
{
46+
name: "YAMLSuccessfullyInterpretV",
47+
input: `apiVersion: v1`,
48+
expected: &schema.GroupVersionKind{Version: "v1"},
49+
},
50+
{
51+
name: "YAMLSuccessfullyInterpretK",
52+
input: `kind: Service`,
53+
expected: &schema.GroupVersionKind{Kind: "Service"},
54+
},
55+
{
56+
name: "YAMLSuccessfullyInterpretEmptyString",
57+
input: ``,
58+
expected: &schema.GroupVersionKind{},
59+
},
60+
{
61+
name: "YAMLSuccessfullyInterpretEmptyDoc",
62+
input: `---`,
63+
expected: &schema.GroupVersionKind{},
64+
},
65+
{
66+
name: "YAMLSuccessfullyInterpretMultiDoc",
67+
input: `---
68+
apiVersion: v1
69+
kind: Service
70+
---
71+
apiVersion: v2
72+
kind: Deployment`,
73+
expected: &schema.GroupVersionKind{Version: "v1", Kind: "Service"},
74+
},
75+
{
76+
name: "YAMLSuccessfullyInterpretOnlyG",
77+
input: `apiVersion: core/`,
78+
expected: &schema.GroupVersionKind{Group: "core"},
79+
},
80+
{
81+
name: "YAMLSuccessfullyWrongFormat",
82+
input: `foo: bar`,
83+
expected: &schema.GroupVersionKind{},
84+
},
85+
{
86+
name: "YAMLFailInterpretWrongSyntax",
87+
input: `foo`,
88+
errFn: func(err error) bool { return err != nil },
89+
},
90+
{
91+
name: "JSONSuccessfullyInterpretVK",
92+
input: `{"apiVersion": "v3", "kind": "DaemonSet"}`,
93+
expected: &schema.GroupVersionKind{Version: "v3", Kind: "DaemonSet"},
94+
},
95+
{
96+
name: "JSONSuccessfullyInterpretGVK",
97+
input: `{"apiVersion": "core/v2", "kind": "Deployment"}`,
98+
expected: &schema.GroupVersionKind{Group: "core", Version: "v2", Kind: "Deployment"},
99+
},
100+
{
101+
name: "JSONSuccessfullyInterpretV",
102+
input: `{"apiVersion": "v1"}`,
103+
expected: &schema.GroupVersionKind{Version: "v1"},
104+
},
105+
{
106+
name: "JSONSuccessfullyInterpretK",
107+
input: `{"kind": "Service"}`,
108+
expected: &schema.GroupVersionKind{Kind: "Service"},
109+
},
110+
{
111+
name: "JSONSuccessfullyInterpretEmptyString",
112+
input: ``,
113+
expected: &schema.GroupVersionKind{},
114+
},
115+
{
116+
name: "JSONSuccessfullyInterpretEmptyObject",
117+
input: `{}`,
118+
expected: &schema.GroupVersionKind{},
119+
},
120+
{
121+
name: "JSONSuccessfullyInterpretMultiDoc",
122+
input: `{"apiVersion": "v1", "kind": "Service"},
123+
{"apiVersion": "v2", "kind": "Deployment"}`,
124+
expected: &schema.GroupVersionKind{Version: "v1", Kind: "Service"},
125+
},
126+
{
127+
name: "JSONSuccessfullyWrongFormat",
128+
input: `{"foo": "bar"}`,
129+
expected: &schema.GroupVersionKind{},
130+
},
131+
{
132+
name: "JSONFailInterpretArray",
133+
input: `[]`,
134+
errFn: func(err error) bool { return err != nil },
135+
},
136+
{
137+
name: "JSONFailInterpretWrongSyntax",
138+
input: `{"foo"`,
139+
errFn: func(err error) bool { return err != nil },
140+
},
141+
}
142+
143+
for _, test := range testCases {
144+
t.Run(test.name, func(t *testing.T) {
145+
actual, err := DefaultMetaFactory.Interpret([]byte(test.input))
146+
switch {
147+
case test.errFn != nil:
148+
if !test.errFn(err) {
149+
t.Errorf("unexpected error: %v", err)
150+
}
151+
case err != nil:
152+
t.Errorf("unexpected error: %v", err)
153+
case !reflect.DeepEqual(test.expected, actual):
154+
t.Errorf("outcome mismatch -- expected: %#v, actual: %#v",
155+
test.expected, actual,
156+
)
157+
}
158+
})
159+
}
160+
}

vendor/modules.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,7 @@ k8s.io/apimachinery/pkg/runtime/serializer/protobuf
12391239
k8s.io/apimachinery/pkg/runtime/serializer/recognizer
12401240
k8s.io/apimachinery/pkg/runtime/serializer/streaming
12411241
k8s.io/apimachinery/pkg/runtime/serializer/versioning
1242+
k8s.io/apimachinery/pkg/runtime/serializer/yaml
12421243
k8s.io/apimachinery/pkg/selection
12431244
k8s.io/apimachinery/pkg/types
12441245
k8s.io/apimachinery/pkg/util/cache

0 commit comments

Comments
 (0)