diff --git a/pkg/kubelet/config/common.go b/pkg/kubelet/config/common.go index 401af5d65e0..cb07511878e 100644 --- a/pkg/kubelet/config/common.go +++ b/pkg/kubelet/config/common.go @@ -30,6 +30,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" "github.com/GoogleCloudPlatform/kubernetes/pkg/types" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + utilyaml "github.com/GoogleCloudPlatform/kubernetes/pkg/util/yaml" "github.com/ghodss/yaml" "github.com/golang/glog" @@ -98,7 +99,12 @@ func getSelfLink(name, namespace string) string { type defaultFunc func(pod *api.Pod) error func tryDecodeSinglePod(data []byte, defaultFn defaultFunc) (parsed bool, pod *api.Pod, err error) { - obj, err := api.Scheme.Decode(data) + // JSON is valid YAML, so this should work for everything. + json, err := utilyaml.ToJSON(data) + if err != nil { + return false, nil, err + } + obj, err := api.Scheme.Decode(json) if err != nil { return false, pod, err } @@ -120,7 +126,11 @@ func tryDecodeSinglePod(data []byte, defaultFn defaultFunc) (parsed bool, pod *a } func tryDecodePodList(data []byte, defaultFn defaultFunc) (parsed bool, pods api.PodList, err error) { - obj, err := api.Scheme.Decode(data) + json, err := utilyaml.ToJSON(data) + if err != nil { + return false, api.PodList{}, err + } + obj, err := api.Scheme.Decode(json) if err != nil { return false, pods, err } diff --git a/pkg/kubelet/config/common_test.go b/pkg/kubelet/config/common_test.go new file mode 100644 index 00000000000..9f8d4da466d --- /dev/null +++ b/pkg/kubelet/config/common_test.go @@ -0,0 +1,156 @@ +/* +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 config + +import ( + "reflect" + "testing" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" + + "github.com/ghodss/yaml" +) + +func noDefault(*api.Pod) error { return nil } + +func TestDecodeSinglePod(t *testing.T) { + pod := &api.Pod{ + TypeMeta: api.TypeMeta{ + APIVersion: "", + }, + ObjectMeta: api.ObjectMeta{ + Name: "test", + UID: "12345", + Namespace: "mynamespace", + }, + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{ + Name: "image", + Image: "test/image", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePath: "/dev/termination-log", + }}, + }, + } + json, err := testapi.Codec().Encode(pod) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + parsed, podOut, err := tryDecodeSinglePod(json, noDefault) + if testapi.Version() == "v1beta1" { + // v1beta1 conversion leaves empty lists that should be nil + podOut.Spec.Containers[0].Resources.Limits = nil + podOut.Spec.Containers[0].Resources.Requests = nil + } + if !parsed { + t.Errorf("expected to have parsed file: (%s)", string(json)) + } + if err != nil { + t.Errorf("unexpected error: %v (%s)", err, string(json)) + } + if !reflect.DeepEqual(pod, podOut) { + t.Errorf("expected:\n%#v\ngot:\n%#v\n%s", pod, podOut, string(json)) + } + + externalPod, err := testapi.Converter().ConvertToVersion(pod, "v1beta3") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + yaml, err := yaml.Marshal(externalPod) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + parsed, podOut, err = tryDecodeSinglePod(yaml, noDefault) + if !parsed { + t.Errorf("expected to have parsed file: (%s)", string(yaml)) + } + if err != nil { + t.Errorf("unexpected error: %v (%s)", err, string(yaml)) + } + if !reflect.DeepEqual(pod, podOut) { + t.Errorf("expected:\n%#v\ngot:\n%#v\n%s", pod, podOut, string(yaml)) + } +} + +func TestDecodePodList(t *testing.T) { + pod := &api.Pod{ + TypeMeta: api.TypeMeta{ + APIVersion: "", + }, + ObjectMeta: api.ObjectMeta{ + Name: "test", + UID: "12345", + Namespace: "mynamespace", + }, + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{ + Name: "image", + Image: "test/image", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePath: "/dev/termination-log", + }}, + }, + } + podList := &api.PodList{ + Items: []api.Pod{*pod}, + } + json, err := testapi.Codec().Encode(podList) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + parsed, podListOut, err := tryDecodePodList(json, noDefault) + if testapi.Version() == "v1beta1" { + // v1beta1 conversion leaves empty lists that should be nil + podListOut.Items[0].Spec.Containers[0].Resources.Limits = nil + podListOut.Items[0].Spec.Containers[0].Resources.Requests = nil + } + if !parsed { + t.Errorf("expected to have parsed file: (%s)", string(json)) + } + if err != nil { + t.Errorf("unexpected error: %v (%s)", err, string(json)) + } + if !reflect.DeepEqual(podList, &podListOut) { + t.Errorf("expected:\n%#v\ngot:\n%#v\n%s", podList, &podListOut, string(json)) + } + + externalPodList, err := testapi.Converter().ConvertToVersion(podList, "v1beta3") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + yaml, err := yaml.Marshal(externalPodList) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + parsed, podListOut, err = tryDecodePodList(yaml, noDefault) + if !parsed { + t.Errorf("expected to have parsed file: (%s)", string(yaml)) + } + if err != nil { + t.Errorf("unexpected error: %v (%s)", err, string(yaml)) + } + if !reflect.DeepEqual(podList, &podListOut) { + t.Errorf("expected:\n%#v\ngot:\n%#v\n%s", pod, &podListOut, string(yaml)) + } +}