diff --git a/bill-of-materials.json b/bill-of-materials.json index b1a3f555d1b0..3673a5b4cc01 100644 --- a/bill-of-materials.json +++ b/bill-of-materials.json @@ -98,15 +98,6 @@ } ] }, - { - "project": "github.com/ghodss/yaml", - "licenses": [ - { - "type": "MIT License and BSD 3-clause \"New\" or \"Revised\" License", - "confidence": 1 - } - ] - }, { "project": "github.com/gogo/protobuf", "licenses": [ @@ -465,5 +456,14 @@ "confidence": 0.8975609756097561 } ] + }, + { + "project": "sigs.k8s.io/yaml", + "licenses": [ + { + "type": "BSD 3-clause \"New\" or \"Revised\" License", + "confidence": 1 + } + ] } ] diff --git a/bill-of-materials.override.json b/bill-of-materials.override.json index 34de90e7142d..5224974a5bab 100644 --- a/bill-of-materials.override.json +++ b/bill-of-materials.override.json @@ -8,10 +8,10 @@ ] }, { - "project": "github.com/ghodss/yaml", + "project": "sigs.k8s.io/yaml", "licenses": [ { - "type": "MIT License and BSD 3-clause \"New\" or \"Revised\" License" + "type": "BSD 3-clause \"New\" or \"Revised\" License" } ] }, diff --git a/clientv3/yaml/config.go b/clientv3/yaml/config.go index 7539da294c1b..ced50389590c 100644 --- a/clientv3/yaml/config.go +++ b/clientv3/yaml/config.go @@ -20,7 +20,7 @@ import ( "crypto/x509" "io/ioutil" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" "github.com/coreos/etcd/clientv3" "github.com/coreos/etcd/pkg/tlsutil" diff --git a/clientv3/yaml/config_test.go b/clientv3/yaml/config_test.go index bcf28b434570..7a8f71280ac2 100644 --- a/clientv3/yaml/config_test.go +++ b/clientv3/yaml/config_test.go @@ -21,7 +21,7 @@ import ( "reflect" "testing" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" ) var ( diff --git a/cmd/vendor/sigs.k8s.io/yaml/.gitignore b/cmd/vendor/sigs.k8s.io/yaml/.gitignore new file mode 100644 index 000000000000..e256a31e00a5 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/yaml/.gitignore @@ -0,0 +1,20 @@ +# OSX leaves these everywhere on SMB shares +._* + +# Eclipse files +.classpath +.project +.settings/** + +# Emacs save files +*~ + +# Vim-related files +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +*.un~ +Session.vim +.netrwhist + +# Go test binaries +*.test diff --git a/cmd/vendor/sigs.k8s.io/yaml/.travis.yml b/cmd/vendor/sigs.k8s.io/yaml/.travis.yml new file mode 100644 index 000000000000..03ddc7318ae6 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/yaml/.travis.yml @@ -0,0 +1,14 @@ +language: go +dist: xenial +go: + - 1.9.x + - 1.10.x + - 1.11.x +script: + - go get -t -v ./... + - diff -u <(echo -n) <(gofmt -d .) + - diff -u <(echo -n) <(golint $(go list -e ./...) | grep -v YAMLToJSON) + - go tool vet . + - go test -v -race ./... +install: + - go get golang.org/x/lint/golint diff --git a/cmd/vendor/sigs.k8s.io/yaml/CONTRIBUTING.md b/cmd/vendor/sigs.k8s.io/yaml/CONTRIBUTING.md new file mode 100644 index 000000000000..de4711513724 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/yaml/CONTRIBUTING.md @@ -0,0 +1,31 @@ +# Contributing Guidelines + +Welcome to Kubernetes. We are excited about the prospect of you joining our [community](https://github.com/kubernetes/community)! The Kubernetes community abides by the CNCF [code of conduct](code-of-conduct.md). Here is an excerpt: + +_As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities._ + +## Getting Started + +We have full documentation on how to get started contributing here: + + + +- [Contributor License Agreement](https://git.k8s.io/community/CLA.md) Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests +- [Kubernetes Contributor Guide](http://git.k8s.io/community/contributors/guide) - Main contributor documentation, or you can just jump directly to the [contributing section](http://git.k8s.io/community/contributors/guide#contributing) +- [Contributor Cheat Sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet.md) - Common resources for existing developers + +## Mentorship + +- [Mentoring Initiatives](https://git.k8s.io/community/mentoring) - We have a diverse set of mentorship programs available that are always looking for volunteers! + + diff --git a/cmd/vendor/github.com/ghodss/yaml/LICENSE b/cmd/vendor/sigs.k8s.io/yaml/LICENSE similarity index 100% rename from cmd/vendor/github.com/ghodss/yaml/LICENSE rename to cmd/vendor/sigs.k8s.io/yaml/LICENSE diff --git a/cmd/vendor/sigs.k8s.io/yaml/OWNERS b/cmd/vendor/sigs.k8s.io/yaml/OWNERS new file mode 100644 index 000000000000..11ad7ce1a40b --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/yaml/OWNERS @@ -0,0 +1,25 @@ +approvers: +- dims +- lavalamp +- smarterclayton +- deads2k +- sttts +- liggitt +- caesarxuchao +reviewers: +- dims +- thockin +- lavalamp +- smarterclayton +- wojtek-t +- deads2k +- derekwaynecarr +- caesarxuchao +- mikedanese +- liggitt +- gmarek +- sttts +- ncdc +- tallclair +labels: +- sig/api-machinery diff --git a/cmd/vendor/sigs.k8s.io/yaml/README.md b/cmd/vendor/sigs.k8s.io/yaml/README.md new file mode 100644 index 000000000000..0200f75b4d12 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/yaml/README.md @@ -0,0 +1,121 @@ +# YAML marshaling and unmarshaling support for Go + +[![Build Status](https://travis-ci.org/ghodss/yaml.svg)](https://travis-ci.org/ghodss/yaml) + +## Introduction + +A wrapper around [go-yaml](https://github.com/go-yaml/yaml) designed to enable a better way of handling YAML when marshaling to and from structs. + +In short, this library first converts YAML to JSON using go-yaml and then uses `json.Marshal` and `json.Unmarshal` to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods `MarshalJSON` and `UnmarshalJSON` unlike go-yaml. For a detailed overview of the rationale behind this method, [see this blog post](http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/). + +## Compatibility + +This package uses [go-yaml](https://github.com/go-yaml/yaml) and therefore supports [everything go-yaml supports](https://github.com/go-yaml/yaml#compatibility). + +## Caveats + +**Caveat #1:** When using `yaml.Marshal` and `yaml.Unmarshal`, binary data should NOT be preceded with the `!!binary` YAML tag. If you do, go-yaml will convert the binary data from base64 to native binary data, which is not compatible with JSON. You can still use binary in your YAML files though - just store them without the `!!binary` tag and decode the base64 in your code (e.g. in the custom JSON methods `MarshalJSON` and `UnmarshalJSON`). This also has the benefit that your YAML and your JSON binary data will be decoded exactly the same way. As an example: + +``` +BAD: + exampleKey: !!binary gIGC + +GOOD: + exampleKey: gIGC +... and decode the base64 data in your code. +``` + +**Caveat #2:** When using `YAMLToJSON` directly, maps with keys that are maps will result in an error since this is not supported by JSON. This error will occur in `Unmarshal` as well since you can't unmarshal map keys anyways since struct fields can't be keys. + +## Installation and usage + +To install, run: + +``` +$ go get github.com/ghodss/yaml +``` + +And import using: + +``` +import "github.com/ghodss/yaml" +``` + +Usage is very similar to the JSON library: + +```go +package main + +import ( + "fmt" + + "github.com/ghodss/yaml" +) + +type Person struct { + Name string `json:"name"` // Affects YAML field names too. + Age int `json:"age"` +} + +func main() { + // Marshal a Person struct to YAML. + p := Person{"John", 30} + y, err := yaml.Marshal(p) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(y)) + /* Output: + age: 30 + name: John + */ + + // Unmarshal the YAML back into a Person struct. + var p2 Person + err = yaml.Unmarshal(y, &p2) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(p2) + /* Output: + {John 30} + */ +} +``` + +`yaml.YAMLToJSON` and `yaml.JSONToYAML` methods are also available: + +```go +package main + +import ( + "fmt" + + "github.com/ghodss/yaml" +) + +func main() { + j := []byte(`{"name": "John", "age": 30}`) + y, err := yaml.JSONToYAML(j) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(y)) + /* Output: + name: John + age: 30 + */ + j2, err := yaml.YAMLToJSON(y) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(j2)) + /* Output: + {"age":30,"name":"John"} + */ +} +``` diff --git a/cmd/vendor/sigs.k8s.io/yaml/RELEASE.md b/cmd/vendor/sigs.k8s.io/yaml/RELEASE.md new file mode 100644 index 000000000000..6b642464e583 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/yaml/RELEASE.md @@ -0,0 +1,9 @@ +# Release Process + +The `yaml` Project is released on an as-needed basis. The process is as follows: + +1. An issue is proposing a new release with a changelog since the last release +1. All [OWNERS](OWNERS) must LGTM this release +1. An OWNER runs `git tag -s $VERSION` and inserts the changelog and pushes the tag with `git push $VERSION` +1. The release issue is closed +1. An announcement email is sent to `kubernetes-dev@googlegroups.com` with the subject `[ANNOUNCE] kubernetes-template-project $VERSION is released` diff --git a/cmd/vendor/sigs.k8s.io/yaml/SECURITY_CONTACTS b/cmd/vendor/sigs.k8s.io/yaml/SECURITY_CONTACTS new file mode 100644 index 000000000000..0648a8ebff7b --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/yaml/SECURITY_CONTACTS @@ -0,0 +1,17 @@ +# Defined below are the security contacts for this repo. +# +# They are the contact point for the Product Security Team to reach out +# to for triaging and handling of incoming issues. +# +# The below names agree to abide by the +# [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-documentation/security-release-process.md#embargo-policy) +# and will be removed and replaced if they violate that agreement. +# +# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE +# INSTRUCTIONS AT https://kubernetes.io/security/ + +cjcullen +jessfraz +liggitt +philips +tallclair diff --git a/cmd/vendor/sigs.k8s.io/yaml/code-of-conduct.md b/cmd/vendor/sigs.k8s.io/yaml/code-of-conduct.md new file mode 100644 index 000000000000..0d15c00cf325 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/yaml/code-of-conduct.md @@ -0,0 +1,3 @@ +# Kubernetes Community Code of Conduct + +Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) diff --git a/cmd/vendor/github.com/ghodss/yaml/fields.go b/cmd/vendor/sigs.k8s.io/yaml/fields.go similarity index 99% rename from cmd/vendor/github.com/ghodss/yaml/fields.go rename to cmd/vendor/sigs.k8s.io/yaml/fields.go index 58600740266c..235b7f2cf612 100644 --- a/cmd/vendor/github.com/ghodss/yaml/fields.go +++ b/cmd/vendor/sigs.k8s.io/yaml/fields.go @@ -1,6 +1,7 @@ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. + package yaml import ( diff --git a/cmd/vendor/github.com/ghodss/yaml/yaml.go b/cmd/vendor/sigs.k8s.io/yaml/yaml.go similarity index 77% rename from cmd/vendor/github.com/ghodss/yaml/yaml.go rename to cmd/vendor/sigs.k8s.io/yaml/yaml.go index 4fb4054a8b74..024596112ac5 100644 --- a/cmd/vendor/github.com/ghodss/yaml/yaml.go +++ b/cmd/vendor/sigs.k8s.io/yaml/yaml.go @@ -4,13 +4,14 @@ import ( "bytes" "encoding/json" "fmt" + "io" "reflect" "strconv" "gopkg.in/yaml.v2" ) -// Marshals the object into JSON then converts JSON to YAML and returns the +// Marshal marshals the object into JSON then converts JSON to YAML and returns the // YAML. func Marshal(o interface{}) ([]byte, error) { j, err := json.Marshal(o) @@ -26,15 +27,35 @@ func Marshal(o interface{}) ([]byte, error) { return y, nil } -// Converts YAML to JSON then uses JSON to unmarshal into an object. -func Unmarshal(y []byte, o interface{}) error { +// JSONOpt is a decoding option for decoding from JSON format. +type JSONOpt func(*json.Decoder) *json.Decoder + +// Unmarshal converts YAML to JSON then uses JSON to unmarshal into an object, +// optionally configuring the behavior of the JSON unmarshal. +func Unmarshal(y []byte, o interface{}, opts ...JSONOpt) error { + return yamlUnmarshal(y, o, false, opts...) +} + +// UnmarshalStrict strictly converts YAML to JSON then uses JSON to unmarshal +// into an object, optionally configuring the behavior of the JSON unmarshal. +func UnmarshalStrict(y []byte, o interface{}, opts ...JSONOpt) error { + return yamlUnmarshal(y, o, true, append(opts, DisallowUnknownFields)...) +} + +// yamlUnmarshal unmarshals the given YAML byte stream into the given interface, +// optionally performing the unmarshalling strictly +func yamlUnmarshal(y []byte, o interface{}, strict bool, opts ...JSONOpt) error { vo := reflect.ValueOf(o) - j, err := yamlToJSON(y, &vo) + unmarshalFn := yaml.Unmarshal + if strict { + unmarshalFn = yaml.UnmarshalStrict + } + j, err := yamlToJSON(y, &vo, unmarshalFn) if err != nil { return fmt.Errorf("error converting YAML to JSON: %v", err) } - err = json.Unmarshal(j, o) + err = jsonUnmarshal(bytes.NewReader(j), o, opts...) if err != nil { return fmt.Errorf("error unmarshaling JSON: %v", err) } @@ -42,7 +63,22 @@ func Unmarshal(y []byte, o interface{}) error { return nil } -// Convert JSON to YAML. +// jsonUnmarshal unmarshals the JSON byte stream from the given reader into the +// object, optionally applying decoder options prior to decoding. We are not +// using json.Unmarshal directly as we want the chance to pass in non-default +// options. +func jsonUnmarshal(r io.Reader, o interface{}, opts ...JSONOpt) error { + d := json.NewDecoder(r) + for _, opt := range opts { + d = opt(d) + } + if err := d.Decode(&o); err != nil { + return fmt.Errorf("while decoding JSON: %v", err) + } + return nil +} + +// JSONToYAML Converts JSON to YAML. func JSONToYAML(j []byte) ([]byte, error) { // Convert the JSON to an object. var jsonObj interface{} @@ -60,8 +96,8 @@ func JSONToYAML(j []byte) ([]byte, error) { return yaml.Marshal(jsonObj) } -// Convert YAML to JSON. Since JSON is a subset of YAML, passing JSON through -// this method should be a no-op. +// YAMLToJSON converts YAML to JSON. Since JSON is a subset of YAML, +// passing JSON through this method should be a no-op. // // Things YAML can do that are not supported by JSON: // * In YAML you can have binary and null keys in your maps. These are invalid @@ -70,14 +106,22 @@ func JSONToYAML(j []byte) ([]byte, error) { // use binary data with this library, encode the data as base64 as usual but do // not use the !!binary tag in your YAML. This will ensure the original base64 // encoded data makes it all the way through to the JSON. +// +// For strict decoding of YAML, use YAMLToJSONStrict. func YAMLToJSON(y []byte) ([]byte, error) { - return yamlToJSON(y, nil) + return yamlToJSON(y, nil, yaml.Unmarshal) } -func yamlToJSON(y []byte, jsonTarget *reflect.Value) ([]byte, error) { +// YAMLToJSONStrict is like YAMLToJSON but enables strict YAML decoding, +// returning an error on any duplicate field names. +func YAMLToJSONStrict(y []byte) ([]byte, error) { + return yamlToJSON(y, nil, yaml.UnmarshalStrict) +} + +func yamlToJSON(y []byte, jsonTarget *reflect.Value, yamlUnmarshal func([]byte, interface{}) error) ([]byte, error) { // Convert the YAML to an object. var yamlObj interface{} - err := yaml.Unmarshal(y, &yamlObj) + err := yamlUnmarshal(y, &yamlObj) if err != nil { return nil, err } @@ -272,6 +316,4 @@ func convertToJSONableObject(yamlObj interface{}, jsonTarget *reflect.Value) (in } return yamlObj, nil } - - return nil, nil } diff --git a/cmd/vendor/sigs.k8s.io/yaml/yaml_go110.go b/cmd/vendor/sigs.k8s.io/yaml/yaml_go110.go new file mode 100644 index 000000000000..ab3e06a222a6 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/yaml/yaml_go110.go @@ -0,0 +1,14 @@ +// This file contains changes that are only compatible with go 1.10 and onwards. + +// +build go1.10 + +package yaml + +import "encoding/json" + +// DisallowUnknownFields configures the JSON decoder to error out if unknown +// fields come along, instead of dropping them by default. +func DisallowUnknownFields(d *json.Decoder) *json.Decoder { + d.DisallowUnknownFields() + return d +} diff --git a/cmd/vendor/sigs.k8s.io/yaml/yaml_go110_test.go b/cmd/vendor/sigs.k8s.io/yaml/yaml_go110_test.go new file mode 100644 index 000000000000..e4707e8abd31 --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/yaml/yaml_go110_test.go @@ -0,0 +1,46 @@ +// +build go1.10 + +package yaml + +import ( + "fmt" + "testing" +) + +func TestUnmarshalWithTags(t *testing.T) { + type WithTaggedField struct { + Field string `json:"field"` + } + + t.Run("Known tagged field", func(t *testing.T) { + y := []byte(`field: "hello"`) + v := WithTaggedField{} + if err := Unmarshal(y, &v, DisallowUnknownFields); err != nil { + t.Errorf("unexpected error: %v", err) + } + if v.Field != "hello" { + t.Errorf("v.Field=%v, want 'hello'", v.Field) + } + + }) + t.Run("With unknown tagged field", func(t *testing.T) { + y := []byte(`unknown: "hello"`) + v := WithTaggedField{} + err := Unmarshal(y, &v, DisallowUnknownFields) + if err == nil { + t.Errorf("want error because of unknown field, got : v=%#v", v) + } + }) + +} + +func exampleUnknown() { + type WithTaggedField struct { + Field string `json:"field"` + } + y := []byte(`unknown: "hello"`) + v := WithTaggedField{} + fmt.Printf("%v\n", Unmarshal(y, &v, DisallowUnknownFields)) + // Ouptut: + // unmarshaling JSON: while decoding JSON: json: unknown field "unknown" +} diff --git a/cmd/vendor/sigs.k8s.io/yaml/yaml_test.go b/cmd/vendor/sigs.k8s.io/yaml/yaml_test.go new file mode 100644 index 000000000000..42a23156790d --- /dev/null +++ b/cmd/vendor/sigs.k8s.io/yaml/yaml_test.go @@ -0,0 +1,423 @@ +package yaml + +import ( + "fmt" + "math" + "reflect" + "strconv" + "testing" +) + +type MarshalTest struct { + A string + B int64 + // Would like to test float64, but it's not supported in go-yaml. + // (See https://github.com/go-yaml/yaml/issues/83.) + C float32 +} + +func TestMarshal(t *testing.T) { + f32String := strconv.FormatFloat(math.MaxFloat32, 'g', -1, 32) + s := MarshalTest{"a", math.MaxInt64, math.MaxFloat32} + e := []byte(fmt.Sprintf("A: a\nB: %d\nC: %s\n", math.MaxInt64, f32String)) + + y, err := Marshal(s) + if err != nil { + t.Errorf("error marshaling YAML: %v", err) + } + + if !reflect.DeepEqual(y, e) { + t.Errorf("marshal YAML was unsuccessful, expected: %#v, got: %#v", + string(e), string(y)) + } +} + +type UnmarshalString struct { + A string + True string +} + +type UnmarshalStringMap struct { + A map[string]string +} + +type UnmarshalNestedString struct { + A NestedString +} + +type NestedString struct { + A string +} + +type UnmarshalSlice struct { + A []NestedSlice +} + +type NestedSlice struct { + B string + C *string +} + +func TestUnmarshal(t *testing.T) { + y := []byte("a: 1") + s1 := UnmarshalString{} + e1 := UnmarshalString{A: "1"} + unmarshal(t, y, &s1, &e1) + + y = []byte("a: true") + s1 = UnmarshalString{} + e1 = UnmarshalString{A: "true"} + unmarshal(t, y, &s1, &e1) + + y = []byte("true: 1") + s1 = UnmarshalString{} + e1 = UnmarshalString{True: "1"} + unmarshal(t, y, &s1, &e1) + + y = []byte("a:\n a: 1") + s2 := UnmarshalNestedString{} + e2 := UnmarshalNestedString{NestedString{"1"}} + unmarshal(t, y, &s2, &e2) + + y = []byte("a:\n - b: abc\n c: def\n - b: 123\n c: 456\n") + s3 := UnmarshalSlice{} + e3 := UnmarshalSlice{[]NestedSlice{NestedSlice{"abc", strPtr("def")}, NestedSlice{"123", strPtr("456")}}} + unmarshal(t, y, &s3, &e3) + + y = []byte("a:\n b: 1") + s4 := UnmarshalStringMap{} + e4 := UnmarshalStringMap{map[string]string{"b": "1"}} + unmarshal(t, y, &s4, &e4) + + y = []byte(` +a: + name: TestA +b: + name: TestB +`) + type NamedThing struct { + Name string `json:"name"` + } + s5 := map[string]*NamedThing{} + e5 := map[string]*NamedThing{ + "a": &NamedThing{Name: "TestA"}, + "b": &NamedThing{Name: "TestB"}, + } + unmarshal(t, y, &s5, &e5) +} + +func unmarshal(t *testing.T, y []byte, s, e interface{}, opts ...JSONOpt) { + err := Unmarshal(y, s, opts...) + if err != nil { + t.Errorf("error unmarshaling YAML: %v", err) + } + + if !reflect.DeepEqual(s, e) { + t.Errorf("unmarshal YAML was unsuccessful, expected: %+#v, got: %+#v", + e, s) + } +} + +func TestUnmarshalStrict(t *testing.T) { + y := []byte("a: 1") + s1 := UnmarshalString{} + e1 := UnmarshalString{A: "1"} + unmarshalStrict(t, y, &s1, &e1) + + y = []byte("a: true") + s1 = UnmarshalString{} + e1 = UnmarshalString{A: "true"} + unmarshalStrict(t, y, &s1, &e1) + + y = []byte("true: 1") + s1 = UnmarshalString{} + e1 = UnmarshalString{True: "1"} + unmarshalStrict(t, y, &s1, &e1) + + y = []byte("a:\n a: 1") + s2 := UnmarshalNestedString{} + e2 := UnmarshalNestedString{NestedString{"1"}} + unmarshalStrict(t, y, &s2, &e2) + + y = []byte("a:\n - b: abc\n c: def\n - b: 123\n c: 456\n") + s3 := UnmarshalSlice{} + e3 := UnmarshalSlice{[]NestedSlice{NestedSlice{"abc", strPtr("def")}, NestedSlice{"123", strPtr("456")}}} + unmarshalStrict(t, y, &s3, &e3) + + y = []byte("a:\n b: 1") + s4 := UnmarshalStringMap{} + e4 := UnmarshalStringMap{map[string]string{"b": "1"}} + unmarshalStrict(t, y, &s4, &e4) + + y = []byte(` +a: + name: TestA +b: + name: TestB +`) + type NamedThing struct { + Name string `json:"name"` + } + s5 := map[string]*NamedThing{} + e5 := map[string]*NamedThing{ + "a": &NamedThing{Name: "TestA"}, + "b": &NamedThing{Name: "TestB"}, + } + unmarshal(t, y, &s5, &e5) + + // When using not-so-strict unmarshal, we should + // be picking up the ID-1 as the value in the "id" field + y = []byte(` +a: + name: TestA + id: ID-A + id: ID-1 +`) + type NamedThing2 struct { + Name string `json:"name"` + ID string `json:"id"` + } + s6 := map[string]*NamedThing2{} + e6 := map[string]*NamedThing2{ + "a": {Name: "TestA", ID: "ID-1"}, + } + unmarshal(t, y, &s6, &e6) +} + +func TestUnmarshalStrictFails(t *testing.T) { + y := []byte("a: true\na: false") + s1 := UnmarshalString{} + unmarshalStrictFail(t, y, &s1) + + y = []byte("a:\n - b: abc\n c: 32\n b: 123") + s2 := UnmarshalSlice{} + unmarshalStrictFail(t, y, &s2) + + y = []byte("a:\n b: 1\n c: 3") + s3 := UnmarshalStringMap{} + unmarshalStrictFail(t, y, &s3) + + type NamedThing struct { + Name string `json:"name"` + ID string `json:"id"` + } + // When using strict unmarshal, we should see + // the unmarshal fail if there are multiple keys + y = []byte(` +a: + name: TestA + id: ID-A + id: ID-1 +`) + s4 := NamedThing{} + unmarshalStrictFail(t, y, &s4) + + // Strict unmarshal should fail for unknown fields + y = []byte(` +name: TestB +id: ID-B +unknown: Some-Value +`) + s5 := NamedThing{} + unmarshalStrictFail(t, y, &s5) +} + +func unmarshalStrict(t *testing.T, y []byte, s, e interface{}, opts ...JSONOpt) { + err := UnmarshalStrict(y, s, opts...) + if err != nil { + t.Errorf("error unmarshaling YAML: %v", err) + } + + if !reflect.DeepEqual(s, e) { + t.Errorf("unmarshal YAML was unsuccessful, expected: %+#v, got: %+#v", + e, s) + } +} + +func unmarshalStrictFail(t *testing.T, y []byte, s interface{}, opts ...JSONOpt) { + err := UnmarshalStrict(y, s, opts...) + if err == nil { + t.Errorf("error unmarshaling YAML: %v", err) + } +} + +type Case struct { + input string + output string + // By default we test that reversing the output == input. But if there is a + // difference in the reversed output, you can optionally specify it here. + reverse *string +} + +type RunType int + +const ( + RunTypeJSONToYAML RunType = iota + RunTypeYAMLToJSON +) + +func TestJSONToYAML(t *testing.T) { + cases := []Case{ + { + `{"t":"a"}`, + "t: a\n", + nil, + }, { + `{"t":null}`, + "t: null\n", + nil, + }, + } + + runCases(t, RunTypeJSONToYAML, cases) +} + +func TestYAMLToJSON(t *testing.T) { + cases := []Case{ + { + "t: a\n", + `{"t":"a"}`, + nil, + }, { + "t: \n", + `{"t":null}`, + strPtr("t: null\n"), + }, { + "t: null\n", + `{"t":null}`, + nil, + }, { + "1: a\n", + `{"1":"a"}`, + strPtr("\"1\": a\n"), + }, { + "1000000000000000000000000000000000000: a\n", + `{"1e+36":"a"}`, + strPtr("\"1e+36\": a\n"), + }, { + "1e+36: a\n", + `{"1e+36":"a"}`, + strPtr("\"1e+36\": a\n"), + }, { + "\"1e+36\": a\n", + `{"1e+36":"a"}`, + nil, + }, { + "\"1.2\": a\n", + `{"1.2":"a"}`, + nil, + }, { + "- t: a\n", + `[{"t":"a"}]`, + nil, + }, { + "- t: a\n" + + "- t:\n" + + " b: 1\n" + + " c: 2\n", + `[{"t":"a"},{"t":{"b":1,"c":2}}]`, + nil, + }, { + `[{t: a}, {t: {b: 1, c: 2}}]`, + `[{"t":"a"},{"t":{"b":1,"c":2}}]`, + strPtr("- t: a\n" + + "- t:\n" + + " b: 1\n" + + " c: 2\n"), + }, { + "- t: \n", + `[{"t":null}]`, + strPtr("- t: null\n"), + }, { + "- t: null\n", + `[{"t":null}]`, + nil, + }, + } + + // Cases that should produce errors. + _ = []Case{ + { + "~: a", + `{"null":"a"}`, + nil, + }, { + "a: !!binary gIGC\n", + "{\"a\":\"\x80\x81\x82\"}", + nil, + }, + } + + runCases(t, RunTypeYAMLToJSON, cases) +} + +func runCases(t *testing.T, runType RunType, cases []Case) { + var f func([]byte) ([]byte, error) + var invF func([]byte) ([]byte, error) + var msg string + var invMsg string + if runType == RunTypeJSONToYAML { + f = JSONToYAML + invF = YAMLToJSON + msg = "JSON to YAML" + invMsg = "YAML back to JSON" + } else { + f = YAMLToJSON + invF = JSONToYAML + msg = "YAML to JSON" + invMsg = "JSON back to YAML" + } + + for _, c := range cases { + // Convert the string. + t.Logf("converting %s\n", c.input) + output, err := f([]byte(c.input)) + if err != nil { + t.Errorf("Failed to convert %s, input: `%s`, err: %v", msg, c.input, err) + } + + // Check it against the expected output. + if string(output) != c.output { + t.Errorf("Failed to convert %s, input: `%s`, expected `%s`, got `%s`", + msg, c.input, c.output, string(output)) + } + + // Set the string that we will compare the reversed output to. + reverse := c.input + // If a special reverse string was specified, use that instead. + if c.reverse != nil { + reverse = *c.reverse + } + + // Reverse the output. + input, err := invF(output) + if err != nil { + t.Errorf("Failed to convert %s, input: `%s`, err: %v", invMsg, string(output), err) + } + + // Check the reverse is equal to the input (or to *c.reverse). + if string(input) != reverse { + t.Errorf("Failed to convert %s, input: `%s`, expected `%s`, got `%s`", + invMsg, string(output), reverse, string(input)) + } + } + +} + +// To be able to easily fill in the *Case.reverse string above. +func strPtr(s string) *string { + return &s +} + +func TestYAMLToJSONStrict(t *testing.T) { + const data = ` +foo: bar +foo: baz +` + if _, err := YAMLToJSON([]byte(data)); err != nil { + t.Error("expected YAMLtoJSON to pass on duplicate field names") + } + if _, err := YAMLToJSONStrict([]byte(data)); err == nil { + t.Error("expected YAMLtoJSONStrict to fail on duplicate field names") + } +} diff --git a/embed/config.go b/embed/config.go index 835e051a7d62..f74ed4b2794a 100644 --- a/embed/config.go +++ b/embed/config.go @@ -36,9 +36,9 @@ import ( "github.com/coreos/etcd/pkg/types" "github.com/coreos/pkg/capnslog" - "github.com/ghodss/yaml" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" + "sigs.k8s.io/yaml" ) const ( diff --git a/embed/config_test.go b/embed/config_test.go index c5db04bcbe6e..0a6961b28e0f 100644 --- a/embed/config_test.go +++ b/embed/config_test.go @@ -23,7 +23,7 @@ import ( "github.com/coreos/etcd/pkg/transport" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" ) func TestConfigFileOtherFields(t *testing.T) { diff --git a/etcdmain/config.go b/etcdmain/config.go index 2a5faa746c9a..99f015365001 100644 --- a/etcdmain/config.go +++ b/etcdmain/config.go @@ -30,7 +30,7 @@ import ( "github.com/coreos/etcd/pkg/types" "github.com/coreos/etcd/version" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" ) var ( diff --git a/etcdmain/config_test.go b/etcdmain/config_test.go index 6ba7cd9573fa..2f768fa4d92f 100644 --- a/etcdmain/config_test.go +++ b/etcdmain/config_test.go @@ -24,7 +24,7 @@ import ( "testing" "github.com/coreos/etcd/embed" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" ) func TestConfigParsingMemberFlags(t *testing.T) { diff --git a/glide.lock b/glide.lock index 4554c845d45a..809619242301 100644 --- a/glide.lock +++ b/glide.lock @@ -32,8 +32,6 @@ imports: version: d2709f9f1f31ebcda9651b03077758c1f3a0018c - name: github.com/dustin/go-humanize version: bb3d318650d48840a39aa21a027c6630e198e626 -- name: github.com/ghodss/yaml - version: 0ca9ea5df5451ffdf184b4428c902747c2c11cd7 - name: github.com/gogo/protobuf version: 342cbe0a04158f6dcb03ca0079991a51a4248c02 subpackages: @@ -196,4 +194,6 @@ imports: version: 226d21d43a305fac52b3a104ef83e721b15275e0 - name: gopkg.in/yaml.v2 version: cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b +- name: sigs.k8s.io/yaml + version: fd68e9863619f6ec2fdd8625fe1f02e7c877e480 testImports: [] diff --git a/glide.yaml b/glide.yaml index cc83a8516468..95570367d2dc 100644 --- a/glide.yaml +++ b/glide.yaml @@ -26,8 +26,8 @@ import: version: 23709d0847197db6021a51fdb193e66e9222d4e7 - package: github.com/dustin/go-humanize version: bb3d318650d48840a39aa21a027c6630e198e626 -- package: github.com/ghodss/yaml - version: v1.0.0 +- package: sigs.k8s.io/yaml + version: v1.1.0 - package: github.com/gogo/protobuf version: v0.5 subpackages: