func OkStrategy() deployapi.DeploymentStrategy { return deployapi.DeploymentStrategy{ Type: deployapi.DeploymentStrategyTypeRecreate, Resources: kapi.ResourceRequirements{ Limits: kapi.ResourceList{ kapi.ResourceName(kapi.ResourceCPU): resource.MustParse("10"), kapi.ResourceName(kapi.ResourceMemory): resource.MustParse("10G"), }, }, } }
func mockSTIBuild() *buildapi.Build { return &buildapi.Build{ ObjectMeta: kapi.ObjectMeta{ Name: "stiBuild", Labels: map[string]string{ "name": "stiBuild", }, }, Spec: buildapi.BuildSpec{ Revision: &buildapi.SourceRevision{ Git: &buildapi.GitSourceRevision{}, }, Source: buildapi.BuildSource{ Git: &buildapi.GitBuildSource{ URI: "http://my.build.com/the/stibuild/Dockerfile", }, SourceSecret: &kapi.LocalObjectReference{Name: "fooSecret"}, }, Strategy: buildapi.BuildStrategy{ Type: buildapi.SourceBuildStrategyType, SourceStrategy: &buildapi.SourceBuildStrategy{ From: kapi.ObjectReference{ Kind: "DockerImage", Name: "repository/sti-builder", }, PullSecret: &kapi.LocalObjectReference{Name: "bar"}, Scripts: "http://my.build.com/the/sti/scripts", Env: []kapi.EnvVar{ {Name: "BUILD_LOGLEVEL", Value: "bar"}, {Name: "ILLEGAL", Value: "foo"}, }, }, }, Output: buildapi.BuildOutput{ To: &kapi.ObjectReference{ Kind: "DockerImage", Name: "docker-registry/repository/stiBuild", }, PushSecret: &kapi.LocalObjectReference{Name: "foo"}, }, Resources: kapi.ResourceRequirements{ Limits: kapi.ResourceList{ kapi.ResourceName(kapi.ResourceCPU): resource.MustParse("10"), kapi.ResourceName(kapi.ResourceMemory): resource.MustParse("10G"), }, }, }, Status: buildapi.BuildStatus{ Phase: buildapi.BuildPhaseNew, }, } }
func mockCustomBuild() *buildapi.Build { return &buildapi.Build{ ObjectMeta: kapi.ObjectMeta{ Name: "customBuild", Labels: map[string]string{ "name": "customBuild", }, }, Spec: buildapi.BuildSpec{ Revision: &buildapi.SourceRevision{ Git: &buildapi.GitSourceRevision{}, }, Source: buildapi.BuildSource{ Type: buildapi.BuildSourceGit, Git: &buildapi.GitBuildSource{ URI: "http://my.build.com/the/dockerbuild/Dockerfile", Ref: "master", }, SourceSecret: &kapi.LocalObjectReference{Name: "secretFoo"}, }, Strategy: buildapi.BuildStrategy{ Type: buildapi.CustomBuildStrategyType, CustomStrategy: &buildapi.CustomBuildStrategy{ From: kapi.ObjectReference{ Kind: "DockerImage", Name: "builder-image", }, Env: []kapi.EnvVar{ {Name: "FOO", Value: "BAR"}, }, ExposeDockerSocket: true, }, }, Output: buildapi.BuildOutput{ To: &kapi.ObjectReference{ Kind: "DockerImage", Name: "docker-registry/repository/customBuild", }, PushSecret: &kapi.LocalObjectReference{Name: "foo"}, }, Resources: kapi.ResourceRequirements{ Limits: kapi.ResourceList{ kapi.ResourceName(kapi.ResourceCPU): resource.MustParse("10"), kapi.ResourceName(kapi.ResourceMemory): resource.MustParse("10G"), }, }, }, Status: buildapi.BuildStatus{ Phase: buildapi.BuildPhaseNew, }, } }
func newNode(name string) *api.Node { return &api.Node{ ObjectMeta: api.ObjectMeta{Name: name}, Spec: api.NodeSpec{ ExternalID: name, }, Status: api.NodeStatus{ Capacity: api.ResourceList{ api.ResourceName(api.ResourceCPU): resource.MustParse("10"), api.ResourceName(api.ResourceMemory): resource.MustParse("10G"), }, }, } }
func TestPersistentVolumeClaimStatusUpdate(t *testing.T) { ns := api.NamespaceDefault persistentVolumeClaim := &api.PersistentVolumeClaim{ ObjectMeta: api.ObjectMeta{ Name: "abc", ResourceVersion: "1", }, Spec: api.PersistentVolumeClaimSpec{ AccessModes: []api.PersistentVolumeAccessMode{ api.ReadWriteOnce, api.ReadOnlyMany, }, Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("10G"), }, }, }, Status: api.PersistentVolumeClaimStatus{ Phase: api.ClaimBound, }, } c := &testClient{ Request: testRequest{ Method: "PUT", Path: testapi.ResourcePath(getPersistentVolumeClaimsResoureName(), ns, "abc") + "/status", Query: buildQueryValues(ns, nil)}, Response: Response{StatusCode: 200, Body: persistentVolumeClaim}, } response, err := c.Setup().PersistentVolumeClaims(ns).UpdateStatus(persistentVolumeClaim) c.Validate(t, response, err) }
func TestPersistentVolumeClaimGet(t *testing.T) { ns := api.NamespaceDefault persistentVolumeClaim := &api.PersistentVolumeClaim{ ObjectMeta: api.ObjectMeta{ Name: "abc", Namespace: "foo", }, Spec: api.PersistentVolumeClaimSpec{ AccessModes: []api.AccessModeType{ api.ReadWriteOnce, api.ReadOnlyMany, }, Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("10G"), }, }, }, } c := &testClient{ Request: testRequest{ Method: "GET", Path: testapi.ResourcePath(getPersistentVolumeClaimsResoureName(), ns, "abc"), Query: buildQueryValues(ns, nil), Body: nil, }, Response: Response{StatusCode: 200, Body: persistentVolumeClaim}, } response, err := c.Setup().PersistentVolumeClaims(ns).Get("abc") c.Validate(t, response, err) }
func makePersistentVolume(serverIP string) *api.PersistentVolume { return &api.PersistentVolume{ ObjectMeta: api.ObjectMeta{ GenerateName: "nfs-", }, Spec: api.PersistentVolumeSpec{ PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimRecycle, Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("2Gi"), }, PersistentVolumeSource: api.PersistentVolumeSource{ NFS: &api.NFSVolumeSource{ Server: serverIP, Path: "/", ReadOnly: false, }, }, AccessModes: []api.PersistentVolumeAccessMode{ api.ReadWriteOnce, api.ReadOnlyMany, api.ReadWriteMany, }, }, } }
func TestPersistentVolumeStatusUpdate(t *testing.T) { persistentVolume := &api.PersistentVolume{ ObjectMeta: api.ObjectMeta{ Name: "abc", ResourceVersion: "1", }, Spec: api.PersistentVolumeSpec{ Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("10G"), }, PersistentVolumeSource: api.PersistentVolumeSource{ HostPath: &api.HostPathVolumeSource{Path: "/foo"}, }, }, Status: api.PersistentVolumeStatus{ Phase: api.VolumeBound, }, } c := &testClient{ Request: testRequest{ Method: "PUT", Path: testapi.ResourcePath(getPersistentVolumesResoureName(), "", "abc") + "/status", Query: buildQueryValues("", nil)}, Response: Response{StatusCode: 200, Body: persistentVolume}, } response, err := c.Setup().PersistentVolumes().UpdateStatus(persistentVolume) c.Validate(t, response, err) }
func TestPersistentVolumeGet(t *testing.T) { persistentVolume := &api.PersistentVolume{ ObjectMeta: api.ObjectMeta{ Name: "abc", Namespace: "foo", }, Spec: api.PersistentVolumeSpec{ Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("10G"), }, PersistentVolumeSource: api.PersistentVolumeSource{ HostPath: &api.HostPathVolumeSource{Path: "/foo"}, }, }, } c := &testClient{ Request: testRequest{ Method: "GET", Path: testapi.ResourcePath(getPersistentVolumesResoureName(), "", "abc"), Query: buildQueryValues("", nil), Body: nil, }, Response: Response{StatusCode: 200, Body: persistentVolume}, } response, err := c.Setup().PersistentVolumes().Get("abc") c.Validate(t, response, err) }
func createTestVolumes() []*api.PersistentVolume { return []*api.PersistentVolume{ { ObjectMeta: api.ObjectMeta{ UID: "gce-pd-10", Name: "gce003", }, Spec: api.PersistentVolumeSpec{ Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("10G"), }, PersistentVolumeSource: api.PersistentVolumeSource{ GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{ PDName: "gce123123123", FSType: "foo", }, }, AccessModes: []api.PersistentVolumeAccessMode{ api.ReadWriteOnce, api.ReadOnlyMany, }, }, }, { ObjectMeta: api.ObjectMeta{ UID: "nfs-5", Name: "nfs002", }, Spec: api.PersistentVolumeSpec{ Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("5G"), }, PersistentVolumeSource: api.PersistentVolumeSource{ Glusterfs: &api.GlusterfsVolumeSource{ EndpointsName: "andintheend", Path: "theloveyoutakeisequaltotheloveyoumake", }, }, AccessModes: []api.PersistentVolumeAccessMode{ api.ReadWriteOnce, api.ReadOnlyMany, api.ReadWriteMany, }, }, }, } }
func createTestClaims() []*api.PersistentVolumeClaim { return []*api.PersistentVolumeClaim{ { ObjectMeta: api.ObjectMeta{ Name: "claim03", Namespace: api.NamespaceDefault, }, Spec: api.PersistentVolumeClaimSpec{ AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("500G"), }, }, }, }, { ObjectMeta: api.ObjectMeta{ Name: "claim01", Namespace: api.NamespaceDefault, }, Spec: api.PersistentVolumeClaimSpec{ AccessModes: []api.PersistentVolumeAccessMode{api.ReadOnlyMany, api.ReadWriteOnce}, Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("8G"), }, }, }, }, { ObjectMeta: api.ObjectMeta{ Name: "claim02", Namespace: api.NamespaceDefault, }, Spec: api.PersistentVolumeClaimSpec{ AccessModes: []api.PersistentVolumeAccessMode{api.ReadOnlyMany, api.ReadWriteOnce, api.ReadWriteMany}, Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("5G"), }, }, }, }, } }
func okContainer() *kapi.Container { return &kapi.Container{ Image: "test/image", Command: []string{"command"}, Env: []kapi.EnvVar{ { Name: "env1", Value: "val1", }, }, Resources: kapi.ResourceRequirements{ Limits: kapi.ResourceList{ kapi.ResourceName(kapi.ResourceCPU): resource.MustParse("10"), kapi.ResourceName(kapi.ResourceMemory): resource.MustParse("10G"), }, }, } }
func validNewNode() *api.Node { return &api.Node{ ObjectMeta: api.ObjectMeta{ Name: "foo", Labels: map[string]string{ "name": "foo", }, }, Spec: api.NodeSpec{ ExternalID: "external", }, Status: api.NodeStatus{ Capacity: api.ResourceList{ api.ResourceName(api.ResourceCPU): resource.MustParse("10"), api.ResourceName(api.ResourceMemory): resource.MustParse("0"), }, }, } }
func mockDockerBuild() *buildapi.Build { return &buildapi.Build{ ObjectMeta: kapi.ObjectMeta{ Name: "dockerBuild", Labels: map[string]string{ "name": "dockerBuild", }, }, Parameters: buildapi.BuildParameters{ Revision: &buildapi.SourceRevision{ Git: &buildapi.GitSourceRevision{}, }, Source: buildapi.BuildSource{ Git: &buildapi.GitBuildSource{ URI: "http://my.build.com/the/dockerbuild/Dockerfile", }, ContextDir: "my/test/dir", SourceSecret: &kapi.LocalObjectReference{Name: "secretFoo"}, }, Strategy: buildapi.BuildStrategy{ Type: buildapi.DockerBuildStrategyType, DockerStrategy: &buildapi.DockerBuildStrategy{ PullSecret: &kapi.LocalObjectReference{Name: "bar"}, Env: []kapi.EnvVar{ {Name: "ILLEGAL", Value: "foo"}, {Name: "BUILD_LOGLEVEL", Value: "bar"}, }, }, }, Output: buildapi.BuildOutput{ DockerImageReference: "docker-registry/repository/dockerBuild", PushSecret: &kapi.LocalObjectReference{Name: "foo"}, }, Resources: kapi.ResourceRequirements{ Limits: kapi.ResourceList{ kapi.ResourceName(kapi.ResourceCPU): resource.MustParse("10"), kapi.ResourceName(kapi.ResourceMemory): resource.MustParse("10G"), }, }, }, Status: buildapi.BuildStatusNew, } }
func OkRollingStrategy() deployapi.DeploymentStrategy { mkintp := func(i int) *int64 { v := int64(i) return &v } return deployapi.DeploymentStrategy{ Type: deployapi.DeploymentStrategyTypeRolling, RollingParams: &deployapi.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: mkintp(1), IntervalSeconds: mkintp(1), TimeoutSeconds: mkintp(20), }, Resources: kapi.ResourceRequirements{ Limits: kapi.ResourceList{ kapi.ResourceName(kapi.ResourceCPU): resource.MustParse("10"), kapi.ResourceName(kapi.ResourceMemory): resource.MustParse("10G"), }, }, } }
// FindByAccessModesAndStorageCapacity is a convenience method that calls Find w/ requisite matchPredicate for storage func (pvIndex *persistentVolumeOrderedIndex) FindByAccessModesAndStorageCapacity(modes []api.PersistentVolumeAccessMode, qty resource.Quantity) (*api.PersistentVolume, error) { pv := &api.PersistentVolume{ Spec: api.PersistentVolumeSpec{ AccessModes: modes, Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): qty, }, }, } return pvIndex.Find(pv, matchStorageCapacity) }
func validNewPersistentVolume(name string) *api.PersistentVolume { pv := &api.PersistentVolume{ ObjectMeta: api.ObjectMeta{ Name: name, }, Spec: api.PersistentVolumeSpec{ Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("10G"), }, PersistentVolumeSource: api.PersistentVolumeSource{ HostPath: &api.HostPathVolumeSource{Path: "/foo"}, }, }, } return pv }
func TestEtcdUpdateStatus(t *testing.T) { storage, statusStorage, fakeClient, helper := newStorage(t) ctx := api.NewDefaultContext() fakeClient.TestIndex = true key, _ := storage.KeyFunc(ctx, "foo") key = etcdtest.AddPrefix(key) pvcStart := validNewPersistentVolumeClaim("foo", api.NamespaceDefault) fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, pvcStart), 1) pvc := &api.PersistentVolumeClaim{ ObjectMeta: api.ObjectMeta{ Name: "foo", Namespace: api.NamespaceDefault, ResourceVersion: "1", }, Spec: api.PersistentVolumeClaimSpec{ AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("3Gi"), }, }, }, Status: api.PersistentVolumeClaimStatus{ Phase: api.ClaimBound, }, } expected := *pvcStart expected.ResourceVersion = "2" expected.Labels = pvc.Labels expected.Status = pvc.Status _, _, err := statusStorage.Update(ctx, pvc) if err != nil { t.Fatalf("Unexpected error: %v", err) } var pvcOut api.PersistentVolumeClaim key, _ = storage.KeyFunc(ctx, "foo") if err := helper.ExtractObj(key, &pvcOut, false); err != nil { t.Fatalf("Unexpected error: %v", err) } if !api.Semantic.DeepEqual(expected, pvcOut) { t.Errorf("unexpected object: %s", util.ObjectDiff(expected, pvcOut)) } }
func validNewPersistentVolumeClaim(name, ns string) *api.PersistentVolumeClaim { pv := &api.PersistentVolumeClaim{ ObjectMeta: api.ObjectMeta{ Name: name, Namespace: ns, }, Spec: api.PersistentVolumeClaimSpec{ AccessModes: []api.AccessModeType{api.ReadWriteOnce}, Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("10G"), }, }, }, } return pv }
func makePersistentVolumeClaim(ns string) *api.PersistentVolumeClaim { return &api.PersistentVolumeClaim{ ObjectMeta: api.ObjectMeta{ GenerateName: "pvc-", Namespace: ns, }, Spec: api.PersistentVolumeClaimSpec{ AccessModes: []api.PersistentVolumeAccessMode{ api.ReadWriteOnce, api.ReadOnlyMany, api.ReadWriteMany, }, Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("1Gi"), }, }, }, } }
func validNewPersistentVolume(name string) *api.PersistentVolume { pv := &api.PersistentVolume{ ObjectMeta: api.ObjectMeta{ Name: name, }, Spec: api.PersistentVolumeSpec{ Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("10G"), }, AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, PersistentVolumeSource: api.PersistentVolumeSource{ HostPath: &api.HostPathVolumeSource{Path: "/foo"}, }, PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimRetain, }, Status: api.PersistentVolumeStatus{ Phase: api.VolumePending, Message: "bar", Reason: "foo", }, } return pv }
func TestDescribeContainers(t *testing.T) { testCases := []struct { container api.Container status api.ContainerStatus expectedElements []string }{ // Running state. { container: api.Container{Name: "test", Image: "image"}, status: api.ContainerStatus{ Name: "test", State: api.ContainerState{ Running: &api.ContainerStateRunning{ StartedAt: util.NewTime(time.Now()), }, }, Ready: true, RestartCount: 7, }, expectedElements: []string{"test", "State", "Running", "Ready", "True", "Restart Count", "7", "Image", "image", "Started"}, }, // Waiting state. { container: api.Container{Name: "test", Image: "image"}, status: api.ContainerStatus{ Name: "test", State: api.ContainerState{ Waiting: &api.ContainerStateWaiting{ Reason: "potato", }, }, Ready: true, RestartCount: 7, }, expectedElements: []string{"test", "State", "Waiting", "Ready", "True", "Restart Count", "7", "Image", "image", "Reason", "potato"}, }, // Terminated state. { container: api.Container{Name: "test", Image: "image"}, status: api.ContainerStatus{ Name: "test", State: api.ContainerState{ Terminated: &api.ContainerStateTerminated{ StartedAt: util.NewTime(time.Now()), FinishedAt: util.NewTime(time.Now()), Reason: "potato", ExitCode: 2, }, }, Ready: true, RestartCount: 7, }, expectedElements: []string{"test", "State", "Terminated", "Ready", "True", "Restart Count", "7", "Image", "image", "Reason", "potato", "Started", "Finished", "Exit Code", "2"}, }, // No state defaults to waiting. { container: api.Container{Name: "test", Image: "image"}, status: api.ContainerStatus{ Name: "test", Ready: true, RestartCount: 7, }, expectedElements: []string{"test", "State", "Waiting", "Ready", "True", "Restart Count", "7", "Image", "image"}, }, //env { container: api.Container{Name: "test", Image: "image", Env: []api.EnvVar{{Name: "envname", Value: "xyz"}}}, status: api.ContainerStatus{ Name: "test", Ready: true, RestartCount: 7, }, expectedElements: []string{"test", "State", "Waiting", "Ready", "True", "Restart Count", "7", "Image", "image", "envname", "xyz"}, }, // Using limits. { container: api.Container{ Name: "test", Image: "image", Resources: api.ResourceRequirements{ Limits: api.ResourceList{ api.ResourceName(api.ResourceCPU): resource.MustParse("1000"), api.ResourceName(api.ResourceMemory): resource.MustParse("4G"), api.ResourceName(api.ResourceStorage): resource.MustParse("20G"), }, }, }, status: api.ContainerStatus{ Name: "test", Ready: true, RestartCount: 7, }, expectedElements: []string{"cpu", "1k", "memory", "4G", "storage", "20G"}, }, } for i, testCase := range testCases { out := new(bytes.Buffer) pod := api.Pod{ Spec: api.PodSpec{ Containers: []api.Container{testCase.container}, }, Status: api.PodStatus{ ContainerStatuses: []api.ContainerStatus{testCase.status}, }, } describeContainers(&pod, out) output := out.String() for _, expected := range testCase.expectedElements { if !strings.Contains(output, expected) { t.Errorf("Test case %d: expected to find %q in output: %q", i, expected, output) } } } }
func createTestVolumes() []*api.PersistentVolume { // these volumes are deliberately out-of-order to test indexing and sorting return []*api.PersistentVolume{ { ObjectMeta: api.ObjectMeta{ UID: "gce-pd-10", Name: "gce003", }, Spec: api.PersistentVolumeSpec{ Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("10G"), }, PersistentVolumeSource: api.PersistentVolumeSource{ GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{}, }, AccessModes: []api.PersistentVolumeAccessMode{ api.ReadWriteOnce, api.ReadOnlyMany, }, }, }, { ObjectMeta: api.ObjectMeta{ UID: "gce-pd-20", Name: "gce004", }, Spec: api.PersistentVolumeSpec{ Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("20G"), }, PersistentVolumeSource: api.PersistentVolumeSource{ GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{}, }, AccessModes: []api.PersistentVolumeAccessMode{ api.ReadWriteOnce, api.ReadOnlyMany, }, // this one we're pretending is already bound ClaimRef: &api.ObjectReference{UID: "def456"}, }, }, { ObjectMeta: api.ObjectMeta{ UID: "nfs-5", Name: "nfs002", }, Spec: api.PersistentVolumeSpec{ Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("5G"), }, PersistentVolumeSource: api.PersistentVolumeSource{ Glusterfs: &api.GlusterfsVolumeSource{}, }, AccessModes: []api.PersistentVolumeAccessMode{ api.ReadWriteOnce, api.ReadOnlyMany, api.ReadWriteMany, }, }, }, { ObjectMeta: api.ObjectMeta{ UID: "gce-pd-1", Name: "gce001", }, Spec: api.PersistentVolumeSpec{ Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("1G"), }, PersistentVolumeSource: api.PersistentVolumeSource{ GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{}, }, AccessModes: []api.PersistentVolumeAccessMode{ api.ReadWriteOnce, api.ReadOnlyMany, }, // this one we're pretending is already bound ClaimRef: &api.ObjectReference{UID: "abc123"}, }, }, { ObjectMeta: api.ObjectMeta{ UID: "nfs-10", Name: "nfs003", }, Spec: api.PersistentVolumeSpec{ Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("10G"), }, PersistentVolumeSource: api.PersistentVolumeSource{ Glusterfs: &api.GlusterfsVolumeSource{}, }, AccessModes: []api.PersistentVolumeAccessMode{ api.ReadWriteOnce, api.ReadOnlyMany, api.ReadWriteMany, }, }, }, { ObjectMeta: api.ObjectMeta{ UID: "gce-pd-5", Name: "gce002", }, Spec: api.PersistentVolumeSpec{ Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("5G"), }, PersistentVolumeSource: api.PersistentVolumeSource{ GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{}, }, AccessModes: []api.PersistentVolumeAccessMode{ api.ReadWriteOnce, api.ReadOnlyMany, }, }, }, { ObjectMeta: api.ObjectMeta{ UID: "nfs-1", Name: "nfs001", }, Spec: api.PersistentVolumeSpec{ Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("1G"), }, PersistentVolumeSource: api.PersistentVolumeSource{ Glusterfs: &api.GlusterfsVolumeSource{}, }, AccessModes: []api.PersistentVolumeAccessMode{ api.ReadWriteOnce, api.ReadOnlyMany, api.ReadWriteMany, }, }, }, } }
func TestMatchVolume(t *testing.T) { volList := NewPersistentVolumeOrderedIndex() for _, pv := range createTestVolumes() { volList.Add(pv) } scenarios := map[string]struct { expectedMatch string claim *api.PersistentVolumeClaim }{ "successful-match-gce-10": { expectedMatch: "gce-pd-10", claim: &api.PersistentVolumeClaim{ ObjectMeta: api.ObjectMeta{ Name: "claim01", Namespace: "myns", }, Spec: api.PersistentVolumeClaimSpec{ AccessModes: []api.PersistentVolumeAccessMode{api.ReadOnlyMany, api.ReadWriteOnce}, Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("8G"), }, }, }, }, }, "successful-match-nfs-5": { expectedMatch: "nfs-5", claim: &api.PersistentVolumeClaim{ ObjectMeta: api.ObjectMeta{ Name: "claim01", Namespace: "myns", }, Spec: api.PersistentVolumeClaimSpec{ AccessModes: []api.PersistentVolumeAccessMode{api.ReadOnlyMany, api.ReadWriteOnce, api.ReadWriteMany}, Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("5G"), }, }, }, }, }, "successful-skip-1g-bound-volume": { expectedMatch: "gce-pd-5", claim: &api.PersistentVolumeClaim{ ObjectMeta: api.ObjectMeta{ Name: "claim01", Namespace: "myns", }, Spec: api.PersistentVolumeClaimSpec{ AccessModes: []api.PersistentVolumeAccessMode{api.ReadOnlyMany, api.ReadWriteOnce}, Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("1G"), }, }, }, }, }, "successful-no-match": { expectedMatch: "", claim: &api.PersistentVolumeClaim{ ObjectMeta: api.ObjectMeta{ Name: "claim01", Namespace: "myns", }, Spec: api.PersistentVolumeClaimSpec{ AccessModes: []api.PersistentVolumeAccessMode{api.ReadOnlyMany, api.ReadWriteOnce}, Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("999G"), }, }, }, }, }, } for name, scenario := range scenarios { volume, err := volList.FindBestMatchForClaim(scenario.claim) if err != nil { t.Errorf("Unexpected error matching volume by claim: %v", err) } if scenario.expectedMatch != "" && volume == nil { t.Errorf("Expected match but received nil volume for scenario: %s", name) } if scenario.expectedMatch != "" && volume != nil && string(volume.UID) != scenario.expectedMatch { t.Errorf("Expected %s but got volume %s in scenario %s", scenario.expectedMatch, volume.UID, name) } if scenario.expectedMatch == "" && volume != nil { t.Errorf("Unexpected match for scenario: %s", name) } } }
func init() { // Our TypeMeta was split into two different structs. newer.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", newer.TypeMeta{}, "TypeMeta") newer.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", newer.ObjectMeta{}, "ObjectMeta") newer.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", newer.ListMeta{}, "ListMeta") newer.Scheme.AddStructFieldConversion(newer.TypeMeta{}, "TypeMeta", TypeMeta{}, "TypeMeta") newer.Scheme.AddStructFieldConversion(newer.ObjectMeta{}, "ObjectMeta", TypeMeta{}, "TypeMeta") newer.Scheme.AddStructFieldConversion(newer.ListMeta{}, "ListMeta", TypeMeta{}, "TypeMeta") // TODO: scope this to a specific type once that becomes available and remove the Event conversion functions below // newer.Scheme.AddStructFieldConversion(string(""), "Status", string(""), "Condition") // newer.Scheme.AddStructFieldConversion(string(""), "Condition", string(""), "Status") err := newer.Scheme.AddConversionFuncs( // TypeMeta must be split into two objects func(in *newer.TypeMeta, out *TypeMeta, s conversion.Scope) error { out.Kind = in.Kind out.APIVersion = in.APIVersion return nil }, func(in *TypeMeta, out *newer.TypeMeta, s conversion.Scope) error { out.Kind = in.Kind out.APIVersion = in.APIVersion return nil }, // ListMeta must be converted to TypeMeta func(in *newer.ListMeta, out *TypeMeta, s conversion.Scope) error { out.SelfLink = in.SelfLink if len(in.ResourceVersion) > 0 { v, err := strconv.ParseUint(in.ResourceVersion, 10, 64) if err != nil { return err } out.ResourceVersion = v } return nil }, func(in *TypeMeta, out *newer.ListMeta, s conversion.Scope) error { out.SelfLink = in.SelfLink if in.ResourceVersion != 0 { out.ResourceVersion = strconv.FormatUint(in.ResourceVersion, 10) } else { out.ResourceVersion = "" } return nil }, // ObjectMeta must be converted to TypeMeta func(in *newer.ObjectMeta, out *TypeMeta, s conversion.Scope) error { out.Namespace = in.Namespace out.ID = in.Name out.GenerateName = in.GenerateName out.UID = in.UID out.CreationTimestamp = in.CreationTimestamp out.SelfLink = in.SelfLink if len(in.ResourceVersion) > 0 { v, err := strconv.ParseUint(in.ResourceVersion, 10, 64) if err != nil { return err } out.ResourceVersion = v } return s.Convert(&in.Annotations, &out.Annotations, 0) }, func(in *TypeMeta, out *newer.ObjectMeta, s conversion.Scope) error { out.Namespace = in.Namespace out.Name = in.ID out.GenerateName = in.GenerateName out.UID = in.UID out.CreationTimestamp = in.CreationTimestamp out.SelfLink = in.SelfLink if in.ResourceVersion != 0 { out.ResourceVersion = strconv.FormatUint(in.ResourceVersion, 10) } else { out.ResourceVersion = "" } return s.Convert(&in.Annotations, &out.Annotations, 0) }, // EnvVar's Key is deprecated in favor of Name. func(in *newer.EnvVar, out *EnvVar, s conversion.Scope) error { out.Value = in.Value out.Key = in.Name out.Name = in.Name return nil }, func(in *EnvVar, out *newer.EnvVar, s conversion.Scope) error { out.Value = in.Value if in.Name != "" { out.Name = in.Name } else { out.Name = in.Key } return nil }, // Path & MountType are deprecated. func(in *newer.VolumeMount, out *VolumeMount, s conversion.Scope) error { out.Name = in.Name out.ReadOnly = in.ReadOnly out.MountPath = in.MountPath out.Path = in.MountPath out.MountType = "" // MountType is ignored. return nil }, func(in *VolumeMount, out *newer.VolumeMount, s conversion.Scope) error { out.Name = in.Name out.ReadOnly = in.ReadOnly if in.MountPath == "" { out.MountPath = in.Path } else { out.MountPath = in.MountPath } return nil }, // MinionList.Items had a wrong name in v1beta1 func(in *newer.NodeList, out *MinionList, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Items, &out.Items, 0); err != nil { return err } out.Minions = out.Items return nil }, func(in *MinionList, out *newer.NodeList, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil { return err } if len(in.Items) == 0 { if err := s.Convert(&in.Minions, &out.Items, 0); err != nil { return err } } else { if err := s.Convert(&in.Items, &out.Items, 0); err != nil { return err } } return nil }, func(in *newer.PodStatus, out *PodState, s conversion.Scope) error { if err := s.Convert(&in.Phase, &out.Status, 0); err != nil { return err } if err := s.Convert(&in.Conditions, &out.Conditions, 0); err != nil { return err } if err := s.Convert(&in.Info, &out.Info, 0); err != nil { return err } out.Message = in.Message out.Host = in.Host out.HostIP = in.HostIP out.PodIP = in.PodIP return nil }, func(in *PodState, out *newer.PodStatus, s conversion.Scope) error { if err := s.Convert(&in.Status, &out.Phase, 0); err != nil { return err } if err := s.Convert(&in.Conditions, &out.Conditions, 0); err != nil { return err } if err := s.Convert(&in.Info, &out.Info, 0); err != nil { return err } out.Message = in.Message out.Host = in.Host out.HostIP = in.HostIP out.PodIP = in.PodIP return nil }, func(in *newer.PodSpec, out *PodState, s conversion.Scope) error { if err := s.Convert(&in, &out.Manifest, 0); err != nil { return err } out.Host = in.Host return nil }, func(in *PodState, out *newer.PodSpec, s conversion.Scope) error { if err := s.Convert(&in.Manifest, &out, 0); err != nil { return err } out.Host = in.Host return nil }, // Convert all to the new PodPhase constants func(in *newer.PodPhase, out *PodStatus, s conversion.Scope) error { switch *in { case "": *out = "" case newer.PodPending: *out = PodWaiting case newer.PodRunning: *out = PodRunning case newer.PodSucceeded: *out = PodSucceeded case newer.PodFailed: *out = PodTerminated case newer.PodUnknown: *out = PodUnknown default: return &newer.ConversionError{ In: in, Out: out, Message: "The string provided is not a valid PodPhase constant value", } } return nil }, func(in *PodStatus, out *newer.PodPhase, s conversion.Scope) error { switch *in { case "": *out = "" case PodWaiting: *out = newer.PodPending case PodRunning: *out = newer.PodRunning case PodTerminated: // Older API versions did not contain enough info to map to PodSucceeded *out = newer.PodFailed case PodSucceeded: *out = newer.PodSucceeded case PodUnknown: *out = newer.PodUnknown default: return &newer.ConversionError{ In: in, Out: out, Message: "The string provided is not a valid PodPhase constant value", } } return nil }, // Convert all the standard objects func(in *newer.Pod, out *Pod, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } // TODO: Change this to use in.ObjectMeta.Labels. if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } if err := s.Convert(&in.Spec, &out.DesiredState.Manifest, 0); err != nil { return err } out.DesiredState.Host = in.Spec.Host if err := s.Convert(&in.Status, &out.CurrentState, 0); err != nil { return err } if err := s.Convert(&in.Spec.NodeSelector, &out.NodeSelector, 0); err != nil { return err } return nil }, func(in *Pod, out *newer.Pod, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } if err := s.Convert(&in.DesiredState.Manifest, &out.Spec, 0); err != nil { return err } out.Spec.Host = in.DesiredState.Host if err := s.Convert(&in.CurrentState, &out.Status, 0); err != nil { return err } if err := s.Convert(&in.NodeSelector, &out.Spec.NodeSelector, 0); err != nil { return err } return nil }, func(in *newer.PodStatusResult, out *PodStatusResult, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.State, 0); err != nil { return err } return nil }, func(in *PodStatusResult, out *newer.PodStatusResult, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.State, &out.Status, 0); err != nil { return err } return nil }, func(in *newer.ReplicationController, out *ReplicationController, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } if err := s.Convert(&in.Spec, &out.DesiredState, 0); err != nil { return err } out.CurrentState.Replicas = in.Status.Replicas return nil }, func(in *ReplicationController, out *newer.ReplicationController, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } if err := s.Convert(&in.DesiredState, &out.Spec, 0); err != nil { return err } out.Status.Replicas = in.CurrentState.Replicas return nil }, func(in *newer.ReplicationControllerSpec, out *ReplicationControllerState, s conversion.Scope) error { out.Replicas = in.Replicas if err := s.Convert(&in.Selector, &out.ReplicaSelector, 0); err != nil { return err } if in.TemplateRef != nil && in.Template == nil { return &newer.ConversionError{ In: in, Out: out, Message: "objects with a template ref cannot be converted to older objects, must populate template", } } if in.Template != nil { if err := s.Convert(in.Template, &out.PodTemplate, 0); err != nil { return err } } return nil }, func(in *ReplicationControllerState, out *newer.ReplicationControllerSpec, s conversion.Scope) error { out.Replicas = in.Replicas if err := s.Convert(&in.ReplicaSelector, &out.Selector, 0); err != nil { return err } out.Template = &newer.PodTemplateSpec{} if err := s.Convert(&in.PodTemplate, out.Template, 0); err != nil { return err } return nil }, func(in *newer.PodTemplateSpec, out *PodTemplate, s conversion.Scope) error { if err := s.Convert(&in.Spec, &out.DesiredState.Manifest, 0); err != nil { return err } out.DesiredState.Host = in.Spec.Host if err := s.Convert(&in.Spec.NodeSelector, &out.NodeSelector, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta.Labels, &out.Labels, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta.Annotations, &out.Annotations, 0); err != nil { return err } return nil }, func(in *PodTemplate, out *newer.PodTemplateSpec, s conversion.Scope) error { if err := s.Convert(&in.DesiredState.Manifest, &out.Spec, 0); err != nil { return err } out.Spec.Host = in.DesiredState.Host if err := s.Convert(&in.NodeSelector, &out.Spec.NodeSelector, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil { return err } if err := s.Convert(&in.Annotations, &out.ObjectMeta.Annotations, 0); err != nil { return err } return nil }, func(in *newer.PodSpec, out *BoundPod, s conversion.Scope) error { if err := s.Convert(&in, &out.Spec, 0); err != nil { return err } return nil }, func(in *BoundPod, out *newer.PodSpec, s conversion.Scope) error { if err := s.Convert(&in.Spec, &out, 0); err != nil { return err } return nil }, // Converts internal Container to v1beta1.Container. // Fields 'CPU' and 'Memory' are not present in the internal Container object. // Hence the need for a custom conversion function. func(in *newer.Container, out *Container, s conversion.Scope) error { if err := s.Convert(&in.Name, &out.Name, 0); err != nil { return err } if err := s.Convert(&in.Image, &out.Image, 0); err != nil { return err } if err := s.Convert(&in.Command, &out.Command, 0); err != nil { return err } if err := s.Convert(&in.WorkingDir, &out.WorkingDir, 0); err != nil { return err } if err := s.Convert(&in.Ports, &out.Ports, 0); err != nil { return err } if err := s.Convert(&in.Env, &out.Env, 0); err != nil { return err } if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil { return err } if err := s.Convert(in.Resources.Limits.Cpu(), &out.CPU, 0); err != nil { return err } if err := s.Convert(in.Resources.Limits.Memory(), &out.Memory, 0); err != nil { return err } if err := s.Convert(&in.VolumeMounts, &out.VolumeMounts, 0); err != nil { return err } if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil { return err } if err := s.Convert(&in.ReadinessProbe, &out.ReadinessProbe, 0); err != nil { return err } if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil { return err } if err := s.Convert(&in.TerminationMessagePath, &out.TerminationMessagePath, 0); err != nil { return err } if err := s.Convert(&in.Privileged, &out.Privileged, 0); err != nil { return err } if err := s.Convert(&in.ImagePullPolicy, &out.ImagePullPolicy, 0); err != nil { return err } if err := s.Convert(&in.Capabilities, &out.Capabilities, 0); err != nil { return err } return nil }, // Internal API does not support CPU to be specified via an explicit field. // Hence it must be stored in Container.Resources. func(in *int, out *newer.ResourceList, s conversion.Scope) error { if *in <= 0 { return nil } quantity := resource.Quantity{} if err := s.Convert(in, &quantity, 0); err != nil { return err } (*out)[newer.ResourceCPU] = quantity return nil }, // Internal API does not support Memory to be specified via an explicit field. // Hence it must be stored in Container.Resources. func(in *int64, out *newer.ResourceList, s conversion.Scope) error { if *in <= 0 { return nil } quantity := resource.Quantity{} if err := s.Convert(in, &quantity, 0); err != nil { return err } (*out)[newer.ResourceMemory] = quantity return nil }, // Converts v1beta1.Container to internal Container. // Fields 'CPU' and 'Memory' are not present in the internal Container object. // Hence the need for a custom conversion function. func(in *Container, out *newer.Container, s conversion.Scope) error { if err := s.Convert(&in.Name, &out.Name, 0); err != nil { return err } if err := s.Convert(&in.Image, &out.Image, 0); err != nil { return err } if err := s.Convert(&in.Command, &out.Command, 0); err != nil { return err } if err := s.Convert(&in.WorkingDir, &out.WorkingDir, 0); err != nil { return err } if err := s.Convert(&in.Ports, &out.Ports, 0); err != nil { return err } if err := s.Convert(&in.Env, &out.Env, 0); err != nil { return err } if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil { return err } if err := s.Convert(&in.CPU, &out.Resources.Limits, 0); err != nil { return err } if err := s.Convert(&in.Memory, &out.Resources.Limits, 0); err != nil { return err } if err := s.Convert(&in.VolumeMounts, &out.VolumeMounts, 0); err != nil { return err } if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil { return err } if err := s.Convert(&in.ReadinessProbe, &out.ReadinessProbe, 0); err != nil { return err } if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil { return err } if err := s.Convert(&in.TerminationMessagePath, &out.TerminationMessagePath, 0); err != nil { return err } if err := s.Convert(&in.Privileged, &out.Privileged, 0); err != nil { return err } if err := s.Convert(&in.ImagePullPolicy, &out.ImagePullPolicy, 0); err != nil { return err } if err := s.Convert(&in.Capabilities, &out.Capabilities, 0); err != nil { return err } return nil }, func(in *newer.PodSpec, out *ContainerManifest, s conversion.Scope) error { if err := s.Convert(&in.Volumes, &out.Volumes, 0); err != nil { return err } if err := s.Convert(&in.Containers, &out.Containers, 0); err != nil { return err } if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil { return err } out.DNSPolicy = DNSPolicy(in.DNSPolicy) out.Version = "v1beta2" return nil }, func(in *ContainerManifest, out *newer.PodSpec, s conversion.Scope) error { if err := s.Convert(&in.Volumes, &out.Volumes, 0); err != nil { return err } if err := s.Convert(&in.Containers, &out.Containers, 0); err != nil { return err } if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil { return err } out.DNSPolicy = newer.DNSPolicy(in.DNSPolicy) return nil }, func(in *newer.Service, out *Service, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } out.Port = in.Spec.Port out.Protocol = Protocol(in.Spec.Protocol) if err := s.Convert(&in.Spec.Selector, &out.Selector, 0); err != nil { return err } out.CreateExternalLoadBalancer = in.Spec.CreateExternalLoadBalancer out.PublicIPs = in.Spec.PublicIPs out.ContainerPort = in.Spec.ContainerPort out.PortalIP = in.Spec.PortalIP if err := s.Convert(&in.Spec.SessionAffinity, &out.SessionAffinity, 0); err != nil { return err } return nil }, func(in *Service, out *newer.Service, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } out.Spec.Port = in.Port out.Spec.Protocol = newer.Protocol(in.Protocol) if err := s.Convert(&in.Selector, &out.Spec.Selector, 0); err != nil { return err } out.Spec.CreateExternalLoadBalancer = in.CreateExternalLoadBalancer out.Spec.PublicIPs = in.PublicIPs out.Spec.ContainerPort = in.ContainerPort out.Spec.PortalIP = in.PortalIP if err := s.Convert(&in.SessionAffinity, &out.Spec.SessionAffinity, 0); err != nil { return err } return nil }, func(in *newer.Node, out *Minion, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta.Labels, &out.Labels, 0); err != nil { return err } if err := s.Convert(&in.Status.Phase, &out.Status.Phase, 0); err != nil { return err } if err := s.Convert(&in.Status.Conditions, &out.Status.Conditions, 0); err != nil { return err } out.HostIP = in.Status.HostIP out.PodCIDR = in.Spec.PodCIDR out.ExternalID = in.Spec.ExternalID return s.Convert(&in.Spec.Capacity, &out.NodeResources.Capacity, 0) }, func(in *Minion, out *newer.Node, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil { return err } if err := s.Convert(&in.Status.Phase, &out.Status.Phase, 0); err != nil { return err } if err := s.Convert(&in.Status.Conditions, &out.Status.Conditions, 0); err != nil { return err } out.Status.HostIP = in.HostIP out.Spec.PodCIDR = in.PodCIDR out.Spec.ExternalID = in.ExternalID return s.Convert(&in.NodeResources.Capacity, &out.Spec.Capacity, 0) }, func(in *newer.LimitRange, out *LimitRange, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { return err } return nil }, func(in *LimitRange, out *newer.LimitRange, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { return err } return nil }, func(in *Namespace, out *newer.Namespace, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil { return err } return nil }, func(in *newer.LimitRangeSpec, out *LimitRangeSpec, s conversion.Scope) error { *out = LimitRangeSpec{} out.Limits = make([]LimitRangeItem, len(in.Limits), len(in.Limits)) for i := range in.Limits { if err := s.Convert(&in.Limits[i], &out.Limits[i], 0); err != nil { return err } } return nil }, func(in *LimitRangeSpec, out *newer.LimitRangeSpec, s conversion.Scope) error { *out = newer.LimitRangeSpec{} out.Limits = make([]newer.LimitRangeItem, len(in.Limits), len(in.Limits)) for i := range in.Limits { if err := s.Convert(&in.Limits[i], &out.Limits[i], 0); err != nil { return err } } return nil }, func(in *newer.LimitRangeItem, out *LimitRangeItem, s conversion.Scope) error { *out = LimitRangeItem{} out.Type = LimitType(in.Type) if err := s.Convert(&in.Max, &out.Max, 0); err != nil { return err } if err := s.Convert(&in.Min, &out.Min, 0); err != nil { return err } return nil }, func(in *LimitRangeItem, out *newer.LimitRangeItem, s conversion.Scope) error { *out = newer.LimitRangeItem{} out.Type = newer.LimitType(in.Type) if err := s.Convert(&in.Max, &out.Max, 0); err != nil { return err } if err := s.Convert(&in.Min, &out.Min, 0); err != nil { return err } return nil }, func(in *newer.ResourceQuota, out *ResourceQuota, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.Status, 0); err != nil { return err } return nil }, func(in *ResourceQuota, out *newer.ResourceQuota, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.Status, 0); err != nil { return err } return nil }, func(in *newer.ResourceQuotaUsage, out *ResourceQuotaUsage, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.Status, 0); err != nil { return err } return nil }, func(in *ResourceQuotaUsage, out *newer.ResourceQuotaUsage, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.Status, 0); err != nil { return err } return nil }, func(in *newer.ResourceQuotaSpec, out *ResourceQuotaSpec, s conversion.Scope) error { *out = ResourceQuotaSpec{} if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil { return err } return nil }, func(in *ResourceQuotaSpec, out *newer.ResourceQuotaSpec, s conversion.Scope) error { *out = newer.ResourceQuotaSpec{} if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil { return err } return nil }, func(in *newer.ResourceQuotaStatus, out *ResourceQuotaStatus, s conversion.Scope) error { *out = ResourceQuotaStatus{} if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil { return err } if err := s.Convert(&in.Used, &out.Used, 0); err != nil { return err } return nil }, func(in *ResourceQuotaStatus, out *newer.ResourceQuotaStatus, s conversion.Scope) error { *out = newer.ResourceQuotaStatus{} if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil { return err } if err := s.Convert(&in.Used, &out.Used, 0); err != nil { return err } return nil }, // Object ID <-> Name // TODO: amend the conversion package to allow overriding specific fields. func(in *ObjectReference, out *newer.ObjectReference, s conversion.Scope) error { out.Kind = in.Kind out.Namespace = in.Namespace out.Name = in.ID out.UID = in.UID out.APIVersion = in.APIVersion out.ResourceVersion = in.ResourceVersion out.FieldPath = in.FieldPath return nil }, func(in *newer.ObjectReference, out *ObjectReference, s conversion.Scope) error { out.Kind = in.Kind out.Namespace = in.Namespace out.ID = in.Name out.UID = in.UID out.APIVersion = in.APIVersion out.ResourceVersion = in.ResourceVersion out.FieldPath = in.FieldPath return nil }, // Event Source <-> Source.Component // Event Host <-> Source.Host // TODO: remove this when it becomes possible to specify a field name conversion on a specific type func(in *newer.Event, out *Event, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } out.Reason = in.Reason out.Message = in.Message out.Source = in.Source.Component out.Host = in.Source.Host out.Timestamp = in.FirstTimestamp out.FirstTimestamp = in.FirstTimestamp out.LastTimestamp = in.LastTimestamp out.Count = in.Count return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0) }, func(in *Event, out *newer.Event, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } out.Reason = in.Reason out.Message = in.Message out.Source.Component = in.Source out.Source.Host = in.Host if in.FirstTimestamp.IsZero() { // Assume this is an old event that does not specify FirstTimestamp/LastTimestamp/Count out.FirstTimestamp = in.Timestamp out.LastTimestamp = in.Timestamp out.Count = 1 } else { out.FirstTimestamp = in.FirstTimestamp out.LastTimestamp = in.LastTimestamp out.Count = in.Count } return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0) }, // This is triggered for the Memory field of Container. func(in *int64, out *resource.Quantity, s conversion.Scope) error { out.Set(*in) out.Format = resource.BinarySI return nil }, func(in *resource.Quantity, out *int64, s conversion.Scope) error { *out = in.Value() return nil }, // This is triggered by the CPU field of Container. // Note that if we add other int/Quantity conversions my // simple hack (int64=Value(), int=MilliValue()) here won't work. func(in *int, out *resource.Quantity, s conversion.Scope) error { out.SetMilli(int64(*in)) out.Format = resource.DecimalSI return nil }, func(in *resource.Quantity, out *int, s conversion.Scope) error { *out = int(in.MilliValue()) return nil }, // Convert resource lists. func(in *ResourceList, out *newer.ResourceList, s conversion.Scope) error { *out = newer.ResourceList{} for k, v := range *in { fv, err := strconv.ParseFloat(v.String(), 64) if err != nil { return &newer.ConversionError{ In: in, Out: out, Message: fmt.Sprintf("value '%v' of '%v': %v", v, k, err), } } if k == ResourceCPU { (*out)[newer.ResourceCPU] = *resource.NewMilliQuantity(int64(fv*1000), resource.DecimalSI) } else { (*out)[newer.ResourceName(k)] = *resource.NewQuantity(int64(fv), resource.BinarySI) } } return nil }, func(in *newer.ResourceList, out *ResourceList, s conversion.Scope) error { *out = ResourceList{} for k, v := range *in { if k == newer.ResourceCPU { (*out)[ResourceCPU] = util.NewIntOrStringFromString(fmt.Sprintf("%v", float64(v.MilliValue())/1000)) } else { (*out)[ResourceName(k)] = util.NewIntOrStringFromInt(int(v.Value())) } } return nil }, // VolumeSource's HostDir is deprecated in favor of HostPath. // TODO: It would be great if I could just map field names to // convert or else maybe say "convert all members of this // struct" and then fix up only the stuff that changed. func(in *newer.VolumeSource, out *VolumeSource, s conversion.Scope) error { if err := s.Convert(&in.EmptyDir, &out.EmptyDir, 0); err != nil { return err } if err := s.Convert(&in.GitRepo, &out.GitRepo, 0); err != nil { return err } if err := s.Convert(&in.GCEPersistentDisk, &out.GCEPersistentDisk, 0); err != nil { return err } if err := s.Convert(&in.HostPath, &out.HostDir, 0); err != nil { return err } if err := s.Convert(&in.Secret, &out.Secret, 0); err != nil { return err } return nil }, func(in *VolumeSource, out *newer.VolumeSource, s conversion.Scope) error { if err := s.Convert(&in.EmptyDir, &out.EmptyDir, 0); err != nil { return err } if err := s.Convert(&in.GitRepo, &out.GitRepo, 0); err != nil { return err } if err := s.Convert(&in.GCEPersistentDisk, &out.GCEPersistentDisk, 0); err != nil { return err } if err := s.Convert(&in.HostDir, &out.HostPath, 0); err != nil { return err } if err := s.Convert(&in.Secret, &out.Secret, 0); err != nil { return err } return nil }, func(in *newer.PullPolicy, out *PullPolicy, s conversion.Scope) error { switch *in { case newer.PullAlways: *out = PullAlways case newer.PullNever: *out = PullNever case newer.PullIfNotPresent: *out = PullIfNotPresent case "": *out = "" default: // Let unknown values through - they will get caught by validation *out = PullPolicy(*in) } return nil }, func(in *PullPolicy, out *newer.PullPolicy, s conversion.Scope) error { switch *in { case PullAlways: *out = newer.PullAlways case PullNever: *out = newer.PullNever case PullIfNotPresent: *out = newer.PullIfNotPresent case "": *out = "" default: // Let unknown values through - they will get caught by validation *out = newer.PullPolicy(*in) } return nil }, func(in *newer.Probe, out *LivenessProbe, s conversion.Scope) error { if err := s.Convert(&in.Exec, &out.Exec, 0); err != nil { return err } if err := s.Convert(&in.HTTPGet, &out.HTTPGet, 0); err != nil { return err } if err := s.Convert(&in.TCPSocket, &out.TCPSocket, 0); err != nil { return err } out.InitialDelaySeconds = in.InitialDelaySeconds out.TimeoutSeconds = in.TimeoutSeconds return nil }, func(in *LivenessProbe, out *newer.Probe, s conversion.Scope) error { if err := s.Convert(&in.Exec, &out.Exec, 0); err != nil { return err } if err := s.Convert(&in.HTTPGet, &out.HTTPGet, 0); err != nil { return err } if err := s.Convert(&in.TCPSocket, &out.TCPSocket, 0); err != nil { return err } out.InitialDelaySeconds = in.InitialDelaySeconds out.TimeoutSeconds = in.TimeoutSeconds return nil }, func(in *newer.Endpoints, out *Endpoints, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Protocol, &out.Protocol, 0); err != nil { return err } for i := range in.Endpoints { ep := &in.Endpoints[i] out.Endpoints = append(out.Endpoints, net.JoinHostPort(ep.IP, strconv.Itoa(ep.Port))) } return nil }, func(in *Endpoints, out *newer.Endpoints, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Protocol, &out.Protocol, 0); err != nil { return err } for i := range in.Endpoints { out.Endpoints = append(out.Endpoints, newer.Endpoint{}) ep := &out.Endpoints[i] host, port, err := net.SplitHostPort(in.Endpoints[i]) if err != nil { return err } ep.IP = host pn, err := strconv.Atoi(port) if err != nil { return err } ep.Port = pn } return nil }, func(in *newer.NodeCondition, out *NodeCondition, s conversion.Scope) error { if err := s.Convert(&in.Type, &out.Kind, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.Status, 0); err != nil { return err } if err := s.Convert(&in.LastProbeTime, &out.LastProbeTime, 0); err != nil { return err } if err := s.Convert(&in.LastTransitionTime, &out.LastTransitionTime, 0); err != nil { return err } if err := s.Convert(&in.Reason, &out.Reason, 0); err != nil { return err } if err := s.Convert(&in.Message, &out.Message, 0); err != nil { return err } return nil }, func(in *NodeCondition, out *newer.NodeCondition, s conversion.Scope) error { if err := s.Convert(&in.Kind, &out.Type, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.Status, 0); err != nil { return err } if err := s.Convert(&in.LastProbeTime, &out.LastProbeTime, 0); err != nil { return err } if err := s.Convert(&in.LastTransitionTime, &out.LastTransitionTime, 0); err != nil { return err } if err := s.Convert(&in.Reason, &out.Reason, 0); err != nil { return err } if err := s.Convert(&in.Message, &out.Message, 0); err != nil { return err } return nil }, func(in *newer.NodeConditionType, out *NodeConditionKind, s conversion.Scope) error { switch *in { case newer.NodeReachable: *out = NodeReachable break case newer.NodeReady: *out = NodeReady break case "": *out = "" default: *out = NodeConditionKind(*in) break } return nil }, func(in *NodeConditionKind, out *newer.NodeConditionType, s conversion.Scope) error { switch *in { case NodeReachable: *out = newer.NodeReachable break case NodeReady: *out = newer.NodeReady break case "": *out = "" default: *out = newer.NodeConditionType(*in) break } return nil }, func(in *newer.PodCondition, out *PodCondition, s conversion.Scope) error { if err := s.Convert(&in.Type, &out.Kind, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.Status, 0); err != nil { return err } return nil }, func(in *PodCondition, out *newer.PodCondition, s conversion.Scope) error { if err := s.Convert(&in.Kind, &out.Type, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.Status, 0); err != nil { return err } return nil }, func(in *newer.PodConditionType, out *PodConditionKind, s conversion.Scope) error { switch *in { case newer.PodReady: *out = PodReady break case "": *out = "" default: *out = PodConditionKind(*in) break } return nil }, func(in *PodConditionKind, out *newer.PodConditionType, s conversion.Scope) error { switch *in { case PodReady: *out = newer.PodReady break case "": *out = "" default: *out = newer.PodConditionType(*in) break } return nil }, ) if err != nil { // If one of the conversion functions is malformed, detect it immediately. panic(err) } }
func TestMonitorNodeStatusUpdateStatus(t *testing.T) { fakeNow := util.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC) table := []struct { fakeNodeHandler *FakeNodeHandler timeToPass time.Duration newNodeStatus api.NodeStatus expectedEvictPods bool expectedRequestCount int expectedNodes []*api.Node }{ // Node created long time ago, without status: // Expect Unknown status posted from node controller. { fakeNodeHandler: &FakeNodeHandler{ Existing: []*api.Node{ { ObjectMeta: api.ObjectMeta{ Name: "node0", CreationTimestamp: util.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC), }, }, }, Fake: testclient.NewSimpleFake(&api.PodList{Items: []api.Pod{*newPod("pod0", "node0")}}), }, expectedRequestCount: 2, // List+Update expectedNodes: []*api.Node{ { ObjectMeta: api.ObjectMeta{ Name: "node0", CreationTimestamp: util.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC), }, Status: api.NodeStatus{ Conditions: []api.NodeCondition{ { Type: api.NodeReady, Status: api.ConditionUnknown, Reason: fmt.Sprintf("Kubelet never posted node status."), LastHeartbeatTime: util.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC), LastTransitionTime: fakeNow, }, }, }, }, }, }, // Node created recently, without status. // Expect no action from node controller (within startup grace period). { fakeNodeHandler: &FakeNodeHandler{ Existing: []*api.Node{ { ObjectMeta: api.ObjectMeta{ Name: "node0", CreationTimestamp: fakeNow, }, }, }, Fake: testclient.NewSimpleFake(&api.PodList{Items: []api.Pod{*newPod("pod0", "node0")}}), }, expectedRequestCount: 1, // List expectedNodes: nil, }, // Node created long time ago, with status updated by kubelet exceeds grace period. // Expect Unknown status posted from node controller. { fakeNodeHandler: &FakeNodeHandler{ Existing: []*api.Node{ { ObjectMeta: api.ObjectMeta{ Name: "node0", CreationTimestamp: util.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC), }, Status: api.NodeStatus{ Conditions: []api.NodeCondition{ { Type: api.NodeReady, Status: api.ConditionTrue, // Node status hasn't been updated for 1hr. LastHeartbeatTime: util.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC), LastTransitionTime: util.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC), }, }, Capacity: api.ResourceList{ api.ResourceName(api.ResourceCPU): resource.MustParse("10"), api.ResourceName(api.ResourceMemory): resource.MustParse("10G"), }, }, Spec: api.NodeSpec{ ExternalID: "node0", }, }, }, Fake: testclient.NewSimpleFake(&api.PodList{Items: []api.Pod{*newPod("pod0", "node0")}}), }, expectedRequestCount: 3, // (List+)List+Update timeToPass: time.Hour, newNodeStatus: api.NodeStatus{ Conditions: []api.NodeCondition{ { Type: api.NodeReady, Status: api.ConditionTrue, // Node status hasn't been updated for 1hr. LastHeartbeatTime: util.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC), LastTransitionTime: util.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC), }, }, Capacity: api.ResourceList{ api.ResourceName(api.ResourceCPU): resource.MustParse("10"), api.ResourceName(api.ResourceMemory): resource.MustParse("10G"), }, }, expectedNodes: []*api.Node{ { ObjectMeta: api.ObjectMeta{ Name: "node0", CreationTimestamp: util.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC), }, Status: api.NodeStatus{ Conditions: []api.NodeCondition{ { Type: api.NodeReady, Status: api.ConditionUnknown, Reason: fmt.Sprintf("Kubelet stopped posting node status."), LastHeartbeatTime: util.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC), LastTransitionTime: util.Time{util.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC).Add(time.Hour)}, }, }, Capacity: api.ResourceList{ api.ResourceName(api.ResourceCPU): resource.MustParse("10"), api.ResourceName(api.ResourceMemory): resource.MustParse("10G"), }, }, Spec: api.NodeSpec{ ExternalID: "node0", }, }, }, }, // Node created long time ago, with status updated recently. // Expect no action from node controller (within monitor grace period). { fakeNodeHandler: &FakeNodeHandler{ Existing: []*api.Node{ { ObjectMeta: api.ObjectMeta{ Name: "node0", CreationTimestamp: util.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC), }, Status: api.NodeStatus{ Conditions: []api.NodeCondition{ { Type: api.NodeReady, Status: api.ConditionTrue, // Node status has just been updated. LastHeartbeatTime: fakeNow, LastTransitionTime: fakeNow, }, }, Capacity: api.ResourceList{ api.ResourceName(api.ResourceCPU): resource.MustParse("10"), api.ResourceName(api.ResourceMemory): resource.MustParse("10G"), }, }, Spec: api.NodeSpec{ ExternalID: "node0", }, }, }, Fake: testclient.NewSimpleFake(&api.PodList{Items: []api.Pod{*newPod("pod0", "node0")}}), }, expectedRequestCount: 1, // List expectedNodes: nil, }, } for _, item := range table { nodeController := NewNodeController(nil, item.fakeNodeHandler, 5*time.Minute, NewPodEvictor(util.NewFakeRateLimiter()), testNodeMonitorGracePeriod, testNodeStartupGracePeriod, testNodeMonitorPeriod, nil, false) nodeController.now = func() util.Time { return fakeNow } if err := nodeController.monitorNodeStatus(); err != nil { t.Errorf("unexpected error: %v", err) } if item.timeToPass > 0 { nodeController.now = func() util.Time { return util.Time{Time: fakeNow.Add(item.timeToPass)} } item.fakeNodeHandler.Existing[0].Status = item.newNodeStatus if err := nodeController.monitorNodeStatus(); err != nil { t.Errorf("unexpected error: %v", err) } } if item.expectedRequestCount != item.fakeNodeHandler.RequestCount { t.Errorf("expected %v call, but got %v.", item.expectedRequestCount, item.fakeNodeHandler.RequestCount) } if len(item.fakeNodeHandler.UpdatedNodes) > 0 && !api.Semantic.DeepEqual(item.expectedNodes, item.fakeNodeHandler.UpdatedNodes) { t.Errorf("expected nodes %+v, got %+v", item.expectedNodes[0], item.fakeNodeHandler.UpdatedNodes[0]) } } }
// FindBestMatchForClaim is a convenience method that finds a volume by the claim's AccessModes and requests for Storage func (pvIndex *persistentVolumeOrderedIndex) FindBestMatchForClaim(claim *api.PersistentVolumeClaim) (*api.PersistentVolume, error) { return pvIndex.FindByAccessModesAndStorageCapacity(claim.Spec.AccessModes, claim.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)]) }
func TestExampleObjects(t *testing.T) { scenarios := map[string]struct { expected interface{} }{ "claims/claim-01.yaml": { expected: &api.PersistentVolumeClaim{ Spec: api.PersistentVolumeClaimSpec{ AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("3Gi"), }, }, }, }, }, "claims/claim-02.yaml": { expected: &api.PersistentVolumeClaim{ Spec: api.PersistentVolumeClaimSpec{ AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("8Gi"), }, }, }, }, }, "volumes/local-01.yaml": { expected: &api.PersistentVolume{ Spec: api.PersistentVolumeSpec{ AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("10Gi"), }, PersistentVolumeSource: api.PersistentVolumeSource{ HostPath: &api.HostPathVolumeSource{ Path: "/tmp/data01", }, }, }, }, }, "volumes/local-02.yaml": { expected: &api.PersistentVolume{ Spec: api.PersistentVolumeSpec{ AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, Capacity: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("8Gi"), }, PersistentVolumeSource: api.PersistentVolumeSource{ HostPath: &api.HostPathVolumeSource{ Path: "/tmp/data02", }, }, PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimRecycle, }, }, }, } for name, scenario := range scenarios { o := testclient.NewObjects(api.Scheme, api.Scheme) if err := testclient.AddObjectsFromPath("../../examples/persistent-volumes/"+name, o, api.Scheme); err != nil { t.Fatal(err) } client := &testclient.Fake{ReactFn: testclient.ObjectReaction(o, latest.RESTMapper)} if reflect.TypeOf(scenario.expected) == reflect.TypeOf(&api.PersistentVolumeClaim{}) { pvc, err := client.PersistentVolumeClaims("ns").Get("doesntmatter") if err != nil { t.Errorf("Error retrieving object: %v", err) } expected := scenario.expected.(*api.PersistentVolumeClaim) if pvc.Spec.AccessModes[0] != expected.Spec.AccessModes[0] { t.Errorf("Unexpected mismatch. Got %v wanted %v", pvc.Spec.AccessModes[0], expected.Spec.AccessModes[0]) } aQty := pvc.Spec.Resources.Requests[api.ResourceStorage] bQty := expected.Spec.Resources.Requests[api.ResourceStorage] aSize := aQty.Value() bSize := bQty.Value() if aSize != bSize { t.Errorf("Unexpected mismatch. Got %v wanted %v", aSize, bSize) } } if reflect.TypeOf(scenario.expected) == reflect.TypeOf(&api.PersistentVolume{}) { pv, err := client.PersistentVolumes().Get("doesntmatter") if err != nil { t.Errorf("Error retrieving object: %v", err) } expected := scenario.expected.(*api.PersistentVolume) if pv.Spec.AccessModes[0] != expected.Spec.AccessModes[0] { t.Errorf("Unexpected mismatch. Got %v wanted %v", pv.Spec.AccessModes[0], expected.Spec.AccessModes[0]) } aQty := pv.Spec.Capacity[api.ResourceStorage] bQty := expected.Spec.Capacity[api.ResourceStorage] aSize := aQty.Value() bSize := bQty.Value() if aSize != bSize { t.Errorf("Unexpected mismatch. Got %v wanted %v", aSize, bSize) } if pv.Spec.HostPath.Path != expected.Spec.HostPath.Path { t.Errorf("Unexpected mismatch. Got %v wanted %v", pv.Spec.HostPath.Path, expected.Spec.HostPath.Path) } } } }
func init() { // Our TypeMeta was split into two different structs. newer.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", newer.TypeMeta{}, "TypeMeta") newer.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", newer.ObjectMeta{}, "ObjectMeta") newer.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", newer.ListMeta{}, "ListMeta") newer.Scheme.AddStructFieldConversion(newer.TypeMeta{}, "TypeMeta", TypeMeta{}, "TypeMeta") newer.Scheme.AddStructFieldConversion(newer.ObjectMeta{}, "ObjectMeta", TypeMeta{}, "TypeMeta") newer.Scheme.AddStructFieldConversion(newer.ListMeta{}, "ListMeta", TypeMeta{}, "TypeMeta") // TODO: scope this to a specific type once that becomes available and remove the Event conversion functions below // newer.Scheme.AddStructFieldConversion(string(""), "Status", string(""), "Condition") // newer.Scheme.AddStructFieldConversion(string(""), "Condition", string(""), "Status") err := newer.Scheme.AddConversionFuncs( // TypeMeta must be split into two objects func(in *newer.TypeMeta, out *TypeMeta, s conversion.Scope) error { out.Kind = in.Kind out.APIVersion = in.APIVersion return nil }, func(in *TypeMeta, out *newer.TypeMeta, s conversion.Scope) error { out.Kind = in.Kind out.APIVersion = in.APIVersion return nil }, // ListMeta must be converted to TypeMeta func(in *newer.ListMeta, out *TypeMeta, s conversion.Scope) error { out.SelfLink = in.SelfLink if len(in.ResourceVersion) > 0 { v, err := strconv.ParseUint(in.ResourceVersion, 10, 64) if err != nil { return err } out.ResourceVersion = v } return nil }, func(in *TypeMeta, out *newer.ListMeta, s conversion.Scope) error { out.SelfLink = in.SelfLink if in.ResourceVersion != 0 { out.ResourceVersion = strconv.FormatUint(in.ResourceVersion, 10) } else { out.ResourceVersion = "" } return nil }, // ObjectMeta must be converted to TypeMeta func(in *newer.ObjectMeta, out *TypeMeta, s conversion.Scope) error { out.Namespace = in.Namespace out.ID = in.Name out.UID = in.UID out.CreationTimestamp = in.CreationTimestamp out.SelfLink = in.SelfLink if len(in.ResourceVersion) > 0 { v, err := strconv.ParseUint(in.ResourceVersion, 10, 64) if err != nil { return err } out.ResourceVersion = v } return s.Convert(&in.Annotations, &out.Annotations, 0) }, func(in *TypeMeta, out *newer.ObjectMeta, s conversion.Scope) error { out.Namespace = in.Namespace out.Name = in.ID out.UID = in.UID out.CreationTimestamp = in.CreationTimestamp out.SelfLink = in.SelfLink if in.ResourceVersion != 0 { out.ResourceVersion = strconv.FormatUint(in.ResourceVersion, 10) } else { out.ResourceVersion = "" } return s.Convert(&in.Annotations, &out.Annotations, 0) }, // EnvVar's Key is deprecated in favor of Name. func(in *newer.EnvVar, out *EnvVar, s conversion.Scope) error { out.Value = in.Value out.Key = in.Name out.Name = in.Name return nil }, func(in *EnvVar, out *newer.EnvVar, s conversion.Scope) error { out.Value = in.Value if in.Name != "" { out.Name = in.Name } else { out.Name = in.Key } return nil }, // Path & MountType are deprecated. func(in *newer.VolumeMount, out *VolumeMount, s conversion.Scope) error { out.Name = in.Name out.ReadOnly = in.ReadOnly out.MountPath = in.MountPath out.Path = in.MountPath out.MountType = "" // MountType is ignored. return nil }, func(in *VolumeMount, out *newer.VolumeMount, s conversion.Scope) error { out.Name = in.Name out.ReadOnly = in.ReadOnly if in.MountPath == "" { out.MountPath = in.Path } else { out.MountPath = in.MountPath } return nil }, // MinionList.Items had a wrong name in v1beta1 func(in *newer.NodeList, out *MinionList, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Items, &out.Items, 0); err != nil { return err } out.Minions = out.Items return nil }, func(in *MinionList, out *newer.NodeList, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil { return err } if len(in.Items) == 0 { if err := s.Convert(&in.Minions, &out.Items, 0); err != nil { return err } } else { if err := s.Convert(&in.Items, &out.Items, 0); err != nil { return err } } return nil }, func(in *newer.PodStatus, out *PodState, s conversion.Scope) error { if err := s.Convert(&in.Phase, &out.Status, 0); err != nil { return err } if err := s.Convert(&in.Info, &out.Info, 0); err != nil { return err } out.Message = in.Message out.Host = in.Host out.HostIP = in.HostIP out.PodIP = in.PodIP return nil }, func(in *PodState, out *newer.PodStatus, s conversion.Scope) error { if err := s.Convert(&in.Status, &out.Phase, 0); err != nil { return err } if err := s.Convert(&in.Info, &out.Info, 0); err != nil { return err } out.Message = in.Message out.Host = in.Host out.HostIP = in.HostIP out.PodIP = in.PodIP return nil }, func(in *newer.PodSpec, out *PodState, s conversion.Scope) error { if err := s.Convert(&in, &out.Manifest, 0); err != nil { return err } out.Host = in.Host return nil }, func(in *PodState, out *newer.PodSpec, s conversion.Scope) error { if err := s.Convert(&in.Manifest, &out, 0); err != nil { return err } out.Host = in.Host return nil }, // Convert all to the new PodPhase constants func(in *newer.PodPhase, out *PodStatus, s conversion.Scope) error { switch *in { case "": *out = "" case newer.PodPending: *out = PodWaiting case newer.PodRunning: *out = PodRunning case newer.PodSucceeded: *out = PodSucceeded case newer.PodFailed: *out = PodTerminated case newer.PodUnknown: *out = PodUnknown default: return &newer.ConversionError{ In: in, Out: out, Message: "The string provided is not a valid PodPhase constant value", } } return nil }, func(in *PodStatus, out *newer.PodPhase, s conversion.Scope) error { switch *in { case "": *out = "" case PodWaiting: *out = newer.PodPending case PodRunning: *out = newer.PodRunning case PodTerminated: // Older API versions did not contain enough info to map to PodSucceeded *out = newer.PodFailed case PodSucceeded: *out = newer.PodSucceeded case PodUnknown: *out = newer.PodUnknown default: return &newer.ConversionError{ In: in, Out: out, Message: "The string provided is not a valid PodPhase constant value", } } return nil }, // Convert all the standard objects func(in *newer.Pod, out *Pod, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } // TODO: Change this to use in.ObjectMeta.Labels. if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } if err := s.Convert(&in.Spec, &out.DesiredState.Manifest, 0); err != nil { return err } out.DesiredState.Host = in.Spec.Host if err := s.Convert(&in.Status, &out.CurrentState, 0); err != nil { return err } if err := s.Convert(&in.Spec.NodeSelector, &out.NodeSelector, 0); err != nil { return err } return nil }, func(in *Pod, out *newer.Pod, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } if err := s.Convert(&in.DesiredState.Manifest, &out.Spec, 0); err != nil { return err } out.Spec.Host = in.DesiredState.Host if err := s.Convert(&in.CurrentState, &out.Status, 0); err != nil { return err } if err := s.Convert(&in.NodeSelector, &out.Spec.NodeSelector, 0); err != nil { return err } return nil }, func(in *newer.PodStatusResult, out *PodStatusResult, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.State, 0); err != nil { return err } return nil }, func(in *PodStatusResult, out *newer.PodStatusResult, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.State, &out.Status, 0); err != nil { return err } return nil }, func(in *newer.ReplicationController, out *ReplicationController, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } if err := s.Convert(&in.Spec, &out.DesiredState, 0); err != nil { return err } out.CurrentState.Replicas = in.Status.Replicas return nil }, func(in *ReplicationController, out *newer.ReplicationController, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } if err := s.Convert(&in.DesiredState, &out.Spec, 0); err != nil { return err } out.Status.Replicas = in.CurrentState.Replicas return nil }, func(in *newer.ReplicationControllerSpec, out *ReplicationControllerState, s conversion.Scope) error { out.Replicas = in.Replicas if err := s.Convert(&in.Selector, &out.ReplicaSelector, 0); err != nil { return err } if in.TemplateRef != nil && in.Template == nil { return &newer.ConversionError{ In: in, Out: out, Message: "objects with a template ref cannot be converted to older objects, must populate template", } } if in.Template != nil { if err := s.Convert(in.Template, &out.PodTemplate, 0); err != nil { return err } } return nil }, func(in *ReplicationControllerState, out *newer.ReplicationControllerSpec, s conversion.Scope) error { out.Replicas = in.Replicas if err := s.Convert(&in.ReplicaSelector, &out.Selector, 0); err != nil { return err } out.Template = &newer.PodTemplateSpec{} if err := s.Convert(&in.PodTemplate, out.Template, 0); err != nil { return err } return nil }, func(in *newer.PodTemplateSpec, out *PodTemplate, s conversion.Scope) error { if err := s.Convert(&in.Spec, &out.DesiredState.Manifest, 0); err != nil { return err } out.DesiredState.Host = in.Spec.Host if err := s.Convert(&in.ObjectMeta.Labels, &out.Labels, 0); err != nil { return err } return nil }, func(in *PodTemplate, out *newer.PodTemplateSpec, s conversion.Scope) error { if err := s.Convert(&in.DesiredState.Manifest, &out.Spec, 0); err != nil { return err } out.Spec.Host = in.DesiredState.Host if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil { return err } return nil }, func(in *newer.PodSpec, out *BoundPod, s conversion.Scope) error { if err := s.Convert(&in, &out.Spec, 0); err != nil { return err } return nil }, func(in *BoundPod, out *newer.PodSpec, s conversion.Scope) error { if err := s.Convert(&in.Spec, &out, 0); err != nil { return err } return nil }, func(in *newer.PodSpec, out *ContainerManifest, s conversion.Scope) error { if err := s.Convert(&in.Volumes, &out.Volumes, 0); err != nil { return err } if err := s.Convert(&in.Containers, &out.Containers, 0); err != nil { return err } if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil { return err } out.DNSPolicy = DNSPolicy(in.DNSPolicy) out.Version = "v1beta2" return nil }, func(in *ContainerManifest, out *newer.PodSpec, s conversion.Scope) error { if err := s.Convert(&in.Volumes, &out.Volumes, 0); err != nil { return err } if err := s.Convert(&in.Containers, &out.Containers, 0); err != nil { return err } if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil { return err } out.DNSPolicy = newer.DNSPolicy(in.DNSPolicy) return nil }, func(in *newer.Service, out *Service, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } out.Port = in.Spec.Port out.Protocol = Protocol(in.Spec.Protocol) if err := s.Convert(&in.Spec.Selector, &out.Selector, 0); err != nil { return err } out.CreateExternalLoadBalancer = in.Spec.CreateExternalLoadBalancer out.PublicIPs = in.Spec.PublicIPs out.ContainerPort = in.Spec.ContainerPort out.PortalIP = in.Spec.PortalIP out.ProxyPort = in.Spec.ProxyPort if err := s.Convert(&in.Spec.SessionAffinity, &out.SessionAffinity, 0); err != nil { return err } return nil }, func(in *Service, out *newer.Service, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } out.Spec.Port = in.Port out.Spec.Protocol = newer.Protocol(in.Protocol) if err := s.Convert(&in.Selector, &out.Spec.Selector, 0); err != nil { return err } out.Spec.CreateExternalLoadBalancer = in.CreateExternalLoadBalancer out.Spec.PublicIPs = in.PublicIPs out.Spec.ContainerPort = in.ContainerPort out.Spec.PortalIP = in.PortalIP out.Spec.ProxyPort = in.ProxyPort if err := s.Convert(&in.SessionAffinity, &out.Spec.SessionAffinity, 0); err != nil { return err } return nil }, func(in *newer.Node, out *Minion, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta.Labels, &out.Labels, 0); err != nil { return err } if err := s.Convert(&in.Status.Phase, &out.Status.Phase, 0); err != nil { return err } if err := s.Convert(&in.Status.Conditions, &out.Status.Conditions, 0); err != nil { return err } out.HostIP = in.Status.HostIP return s.Convert(&in.Spec.Capacity, &out.NodeResources.Capacity, 0) }, func(in *Minion, out *newer.Node, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil { return err } if err := s.Convert(&in.Status.Phase, &out.Status.Phase, 0); err != nil { return err } if err := s.Convert(&in.Status.Conditions, &out.Status.Conditions, 0); err != nil { return err } out.Status.HostIP = in.HostIP return s.Convert(&in.NodeResources.Capacity, &out.Spec.Capacity, 0) }, // Object ID <-> Name // TODO: amend the conversion package to allow overriding specific fields. func(in *ObjectReference, out *newer.ObjectReference, s conversion.Scope) error { out.Kind = in.Kind out.Namespace = in.Namespace out.Name = in.ID out.UID = in.UID out.APIVersion = in.APIVersion out.ResourceVersion = in.ResourceVersion out.FieldPath = in.FieldPath return nil }, func(in *newer.ObjectReference, out *ObjectReference, s conversion.Scope) error { out.Kind = in.Kind out.Namespace = in.Namespace out.ID = in.Name out.UID = in.UID out.APIVersion = in.APIVersion out.ResourceVersion = in.ResourceVersion out.FieldPath = in.FieldPath return nil }, // Event Source <-> Source.Component // Event Host <-> Source.Host // TODO: remove this when it becomes possible to specify a field name conversion on a specific type func(in *newer.Event, out *Event, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } out.Reason = in.Reason out.Message = in.Message out.Source = in.Source.Component out.Host = in.Source.Host out.Timestamp = in.Timestamp return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0) }, func(in *Event, out *newer.Event, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } out.Reason = in.Reason out.Message = in.Message out.Source.Component = in.Source out.Source.Host = in.Host out.Timestamp = in.Timestamp return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0) }, // This is triggered for the Memory field of Container. func(in *int64, out *resource.Quantity, s conversion.Scope) error { out.Set(*in) out.Format = resource.BinarySI return nil }, func(in *resource.Quantity, out *int64, s conversion.Scope) error { *out = in.Value() return nil }, // This is triggered by the CPU field of Container. // Note that if we add other int/Quantity conversions my // simple hack (int64=Value(), int=MilliValue()) here won't work. func(in *int, out *resource.Quantity, s conversion.Scope) error { out.SetMilli(int64(*in)) out.Format = resource.DecimalSI return nil }, func(in *resource.Quantity, out *int, s conversion.Scope) error { *out = int(in.MilliValue()) return nil }, // Convert resource lists. func(in *ResourceList, out *newer.ResourceList, s conversion.Scope) error { *out = newer.ResourceList{} for k, v := range *in { fv, err := strconv.ParseFloat(v.String(), 64) if err != nil { return &newer.ConversionError{ In: in, Out: out, Message: fmt.Sprintf("value '%v' of '%v': %v", v, k, err), } } if k == ResourceCPU { (*out)[newer.ResourceCPU] = *resource.NewMilliQuantity(int64(fv*1000), resource.DecimalSI) } else { (*out)[newer.ResourceName(k)] = *resource.NewQuantity(int64(fv), resource.BinarySI) } } return nil }, func(in *newer.ResourceList, out *ResourceList, s conversion.Scope) error { *out = ResourceList{} for k, v := range *in { if k == newer.ResourceCPU { (*out)[ResourceCPU] = util.NewIntOrStringFromString(fmt.Sprintf("%v", float64(v.MilliValue())/1000)) } else { (*out)[ResourceName(k)] = util.NewIntOrStringFromInt(int(v.Value())) } } return nil }, // VolumeSource's HostDir is deprecated in favor of HostPath. // TODO: It would be great if I could just map field names to // convert or else maybe say "convert all members of this // struct" and then fix up only the stuff that changed. func(in *newer.VolumeSource, out *VolumeSource, s conversion.Scope) error { if err := s.Convert(&in.EmptyDir, &out.EmptyDir, 0); err != nil { return err } if err := s.Convert(&in.GitRepo, &out.GitRepo, 0); err != nil { return err } if err := s.Convert(&in.GCEPersistentDisk, &out.GCEPersistentDisk, 0); err != nil { return err } if err := s.Convert(&in.HostPath, &out.HostDir, 0); err != nil { return err } return nil }, func(in *VolumeSource, out *newer.VolumeSource, s conversion.Scope) error { if err := s.Convert(&in.EmptyDir, &out.EmptyDir, 0); err != nil { return err } if err := s.Convert(&in.GitRepo, &out.GitRepo, 0); err != nil { return err } if err := s.Convert(&in.GCEPersistentDisk, &out.GCEPersistentDisk, 0); err != nil { return err } if err := s.Convert(&in.HostDir, &out.HostPath, 0); err != nil { return err } return nil }, ) if err != nil { // If one of the conversion functions is malformed, detect it immediately. panic(err) } }
func addConversionFuncs() { // Our TypeMeta was split into two different structs. api.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", api.TypeMeta{}, "TypeMeta") api.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", api.ObjectMeta{}, "ObjectMeta") api.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", api.ListMeta{}, "ListMeta") api.Scheme.AddStructFieldConversion(api.TypeMeta{}, "TypeMeta", TypeMeta{}, "TypeMeta") api.Scheme.AddStructFieldConversion(api.ObjectMeta{}, "ObjectMeta", TypeMeta{}, "TypeMeta") api.Scheme.AddStructFieldConversion(api.ListMeta{}, "ListMeta", TypeMeta{}, "TypeMeta") api.Scheme.AddStructFieldConversion(api.Endpoints{}, "Endpoints", Endpoints{}, "Endpoints") // TODO: scope this to a specific type once that becomes available and remove the Event conversion functions below // api.Scheme.AddStructFieldConversion(string(""), "Status", string(""), "Condition") // api.Scheme.AddStructFieldConversion(string(""), "Condition", string(""), "Status") err := api.Scheme.AddConversionFuncs( // TypeMeta must be split into two objects func(in *api.TypeMeta, out *TypeMeta, s conversion.Scope) error { out.Kind = in.Kind out.APIVersion = in.APIVersion return nil }, func(in *TypeMeta, out *api.TypeMeta, s conversion.Scope) error { out.Kind = in.Kind out.APIVersion = in.APIVersion return nil }, // ListMeta must be converted to TypeMeta func(in *api.ListMeta, out *TypeMeta, s conversion.Scope) error { out.SelfLink = in.SelfLink if len(in.ResourceVersion) > 0 { v, err := strconv.ParseUint(in.ResourceVersion, 10, 64) if err != nil { return err } out.ResourceVersion = v } return nil }, func(in *TypeMeta, out *api.ListMeta, s conversion.Scope) error { out.SelfLink = in.SelfLink if in.ResourceVersion != 0 { out.ResourceVersion = strconv.FormatUint(in.ResourceVersion, 10) } else { out.ResourceVersion = "" } return nil }, // ObjectMeta must be converted to TypeMeta func(in *api.ObjectMeta, out *TypeMeta, s conversion.Scope) error { out.Namespace = in.Namespace out.ID = in.Name out.GenerateName = in.GenerateName out.UID = in.UID out.CreationTimestamp = in.CreationTimestamp out.DeletionTimestamp = in.DeletionTimestamp out.SelfLink = in.SelfLink if len(in.ResourceVersion) > 0 { v, err := strconv.ParseUint(in.ResourceVersion, 10, 64) if err != nil { return err } out.ResourceVersion = v } return s.Convert(&in.Annotations, &out.Annotations, 0) }, func(in *TypeMeta, out *api.ObjectMeta, s conversion.Scope) error { out.Namespace = in.Namespace out.Name = in.ID out.GenerateName = in.GenerateName out.UID = in.UID out.CreationTimestamp = in.CreationTimestamp out.DeletionTimestamp = in.DeletionTimestamp out.SelfLink = in.SelfLink if in.ResourceVersion != 0 { out.ResourceVersion = strconv.FormatUint(in.ResourceVersion, 10) } else { out.ResourceVersion = "" } return s.Convert(&in.Annotations, &out.Annotations, 0) }, // Convert all to the new PodPhase constants func(in *api.PodPhase, out *PodStatus, s conversion.Scope) error { switch *in { case "": *out = "" case api.PodPending: *out = PodWaiting case api.PodRunning: *out = PodRunning case api.PodSucceeded: *out = PodSucceeded case api.PodFailed: *out = PodTerminated case api.PodUnknown: *out = PodUnknown default: return &api.ConversionError{ In: in, Out: out, Message: "The string provided is not a valid PodPhase constant value", } } return nil }, func(in *PodStatus, out *api.PodPhase, s conversion.Scope) error { switch *in { case "": *out = "" case PodWaiting: *out = api.PodPending case PodRunning: *out = api.PodRunning case PodTerminated: // Older API versions did not contain enough info to map to PodSucceeded *out = api.PodFailed case PodSucceeded: *out = api.PodSucceeded case PodUnknown: *out = api.PodUnknown default: return &api.ConversionError{ In: in, Out: out, Message: "The string provided is not a valid PodPhase constant value", } } return nil }, // Convert all the standard objects func(in *api.Pod, out *Pod, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } // TODO: Change this to use in.ObjectMeta.Labels. if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } if err := s.Convert(&in.Spec, &out.DesiredState.Manifest, 0); err != nil { return err } out.DesiredState.Host = in.Spec.Host out.CurrentState.Host = in.Spec.Host out.ServiceAccount = in.Spec.ServiceAccount if err := s.Convert(&in.Status, &out.CurrentState, 0); err != nil { return err } if err := s.Convert(&in.Spec.NodeSelector, &out.NodeSelector, 0); err != nil { return err } return nil }, func(in *Pod, out *api.Pod, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } if err := s.Convert(&in.DesiredState.Manifest, &out.Spec, 0); err != nil { return err } out.Spec.ServiceAccount = in.ServiceAccount out.Spec.Host = in.DesiredState.Host if err := s.Convert(&in.CurrentState, &out.Status, 0); err != nil { return err } if err := s.Convert(&in.NodeSelector, &out.Spec.NodeSelector, 0); err != nil { return err } return nil }, func(in *api.ReplicationController, out *ReplicationController, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } if err := s.Convert(&in.Spec, &out.DesiredState, 0); err != nil { return err } out.CurrentState.Replicas = in.Status.Replicas return nil }, func(in *ReplicationController, out *api.ReplicationController, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } if err := s.Convert(&in.DesiredState, &out.Spec, 0); err != nil { return err } out.Status.Replicas = in.CurrentState.Replicas return nil }, func(in *api.ReplicationControllerSpec, out *ReplicationControllerState, s conversion.Scope) error { out.Replicas = in.Replicas if err := s.Convert(&in.Selector, &out.ReplicaSelector, 0); err != nil { return err } if in.TemplateRef != nil && in.Template == nil { return &api.ConversionError{ In: in, Out: out, Message: "objects with a template ref cannot be converted to older objects, must populate template", } } if in.Template != nil { if err := s.Convert(in.Template, &out.PodTemplate, 0); err != nil { return err } } return nil }, func(in *ReplicationControllerState, out *api.ReplicationControllerSpec, s conversion.Scope) error { out.Replicas = in.Replicas if err := s.Convert(&in.ReplicaSelector, &out.Selector, 0); err != nil { return err } out.Template = &api.PodTemplateSpec{} if err := s.Convert(&in.PodTemplate, out.Template, 0); err != nil { return err } return nil }, func(in *api.PodTemplateSpec, out *PodTemplate, s conversion.Scope) error { if err := s.Convert(&in.Spec, &out.DesiredState.Manifest, 0); err != nil { return err } out.DesiredState.Host = in.Spec.Host out.ServiceAccount = in.Spec.ServiceAccount if err := s.Convert(&in.Spec.NodeSelector, &out.NodeSelector, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta.Labels, &out.Labels, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta.Annotations, &out.Annotations, 0); err != nil { return err } return nil }, func(in *PodTemplate, out *api.PodTemplateSpec, s conversion.Scope) error { if err := s.Convert(&in.DesiredState.Manifest, &out.Spec, 0); err != nil { return err } out.Spec.Host = in.DesiredState.Host out.Spec.ServiceAccount = in.ServiceAccount if err := s.Convert(&in.NodeSelector, &out.Spec.NodeSelector, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil { return err } if err := s.Convert(&in.Annotations, &out.ObjectMeta.Annotations, 0); err != nil { return err } return nil }, // Converts internal Container to v1beta2.Container. // Fields 'CPU' and 'Memory' are not present in the internal Container object. // Hence the need for a custom conversion function. func(in *api.Container, out *Container, s conversion.Scope) error { if err := s.Convert(&in.Name, &out.Name, 0); err != nil { return err } if err := s.Convert(&in.Image, &out.Image, 0); err != nil { return err } if err := s.Convert(&in.Command, &out.Entrypoint, 0); err != nil { return err } if err := s.Convert(&in.Args, &out.Command, 0); err != nil { return err } if err := s.Convert(&in.WorkingDir, &out.WorkingDir, 0); err != nil { return err } if err := s.Convert(&in.Ports, &out.Ports, 0); err != nil { return err } if err := s.Convert(&in.Env, &out.Env, 0); err != nil { return err } if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil { return err } if err := s.Convert(in.Resources.Limits.Cpu(), &out.CPU, 0); err != nil { return err } if err := s.Convert(in.Resources.Limits.Memory(), &out.Memory, 0); err != nil { return err } if err := s.Convert(&in.VolumeMounts, &out.VolumeMounts, 0); err != nil { return err } if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil { return err } if err := s.Convert(&in.ReadinessProbe, &out.ReadinessProbe, 0); err != nil { return err } if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil { return err } if err := s.Convert(&in.TerminationMessagePath, &out.TerminationMessagePath, 0); err != nil { return err } if err := s.Convert(&in.ImagePullPolicy, &out.ImagePullPolicy, 0); err != nil { return err } if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil { return err } // now that we've converted set the container field from security context if out.SecurityContext != nil && out.SecurityContext.Privileged != nil { out.Privileged = *out.SecurityContext.Privileged } // now that we've converted set the container field from security context if out.SecurityContext != nil && out.SecurityContext.Capabilities != nil { out.Capabilities = *out.SecurityContext.Capabilities } return nil }, // Internal API does not support CPU to be specified via an explicit field. // Hence it must be stored in Container.Resources. func(in *int, out *api.ResourceList, s conversion.Scope) error { if *in == 0 { return nil } quantity := resource.Quantity{} if err := s.Convert(in, &quantity, 0); err != nil { return err } (*out)[api.ResourceCPU] = quantity return nil }, // Internal API does not support Memory to be specified via an explicit field. // Hence it must be stored in Container.Resources. func(in *int64, out *api.ResourceList, s conversion.Scope) error { if *in == 0 { return nil } quantity := resource.Quantity{} if err := s.Convert(in, &quantity, 0); err != nil { return err } (*out)[api.ResourceMemory] = quantity return nil }, // Converts v1beta2.Container to internal api.Container. // Fields 'CPU' and 'Memory' are not present in the internal api.Container object. // Hence the need for a custom conversion function. func(in *Container, out *api.Container, s conversion.Scope) error { if err := s.Convert(&in.Name, &out.Name, 0); err != nil { return err } if err := s.Convert(&in.Image, &out.Image, 0); err != nil { return err } if err := s.Convert(&in.Command, &out.Args, 0); err != nil { return err } if err := s.Convert(&in.Entrypoint, &out.Command, 0); err != nil { return err } if err := s.Convert(&in.WorkingDir, &out.WorkingDir, 0); err != nil { return err } if err := s.Convert(&in.Ports, &out.Ports, 0); err != nil { return err } if err := s.Convert(&in.Env, &out.Env, 0); err != nil { return err } if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil { return err } if err := s.Convert(&in.CPU, &out.Resources.Limits, 0); err != nil { return err } if err := s.Convert(&in.Memory, &out.Resources.Limits, 0); err != nil { return err } if err := s.Convert(&in.VolumeMounts, &out.VolumeMounts, 0); err != nil { return err } if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil { return err } if err := s.Convert(&in.ReadinessProbe, &out.ReadinessProbe, 0); err != nil { return err } if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil { return err } if err := s.Convert(&in.TerminationMessagePath, &out.TerminationMessagePath, 0); err != nil { return err } if err := s.Convert(&in.ImagePullPolicy, &out.ImagePullPolicy, 0); err != nil { return err } if in.SecurityContext != nil { if in.SecurityContext.Capabilities != nil { if !reflect.DeepEqual(in.SecurityContext.Capabilities.Add, in.Capabilities.Add) || !reflect.DeepEqual(in.SecurityContext.Capabilities.Drop, in.Capabilities.Drop) { return fmt.Errorf("container capability settings do not match security context settings, cannot convert") } } if in.SecurityContext.Privileged != nil { if in.Privileged != *in.SecurityContext.Privileged { return fmt.Errorf("container privileged settings do not match security context settings, cannot convert") } } } if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil { return err } return nil }, func(in *api.PodSpec, out *ContainerManifest, s conversion.Scope) error { if err := s.Convert(&in.Volumes, &out.Volumes, 0); err != nil { return err } if err := s.Convert(&in.Containers, &out.Containers, 0); err != nil { return err } if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil { return err } if err := s.Convert(&in.ImagePullSecrets, &out.ImagePullSecrets, 0); err != nil { return err } if in.TerminationGracePeriodSeconds != nil { out.TerminationGracePeriodSeconds = new(int64) *out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds } if in.ActiveDeadlineSeconds != nil { out.ActiveDeadlineSeconds = new(int64) *out.ActiveDeadlineSeconds = *in.ActiveDeadlineSeconds } out.DNSPolicy = DNSPolicy(in.DNSPolicy) out.Version = "v1beta2" out.HostNetwork = in.HostNetwork return nil }, func(in *ContainerManifest, out *api.PodSpec, s conversion.Scope) error { if err := s.Convert(&in.Volumes, &out.Volumes, 0); err != nil { return err } if err := s.Convert(&in.Containers, &out.Containers, 0); err != nil { return err } if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil { return err } if err := s.Convert(&in.ImagePullSecrets, &out.ImagePullSecrets, 0); err != nil { return err } if in.TerminationGracePeriodSeconds != nil { out.TerminationGracePeriodSeconds = new(int64) *out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds } if in.ActiveDeadlineSeconds != nil { out.ActiveDeadlineSeconds = new(int64) *out.ActiveDeadlineSeconds = *in.ActiveDeadlineSeconds } out.DNSPolicy = api.DNSPolicy(in.DNSPolicy) out.HostNetwork = in.HostNetwork return nil }, func(in *api.PodStatus, out *PodState, s conversion.Scope) error { if err := s.Convert(&in.Phase, &out.Status, 0); err != nil { return err } if err := s.Convert(&in.ContainerStatuses, &out.Info, 0); err != nil { return err } if err := s.Convert(&in.Conditions, &out.Conditions, 0); err != nil { return err } out.Message = in.Message out.HostIP = in.HostIP out.PodIP = in.PodIP return nil }, func(in *PodState, out *api.PodStatus, s conversion.Scope) error { if err := s.Convert(&in.Status, &out.Phase, 0); err != nil { return err } if err := s.Convert(&in.Info, &out.ContainerStatuses, 0); err != nil { return err } if err := s.Convert(&in.Conditions, &out.Conditions, 0); err != nil { return err } out.Message = in.Message out.HostIP = in.HostIP out.PodIP = in.PodIP return nil }, func(in *[]api.ContainerStatus, out *PodInfo, s conversion.Scope) error { *out = make(map[string]ContainerStatus) for _, st := range *in { v := ContainerStatus{} if err := s.Convert(&st, &v, 0); err != nil { return err } (*out)[st.Name] = v } return nil }, func(in *PodInfo, out *[]api.ContainerStatus, s conversion.Scope) error { for k, v := range *in { st := api.ContainerStatus{} if err := s.Convert(&v, &st, 0); err != nil { return err } st.Name = k *out = append(*out, st) } return nil }, func(in *api.ContainerStatus, out *ContainerStatus, s conversion.Scope) error { if err := s.Convert(&in.State, &out.State, 0); err != nil { return err } if err := s.Convert(&in.LastTerminationState, &out.LastTerminationState, 0); err != nil { return err } if err := s.Convert(&in.Ready, &out.Ready, 0); err != nil { return err } if err := s.Convert(&in.RestartCount, &out.RestartCount, 0); err != nil { return err } if err := s.Convert(&in.Image, &out.Image, 0); err != nil { return err } if err := s.Convert(&in.ImageID, &out.ImageID, 0); err != nil { return err } if err := s.Convert(&in.ContainerID, &out.ContainerID, 0); err != nil { return err } return nil }, func(in *ContainerStatus, out *api.ContainerStatus, s conversion.Scope) error { if err := s.Convert(&in.State, &out.State, 0); err != nil { return err } if err := s.Convert(&in.LastTerminationState, &out.LastTerminationState, 0); err != nil { return err } if err := s.Convert(&in.Ready, &out.Ready, 0); err != nil { return err } if err := s.Convert(&in.RestartCount, &out.RestartCount, 0); err != nil { return err } if err := s.Convert(&in.Image, &out.Image, 0); err != nil { return err } if err := s.Convert(&in.ImageID, &out.ImageID, 0); err != nil { return err } if err := s.Convert(&in.ContainerID, &out.ContainerID, 0); err != nil { return err } return nil }, func(in *api.PodStatusResult, out *PodStatusResult, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.State, 0); err != nil { return err } return nil }, func(in *PodStatusResult, out *api.PodStatusResult, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.State, &out.Status, 0); err != nil { return err } return nil }, func(in *api.PodSpec, out *PodState, s conversion.Scope) error { if err := s.Convert(&in, &out.Manifest, 0); err != nil { return err } out.Host = in.Host return nil }, func(in *PodState, out *api.PodSpec, s conversion.Scope) error { if err := s.Convert(&in.Manifest, &out, 0); err != nil { return err } out.Host = in.Host return nil }, func(in *api.Service, out *Service, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } // Produce legacy fields. out.Protocol = ProtocolTCP if len(in.Spec.Ports) > 0 { out.PortName = in.Spec.Ports[0].Name out.Port = in.Spec.Ports[0].Port out.Protocol = Protocol(in.Spec.Ports[0].Protocol) out.ContainerPort = in.Spec.Ports[0].TargetPort } // Copy modern fields. for i := range in.Spec.Ports { out.Ports = append(out.Ports, ServicePort{ Name: in.Spec.Ports[i].Name, Port: in.Spec.Ports[i].Port, Protocol: Protocol(in.Spec.Ports[i].Protocol), ContainerPort: in.Spec.Ports[i].TargetPort, NodePort: in.Spec.Ports[i].NodePort, }) } if err := s.Convert(&in.Spec.Selector, &out.Selector, 0); err != nil { return err } out.PublicIPs = in.Spec.DeprecatedPublicIPs out.PortalIP = in.Spec.PortalIP if err := s.Convert(&in.Spec.SessionAffinity, &out.SessionAffinity, 0); err != nil { return err } if err := s.Convert(&in.Status.LoadBalancer, &out.LoadBalancerStatus, 0); err != nil { return err } if err := s.Convert(&in.Spec.Type, &out.Type, 0); err != nil { return err } out.CreateExternalLoadBalancer = in.Spec.Type == api.ServiceTypeLoadBalancer return nil }, func(in *Service, out *api.Service, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } if len(in.Ports) == 0 && in.Port != 0 { // Use legacy fields to produce modern fields. out.Spec.Ports = append(out.Spec.Ports, api.ServicePort{ Name: in.PortName, Port: in.Port, Protocol: api.Protocol(in.Protocol), TargetPort: in.ContainerPort, }) } else { // Use modern fields, ignore legacy. for i := range in.Ports { out.Spec.Ports = append(out.Spec.Ports, api.ServicePort{ Name: in.Ports[i].Name, Port: in.Ports[i].Port, Protocol: api.Protocol(in.Ports[i].Protocol), TargetPort: in.Ports[i].ContainerPort, NodePort: in.Ports[i].NodePort, }) } } if err := s.Convert(&in.Selector, &out.Spec.Selector, 0); err != nil { return err } out.Spec.DeprecatedPublicIPs = in.PublicIPs out.Spec.PortalIP = in.PortalIP if err := s.Convert(&in.SessionAffinity, &out.Spec.SessionAffinity, 0); err != nil { return err } if err := s.Convert(&in.LoadBalancerStatus, &out.Status.LoadBalancer, 0); err != nil { return err } typeIn := in.Type if typeIn == "" { if in.CreateExternalLoadBalancer { typeIn = ServiceTypeLoadBalancer } else { typeIn = ServiceTypeClusterIP } } if err := s.Convert(&typeIn, &out.Spec.Type, 0); err != nil { return err } return nil }, func(in *api.Node, out *Minion, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta.Labels, &out.Labels, 0); err != nil { return err } if err := s.Convert(&in.Status.Phase, &out.Status.Phase, 0); err != nil { return err } if err := s.Convert(&in.Status.Conditions, &out.Status.Conditions, 0); err != nil { return err } if err := s.Convert(&in.Status.Addresses, &out.Status.Addresses, 0); err != nil { return err } if err := s.Convert(&in.Status.NodeInfo, &out.Status.NodeInfo, 0); err != nil { return err } for _, address := range in.Status.Addresses { if address.Type == api.NodeLegacyHostIP { out.HostIP = address.Address } } out.PodCIDR = in.Spec.PodCIDR out.ExternalID = in.Spec.ExternalID out.Unschedulable = in.Spec.Unschedulable return s.Convert(&in.Status.Capacity, &out.NodeResources.Capacity, 0) }, func(in *Minion, out *api.Node, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil { return err } if err := s.Convert(&in.Status.Phase, &out.Status.Phase, 0); err != nil { return err } if err := s.Convert(&in.Status.Conditions, &out.Status.Conditions, 0); err != nil { return err } if err := s.Convert(&in.Status.Addresses, &out.Status.Addresses, 0); err != nil { return err } if err := s.Convert(&in.Status.NodeInfo, &out.Status.NodeInfo, 0); err != nil { return err } if in.HostIP != "" { api.AddToNodeAddresses(&out.Status.Addresses, api.NodeAddress{Type: api.NodeLegacyHostIP, Address: in.HostIP}) } out.Spec.PodCIDR = in.PodCIDR out.Spec.ExternalID = in.ExternalID out.Spec.Unschedulable = in.Unschedulable return s.Convert(&in.NodeResources.Capacity, &out.Status.Capacity, 0) }, func(in *api.LimitRange, out *LimitRange, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { return err } return nil }, func(in *LimitRange, out *api.LimitRange, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { return err } return nil }, func(in *Namespace, out *api.Namespace, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.Status, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil { return err } return nil }, func(in *api.LimitRangeSpec, out *LimitRangeSpec, s conversion.Scope) error { *out = LimitRangeSpec{} out.Limits = make([]LimitRangeItem, len(in.Limits), len(in.Limits)) for i := range in.Limits { if err := s.Convert(&in.Limits[i], &out.Limits[i], 0); err != nil { return err } } return nil }, func(in *LimitRangeSpec, out *api.LimitRangeSpec, s conversion.Scope) error { *out = api.LimitRangeSpec{} out.Limits = make([]api.LimitRangeItem, len(in.Limits), len(in.Limits)) for i := range in.Limits { if err := s.Convert(&in.Limits[i], &out.Limits[i], 0); err != nil { return err } } return nil }, func(in *api.LimitRangeItem, out *LimitRangeItem, s conversion.Scope) error { *out = LimitRangeItem{} out.Type = LimitType(in.Type) if err := s.Convert(&in.Max, &out.Max, 0); err != nil { return err } if err := s.Convert(&in.Min, &out.Min, 0); err != nil { return err } if err := s.Convert(&in.Default, &out.Default, 0); err != nil { return err } return nil }, func(in *LimitRangeItem, out *api.LimitRangeItem, s conversion.Scope) error { *out = api.LimitRangeItem{} out.Type = api.LimitType(in.Type) if err := s.Convert(&in.Max, &out.Max, 0); err != nil { return err } if err := s.Convert(&in.Min, &out.Min, 0); err != nil { return err } if err := s.Convert(&in.Default, &out.Default, 0); err != nil { return err } return nil }, func(in *api.ResourceQuota, out *ResourceQuota, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.Status, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } return nil }, func(in *ResourceQuota, out *api.ResourceQuota, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.Status, 0); err != nil { return err } if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil { return err } return nil }, func(in *api.ResourceQuotaSpec, out *ResourceQuotaSpec, s conversion.Scope) error { *out = ResourceQuotaSpec{} if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil { return err } return nil }, func(in *ResourceQuotaSpec, out *api.ResourceQuotaSpec, s conversion.Scope) error { *out = api.ResourceQuotaSpec{} if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil { return err } return nil }, func(in *api.ResourceQuotaStatus, out *ResourceQuotaStatus, s conversion.Scope) error { *out = ResourceQuotaStatus{} if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil { return err } if err := s.Convert(&in.Used, &out.Used, 0); err != nil { return err } return nil }, func(in *ResourceQuotaStatus, out *api.ResourceQuotaStatus, s conversion.Scope) error { *out = api.ResourceQuotaStatus{} if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil { return err } if err := s.Convert(&in.Used, &out.Used, 0); err != nil { return err } return nil }, // Object ID <-> Name // TODO: amend the conversion package to allow overriding specific fields. func(in *ObjectReference, out *api.ObjectReference, s conversion.Scope) error { out.Kind = in.Kind out.Namespace = in.Namespace out.Name = in.ID out.UID = in.UID out.APIVersion = in.APIVersion out.ResourceVersion = in.ResourceVersion out.FieldPath = in.FieldPath return nil }, func(in *api.ObjectReference, out *ObjectReference, s conversion.Scope) error { out.Kind = in.Kind out.Namespace = in.Namespace out.ID = in.Name out.UID = in.UID out.APIVersion = in.APIVersion out.ResourceVersion = in.ResourceVersion out.FieldPath = in.FieldPath return nil }, // Event Status <-> Condition // Event Source <-> Source.Component // Event Host <-> Source.Host // TODO: remove this when it becomes possible to specify a field name conversion on a specific type func(in *api.Event, out *Event, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } out.Reason = in.Reason out.Message = in.Message out.Source = in.Source.Component out.Host = in.Source.Host out.Timestamp = in.FirstTimestamp out.FirstTimestamp = in.FirstTimestamp out.LastTimestamp = in.LastTimestamp out.Count = in.Count return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0) }, func(in *Event, out *api.Event, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } out.Reason = in.Reason out.Message = in.Message out.Source.Component = in.Source out.Source.Host = in.Host if in.FirstTimestamp.IsZero() { // Assume this is an old event that does not specify FirstTimestamp/LastTimestamp/Count out.FirstTimestamp = in.Timestamp out.LastTimestamp = in.Timestamp out.Count = 1 } else { out.FirstTimestamp = in.FirstTimestamp out.LastTimestamp = in.LastTimestamp out.Count = in.Count } return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0) }, // This is triggered for the Memory field of Container. func(in *int64, out *resource.Quantity, s conversion.Scope) error { out.Set(*in) out.Format = resource.BinarySI return nil }, func(in *resource.Quantity, out *int64, s conversion.Scope) error { *out = in.Value() return nil }, // This is triggered by the CPU field of Container. // Note that if we add other int/Quantity conversions my // simple hack (int64=Value(), int=MilliValue()) here won't work. func(in *int, out *resource.Quantity, s conversion.Scope) error { out.SetMilli(int64(*in)) out.Format = resource.DecimalSI return nil }, func(in *resource.Quantity, out *int, s conversion.Scope) error { *out = int(in.MilliValue()) return nil }, // Convert resource lists. func(in *ResourceList, out *api.ResourceList, s conversion.Scope) error { *out = api.ResourceList{} for k, v := range *in { fv, err := strconv.ParseFloat(v.String(), 64) if err != nil { return &api.ConversionError{ In: in, Out: out, Message: fmt.Sprintf("value '%v' of '%v': %v", v, k, err), } } if k == ResourceCPU { (*out)[api.ResourceCPU] = *resource.NewMilliQuantity(int64(fv*1000), resource.DecimalSI) } else { (*out)[api.ResourceName(k)] = *resource.NewQuantity(int64(fv), resource.BinarySI) } } return nil }, func(in *api.ResourceList, out *ResourceList, s conversion.Scope) error { *out = ResourceList{} for k, v := range *in { if k == api.ResourceCPU { (*out)[ResourceCPU] = util.NewIntOrStringFromString(fmt.Sprintf("%v", float64(v.MilliValue())/1000)) } else { (*out)[ResourceName(k)] = util.NewIntOrStringFromInt(int(v.Value())) } } return nil }, func(in *api.Volume, out *Volume, s conversion.Scope) error { if err := s.Convert(&in.VolumeSource, &out.Source, 0); err != nil { return err } out.Name = in.Name return nil }, func(in *Volume, out *api.Volume, s conversion.Scope) error { if err := s.Convert(&in.Source, &out.VolumeSource, 0); err != nil { return err } out.Name = in.Name return nil }, func(in *api.VolumeSource, out *VolumeSource, s conversion.Scope) error { if err := s.Convert(&in.EmptyDir, &out.EmptyDir, 0); err != nil { return err } if err := s.Convert(&in.GitRepo, &out.GitRepo, 0); err != nil { return err } if err := s.Convert(&in.ISCSI, &out.ISCSI, 0); err != nil { return err } if err := s.Convert(&in.GCEPersistentDisk, &out.GCEPersistentDisk, 0); err != nil { return err } if err := s.Convert(&in.AWSElasticBlockStore, &out.AWSElasticBlockStore, 0); err != nil { return err } if err := s.Convert(&in.HostPath, &out.HostDir, 0); err != nil { return err } if err := s.Convert(&in.Secret, &out.Secret, 0); err != nil { return err } if err := s.Convert(&in.NFS, &out.NFS, 0); err != nil { return err } if err := s.Convert(&in.Glusterfs, &out.Glusterfs, 0); err != nil { return err } if err := s.Convert(&in.PersistentVolumeClaimVolumeSource, &out.PersistentVolumeClaimVolumeSource, 0); err != nil { return err } if err := s.Convert(&in.RBD, &out.RBD, 0); err != nil { return err } return nil }, func(in *VolumeSource, out *api.VolumeSource, s conversion.Scope) error { if err := s.Convert(&in.EmptyDir, &out.EmptyDir, 0); err != nil { return err } if err := s.Convert(&in.GitRepo, &out.GitRepo, 0); err != nil { return err } if err := s.Convert(&in.GCEPersistentDisk, &out.GCEPersistentDisk, 0); err != nil { return err } if err := s.Convert(&in.AWSElasticBlockStore, &out.AWSElasticBlockStore, 0); err != nil { return err } if err := s.Convert(&in.ISCSI, &out.ISCSI, 0); err != nil { return err } if err := s.Convert(&in.HostDir, &out.HostPath, 0); err != nil { return err } if err := s.Convert(&in.Secret, &out.Secret, 0); err != nil { return err } if err := s.Convert(&in.NFS, &out.NFS, 0); err != nil { return err } if err := s.Convert(&in.PersistentVolumeClaimVolumeSource, &out.PersistentVolumeClaimVolumeSource, 0); err != nil { return err } if err := s.Convert(&in.Glusterfs, &out.Glusterfs, 0); err != nil { return err } if err := s.Convert(&in.RBD, &out.RBD, 0); err != nil { return err } return nil }, func(in *api.PullPolicy, out *PullPolicy, s conversion.Scope) error { switch *in { case api.PullAlways: *out = PullAlways case api.PullNever: *out = PullNever case api.PullIfNotPresent: *out = PullIfNotPresent case "": *out = "" default: // Let unknown values through - they will get caught by validation *out = PullPolicy(*in) } return nil }, func(in *PullPolicy, out *api.PullPolicy, s conversion.Scope) error { switch *in { case PullAlways: *out = api.PullAlways case PullNever: *out = api.PullNever case PullIfNotPresent: *out = api.PullIfNotPresent case "": *out = "" default: // Let unknown values through - they will get caught by validation *out = api.PullPolicy(*in) } return nil }, func(in *api.RestartPolicy, out *RestartPolicy, s conversion.Scope) error { switch *in { case api.RestartPolicyAlways: *out = RestartPolicy{Always: &RestartPolicyAlways{}} case api.RestartPolicyNever: *out = RestartPolicy{Never: &RestartPolicyNever{}} case api.RestartPolicyOnFailure: *out = RestartPolicy{OnFailure: &RestartPolicyOnFailure{}} default: *out = RestartPolicy{} } return nil }, func(in *RestartPolicy, out *api.RestartPolicy, s conversion.Scope) error { switch { case in.Always != nil: *out = api.RestartPolicyAlways case in.Never != nil: *out = api.RestartPolicyNever case in.OnFailure != nil: *out = api.RestartPolicyOnFailure default: *out = "" } return nil }, func(in *api.Probe, out *LivenessProbe, s conversion.Scope) error { if err := s.Convert(&in.Exec, &out.Exec, 0); err != nil { return err } if err := s.Convert(&in.HTTPGet, &out.HTTPGet, 0); err != nil { return err } if err := s.Convert(&in.TCPSocket, &out.TCPSocket, 0); err != nil { return err } out.InitialDelaySeconds = in.InitialDelaySeconds out.TimeoutSeconds = in.TimeoutSeconds return nil }, func(in *LivenessProbe, out *api.Probe, s conversion.Scope) error { if err := s.Convert(&in.Exec, &out.Exec, 0); err != nil { return err } if err := s.Convert(&in.HTTPGet, &out.HTTPGet, 0); err != nil { return err } if err := s.Convert(&in.TCPSocket, &out.TCPSocket, 0); err != nil { return err } out.InitialDelaySeconds = in.InitialDelaySeconds out.TimeoutSeconds = in.TimeoutSeconds return nil }, func(in *api.Endpoints, out *Endpoints, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.Subsets, &out.Subsets, 0); err != nil { return err } // Produce back-compat fields. firstPortName := "" if len(in.Subsets) > 0 { if len(in.Subsets[0].Ports) > 0 { if err := s.Convert(&in.Subsets[0].Ports[0].Protocol, &out.Protocol, 0); err != nil { return err } firstPortName = in.Subsets[0].Ports[0].Name } } else { out.Protocol = ProtocolTCP } for i := range in.Subsets { ss := &in.Subsets[i] for j := range ss.Ports { ssp := &ss.Ports[j] if ssp.Name != firstPortName { continue } for k := range ss.Addresses { ssa := &ss.Addresses[k] hostPort := net.JoinHostPort(ssa.IP, strconv.Itoa(ssp.Port)) out.Endpoints = append(out.Endpoints, hostPort) if ssa.TargetRef != nil { target := EndpointObjectReference{ Endpoint: hostPort, } if err := s.Convert(ssa.TargetRef, &target.ObjectReference, 0); err != nil { return err } out.TargetRefs = append(out.TargetRefs, target) } } } } return nil }, func(in *Endpoints, out *api.Endpoints, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { return err } if err := s.Convert(&in.Subsets, &out.Subsets, 0); err != nil { return err } // Back-compat fields are handled in the defaulting phase. return nil }, func(in *api.NodeCondition, out *NodeCondition, s conversion.Scope) error { if err := s.Convert(&in.Type, &out.Kind, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.Status, 0); err != nil { return err } if err := s.Convert(&in.LastHeartbeatTime, &out.LastProbeTime, 0); err != nil { return err } if err := s.Convert(&in.LastTransitionTime, &out.LastTransitionTime, 0); err != nil { return err } if err := s.Convert(&in.Reason, &out.Reason, 0); err != nil { return err } if err := s.Convert(&in.Message, &out.Message, 0); err != nil { return err } return nil }, func(in *NodeCondition, out *api.NodeCondition, s conversion.Scope) error { if err := s.Convert(&in.Kind, &out.Type, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.Status, 0); err != nil { return err } if err := s.Convert(&in.LastProbeTime, &out.LastHeartbeatTime, 0); err != nil { return err } if err := s.Convert(&in.LastTransitionTime, &out.LastTransitionTime, 0); err != nil { return err } if err := s.Convert(&in.Reason, &out.Reason, 0); err != nil { return err } if err := s.Convert(&in.Message, &out.Message, 0); err != nil { return err } return nil }, func(in *api.NodeConditionType, out *NodeConditionKind, s conversion.Scope) error { switch *in { case api.NodeReady: *out = NodeReady break case "": *out = "" default: *out = NodeConditionKind(*in) break } return nil }, func(in *NodeConditionKind, out *api.NodeConditionType, s conversion.Scope) error { switch *in { case NodeReady: *out = api.NodeReady break case "": *out = "" default: *out = api.NodeConditionType(*in) break } return nil }, func(in *api.ConditionStatus, out *ConditionStatus, s conversion.Scope) error { switch *in { case api.ConditionTrue: *out = ConditionFull break case api.ConditionFalse: *out = ConditionNone break default: *out = ConditionStatus(*in) break } return nil }, func(in *ConditionStatus, out *api.ConditionStatus, s conversion.Scope) error { switch *in { case ConditionFull: *out = api.ConditionTrue break case ConditionNone: *out = api.ConditionFalse break default: *out = api.ConditionStatus(*in) break } return nil }, func(in *api.PodCondition, out *PodCondition, s conversion.Scope) error { if err := s.Convert(&in.Type, &out.Kind, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.Status, 0); err != nil { return err } return nil }, func(in *PodCondition, out *api.PodCondition, s conversion.Scope) error { if err := s.Convert(&in.Kind, &out.Type, 0); err != nil { return err } if err := s.Convert(&in.Status, &out.Status, 0); err != nil { return err } return nil }, func(in *api.PodConditionType, out *PodConditionKind, s conversion.Scope) error { switch *in { case api.PodReady: *out = PodReady break case "": *out = "" default: *out = PodConditionKind(*in) break } return nil }, func(in *PodConditionKind, out *api.PodConditionType, s conversion.Scope) error { switch *in { case PodReady: *out = api.PodReady break case "": *out = "" default: *out = api.PodConditionType(*in) break } return nil }, func(in *Binding, out *api.Binding, s conversion.Scope) error { if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil { return err } out.Target = api.ObjectReference{ Name: in.Host, } out.Name = in.PodID return nil }, func(in *api.Binding, out *Binding, s conversion.Scope) error { if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil { return err } out.Host = in.Target.Name out.PodID = in.Name return nil }, func(in *api.SecretVolumeSource, out *SecretVolumeSource, s conversion.Scope) error { out.Target.ID = in.SecretName return nil }, func(in *SecretVolumeSource, out *api.SecretVolumeSource, s conversion.Scope) error { out.SecretName = in.Target.ID return nil }, ) if err != nil { // If one of the conversion functions is malformed, detect it immediately. panic(err) } // Add field conversion funcs. err = api.Scheme.AddFieldLabelConversionFunc("v1beta2", "Pod", func(label, value string) (string, string, error) { switch label { case "name": return "metadata.name", value, nil case "DesiredState.Host": return "spec.host", value, nil case "DesiredState.Status": podStatus := PodStatus(value) var internalValue api.PodPhase api.Scheme.Convert(&podStatus, &internalValue) return "status.phase", string(internalValue), nil default: return "", "", fmt.Errorf("field label not supported: %s", label) } }) if err != nil { // If one of the conversion functions is malformed, detect it immediately. panic(err) } err = api.Scheme.AddFieldLabelConversionFunc("v1beta2", "Node", func(label, value string) (string, string, error) { switch label { case "name": return "metadata.name", value, nil case "unschedulable": return "spec.unschedulable", value, nil default: return "", "", fmt.Errorf("field label not supported: %s", label) } }) if err != nil { // if one of the conversion functions is malformed, detect it immediately. panic(err) } err = api.Scheme.AddFieldLabelConversionFunc("v1beta2", "ReplicationController", func(label, value string) (string, string, error) { switch label { case "name": return "metadata.name", value, nil case "currentState.replicas": return "status.replicas", value, nil default: return "", "", fmt.Errorf("field label not supported: %s", label) } }) if err != nil { // If one of the conversion functions is malformed, detect it immediately. panic(err) } err = api.Scheme.AddFieldLabelConversionFunc("v1beta2", "Event", func(label, value string) (string, string, error) { switch label { case "involvedObject.kind", "involvedObject.namespace", "involvedObject.uid", "involvedObject.apiVersion", "involvedObject.resourceVersion", "involvedObject.fieldPath", "reason", "source": return label, value, nil case "involvedObject.id": return "involvedObject.name", value, nil default: return "", "", fmt.Errorf("field label not supported: %s", label) } }) if err != nil { // If one of the conversion functions is malformed, detect it immediately. panic(err) } err = api.Scheme.AddFieldLabelConversionFunc("v1beta2", "Namespace", func(label, value string) (string, string, error) { switch label { case "status.phase": return label, value, nil default: return "", "", fmt.Errorf("field label not supported: %s", label) } }) if err != nil { // If one of the conversion functions is malformed, detect it immediately. panic(err) } err = api.Scheme.AddFieldLabelConversionFunc("v1beta2", "Secret", func(label, value string) (string, string, error) { switch label { case "type": return label, value, nil default: return "", "", fmt.Errorf("field label not supported: %s", label) } }) if err != nil { // If one of the conversion functions is malformed, detect it immediately. panic(err) } err = api.Scheme.AddFieldLabelConversionFunc("v1beta2", "ServiceAccount", func(label, value string) (string, string, error) { switch label { case "name": return "metadata.name", value, nil default: return "", "", fmt.Errorf("field label not supported: %s", label) } }) if err != nil { // If one of the conversion functions is malformed, detect it immediately. panic(err) } }