diff --git a/contrib/enscope/enscope.go b/contrib/enscope/enscope.go index 5df9f8e21ad..594d5625bc3 100644 --- a/contrib/enscope/enscope.go +++ b/contrib/enscope/enscope.go @@ -23,8 +23,8 @@ import ( "os" "strings" + "github.com/ghodss/yaml" "github.com/golang/glog" - "gopkg.in/v1/yaml" ) const usage = "usage: enscope specFilename configFilename" diff --git a/contrib/podex/podex.go b/contrib/podex/podex.go index 806927c3584..8f5760d3aa6 100644 --- a/contrib/podex/podex.go +++ b/contrib/podex/podex.go @@ -37,7 +37,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" dockerclient "github.com/fsouza/go-dockerclient" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) const usage = "usage: podex [-json|-yaml] [-id PODNAME] IMAGES" diff --git a/contrib/simplegen/simplegen.go b/contrib/simplegen/simplegen.go index aa569d07b94..a4ff7fc58cf 100644 --- a/contrib/simplegen/simplegen.go +++ b/contrib/simplegen/simplegen.go @@ -35,8 +35,8 @@ import ( // TODO: handle multiple versions correctly "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + "github.com/ghodss/yaml" "github.com/golang/glog" - "gopkg.in/v1/yaml" ) // TODO: Also handle lists of simple services, and multiple input files diff --git a/contrib/srvexpand/srvexpand.go b/contrib/srvexpand/srvexpand.go index 1aeb61e3a0b..f94a7eb14df 100644 --- a/contrib/srvexpand/srvexpand.go +++ b/contrib/srvexpand/srvexpand.go @@ -45,8 +45,8 @@ import ( // it should be possible to specify the version for the whole map. "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + "github.com/ghodss/yaml" "github.com/golang/glog" - "gopkg.in/v1/yaml" ) const usage = "usage: srvexpand filename" diff --git a/pkg/api/serialization_test.go b/pkg/api/serialization_test.go index ac230c4306c..3a36a1816b8 100644 --- a/pkg/api/serialization_test.go +++ b/pkg/api/serialization_test.go @@ -23,6 +23,7 @@ import ( "reflect" "strconv" "testing" + "time" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" @@ -138,6 +139,14 @@ var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs( c.RandString(): c.RandString(), } }, + func(t *time.Time, c fuzz.Continue) { + // This is necessary because the standard fuzzed time.Time object is + // completely nil, but when JSON unmarshals dates it fills in the + // unexported loc field with the time.UTC object, resulting in + // reflect.DeepEqual returning false in the round trip tests. We solve it + // by using a date that will be identical to the one JSON unmarshals. + *t = time.Date(2000, 1, 1, 1, 1, 1, 0, time.UTC) + }, ) func runTest(t *testing.T, codec runtime.Codec, source runtime.Object) { @@ -162,7 +171,7 @@ func runTest(t *testing.T, codec runtime.Codec, source runtime.Object) { return } if !reflect.DeepEqual(source, obj2) { - t.Errorf("1: %v: diff: %v\nCodec: %v\nData: %s\nSource: %#v", name, util.ObjectDiff(source, obj2), codec, string(data), source) + t.Errorf("1: %v: diff: %v\nCodec: %v\nData: %s\nSource: %#v", name, util.ObjectGoPrintDiff(source, obj2), codec, string(data), source) return } diff --git a/pkg/conversion/decode.go b/pkg/conversion/decode.go index bf5dc16c5b9..81be6bb5bef 100644 --- a/pkg/conversion/decode.go +++ b/pkg/conversion/decode.go @@ -20,7 +20,7 @@ import ( "errors" "fmt" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) // Decode converts a YAML or JSON string back into a pointer to an api object. diff --git a/pkg/conversion/meta.go b/pkg/conversion/meta.go index 0fe9cdd6484..533193d6e7e 100644 --- a/pkg/conversion/meta.go +++ b/pkg/conversion/meta.go @@ -20,7 +20,7 @@ import ( "fmt" "reflect" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) // MetaFactory is used to store and retrieve the version and kind diff --git a/pkg/conversion/scheme_test.go b/pkg/conversion/scheme_test.go index 0c0ef43b728..2f6f1e8e378 100644 --- a/pkg/conversion/scheme_test.go +++ b/pkg/conversion/scheme_test.go @@ -26,8 +26,8 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + "github.com/ghodss/yaml" "github.com/google/gofuzz" - "gopkg.in/v1/yaml" ) var fuzzIters = flag.Int("fuzz_iters", 50, "How many fuzzing iterations to do.") diff --git a/pkg/kubecfg/kubecfg.go b/pkg/kubecfg/kubecfg.go index dd120b58bc2..2e9b73b3453 100644 --- a/pkg/kubecfg/kubecfg.go +++ b/pkg/kubecfg/kubecfg.go @@ -33,8 +33,8 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util/wait" "github.com/GoogleCloudPlatform/kubernetes/pkg/version" + "github.com/ghodss/yaml" "github.com/golang/glog" - "gopkg.in/v1/yaml" ) func GetServerVersion(client *client.Client) (*version.Info, error) { diff --git a/pkg/kubecfg/parse_test.go b/pkg/kubecfg/parse_test.go index d9a53fb9818..1ba5c1d1f2b 100644 --- a/pkg/kubecfg/parse_test.go +++ b/pkg/kubecfg/parse_test.go @@ -24,7 +24,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) func TestParseBadStorage(t *testing.T) { diff --git a/pkg/kubecfg/resource_printer.go b/pkg/kubecfg/resource_printer.go index 263525b377a..1bef4e1cab2 100644 --- a/pkg/kubecfg/resource_printer.go +++ b/pkg/kubecfg/resource_printer.go @@ -29,8 +29,8 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" + "github.com/ghodss/yaml" "github.com/golang/glog" - "gopkg.in/v1/yaml" ) // ResourcePrinter is an interface that knows how to print API resources. diff --git a/pkg/kubecfg/resource_printer_test.go b/pkg/kubecfg/resource_printer_test.go index ef16bdc0884..0efd8c66574 100644 --- a/pkg/kubecfg/resource_printer_test.go +++ b/pkg/kubecfg/resource_printer_test.go @@ -26,7 +26,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) func TestYAMLPrinterPrint(t *testing.T) { diff --git a/pkg/kubectl/cmd/createall.go b/pkg/kubectl/cmd/createall.go index b8e912db1d6..4f7aa26b7b1 100644 --- a/pkg/kubectl/cmd/createall.go +++ b/pkg/kubectl/cmd/createall.go @@ -24,9 +24,9 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/config" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + "github.com/ghodss/yaml" "github.com/golang/glog" "github.com/spf13/cobra" - "gopkg.in/v1/yaml" ) // DataToObjects converts the raw JSON data into API objects diff --git a/pkg/kubectl/resource_printer.go b/pkg/kubectl/resource_printer.go index b3b4955b732..384d6c84c1c 100644 --- a/pkg/kubectl/resource_printer.go +++ b/pkg/kubectl/resource_printer.go @@ -29,8 +29,8 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" + "github.com/ghodss/yaml" "github.com/golang/glog" - "gopkg.in/v1/yaml" ) // GetPrinter takes a format type, an optional format argument, a version and a convertor diff --git a/pkg/kubectl/resource_printer_test.go b/pkg/kubectl/resource_printer_test.go index 676d9d7a0d3..17eafb0394d 100644 --- a/pkg/kubectl/resource_printer_test.go +++ b/pkg/kubectl/resource_printer_test.go @@ -29,7 +29,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) type testStruct struct { diff --git a/pkg/kubelet/config/config.go b/pkg/kubelet/config/config.go index d2868c71af2..01e29c7afda 100644 --- a/pkg/kubelet/config/config.go +++ b/pkg/kubelet/config/config.go @@ -287,7 +287,7 @@ func (s *podStorage) Sync() { func (s *podStorage) MergedState() interface{} { s.podLock.RLock() defer s.podLock.RUnlock() - var pods []api.BoundPod + pods := make([]api.BoundPod, 0) for _, sourcePods := range s.pods { for _, podRef := range sourcePods { pod, err := api.Scheme.Copy(podRef) diff --git a/pkg/kubelet/config/config_test.go b/pkg/kubelet/config/config_test.go index 5c291aa31ff..30921d814fe 100644 --- a/pkg/kubelet/config/config_test.go +++ b/pkg/kubelet/config/config_test.go @@ -59,10 +59,13 @@ func CreateValidPod(name, namespace, source string) api.BoundPod { } func CreatePodUpdate(op kubelet.PodOperation, pods ...api.BoundPod) kubelet.PodUpdate { - if len(pods) == 0 { - return kubelet.PodUpdate{Op: op} - } + // We deliberately return an empty slice instead of a nil pointer here + // because reflect.DeepEqual differentiates between the two and we need to + // pick one for consistency. newPods := make([]api.BoundPod, len(pods)) + if len(pods) == 0 { + return kubelet.PodUpdate{newPods, op} + } for i := range pods { newPods[i] = pods[i] } diff --git a/pkg/kubelet/config/file.go b/pkg/kubelet/config/file.go index 7728716b898..6f45ea5d945 100644 --- a/pkg/kubelet/config/file.go +++ b/pkg/kubelet/config/file.go @@ -33,8 +33,8 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + "github.com/ghodss/yaml" "github.com/golang/glog" - "gopkg.in/v1/yaml" ) type sourceFile struct { @@ -97,12 +97,13 @@ func extractFromDir(name string) ([]api.BoundPod, error) { if err != nil { return nil, fmt.Errorf("glob failed: %v", err) } + + pods := make([]api.BoundPod, 0) if len(dirents) == 0 { - return nil, nil + return pods, nil } sort.Strings(dirents) - pods := []api.BoundPod{} for _, path := range dirents { statInfo, err := os.Stat(path) if err != nil { diff --git a/pkg/kubelet/config/file_test.go b/pkg/kubelet/config/file_test.go index 91e6ab9c380..7e47e7d350e 100644 --- a/pkg/kubelet/config/file_test.go +++ b/pkg/kubelet/config/file_test.go @@ -29,7 +29,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) func ExampleManifestAndPod(id string) (api.ContainerManifest, api.BoundPod) { diff --git a/pkg/kubelet/config/http.go b/pkg/kubelet/config/http.go index 39dc9a46c2e..b9694f3cfbc 100644 --- a/pkg/kubelet/config/http.go +++ b/pkg/kubelet/config/http.go @@ -29,8 +29,8 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + "github.com/ghodss/yaml" "github.com/golang/glog" - "gopkg.in/v1/yaml" ) type sourceURL struct { diff --git a/pkg/kubelet/server.go b/pkg/kubelet/server.go index b77f6ca2526..a32e3cf2522 100644 --- a/pkg/kubelet/server.go +++ b/pkg/kubelet/server.go @@ -35,9 +35,9 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/healthz" "github.com/GoogleCloudPlatform/kubernetes/pkg/httplog" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools" + "github.com/ghodss/yaml" "github.com/golang/glog" "github.com/google/cadvisor/info" - "gopkg.in/v1/yaml" ) // Server is a http.Handler which exposes kubelet functionality over HTTP. diff --git a/pkg/kubelet/types.go b/pkg/kubelet/types.go index 818104a9a12..bb2d87f7d19 100644 --- a/pkg/kubelet/types.go +++ b/pkg/kubelet/types.go @@ -43,6 +43,10 @@ const ( // For setting the state of the system to a given state for this source configuration, set // Pods as desired and Op to SET, which will reset the system state to that specified in this // operation for this source channel. To remove all pods, set Pods to empty object and Op to SET. +// +// Additionally, Pods should never be nil - it should always point to an empty slice. While +// functionally similar, this helps our unit tests properly check that the correct PodUpdates +// are generated. type PodUpdate struct { Pods []api.BoundPod Op PodOperation diff --git a/pkg/runtime/embedded.go b/pkg/runtime/embedded.go deleted file mode 100644 index 11ac2894651..00000000000 --- a/pkg/runtime/embedded.go +++ /dev/null @@ -1,86 +0,0 @@ -/* -Copyright 2014 Google Inc. All rights reserved. - -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 runtime - -import ( - "gopkg.in/v1/yaml" -) - -// Encode()/Decode() are the canonical way of converting an API object to/from -// wire format. This file provides utility functions which permit doing so -// recursively, such that API objects of types known only at run time can be -// embedded within other API types. - -// UnmarshalJSON implements the json.Unmarshaler interface. -func CodecUnmarshalJSON(codec Codec, b []byte) (Object, error) { - // Handle JSON's "null": Decode() doesn't expect it. - if len(b) == 4 && string(b) == "null" { - return nil, nil - } - - obj, err := codec.Decode(b) - if err != nil { - return nil, err - } - return obj, nil -} - -// MarshalJSON implements the json.Marshaler interface. -func CodecMarshalJSON(codec Codec, obj Object) ([]byte, error) { - if obj == nil { - // Encode unset/nil objects as JSON's "null". - return []byte("null"), nil - } - - return codec.Encode(obj) -} - -// SetYAML implements the yaml.Setter interface. -func CodecSetYAML(codec Codec, tag string, value interface{}) (Object, bool) { - if value == nil { - return nil, true - } - // Why does the yaml package send value as a map[interface{}]interface{}? - // It's especially frustrating because encoding/json does the right thing - // by giving a []byte. So here we do the embarrasing thing of re-encode and - // de-encode the right way. - // TODO: Write a version of Decode that uses reflect to turn this value - // into an API object. - b, err := yaml.Marshal(value) - if err != nil { - panic("yaml can't reverse its own object") - } - obj, err := codec.Decode(b) - if err != nil { - return nil, false - } - return obj, true -} - -// GetYAML implements the yaml.Getter interface. -func CodecGetYAML(codec Codec, obj Object) (tag string, value interface{}) { - if obj == nil { - value = "null" - return - } - // Encode returns JSON, which is conveniently a subset of YAML. - v, err := codec.Encode(obj) - if err != nil { - panic("impossible to encode API object!") - } - return tag, v -} diff --git a/pkg/runtime/extension.go b/pkg/runtime/extension.go index eebc9dcfa94..6fe7fea2e91 100644 --- a/pkg/runtime/extension.go +++ b/pkg/runtime/extension.go @@ -19,7 +19,7 @@ package runtime import ( "errors" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) func (re *RawExtension) UnmarshalJSON(in []byte) error { diff --git a/pkg/util/diff.go b/pkg/util/diff.go index 343733ded45..0000fa35747 100644 --- a/pkg/util/diff.go +++ b/pkg/util/diff.go @@ -19,6 +19,8 @@ package util import ( "encoding/json" "fmt" + + "github.com/davecgh/go-spew/spew" ) // StringDiff diffs a and b and returns a human readable diff. @@ -56,13 +58,19 @@ func ObjectDiff(a, b interface{}) string { return StringDiff(string(ab), string(bb)) } -// ObjectGoPrintDiff is like ObjectDiff, but uses go's %#v formatter to print the -// objects, in case json isn't showing you the difference. (reflect.DeepEqual makes -// a distinction between nil and empty slices, for example, even though nothing else -// really does.) +// ObjectGoPrintDiff is like ObjectDiff, but uses go-spew to print the objects, +// which shows absolutely everything by recursing into every single pointer +// (go's %#v formatters OTOH stop at a certain point). This is needed when you +// can't figure out why reflect.DeepEqual is returning false and nothing is +// showing you differences. This will. func ObjectGoPrintDiff(a, b interface{}) string { + s := spew.ConfigState{ + Indent: " ", + // Extra deep spew. + DisableMethods: true, + } return StringDiff( - fmt.Sprintf("%#v", a), - fmt.Sprintf("%#v", b), + s.Sdump(a), + s.Sdump(b), ) } diff --git a/pkg/util/time_test.go b/pkg/util/time_test.go index 3722ada63f2..aef8517f481 100644 --- a/pkg/util/time_test.go +++ b/pkg/util/time_test.go @@ -22,7 +22,7 @@ import ( "testing" "time" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) type TimeHolder struct { @@ -34,7 +34,7 @@ func TestTimeMarshalYAML(t *testing.T) { input Time result string }{ - {Time{}, "t: \"null\"\n"}, + {Time{}, "t: null\n"}, {Date(1998, time.May, 5, 5, 5, 5, 50, time.UTC), "t: 1998-05-05T05:05:05Z\n"}, {Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "t: 1998-05-05T05:05:05Z\n"}, } @@ -56,7 +56,7 @@ func TestTimeUnmarshalYAML(t *testing.T) { input string result Time }{ - {"t: \"null\"\n", Time{}}, + {"t: null\n", Time{}}, {"t: 1998-05-05T05:05:05Z\n", Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC)}, } diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go index 2c253c33a27..9c3c0300048 100644 --- a/pkg/util/util_test.go +++ b/pkg/util/util_test.go @@ -21,7 +21,7 @@ import ( "reflect" "testing" - "gopkg.in/v1/yaml" + "github.com/ghodss/yaml" ) func TestHandleCrash(t *testing.T) {