Delete deprecated API versions

pkg/service:

There were a couple of references here just as a reminder to change the
behavior of findPort. As of v1beta3, TargetPort was always defaulted, so
we could remove findDefaultPort and related tests.

pkg/apiserver:

The tests were using versioned API codecs for some of their encoding
tests. Necessary API types had to be written and registered with the
fake versioned codecs.

pkg/kubectl:

Some tests were converted to current versions where it made sense.
This commit is contained in:
Kris
2015-05-22 08:20:27 -07:00
parent f3b4b1aa31
commit f4e2c738f6
55 changed files with 3449 additions and 37462 deletions

View File

@@ -22,8 +22,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
)

View File

@@ -24,8 +24,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/registered"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
@@ -36,7 +34,7 @@ var Version string
// OldestVersion is the string that represents the oldest server version supported,
// for client code that wants to hardcode the lowest common denominator.
const OldestVersion = "v1beta1"
const OldestVersion = "v1beta3"
// Versions is the list of versions that are recognized in code. The order provided
// may be assumed to be least feature rich to most feature rich, and clients may
@@ -88,20 +86,6 @@ func init() {
},
)
// versions that used mixed case URL formats
versionMixedCase := map[string]bool{
"v1beta1": true,
"v1beta2": true,
}
// backwards compatibility, prior to v1beta3, we identified the namespace as a query parameter
versionToNamespaceScope := map[string]meta.RESTScope{
"v1beta1": meta.RESTScopeNamespaceLegacy,
"v1beta2": meta.RESTScopeNamespaceLegacy,
"v1beta3": meta.RESTScopeNamespace,
"v1": meta.RESTScopeNamespace,
}
// the list of kinds that are scoped at the root of the api hierarchy
// if a kind is not enumerated here, it is assumed to have a namespace scope
kindToRootScope := map[string]bool{
@@ -130,16 +114,11 @@ func init() {
if ignoredKinds.Has(kind) {
continue
}
mixedCase, found := versionMixedCase[version]
if !found {
mixedCase = false
}
scope := versionToNamespaceScope[version]
_, found = kindToRootScope[kind]
if found {
scope := meta.RESTScopeNamespace
if kindToRootScope[kind] {
scope = meta.RESTScopeRoot
}
mapper.Add(scope, kind, version, mixedCase)
mapper.Add(scope, kind, version, false)
}
}
RESTMapper = mapper
@@ -149,18 +128,6 @@ func init() {
// string, or an error if the version is not known.
func InterfacesFor(version string) (*meta.VersionInterfaces, error) {
switch version {
case "v1beta1":
return &meta.VersionInterfaces{
Codec: v1beta1.Codec,
ObjectConvertor: api.Scheme,
MetadataAccessor: accessor,
}, nil
case "v1beta2":
return &meta.VersionInterfaces{
Codec: v1beta2.Codec,
ObjectConvertor: api.Scheme,
MetadataAccessor: accessor,
}, nil
case "v1beta3":
return &meta.VersionInterfaces{
Codec: v1beta3.Codec,

View File

@@ -21,8 +21,6 @@ import (
"testing"
internal "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
)
func TestResourceVersioner(t *testing.T) {

View File

@@ -31,13 +31,11 @@ var RegisteredVersions []string
func init() {
validAPIVersions := map[string]bool{
"v1": true,
"v1beta1": true,
"v1beta2": true,
"v1beta3": true,
}
// The default list of supported api versions, in order of most preferred to the least.
defaultSupportedVersions := "v1beta3,v1beta1,v1beta2,v1"
defaultSupportedVersions := "v1beta3,v1"
// Env var KUBE_API_VERSIONS is a comma separated list of API versions that should be registered in the scheme.
// The versions should be in the order of most preferred to the least.
supportedVersions := os.Getenv("KUBE_API_VERSIONS")

View File

@@ -27,8 +27,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
apitesting "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
@@ -89,12 +87,6 @@ func roundTripSame(t *testing.T, item runtime.Object, except ...string) {
set := util.NewStringSet(except...)
seed := rand.Int63()
fuzzInternalObject(t, "", item, seed)
if !set.Has("v1beta1") {
roundTrip(t, v1beta1.Codec, item)
}
if !set.Has("v1beta2") {
roundTrip(t, v1beta2.Codec, item)
}
if !set.Has("v1beta3") {
fuzzInternalObject(t, "v1beta3", item, seed)
roundTrip(t, v1beta3.Codec, item)
@@ -103,8 +95,6 @@ func roundTripSame(t *testing.T, item runtime.Object, except ...string) {
func roundTripAll(t *testing.T, item runtime.Object) {
seed := rand.Int63()
roundTrip(t, v1beta1.Codec, fuzzInternalObject(t, "v1beta1", item, seed))
roundTrip(t, v1beta2.Codec, fuzzInternalObject(t, "v1beta2", item, seed))
roundTrip(t, v1beta3.Codec, fuzzInternalObject(t, "v1beta3", item, seed))
}
@@ -137,10 +127,7 @@ func TestList(t *testing.T) {
var nonRoundTrippableTypes = util.NewStringSet("ContainerManifest", "ContainerManifestList")
var nonInternalRoundTrippableTypes = util.NewStringSet("List", "ListOptions", "PodExecOptions")
var nonRoundTrippableTypesByVersion = map[string][]string{
"PodTemplate": {"v1beta1", "v1beta2"},
"PodTemplateList": {"v1beta1", "v1beta2"},
}
var nonRoundTrippableTypesByVersion = map[string][]string{}
func TestRoundTripTypes(t *testing.T) {
// api.Scheme.Log(t)

File diff suppressed because it is too large Load Diff

View File

@@ -1,811 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta1_test
import (
"encoding/json"
"reflect"
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
versioned "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
var Convert = api.Scheme.Convert
func TestEmptyObjectConversion(t *testing.T) {
s, err := versioned.Codec.Encode(&versioned.LimitRange{})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// DeletionTimestamp is not included, while CreationTimestamp is (would always be set)
if string(s) != `{"kind":"LimitRange","creationTimestamp":null,"apiVersion":"v1beta1","spec":{"limits":null}}` {
t.Errorf("unexpected empty object: %s", string(s))
}
}
func TestNodeConversion(t *testing.T) {
version, kind, err := api.Scheme.ObjectVersionAndKind(&versioned.Minion{})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if version != "v1beta1" || kind != "Minion" {
t.Errorf("unexpected version and kind: %s %s", version, kind)
}
api.Scheme.Log(t)
obj, err := versioned.Codec.Decode([]byte(`{"kind":"Node","apiVersion":"v1beta1"}`))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if _, ok := obj.(*api.Node); !ok {
t.Errorf("unexpected type: %#v", obj)
}
obj, err = versioned.Codec.Decode([]byte(`{"kind":"NodeList","apiVersion":"v1beta1"}`))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if _, ok := obj.(*api.NodeList); !ok {
t.Errorf("unexpected type: %#v", obj)
}
obj = &api.Node{}
if err := versioned.Codec.DecodeInto([]byte(`{"kind":"Node","apiVersion":"v1beta1"}`), obj); err != nil {
t.Fatalf("unexpected error: %v", err)
}
obj = &api.Node{}
data, err := versioned.Codec.Encode(obj)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
m := map[string]interface{}{}
if err := json.Unmarshal(data, &m); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if m["kind"] != "Minion" {
t.Errorf("unexpected encoding: %s - %#v", m["kind"], string(data))
}
}
func TestEnvConversion(t *testing.T) {
nonCanonical := []versioned.EnvVar{
{Key: "EV"},
{Key: "EV", Name: "EX"},
}
canonical := []api.EnvVar{
{Name: "EV"},
{Name: "EX"},
}
for i := range nonCanonical {
var got api.EnvVar
err := Convert(&nonCanonical[i], &got)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if e, a := canonical[i], got; !reflect.DeepEqual(e, a) {
t.Errorf("expected %v, got %v", e, a)
}
}
// Test conversion the other way, too.
for i := range canonical {
var got versioned.EnvVar
err := Convert(&canonical[i], &got)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if e, a := canonical[i].Name, got.Key; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := canonical[i].Name, got.Name; e != a {
t.Errorf("expected %v, got %v", e, a)
}
}
}
func TestVolumeMountConversionToOld(t *testing.T) {
table := []struct {
in api.VolumeMount
out versioned.VolumeMount
}{
{
in: api.VolumeMount{Name: "foo", MountPath: "/dev/foo", ReadOnly: true},
out: versioned.VolumeMount{Name: "foo", MountPath: "/dev/foo", Path: "/dev/foo", ReadOnly: true},
},
}
for _, item := range table {
got := versioned.VolumeMount{}
err := Convert(&item.in, &got)
if err != nil {
t.Errorf("Unexpected error: %v", err)
continue
}
if e, a := item.out, got; !reflect.DeepEqual(e, a) {
t.Errorf("Expected: %#v, got %#v", e, a)
}
}
}
func TestVolumeMountConversionToNew(t *testing.T) {
table := []struct {
in versioned.VolumeMount
out api.VolumeMount
}{
{
in: versioned.VolumeMount{Name: "foo", MountPath: "/dev/foo", ReadOnly: true},
out: api.VolumeMount{Name: "foo", MountPath: "/dev/foo", ReadOnly: true},
}, {
in: versioned.VolumeMount{Name: "foo", MountPath: "/dev/foo", Path: "/dev/bar", ReadOnly: true},
out: api.VolumeMount{Name: "foo", MountPath: "/dev/foo", ReadOnly: true},
}, {
in: versioned.VolumeMount{Name: "foo", Path: "/dev/bar", ReadOnly: true},
out: api.VolumeMount{Name: "foo", MountPath: "/dev/bar", ReadOnly: true},
},
}
for _, item := range table {
got := api.VolumeMount{}
err := Convert(&item.in, &got)
if err != nil {
t.Errorf("Unexpected error: %v", err)
continue
}
if e, a := item.out, got; !reflect.DeepEqual(e, a) {
t.Errorf("Expected: %#v, got %#v", e, a)
}
}
}
func TestMinionListConversionToNew(t *testing.T) {
oldMinion := func(id string) versioned.Minion {
return versioned.Minion{
TypeMeta: versioned.TypeMeta{ID: id},
ExternalID: id}
}
newNode := func(id string) api.Node {
return api.Node{
ObjectMeta: api.ObjectMeta{Name: id},
Spec: api.NodeSpec{ExternalID: id},
}
}
oldMinions := []versioned.Minion{
oldMinion("foo"),
oldMinion("bar"),
}
newMinions := []api.Node{
newNode("foo"),
newNode("bar"),
}
table := []struct {
oldML *versioned.MinionList
newML *api.NodeList
}{
{
oldML: &versioned.MinionList{Items: oldMinions},
newML: &api.NodeList{Items: newMinions},
}, {
oldML: &versioned.MinionList{Minions: oldMinions},
newML: &api.NodeList{Items: newMinions},
}, {
oldML: &versioned.MinionList{
Items: oldMinions,
Minions: []versioned.Minion{oldMinion("baz")},
},
newML: &api.NodeList{Items: newMinions},
},
}
for _, item := range table {
got := &api.NodeList{}
err := Convert(item.oldML, got)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if e, a := item.newML, got; !api.Semantic.DeepEqual(e, a) {
t.Errorf("Expected: %#v, got %#v", e, a)
}
}
}
func TestMinionListConversionToOld(t *testing.T) {
oldMinion := func(id string) versioned.Minion {
return versioned.Minion{TypeMeta: versioned.TypeMeta{ID: id}}
}
newNode := func(id string) api.Node {
return api.Node{ObjectMeta: api.ObjectMeta{Name: id}}
}
oldMinions := []versioned.Minion{
oldMinion("foo"),
oldMinion("bar"),
}
newMinions := []api.Node{
newNode("foo"),
newNode("bar"),
}
newML := &api.NodeList{Items: newMinions}
oldML := &versioned.MinionList{
Items: oldMinions,
Minions: oldMinions,
}
got := &versioned.MinionList{}
err := Convert(newML, got)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if e, a := oldML, got; !api.Semantic.DeepEqual(e, a) {
t.Errorf("Expected: %#v, got %#v", e, a)
}
}
func TestServiceEmptySelector(t *testing.T) {
// Nil map should be preserved
svc := &versioned.Service{Selector: nil}
data, err := api.Scheme.EncodeToVersion(svc, "v1beta1")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
obj, err := api.Scheme.Decode(data)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
selector := obj.(*api.Service).Spec.Selector
if selector != nil {
t.Errorf("unexpected selector: %#v", obj)
}
// Empty map should be preserved
svc2 := &versioned.Service{Selector: map[string]string{}}
data, err = api.Scheme.EncodeToVersion(svc2, "v1beta1")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
obj, err = api.Scheme.Decode(data)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
selector = obj.(*api.Service).Spec.Selector
if selector == nil || len(selector) != 0 {
t.Errorf("unexpected selector: %#v", obj)
}
}
func TestServicePorts(t *testing.T) {
testCases := []struct {
given versioned.Service
expected api.Service
roundtrip versioned.Service
}{
{
given: versioned.Service{
TypeMeta: versioned.TypeMeta{
ID: "legacy-with-defaults",
},
Port: 111,
Protocol: versioned.ProtocolTCP,
},
expected: api.Service{
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
Port: 111,
Protocol: api.ProtocolTCP,
}}},
},
roundtrip: versioned.Service{
Ports: []versioned.ServicePort{{
Port: 111,
Protocol: versioned.ProtocolTCP,
}},
},
},
{
given: versioned.Service{
TypeMeta: versioned.TypeMeta{
ID: "legacy-full",
},
PortName: "p",
Port: 111,
Protocol: versioned.ProtocolTCP,
ContainerPort: util.NewIntOrStringFromString("p"),
},
expected: api.Service{
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
Name: "p",
Port: 111,
Protocol: api.ProtocolTCP,
TargetPort: util.NewIntOrStringFromString("p"),
}}},
},
roundtrip: versioned.Service{
Ports: []versioned.ServicePort{{
Name: "p",
Port: 111,
Protocol: versioned.ProtocolTCP,
ContainerPort: util.NewIntOrStringFromString("p"),
}},
},
},
{
given: versioned.Service{
TypeMeta: versioned.TypeMeta{
ID: "both",
},
PortName: "p",
Port: 111,
Protocol: versioned.ProtocolTCP,
ContainerPort: util.NewIntOrStringFromString("p"),
Ports: []versioned.ServicePort{{
Name: "q",
Port: 222,
Protocol: versioned.ProtocolUDP,
ContainerPort: util.NewIntOrStringFromInt(93),
}},
},
expected: api.Service{
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
Name: "q",
Port: 222,
Protocol: api.ProtocolUDP,
TargetPort: util.NewIntOrStringFromInt(93),
}}},
},
roundtrip: versioned.Service{
Ports: []versioned.ServicePort{{
Name: "q",
Port: 222,
Protocol: versioned.ProtocolUDP,
ContainerPort: util.NewIntOrStringFromInt(93),
}},
},
},
{
given: versioned.Service{
TypeMeta: versioned.TypeMeta{
ID: "one",
},
Ports: []versioned.ServicePort{{
Name: "p",
Port: 111,
Protocol: versioned.ProtocolUDP,
ContainerPort: util.NewIntOrStringFromInt(93),
}},
},
expected: api.Service{
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
Name: "p",
Port: 111,
Protocol: api.ProtocolUDP,
TargetPort: util.NewIntOrStringFromInt(93),
}}},
},
roundtrip: versioned.Service{
Ports: []versioned.ServicePort{{
Name: "p",
Port: 111,
Protocol: versioned.ProtocolUDP,
ContainerPort: util.NewIntOrStringFromInt(93),
}},
},
},
{
given: versioned.Service{
TypeMeta: versioned.TypeMeta{
ID: "two",
},
Ports: []versioned.ServicePort{{
Name: "p",
Port: 111,
Protocol: versioned.ProtocolUDP,
ContainerPort: util.NewIntOrStringFromInt(93),
}, {
Name: "q",
Port: 222,
Protocol: versioned.ProtocolTCP,
ContainerPort: util.NewIntOrStringFromInt(76),
}},
},
expected: api.Service{
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
Name: "p",
Port: 111,
Protocol: api.ProtocolUDP,
TargetPort: util.NewIntOrStringFromInt(93),
}, {
Name: "q",
Port: 222,
Protocol: api.ProtocolTCP,
TargetPort: util.NewIntOrStringFromInt(76),
}}},
},
roundtrip: versioned.Service{
Ports: []versioned.ServicePort{{
Name: "p",
Port: 111,
Protocol: versioned.ProtocolUDP,
ContainerPort: util.NewIntOrStringFromInt(93),
}, {
Name: "q",
Port: 222,
Protocol: versioned.ProtocolTCP,
ContainerPort: util.NewIntOrStringFromInt(76),
}},
},
},
}
for i, tc := range testCases {
// Convert versioned -> internal.
got := api.Service{}
if err := Convert(&tc.given, &got); err != nil {
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
continue
}
if !reflect.DeepEqual(got.Spec.Ports, tc.expected.Spec.Ports) {
t.Errorf("[Case: %d] Expected %v, got %v", i, tc.expected.Spec.Ports, got.Spec.Ports)
}
// Convert internal -> versioned.
got2 := versioned.Service{}
if err := Convert(&got, &got2); err != nil {
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
continue
}
if !reflect.DeepEqual(got2.Ports, tc.roundtrip.Ports) {
t.Errorf("[Case: %d] Expected %v, got %v", i, tc.roundtrip.Ports, got2.Ports)
}
}
}
func TestPullPolicyConversion(t *testing.T) {
table := []struct {
versioned versioned.PullPolicy
internal api.PullPolicy
}{
{
versioned: versioned.PullAlways,
internal: api.PullAlways,
}, {
versioned: versioned.PullNever,
internal: api.PullNever,
}, {
versioned: versioned.PullIfNotPresent,
internal: api.PullIfNotPresent,
}, {
versioned: "",
internal: "",
}, {
versioned: "invalid value",
internal: "invalid value",
},
}
for _, item := range table {
var got api.PullPolicy
err := Convert(&item.versioned, &got)
if err != nil {
t.Errorf("Unexpected error: %v", err)
continue
}
if e, a := item.internal, got; e != a {
t.Errorf("Expected: %q, got %q", e, a)
}
}
for _, item := range table {
var got versioned.PullPolicy
err := Convert(&item.internal, &got)
if err != nil {
t.Errorf("Unexpected error: %v", err)
continue
}
if e, a := item.versioned, got; e != a {
t.Errorf("Expected: %q, got %q", e, a)
}
}
}
func getResourceRequirements(cpu, memory resource.Quantity) versioned.ResourceRequirements {
res := versioned.ResourceRequirements{}
res.Limits = versioned.ResourceList{}
if cpu.Value() > 0 {
res.Limits[versioned.ResourceCPU] = util.NewIntOrStringFromInt(int(cpu.Value()))
}
if memory.Value() > 0 {
res.Limits[versioned.ResourceMemory] = util.NewIntOrStringFromInt(int(memory.Value()))
}
return res
}
func TestContainerConversion(t *testing.T) {
cpuLimit := resource.MustParse("10")
memoryLimit := resource.MustParse("10M")
null := resource.Quantity{}
testCases := []versioned.Container{
{
Name: "container",
Resources: getResourceRequirements(cpuLimit, memoryLimit),
},
{
Name: "container",
CPU: int(cpuLimit.MilliValue()),
Resources: getResourceRequirements(null, memoryLimit),
},
{
Name: "container",
Memory: memoryLimit.Value(),
Resources: getResourceRequirements(cpuLimit, null),
},
{
Name: "container",
CPU: int(cpuLimit.MilliValue()),
Memory: memoryLimit.Value(),
},
{
Name: "container",
Memory: memoryLimit.Value(),
Resources: getResourceRequirements(cpuLimit, resource.MustParse("100M")),
},
{
Name: "container",
CPU: int(cpuLimit.MilliValue()),
Resources: getResourceRequirements(resource.MustParse("500"), memoryLimit),
},
}
for i, tc := range testCases {
got := api.Container{}
if err := Convert(&tc, &got); err != nil {
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
continue
}
if cpu := got.Resources.Limits.Cpu(); cpu.Value() != cpuLimit.Value() {
t.Errorf("[Case: %d] Expected cpu: %v, got: %v", i, cpuLimit, *cpu)
}
if memory := got.Resources.Limits.Memory(); memory.Value() != memoryLimit.Value() {
t.Errorf("[Case: %d] Expected memory: %v, got: %v", i, memoryLimit, *memory)
}
}
}
func TestEndpointsConversion(t *testing.T) {
testCases := []struct {
given versioned.Endpoints
expected api.Endpoints
}{
{
given: versioned.Endpoints{
TypeMeta: versioned.TypeMeta{
ID: "empty",
},
Protocol: versioned.ProtocolTCP,
Endpoints: []string{},
},
expected: api.Endpoints{
Subsets: []api.EndpointSubset{},
},
},
{
given: versioned.Endpoints{
TypeMeta: versioned.TypeMeta{
ID: "one legacy",
},
Protocol: versioned.ProtocolTCP,
Endpoints: []string{"1.2.3.4:88"},
},
expected: api.Endpoints{
Subsets: []api.EndpointSubset{{
Ports: []api.EndpointPort{{Name: "", Port: 88, Protocol: api.ProtocolTCP}},
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
}},
},
},
{
given: versioned.Endpoints{
TypeMeta: versioned.TypeMeta{
ID: "several legacy",
},
Protocol: versioned.ProtocolUDP,
Endpoints: []string{"1.2.3.4:88", "1.2.3.4:89", "1.2.3.4:90"},
},
expected: api.Endpoints{
Subsets: []api.EndpointSubset{
{
Ports: []api.EndpointPort{{Name: "", Port: 88, Protocol: api.ProtocolUDP}},
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
},
{
Ports: []api.EndpointPort{{Name: "", Port: 89, Protocol: api.ProtocolUDP}},
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
},
{
Ports: []api.EndpointPort{{Name: "", Port: 90, Protocol: api.ProtocolUDP}},
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
},
}},
},
{
given: versioned.Endpoints{
TypeMeta: versioned.TypeMeta{
ID: "one subset",
},
Protocol: versioned.ProtocolTCP,
Endpoints: []string{"1.2.3.4:88"},
Subsets: []versioned.EndpointSubset{{
Ports: []versioned.EndpointPort{{Name: "", Port: 88, Protocol: versioned.ProtocolTCP}},
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4"}},
}},
},
expected: api.Endpoints{
Subsets: []api.EndpointSubset{{
Ports: []api.EndpointPort{{Name: "", Port: 88, Protocol: api.ProtocolTCP}},
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
}},
},
},
{
given: versioned.Endpoints{
TypeMeta: versioned.TypeMeta{
ID: "several subset",
},
Protocol: versioned.ProtocolUDP,
Endpoints: []string{"1.2.3.4:88", "5.6.7.8:88", "1.2.3.4:89", "5.6.7.8:89"},
Subsets: []versioned.EndpointSubset{
{
Ports: []versioned.EndpointPort{{Name: "", Port: 88, Protocol: versioned.ProtocolUDP}},
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
},
{
Ports: []versioned.EndpointPort{{Name: "", Port: 89, Protocol: versioned.ProtocolUDP}},
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
},
{
Ports: []versioned.EndpointPort{{Name: "named", Port: 90, Protocol: versioned.ProtocolUDP}},
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
},
},
},
expected: api.Endpoints{
Subsets: []api.EndpointSubset{
{
Ports: []api.EndpointPort{{Name: "", Port: 88, Protocol: api.ProtocolUDP}},
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
},
{
Ports: []api.EndpointPort{{Name: "", Port: 89, Protocol: api.ProtocolUDP}},
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
},
{
Ports: []api.EndpointPort{{Name: "named", Port: 90, Protocol: api.ProtocolUDP}},
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
},
}},
},
}
for i, tc := range testCases {
// Convert versioned -> internal.
got := api.Endpoints{}
if err := Convert(&tc.given, &got); err != nil {
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
continue
}
if !api.Semantic.DeepEqual(got.Subsets, tc.expected.Subsets) {
t.Errorf("[Case: %d] Expected %#v, got %#v", i, tc.expected.Subsets, got.Subsets)
}
// Convert internal -> versioned.
got2 := versioned.Endpoints{}
if err := Convert(&got, &got2); err != nil {
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
continue
}
if got2.Protocol != tc.given.Protocol || !api.Semantic.DeepEqual(got2.Endpoints, tc.given.Endpoints) {
t.Errorf("[Case: %d] Expected %s %#v, got %s %#v", i, tc.given.Protocol, tc.given.Endpoints, got2.Protocol, got2.Endpoints)
}
}
}
func TestSecretVolumeSourceConversion(t *testing.T) {
given := versioned.SecretVolumeSource{
Target: versioned.ObjectReference{
ID: "foo",
},
}
expected := api.SecretVolumeSource{
SecretName: "foo",
}
got := api.SecretVolumeSource{}
if err := Convert(&given, &got); err != nil {
t.Errorf("Unexpected error: %v", err)
}
if got.SecretName != expected.SecretName {
t.Errorf("Expected %v; got %v", expected, got)
}
got2 := versioned.SecretVolumeSource{}
if err := Convert(&got, &got2); err != nil {
t.Errorf("Unexpected error: %v", err)
}
if got2.Target.ID != given.Target.ID {
t.Errorf("Expected %v; got %v", given, got2)
}
}
func TestBadSecurityContextConversion(t *testing.T) {
priv := false
testCases := map[string]struct {
c *versioned.Container
err string
}{
// this use case must use true for the container and false for the sc. Otherwise the defaulter
// will assume privileged was left undefined (since it is the default value) and copy the
// sc setting upwards
"mismatched privileged": {
c: &versioned.Container{
Privileged: true,
SecurityContext: &versioned.SecurityContext{
Privileged: &priv,
},
},
err: "container privileged settings do not match security context settings, cannot convert",
},
"mismatched caps add": {
c: &versioned.Container{
Capabilities: versioned.Capabilities{
Add: []versioned.Capability{"foo"},
},
SecurityContext: &versioned.SecurityContext{
Capabilities: &versioned.Capabilities{
Add: []versioned.Capability{"bar"},
},
},
},
err: "container capability settings do not match security context settings, cannot convert",
},
"mismatched caps drop": {
c: &versioned.Container{
Capabilities: versioned.Capabilities{
Drop: []versioned.Capability{"foo"},
},
SecurityContext: &versioned.SecurityContext{
Capabilities: &versioned.Capabilities{
Drop: []versioned.Capability{"bar"},
},
},
},
err: "container capability settings do not match security context settings, cannot convert",
},
}
for k, v := range testCases {
got := api.Container{}
err := Convert(v.c, &got)
if err == nil {
t.Errorf("expected error for case %s but got none", k)
} else {
if err.Error() != v.err {
t.Errorf("unexpected error for case %s. Expected: %s but got: %s", k, v.err, err.Error())
}
}
}
}

View File

@@ -1,242 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta1
import (
"net"
"strconv"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/golang/glog"
)
func addDefaultingFuncs() {
api.Scheme.AddDefaultingFuncs(
func(obj *ReplicationController) {
if len(obj.DesiredState.ReplicaSelector) == 0 {
obj.DesiredState.ReplicaSelector = obj.DesiredState.PodTemplate.Labels
}
if len(obj.Labels) == 0 {
obj.Labels = obj.DesiredState.PodTemplate.Labels
}
},
func(obj *Volume) {
if util.AllPtrFieldsNil(&obj.Source) {
obj.Source = VolumeSource{
EmptyDir: &EmptyDirVolumeSource{},
}
}
},
func(obj *ContainerPort) {
if obj.Protocol == "" {
obj.Protocol = ProtocolTCP
}
},
func(obj *Container) {
if obj.ImagePullPolicy == "" {
// TODO(dchen1107): Move ParseImageName code to pkg/util
parts := strings.Split(obj.Image, ":")
// Check image tag
if parts[len(parts)-1] == "latest" {
obj.ImagePullPolicy = PullAlways
} else {
obj.ImagePullPolicy = PullIfNotPresent
}
}
if obj.TerminationMessagePath == "" {
obj.TerminationMessagePath = TerminationMessagePathDefault
}
defaultSecurityContext(obj)
},
func(obj *RestartPolicy) {
if util.AllPtrFieldsNil(obj) {
obj.Always = &RestartPolicyAlways{}
}
},
func(obj *Service) {
if obj.Protocol == "" {
obj.Protocol = ProtocolTCP
}
if obj.SessionAffinity == "" {
obj.SessionAffinity = ServiceAffinityNone
}
if obj.Type == "" {
if obj.CreateExternalLoadBalancer {
obj.Type = ServiceTypeLoadBalancer
} else {
obj.Type = ServiceTypeClusterIP
}
} else if obj.Type == ServiceTypeLoadBalancer {
obj.CreateExternalLoadBalancer = true
}
for i := range obj.Ports {
sp := &obj.Ports[i]
if sp.Protocol == "" {
sp.Protocol = ProtocolTCP
}
if sp.ContainerPort == util.NewIntOrStringFromInt(0) || sp.ContainerPort == util.NewIntOrStringFromString("") {
sp.ContainerPort = util.NewIntOrStringFromInt(sp.Port)
}
}
},
func(obj *PodSpec) {
if obj.DNSPolicy == "" {
obj.DNSPolicy = DNSClusterFirst
}
if obj.HostNetwork {
defaultHostNetworkPorts(&obj.Containers)
}
},
func(obj *ContainerManifest) {
if obj.DNSPolicy == "" {
obj.DNSPolicy = DNSClusterFirst
}
if obj.HostNetwork {
defaultHostNetworkPorts(&obj.Containers)
}
},
func(obj *LivenessProbe) {
if obj.TimeoutSeconds == 0 {
obj.TimeoutSeconds = 1
}
},
func(obj *Secret) {
if obj.Type == "" {
obj.Type = SecretTypeOpaque
}
},
func(obj *PersistentVolume) {
if obj.Status.Phase == "" {
obj.Status.Phase = VolumePending
}
},
func(obj *PersistentVolumeClaim) {
if obj.Status.Phase == "" {
obj.Status.Phase = ClaimPending
}
},
func(obj *Endpoints) {
if obj.Protocol == "" {
obj.Protocol = ProtocolTCP
}
if len(obj.Subsets) == 0 && len(obj.Endpoints) > 0 {
// Must be a legacy-style object - populate
// Subsets from the older fields. Do this the
// simplest way, which is dumb (but valid).
for i := range obj.Endpoints {
host, portStr, err := net.SplitHostPort(obj.Endpoints[i])
if err != nil {
glog.Errorf("failed to SplitHostPort(%q)", obj.Endpoints[i])
}
var tgtRef *ObjectReference
for j := range obj.TargetRefs {
if obj.TargetRefs[j].Endpoint == obj.Endpoints[i] {
tgtRef = &ObjectReference{}
*tgtRef = obj.TargetRefs[j].ObjectReference
}
}
port, err := strconv.Atoi(portStr)
if err != nil {
glog.Errorf("failed to Atoi(%q)", portStr)
}
obj.Subsets = append(obj.Subsets, EndpointSubset{
Addresses: []EndpointAddress{{IP: host, TargetRef: tgtRef}},
Ports: []EndpointPort{{Protocol: obj.Protocol, Port: port}},
})
}
}
for i := range obj.Subsets {
ss := &obj.Subsets[i]
for i := range ss.Ports {
ep := &ss.Ports[i]
if ep.Protocol == "" {
ep.Protocol = ProtocolTCP
}
}
}
},
func(obj *HTTPGetAction) {
if obj.Path == "" {
obj.Path = "/"
}
},
func(obj *NamespaceStatus) {
if obj.Phase == "" {
obj.Phase = NamespaceActive
}
},
func(obj *Minion) {
if obj.ExternalID == "" {
obj.ExternalID = obj.ID
}
},
func(obj *ObjectFieldSelector) {
if obj.APIVersion == "" {
obj.APIVersion = "v1beta1"
}
},
)
}
// With host networking default all host ports to container ports.
func defaultHostNetworkPorts(containers *[]Container) {
for i := range *containers {
for j := range (*containers)[i].Ports {
if (*containers)[i].Ports[j].HostPort == 0 {
(*containers)[i].Ports[j].HostPort = (*containers)[i].Ports[j].ContainerPort
}
}
}
}
// defaultSecurityContext performs the downward and upward merges of a pod definition
func defaultSecurityContext(container *Container) {
if container.SecurityContext == nil {
glog.V(5).Infof("creating security context for container %s", container.Name)
container.SecurityContext = &SecurityContext{}
}
// if there are no capabilities defined on the SecurityContext then copy the container settings
if container.SecurityContext.Capabilities == nil {
container.SecurityContext.Capabilities = &container.Capabilities
} else {
// if there are capabilities defined on the security context and the container setting is
// empty then assume that it was left off the pod definition and ensure that the container
// settings match the security context settings (checked by the convert functions). If
// there are settings in both then don't touch it, the converter will error if they don't
// match
if len(container.Capabilities.Add) == 0 {
container.Capabilities.Add = container.SecurityContext.Capabilities.Add
}
if len(container.Capabilities.Drop) == 0 {
container.Capabilities.Drop = container.SecurityContext.Capabilities.Drop
}
}
// if there are no privileged settings on the security context then copy the container settings
if container.SecurityContext.Privileged == nil {
container.SecurityContext.Privileged = &container.Privileged
} else {
// we don't have a good way to know if container.Privileged was set or just defaulted to false
// so the best we can do here is check if the securityContext is set to true and the
// container is set to false and assume that the Privileged field was left off the container
// definition and not an intentional mismatch
if *container.SecurityContext.Privileged && !container.Privileged {
container.Privileged = *container.SecurityContext.Privileged
}
}
}

View File

@@ -1,461 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta1_test
import (
"reflect"
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
versioned "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
data, err := versioned.Codec.Encode(obj)
if err != nil {
t.Errorf("%v\n %#v", err, obj)
return nil
}
obj2, err := api.Codec.Decode(data)
if err != nil {
t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), obj)
return nil
}
obj3 := reflect.New(reflect.TypeOf(obj).Elem()).Interface().(runtime.Object)
err = api.Scheme.Convert(obj2, obj3)
if err != nil {
t.Errorf("%v\nSource: %#v", err, obj2)
return nil
}
return obj3
}
func TestSetDefaultReplicationController(t *testing.T) {
tests := []struct {
rc *versioned.ReplicationController
expectLabels bool
expectSelector bool
}{
{
rc: &versioned.ReplicationController{
DesiredState: versioned.ReplicationControllerState{
PodTemplate: versioned.PodTemplate{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
expectLabels: true,
expectSelector: true,
},
{
rc: &versioned.ReplicationController{
Labels: map[string]string{
"bar": "foo",
},
DesiredState: versioned.ReplicationControllerState{
PodTemplate: versioned.PodTemplate{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
expectLabels: false,
expectSelector: true,
},
{
rc: &versioned.ReplicationController{
Labels: map[string]string{
"bar": "foo",
},
DesiredState: versioned.ReplicationControllerState{
ReplicaSelector: map[string]string{
"some": "other",
},
PodTemplate: versioned.PodTemplate{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
expectLabels: false,
expectSelector: false,
},
{
rc: &versioned.ReplicationController{
DesiredState: versioned.ReplicationControllerState{
ReplicaSelector: map[string]string{
"some": "other",
},
PodTemplate: versioned.PodTemplate{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
expectLabels: true,
expectSelector: false,
},
}
for _, test := range tests {
rc := test.rc
obj2 := roundTrip(t, runtime.Object(rc))
rc2, ok := obj2.(*versioned.ReplicationController)
if !ok {
t.Errorf("unexpected object: %v", rc2)
t.FailNow()
}
if test.expectSelector != reflect.DeepEqual(rc2.DesiredState.ReplicaSelector, rc2.DesiredState.PodTemplate.Labels) {
if test.expectSelector {
t.Errorf("expected: %v, got: %v", rc2.DesiredState.PodTemplate.Labels, rc2.DesiredState.ReplicaSelector)
} else {
t.Errorf("unexpected equality: %v", rc2.DesiredState.PodTemplate.Labels)
}
}
if test.expectLabels != reflect.DeepEqual(rc2.Labels, rc2.DesiredState.PodTemplate.Labels) {
if test.expectLabels {
t.Errorf("expected: %v, got: %v", rc2.DesiredState.PodTemplate.Labels, rc2.Labels)
} else {
t.Errorf("unexpected equality: %v", rc2.DesiredState.PodTemplate.Labels)
}
}
}
}
func TestSetDefaultService(t *testing.T) {
svc := &versioned.Service{}
obj2 := roundTrip(t, runtime.Object(svc))
svc2 := obj2.(*versioned.Service)
if svc2.Protocol != versioned.ProtocolTCP {
t.Errorf("Expected default protocol :%s, got: %s", versioned.ProtocolTCP, svc2.Protocol)
}
if svc2.SessionAffinity != versioned.ServiceAffinityNone {
t.Errorf("Expected default session affinity type:%s, got: %s", versioned.ServiceAffinityNone, svc2.SessionAffinity)
}
if svc2.Type != versioned.ServiceTypeClusterIP {
t.Errorf("Expected default type:%s, got: %s", versioned.ServiceTypeClusterIP, svc2.Type)
}
}
func TestSetDefaultServiceWithLoadbalancer(t *testing.T) {
svc := &versioned.Service{}
svc.CreateExternalLoadBalancer = true
obj2 := roundTrip(t, runtime.Object(svc))
svc2 := obj2.(*versioned.Service)
if svc2.Type != versioned.ServiceTypeLoadBalancer {
t.Errorf("Expected default type:%s, got: %s", versioned.ServiceTypeLoadBalancer, svc2.Type)
}
}
func TestSetDefaultSecret(t *testing.T) {
s := &versioned.Secret{}
obj2 := roundTrip(t, runtime.Object(s))
s2 := obj2.(*versioned.Secret)
if s2.Type != versioned.SecretTypeOpaque {
t.Errorf("Expected secret type %v, got %v", versioned.SecretTypeOpaque, s2.Type)
}
}
func TestSetDefaultPersistentVolume(t *testing.T) {
pv := &versioned.PersistentVolume{}
obj2 := roundTrip(t, runtime.Object(pv))
pv2 := obj2.(*versioned.PersistentVolume)
if pv2.Status.Phase != versioned.VolumePending {
t.Errorf("Expected volume phase %v, got %v", versioned.VolumePending, pv2.Status.Phase)
}
}
func TestSetDefaultPersistentVolumeClaim(t *testing.T) {
pvc := &versioned.PersistentVolumeClaim{}
obj2 := roundTrip(t, runtime.Object(pvc))
pvc2 := obj2.(*versioned.PersistentVolumeClaim)
if pvc2.Status.Phase != versioned.ClaimPending {
t.Errorf("Expected claim phase %v, got %v", versioned.ClaimPending, pvc2.Status.Phase)
}
}
// Test that we use "legacy" fields if "modern" fields are not provided.
func TestSetDefaulEndpointsLegacy(t *testing.T) {
in := &versioned.Endpoints{
Protocol: "UDP",
Endpoints: []string{"1.2.3.4:93", "5.6.7.8:76"},
TargetRefs: []versioned.EndpointObjectReference{{Endpoint: "1.2.3.4:93", ObjectReference: versioned.ObjectReference{ID: "foo"}}},
}
obj := roundTrip(t, runtime.Object(in))
out := obj.(*versioned.Endpoints)
if len(out.Subsets) != 2 {
t.Errorf("Expected 2 EndpointSubsets, got %d (%#v)", len(out.Subsets), out.Subsets)
}
expected := []versioned.EndpointSubset{
{
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4", TargetRef: &versioned.ObjectReference{ID: "foo"}}},
Ports: []versioned.EndpointPort{{Protocol: versioned.ProtocolUDP, Port: 93}},
},
{
Addresses: []versioned.EndpointAddress{{IP: "5.6.7.8"}},
Ports: []versioned.EndpointPort{{Protocol: versioned.ProtocolUDP, Port: 76}},
},
}
if !reflect.DeepEqual(out.Subsets, expected) {
t.Errorf("Expected %#v, got %#v", expected, out.Subsets)
}
}
func TestSetDefaulEndpointsProtocol(t *testing.T) {
in := &versioned.Endpoints{Subsets: []versioned.EndpointSubset{
{Ports: []versioned.EndpointPort{{}, {Protocol: "UDP"}, {}}},
}}
obj := roundTrip(t, runtime.Object(in))
out := obj.(*versioned.Endpoints)
if out.Protocol != versioned.ProtocolTCP {
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Protocol)
}
for i := range out.Subsets {
for j := range out.Subsets[i].Ports {
if in.Subsets[i].Ports[j].Protocol == "" {
if out.Subsets[i].Ports[j].Protocol != versioned.ProtocolTCP {
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Subsets[i].Ports[j].Protocol)
}
} else {
if out.Subsets[i].Ports[j].Protocol != in.Subsets[i].Ports[j].Protocol {
t.Errorf("Expected protocol %s, got %s", in.Subsets[i].Ports[j].Protocol, out.Subsets[i].Ports[j].Protocol)
}
}
}
}
}
func TestSetDefaultNamespace(t *testing.T) {
s := &versioned.Namespace{}
obj2 := roundTrip(t, runtime.Object(s))
s2 := obj2.(*versioned.Namespace)
if s2.Status.Phase != versioned.NamespaceActive {
t.Errorf("Expected phase %v, got %v", versioned.NamespaceActive, s2.Status.Phase)
}
}
func TestSetDefaultContainerManifestHostNetwork(t *testing.T) {
portNum := 8080
s := versioned.ContainerManifest{}
s.HostNetwork = true
s.Containers = []versioned.Container{
{
Ports: []versioned.ContainerPort{
{
ContainerPort: portNum,
},
},
},
}
obj2 := roundTrip(t, runtime.Object(&versioned.ContainerManifestList{
Items: []versioned.ContainerManifest{s},
}))
sList2 := obj2.(*versioned.ContainerManifestList)
s2 := sList2.Items[0]
hostPortNum := s2.Containers[0].Ports[0].HostPort
if hostPortNum != portNum {
t.Errorf("Expected container port to be defaulted, was made %d instead of %d", hostPortNum, portNum)
}
}
func TestSetDefaultServicePort(t *testing.T) {
// Unchanged if set.
in := &versioned.Service{Ports: []versioned.ServicePort{{Protocol: "UDP", Port: 9376, ContainerPort: util.NewIntOrStringFromInt(118)}}}
out := roundTrip(t, runtime.Object(in)).(*versioned.Service)
if out.Ports[0].Protocol != versioned.ProtocolUDP {
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolUDP, out.Ports[0].Protocol)
}
if out.Ports[0].ContainerPort != in.Ports[0].ContainerPort {
t.Errorf("Expected port %d, got %d", in.Ports[0].ContainerPort, out.Ports[0].ContainerPort)
}
// Defaulted.
in = &versioned.Service{Ports: []versioned.ServicePort{{Protocol: "", Port: 9376, ContainerPort: util.NewIntOrStringFromInt(0)}}}
out = roundTrip(t, runtime.Object(in)).(*versioned.Service)
if out.Ports[0].Protocol != versioned.ProtocolTCP {
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Ports[0].Protocol)
}
if out.Ports[0].ContainerPort != util.NewIntOrStringFromInt(in.Ports[0].Port) {
t.Errorf("Expected port %d, got %v", in.Ports[0].Port, out.Ports[0].ContainerPort)
}
// Defaulted.
in = &versioned.Service{Ports: []versioned.ServicePort{{Protocol: "", Port: 9376, ContainerPort: util.NewIntOrStringFromString("")}}}
out = roundTrip(t, runtime.Object(in)).(*versioned.Service)
if out.Ports[0].Protocol != versioned.ProtocolTCP {
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Ports[0].Protocol)
}
if out.Ports[0].ContainerPort != util.NewIntOrStringFromInt(in.Ports[0].Port) {
t.Errorf("Expected port %d, got %v", in.Ports[0].Port, out.Ports[0].ContainerPort)
}
}
func TestSetDefaultMinionExternalID(t *testing.T) {
name := "node0"
m := &versioned.Minion{}
m.ID = name
obj2 := roundTrip(t, runtime.Object(m))
m2 := obj2.(*versioned.Minion)
if m2.ExternalID != name {
t.Errorf("Expected default External ID: %s, got: %s", name, m2.ExternalID)
}
if m2.ProviderID != "" {
t.Errorf("Expected empty default Cloud Provider ID, got: %s", m2.ProviderID)
}
}
func TestSetDefaultObjectFieldSelectorAPIVersion(t *testing.T) {
s := versioned.ContainerManifest{
Containers: []versioned.Container{
{
Env: []versioned.EnvVar{
{
ValueFrom: &versioned.EnvVarSource{
FieldRef: &versioned.ObjectFieldSelector{},
},
},
},
},
},
}
obj2 := roundTrip(t, runtime.Object(&versioned.ContainerManifestList{
Items: []versioned.ContainerManifest{s},
}))
sList2 := obj2.(*versioned.ContainerManifestList)
s2 := sList2.Items[0]
apiVersion := s2.Containers[0].Env[0].ValueFrom.FieldRef.APIVersion
if apiVersion != "v1beta1" {
t.Errorf("Expected default APIVersion v1beta1, got: %v", apiVersion)
}
}
func TestSetDefaultSecurityContext(t *testing.T) {
priv := false
privTrue := true
testCases := map[string]struct {
c versioned.Container
}{
"downward defaulting caps": {
c: versioned.Container{
Privileged: false,
Capabilities: versioned.Capabilities{
Add: []versioned.Capability{"foo"},
Drop: []versioned.Capability{"bar"},
},
SecurityContext: &versioned.SecurityContext{
Privileged: &priv,
},
},
},
"downward defaulting priv": {
c: versioned.Container{
Privileged: false,
Capabilities: versioned.Capabilities{
Add: []versioned.Capability{"foo"},
Drop: []versioned.Capability{"bar"},
},
SecurityContext: &versioned.SecurityContext{
Capabilities: &versioned.Capabilities{
Add: []versioned.Capability{"foo"},
Drop: []versioned.Capability{"bar"},
},
},
},
},
"upward defaulting caps": {
c: versioned.Container{
Privileged: false,
SecurityContext: &versioned.SecurityContext{
Privileged: &priv,
Capabilities: &versioned.Capabilities{
Add: []versioned.Capability{"biz"},
Drop: []versioned.Capability{"baz"},
},
},
},
},
"upward defaulting priv": {
c: versioned.Container{
Capabilities: versioned.Capabilities{
Add: []versioned.Capability{"foo"},
Drop: []versioned.Capability{"bar"},
},
SecurityContext: &versioned.SecurityContext{
Privileged: &privTrue,
Capabilities: &versioned.Capabilities{
Add: []versioned.Capability{"foo"},
Drop: []versioned.Capability{"bar"},
},
},
},
},
}
pod := &versioned.Pod{
DesiredState: versioned.PodState{
Manifest: versioned.ContainerManifest{},
},
}
for k, v := range testCases {
pod.DesiredState.Manifest.Containers = []versioned.Container{v.c}
obj := roundTrip(t, runtime.Object(pod))
defaultedPod := obj.(*versioned.Pod)
c := defaultedPod.DesiredState.Manifest.Containers[0]
if isEqual, issues := areSecurityContextAndContainerEqual(&c); !isEqual {
t.Errorf("test case %s expected the security context to have the same values as the container but found %#v", k, issues)
}
}
}
func areSecurityContextAndContainerEqual(c *versioned.Container) (bool, []string) {
issues := make([]string, 0)
equal := true
if c.SecurityContext == nil || c.SecurityContext.Privileged == nil || c.SecurityContext.Capabilities == nil {
equal = false
issues = append(issues, "Expected non nil settings for SecurityContext")
return equal, issues
}
if *c.SecurityContext.Privileged != c.Privileged {
equal = false
issues = append(issues, "The defaulted SecurityContext.Privileged value did not match the container value")
}
if !reflect.DeepEqual(c.Capabilities.Add, c.Capabilities.Add) {
equal = false
issues = append(issues, "The defaulted SecurityContext.Capabilities.Add did not match the container settings")
}
if !reflect.DeepEqual(c.Capabilities.Drop, c.Capabilities.Drop) {
equal = false
issues = append(issues, "The defaulted SecurityContext.Capabilities.Drop did not match the container settings")
}
return equal, issues
}

View File

@@ -1,18 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package v1beta1 is the v1beta1 version of the API.
package v1beta1

View File

@@ -1,138 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta1
import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/registered"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)
// Codec encodes internal objects to the v1beta1 scheme
var Codec = runtime.CodecFor(api.Scheme, "v1beta1")
// Dependency does nothing but give a hook for other packages to force a
// compile-time error when this API version is eventually removed. This is
// useful, for example, to clean up things that are implicitly tied to
// semantics of older APIs.
const Dependency = true
func init() {
// Check if v1beta1 is in the list of supported API versions.
if !registered.IsRegisteredAPIVersion("v1beta1") {
return
}
// Register the API.
addKnownTypes()
addConversionFuncs()
addDefaultingFuncs()
}
// Adds the list of known types to api.Scheme.
func addKnownTypes() {
api.Scheme.AddKnownTypes("v1beta1",
&Pod{},
&PodStatusResult{},
&PodList{},
&ReplicationController{},
&ReplicationControllerList{},
&Service{},
&ServiceList{},
&Endpoints{},
&EndpointsList{},
&Minion{},
&MinionList{},
&NodeInfo{},
&Binding{},
&Status{},
&Event{},
&EventList{},
&ContainerManifest{},
&ContainerManifestList{},
&List{},
&LimitRange{},
&LimitRangeList{},
&ResourceQuota{},
&ResourceQuotaList{},
&Namespace{},
&NamespaceList{},
&Secret{},
&SecretList{},
&ServiceAccount{},
&ServiceAccountList{},
&PersistentVolume{},
&PersistentVolumeList{},
&PersistentVolumeClaim{},
&PersistentVolumeClaimList{},
&DeleteOptions{},
&ListOptions{},
&PodLogOptions{},
&PodExecOptions{},
&PodProxyOptions{},
&ComponentStatus{},
&ComponentStatusList{},
&SerializedReference{},
&RangeAllocation{},
)
// Future names are supported
api.Scheme.AddKnownTypeWithName("v1beta1", "Node", &Minion{})
api.Scheme.AddKnownTypeWithName("v1beta1", "NodeList", &MinionList{})
}
func (*Pod) IsAnAPIObject() {}
func (*PodStatusResult) IsAnAPIObject() {}
func (*PodList) IsAnAPIObject() {}
func (*ReplicationController) IsAnAPIObject() {}
func (*ReplicationControllerList) IsAnAPIObject() {}
func (*Service) IsAnAPIObject() {}
func (*ServiceList) IsAnAPIObject() {}
func (*Endpoints) IsAnAPIObject() {}
func (*EndpointsList) IsAnAPIObject() {}
func (*Minion) IsAnAPIObject() {}
func (*NodeInfo) IsAnAPIObject() {}
func (*MinionList) IsAnAPIObject() {}
func (*Binding) IsAnAPIObject() {}
func (*Status) IsAnAPIObject() {}
func (*Event) IsAnAPIObject() {}
func (*EventList) IsAnAPIObject() {}
func (*ContainerManifest) IsAnAPIObject() {}
func (*ContainerManifestList) IsAnAPIObject() {}
func (*List) IsAnAPIObject() {}
func (*LimitRange) IsAnAPIObject() {}
func (*LimitRangeList) IsAnAPIObject() {}
func (*ResourceQuota) IsAnAPIObject() {}
func (*ResourceQuotaList) IsAnAPIObject() {}
func (*Namespace) IsAnAPIObject() {}
func (*NamespaceList) IsAnAPIObject() {}
func (*Secret) IsAnAPIObject() {}
func (*SecretList) IsAnAPIObject() {}
func (*ServiceAccount) IsAnAPIObject() {}
func (*ServiceAccountList) IsAnAPIObject() {}
func (*PersistentVolume) IsAnAPIObject() {}
func (*PersistentVolumeList) IsAnAPIObject() {}
func (*PersistentVolumeClaim) IsAnAPIObject() {}
func (*PersistentVolumeClaimList) IsAnAPIObject() {}
func (*DeleteOptions) IsAnAPIObject() {}
func (*ListOptions) IsAnAPIObject() {}
func (*PodLogOptions) IsAnAPIObject() {}
func (*PodExecOptions) IsAnAPIObject() {}
func (*PodProxyOptions) IsAnAPIObject() {}
func (*ComponentStatus) IsAnAPIObject() {}
func (*ComponentStatusList) IsAnAPIObject() {}
func (*SerializedReference) IsAnAPIObject() {}
func (*RangeAllocation) IsAnAPIObject() {}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,626 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta2_test
import (
"encoding/json"
"reflect"
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
versioned "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
func TestServiceEmptySelector(t *testing.T) {
// Nil map should be preserved
svc := &versioned.Service{Selector: nil}
data, err := api.Scheme.EncodeToVersion(svc, "v1beta2")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
obj, err := api.Scheme.Decode(data)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
selector := obj.(*api.Service).Spec.Selector
if selector != nil {
t.Errorf("unexpected selector: %#v", obj)
}
// Empty map should be preserved
svc2 := &versioned.Service{Selector: map[string]string{}}
data, err = api.Scheme.EncodeToVersion(svc2, "v1beta2")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
obj, err = api.Scheme.Decode(data)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
selector = obj.(*api.Service).Spec.Selector
if selector == nil || len(selector) != 0 {
t.Errorf("unexpected selector: %#v", obj)
}
}
func TestServicePorts(t *testing.T) {
testCases := []struct {
given versioned.Service
expected api.Service
roundtrip versioned.Service
}{
{
given: versioned.Service{
TypeMeta: versioned.TypeMeta{
ID: "legacy-with-defaults",
},
Port: 111,
Protocol: versioned.ProtocolTCP,
},
expected: api.Service{
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
Port: 111,
Protocol: api.ProtocolTCP,
}}},
},
roundtrip: versioned.Service{
Ports: []versioned.ServicePort{{
Port: 111,
Protocol: versioned.ProtocolTCP,
}},
},
},
{
given: versioned.Service{
TypeMeta: versioned.TypeMeta{
ID: "legacy-full",
},
PortName: "p",
Port: 111,
Protocol: versioned.ProtocolTCP,
ContainerPort: util.NewIntOrStringFromString("p"),
},
expected: api.Service{
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
Name: "p",
Port: 111,
Protocol: api.ProtocolTCP,
TargetPort: util.NewIntOrStringFromString("p"),
}}},
},
roundtrip: versioned.Service{
Ports: []versioned.ServicePort{{
Name: "p",
Port: 111,
Protocol: versioned.ProtocolTCP,
ContainerPort: util.NewIntOrStringFromString("p"),
}},
},
},
{
given: versioned.Service{
TypeMeta: versioned.TypeMeta{
ID: "both",
},
PortName: "p",
Port: 111,
Protocol: versioned.ProtocolTCP,
ContainerPort: util.NewIntOrStringFromString("p"),
Ports: []versioned.ServicePort{{
Name: "q",
Port: 222,
Protocol: versioned.ProtocolUDP,
ContainerPort: util.NewIntOrStringFromInt(93),
}},
},
expected: api.Service{
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
Name: "q",
Port: 222,
Protocol: api.ProtocolUDP,
TargetPort: util.NewIntOrStringFromInt(93),
}}},
},
roundtrip: versioned.Service{
Ports: []versioned.ServicePort{{
Name: "q",
Port: 222,
Protocol: versioned.ProtocolUDP,
ContainerPort: util.NewIntOrStringFromInt(93),
}},
},
},
{
given: versioned.Service{
TypeMeta: versioned.TypeMeta{
ID: "one",
},
Ports: []versioned.ServicePort{{
Name: "p",
Port: 111,
Protocol: versioned.ProtocolUDP,
ContainerPort: util.NewIntOrStringFromInt(93),
}},
},
expected: api.Service{
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
Name: "p",
Port: 111,
Protocol: api.ProtocolUDP,
TargetPort: util.NewIntOrStringFromInt(93),
}}},
},
roundtrip: versioned.Service{
Ports: []versioned.ServicePort{{
Name: "p",
Port: 111,
Protocol: versioned.ProtocolUDP,
ContainerPort: util.NewIntOrStringFromInt(93),
}},
},
},
{
given: versioned.Service{
TypeMeta: versioned.TypeMeta{
ID: "two",
},
Ports: []versioned.ServicePort{{
Name: "p",
Port: 111,
Protocol: versioned.ProtocolUDP,
ContainerPort: util.NewIntOrStringFromInt(93),
}, {
Name: "q",
Port: 222,
Protocol: versioned.ProtocolTCP,
ContainerPort: util.NewIntOrStringFromInt(76),
}},
},
expected: api.Service{
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
Name: "p",
Port: 111,
Protocol: api.ProtocolUDP,
TargetPort: util.NewIntOrStringFromInt(93),
}, {
Name: "q",
Port: 222,
Protocol: api.ProtocolTCP,
TargetPort: util.NewIntOrStringFromInt(76),
}}},
},
roundtrip: versioned.Service{
Ports: []versioned.ServicePort{{
Name: "p",
Port: 111,
Protocol: versioned.ProtocolUDP,
ContainerPort: util.NewIntOrStringFromInt(93),
}, {
Name: "q",
Port: 222,
Protocol: versioned.ProtocolTCP,
ContainerPort: util.NewIntOrStringFromInt(76),
}},
},
},
}
for i, tc := range testCases {
// Convert versioned -> internal.
got := api.Service{}
if err := api.Scheme.Convert(&tc.given, &got); err != nil {
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
continue
}
if !reflect.DeepEqual(got.Spec.Ports, tc.expected.Spec.Ports) {
t.Errorf("[Case: %d] Expected %v, got %v", i, tc.expected.Spec.Ports, got.Spec.Ports)
}
// Convert internal -> versioned.
got2 := versioned.Service{}
if err := api.Scheme.Convert(&got, &got2); err != nil {
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
continue
}
if !reflect.DeepEqual(got2.Ports, tc.roundtrip.Ports) {
t.Errorf("[Case: %d] Expected %v, got %v", i, tc.roundtrip.Ports, got2.Ports)
}
}
}
func TestNodeConversion(t *testing.T) {
version, kind, err := api.Scheme.ObjectVersionAndKind(&versioned.Minion{})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if version != "v1beta2" || kind != "Minion" {
t.Errorf("unexpected version and kind: %s %s", version, kind)
}
api.Scheme.Log(t)
obj, err := versioned.Codec.Decode([]byte(`{"kind":"Node","apiVersion":"v1beta2"}`))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if _, ok := obj.(*api.Node); !ok {
t.Errorf("unexpected type: %#v", obj)
}
obj, err = versioned.Codec.Decode([]byte(`{"kind":"NodeList","apiVersion":"v1beta2"}`))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if _, ok := obj.(*api.NodeList); !ok {
t.Errorf("unexpected type: %#v", obj)
}
obj = &api.Node{}
if err := versioned.Codec.DecodeInto([]byte(`{"kind":"Node","apiVersion":"v1beta2"}`), obj); err != nil {
t.Fatalf("unexpected error: %v", err)
}
obj = &api.Node{}
data, err := versioned.Codec.Encode(obj)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
m := map[string]interface{}{}
if err := json.Unmarshal(data, &m); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if m["kind"] != "Minion" {
t.Errorf("unexpected encoding: %s - %#v", m["kind"], string(data))
}
}
func TestPullPolicyConversion(t *testing.T) {
table := []struct {
versioned versioned.PullPolicy
internal api.PullPolicy
}{
{
versioned: versioned.PullAlways,
internal: api.PullAlways,
}, {
versioned: versioned.PullNever,
internal: api.PullNever,
}, {
versioned: versioned.PullIfNotPresent,
internal: api.PullIfNotPresent,
}, {
versioned: "",
internal: "",
}, {
versioned: "invalid value",
internal: "invalid value",
},
}
for _, item := range table {
var got api.PullPolicy
err := api.Scheme.Convert(&item.versioned, &got)
if err != nil {
t.Errorf("Unexpected error: %v", err)
continue
}
if e, a := item.internal, got; e != a {
t.Errorf("Expected: %q, got %q", e, a)
}
}
for _, item := range table {
var got versioned.PullPolicy
err := api.Scheme.Convert(&item.internal, &got)
if err != nil {
t.Errorf("Unexpected error: %v", err)
continue
}
if e, a := item.versioned, got; e != a {
t.Errorf("Expected: %q, got %q", e, a)
}
}
}
func getResourceRequirements(cpu, memory resource.Quantity) versioned.ResourceRequirements {
res := versioned.ResourceRequirements{}
res.Limits = versioned.ResourceList{}
if cpu.Value() > 0 {
res.Limits[versioned.ResourceCPU] = util.NewIntOrStringFromInt(int(cpu.Value()))
}
if memory.Value() > 0 {
res.Limits[versioned.ResourceMemory] = util.NewIntOrStringFromInt(int(memory.Value()))
}
return res
}
func TestContainerConversion(t *testing.T) {
cpuLimit := resource.MustParse("10")
memoryLimit := resource.MustParse("10M")
null := resource.Quantity{}
testCases := []versioned.Container{
{
Name: "container",
Resources: getResourceRequirements(cpuLimit, memoryLimit),
},
{
Name: "container",
CPU: int(cpuLimit.MilliValue()),
Resources: getResourceRequirements(null, memoryLimit),
},
{
Name: "container",
Memory: memoryLimit.Value(),
Resources: getResourceRequirements(cpuLimit, null),
},
{
Name: "container",
CPU: int(cpuLimit.MilliValue()),
Memory: memoryLimit.Value(),
},
{
Name: "container",
Memory: memoryLimit.Value(),
Resources: getResourceRequirements(cpuLimit, resource.MustParse("100M")),
},
{
Name: "container",
CPU: int(cpuLimit.MilliValue()),
Resources: getResourceRequirements(resource.MustParse("500"), memoryLimit),
},
}
for i, tc := range testCases {
got := api.Container{}
if err := api.Scheme.Convert(&tc, &got); err != nil {
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
continue
}
if cpu := got.Resources.Limits.Cpu(); cpu.Value() != cpuLimit.Value() {
t.Errorf("[Case: %d] Expected cpu: %v, got: %v", i, cpuLimit, *cpu)
}
if memory := got.Resources.Limits.Memory(); memory.Value() != memoryLimit.Value() {
t.Errorf("[Case: %d] Expected memory: %v, got: %v", i, memoryLimit, *memory)
}
}
}
func TestEndpointsConversion(t *testing.T) {
testCases := []struct {
given versioned.Endpoints
expected api.Endpoints
}{
{
given: versioned.Endpoints{
TypeMeta: versioned.TypeMeta{
ID: "empty",
},
Protocol: versioned.ProtocolTCP,
Endpoints: []string{},
},
expected: api.Endpoints{
Subsets: []api.EndpointSubset{},
},
},
{
given: versioned.Endpoints{
TypeMeta: versioned.TypeMeta{
ID: "one legacy",
},
Protocol: versioned.ProtocolTCP,
Endpoints: []string{"1.2.3.4:88"},
},
expected: api.Endpoints{
Subsets: []api.EndpointSubset{{
Ports: []api.EndpointPort{{Name: "", Port: 88, Protocol: api.ProtocolTCP}},
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
}},
},
},
{
given: versioned.Endpoints{
TypeMeta: versioned.TypeMeta{
ID: "several legacy",
},
Protocol: versioned.ProtocolUDP,
Endpoints: []string{"1.2.3.4:88", "1.2.3.4:89", "1.2.3.4:90"},
},
expected: api.Endpoints{
Subsets: []api.EndpointSubset{
{
Ports: []api.EndpointPort{{Name: "", Port: 88, Protocol: api.ProtocolUDP}},
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
},
{
Ports: []api.EndpointPort{{Name: "", Port: 89, Protocol: api.ProtocolUDP}},
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
},
{
Ports: []api.EndpointPort{{Name: "", Port: 90, Protocol: api.ProtocolUDP}},
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
},
}},
},
{
given: versioned.Endpoints{
TypeMeta: versioned.TypeMeta{
ID: "one subset",
},
Protocol: versioned.ProtocolTCP,
Endpoints: []string{"1.2.3.4:88"},
Subsets: []versioned.EndpointSubset{{
Ports: []versioned.EndpointPort{{Name: "", Port: 88, Protocol: versioned.ProtocolTCP}},
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4"}},
}},
},
expected: api.Endpoints{
Subsets: []api.EndpointSubset{{
Ports: []api.EndpointPort{{Name: "", Port: 88, Protocol: api.ProtocolTCP}},
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
}},
},
},
{
given: versioned.Endpoints{
TypeMeta: versioned.TypeMeta{
ID: "several subset",
},
Protocol: versioned.ProtocolUDP,
Endpoints: []string{"1.2.3.4:88", "5.6.7.8:88", "1.2.3.4:89", "5.6.7.8:89"},
Subsets: []versioned.EndpointSubset{
{
Ports: []versioned.EndpointPort{{Name: "", Port: 88, Protocol: versioned.ProtocolUDP}},
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
},
{
Ports: []versioned.EndpointPort{{Name: "", Port: 89, Protocol: versioned.ProtocolUDP}},
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
},
{
Ports: []versioned.EndpointPort{{Name: "named", Port: 90, Protocol: versioned.ProtocolUDP}},
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
},
},
},
expected: api.Endpoints{
Subsets: []api.EndpointSubset{
{
Ports: []api.EndpointPort{{Name: "", Port: 88, Protocol: api.ProtocolUDP}},
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
},
{
Ports: []api.EndpointPort{{Name: "", Port: 89, Protocol: api.ProtocolUDP}},
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
},
{
Ports: []api.EndpointPort{{Name: "named", Port: 90, Protocol: api.ProtocolUDP}},
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
},
}},
},
}
for i, tc := range testCases {
// Convert versioned -> internal.
got := api.Endpoints{}
if err := api.Scheme.Convert(&tc.given, &got); err != nil {
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
continue
}
if !api.Semantic.DeepEqual(got.Subsets, tc.expected.Subsets) {
t.Errorf("[Case: %d] Expected %#v, got %#v", i, tc.expected.Subsets, got.Subsets)
}
// Convert internal -> versioned.
got2 := versioned.Endpoints{}
if err := api.Scheme.Convert(&got, &got2); err != nil {
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
continue
}
if got2.Protocol != tc.given.Protocol || !api.Semantic.DeepEqual(got2.Endpoints, tc.given.Endpoints) {
t.Errorf("[Case: %d] Expected %#v, got %#v", i, tc.given.Endpoints, got2.Endpoints)
}
}
}
func TestSecretVolumeSourceConversion(t *testing.T) {
given := versioned.SecretVolumeSource{
Target: versioned.ObjectReference{
ID: "foo",
},
}
expected := api.SecretVolumeSource{
SecretName: "foo",
}
got := api.SecretVolumeSource{}
if err := api.Scheme.Convert(&given, &got); err != nil {
t.Errorf("Unexpected error: %v", err)
}
if got.SecretName != expected.SecretName {
t.Errorf("Expected %v; got %v", expected, got)
}
got2 := versioned.SecretVolumeSource{}
if err := api.Scheme.Convert(&got, &got2); err != nil {
t.Errorf("Unexpected error: %v", err)
}
if got2.Target.ID != given.Target.ID {
t.Errorf("Expected %v; got %v", given, got2)
}
}
func TestBadSecurityContextConversion(t *testing.T) {
priv := false
testCases := map[string]struct {
c *versioned.Container
err string
}{
// this use case must use true for the container and false for the sc. Otherwise the defaulter
// will assume privileged was left undefined (since it is the default value) and copy the
// sc setting upwards
"mismatched privileged": {
c: &versioned.Container{
Privileged: true,
SecurityContext: &versioned.SecurityContext{
Privileged: &priv,
},
},
err: "container privileged settings do not match security context settings, cannot convert",
},
"mismatched caps add": {
c: &versioned.Container{
Capabilities: versioned.Capabilities{
Add: []versioned.Capability{"foo"},
},
SecurityContext: &versioned.SecurityContext{
Capabilities: &versioned.Capabilities{
Add: []versioned.Capability{"bar"},
},
},
},
err: "container capability settings do not match security context settings, cannot convert",
},
"mismatched caps drop": {
c: &versioned.Container{
Capabilities: versioned.Capabilities{
Drop: []versioned.Capability{"foo"},
},
SecurityContext: &versioned.SecurityContext{
Capabilities: &versioned.Capabilities{
Drop: []versioned.Capability{"bar"},
},
},
},
err: "container capability settings do not match security context settings, cannot convert",
},
}
for k, v := range testCases {
got := api.Container{}
err := api.Scheme.Convert(v.c, &got)
if err == nil {
t.Errorf("expected error for case %s but got none", k)
} else {
if err.Error() != v.err {
t.Errorf("unexpected error for case %s. Expected: %s but got: %s", k, v.err, err.Error())
}
}
}
}

View File

@@ -1,243 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta2
import (
"net"
"strconv"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/golang/glog"
)
func addDefaultingFuncs() {
api.Scheme.AddDefaultingFuncs(
func(obj *ReplicationController) {
if len(obj.DesiredState.ReplicaSelector) == 0 {
obj.DesiredState.ReplicaSelector = obj.DesiredState.PodTemplate.Labels
}
if len(obj.Labels) == 0 {
obj.Labels = obj.DesiredState.PodTemplate.Labels
}
},
func(obj *Volume) {
if util.AllPtrFieldsNil(&obj.Source) {
glog.Errorf("Defaulting volume source for %v", obj)
obj.Source = VolumeSource{
EmptyDir: &EmptyDirVolumeSource{},
}
}
},
func(obj *ContainerPort) {
if obj.Protocol == "" {
obj.Protocol = ProtocolTCP
}
},
func(obj *Container) {
if obj.ImagePullPolicy == "" {
// TODO(dchen1107): Move ParseImageName code to pkg/util
parts := strings.Split(obj.Image, ":")
// Check image tag
if parts[len(parts)-1] == "latest" {
obj.ImagePullPolicy = PullAlways
} else {
obj.ImagePullPolicy = PullIfNotPresent
}
}
if obj.TerminationMessagePath == "" {
obj.TerminationMessagePath = TerminationMessagePathDefault
}
defaultSecurityContext(obj)
},
func(obj *RestartPolicy) {
if util.AllPtrFieldsNil(obj) {
obj.Always = &RestartPolicyAlways{}
}
},
func(obj *Service) {
if obj.Protocol == "" {
obj.Protocol = ProtocolTCP
}
if obj.SessionAffinity == "" {
obj.SessionAffinity = ServiceAffinityNone
}
if obj.Type == "" {
if obj.CreateExternalLoadBalancer {
obj.Type = ServiceTypeLoadBalancer
} else {
obj.Type = ServiceTypeClusterIP
}
} else if obj.Type == ServiceTypeLoadBalancer {
obj.CreateExternalLoadBalancer = true
}
for i := range obj.Ports {
sp := &obj.Ports[i]
if sp.Protocol == "" {
sp.Protocol = ProtocolTCP
}
if sp.ContainerPort == util.NewIntOrStringFromInt(0) || sp.ContainerPort == util.NewIntOrStringFromString("") {
sp.ContainerPort = util.NewIntOrStringFromInt(sp.Port)
}
}
},
func(obj *PodSpec) {
if obj.DNSPolicy == "" {
obj.DNSPolicy = DNSClusterFirst
}
if obj.HostNetwork {
defaultHostNetworkPorts(&obj.Containers)
}
},
func(obj *ContainerManifest) {
if obj.DNSPolicy == "" {
obj.DNSPolicy = DNSClusterFirst
}
if obj.HostNetwork {
defaultHostNetworkPorts(&obj.Containers)
}
},
func(obj *LivenessProbe) {
if obj.TimeoutSeconds == 0 {
obj.TimeoutSeconds = 1
}
},
func(obj *Secret) {
if obj.Type == "" {
obj.Type = SecretTypeOpaque
}
},
func(obj *PersistentVolume) {
if obj.Status.Phase == "" {
obj.Status.Phase = VolumePending
}
},
func(obj *PersistentVolumeClaim) {
if obj.Status.Phase == "" {
obj.Status.Phase = ClaimPending
}
},
func(obj *Endpoints) {
if obj.Protocol == "" {
obj.Protocol = ProtocolTCP
}
if len(obj.Subsets) == 0 && len(obj.Endpoints) > 0 {
// Must be a legacy-style object - populate
// Subsets from the older fields. Do this the
// simplest way, which is dumb (but valid).
for i := range obj.Endpoints {
host, portStr, err := net.SplitHostPort(obj.Endpoints[i])
if err != nil {
glog.Errorf("failed to SplitHostPort(%q)", obj.Endpoints[i])
}
var tgtRef *ObjectReference
for j := range obj.TargetRefs {
if obj.TargetRefs[j].Endpoint == obj.Endpoints[i] {
tgtRef = &ObjectReference{}
*tgtRef = obj.TargetRefs[j].ObjectReference
}
}
port, err := strconv.Atoi(portStr)
if err != nil {
glog.Errorf("failed to Atoi(%q)", portStr)
}
obj.Subsets = append(obj.Subsets, EndpointSubset{
Addresses: []EndpointAddress{{IP: host, TargetRef: tgtRef}},
Ports: []EndpointPort{{Protocol: obj.Protocol, Port: port}},
})
}
}
for i := range obj.Subsets {
ss := &obj.Subsets[i]
for i := range ss.Ports {
ep := &ss.Ports[i]
if ep.Protocol == "" {
ep.Protocol = ProtocolTCP
}
}
}
},
func(obj *HTTPGetAction) {
if obj.Path == "" {
obj.Path = "/"
}
},
func(obj *NamespaceStatus) {
if obj.Phase == "" {
obj.Phase = NamespaceActive
}
},
func(obj *Minion) {
if obj.ExternalID == "" {
obj.ExternalID = obj.ID
}
},
func(obj *ObjectFieldSelector) {
if obj.APIVersion == "" {
obj.APIVersion = "v1beta2"
}
},
)
}
// With host networking default all container ports to host ports.
func defaultHostNetworkPorts(containers *[]Container) {
for i := range *containers {
for j := range (*containers)[i].Ports {
if (*containers)[i].Ports[j].HostPort == 0 {
(*containers)[i].Ports[j].HostPort = (*containers)[i].Ports[j].ContainerPort
}
}
}
}
// defaultSecurityContext performs the downward and upward merges of a pod definition
func defaultSecurityContext(container *Container) {
if container.SecurityContext == nil {
glog.V(5).Infof("creating security context for container %s", container.Name)
container.SecurityContext = &SecurityContext{}
}
// if there are no capabilities defined on the SecurityContext then copy the container settings
if container.SecurityContext.Capabilities == nil {
container.SecurityContext.Capabilities = &container.Capabilities
} else {
// if there are capabilities defined on the security context and the container setting is
// empty then assume that it was left off the pod definition and ensure that the container
// settings match the security context settings (checked by the convert functions). If
// there are settings in both then don't touch it, the converter will error if they don't
// match
if len(container.Capabilities.Add) == 0 {
container.Capabilities.Add = container.SecurityContext.Capabilities.Add
}
if len(container.Capabilities.Drop) == 0 {
container.Capabilities.Drop = container.SecurityContext.Capabilities.Drop
}
}
// if there are no privileged settings on the security context then copy the container settings
if container.SecurityContext.Privileged == nil {
container.SecurityContext.Privileged = &container.Privileged
} else {
// we don't have a good way to know if container.Privileged was set or just defaulted to false
// so the best we can do here is check if the securityContext is set to true and the
// container is set to false and assume that the Privileged field was left off the container
// definition and not an intentional mismatch
if *container.SecurityContext.Privileged && !container.Privileged {
container.Privileged = *container.SecurityContext.Privileged
}
}
}

View File

@@ -1,460 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta2_test
import (
"reflect"
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
versioned "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
data, err := versioned.Codec.Encode(obj)
if err != nil {
t.Errorf("%v\n %#v", err, obj)
return nil
}
obj2, err := api.Codec.Decode(data)
if err != nil {
t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), obj)
return nil
}
obj3 := reflect.New(reflect.TypeOf(obj).Elem()).Interface().(runtime.Object)
err = api.Scheme.Convert(obj2, obj3)
if err != nil {
t.Errorf("%v\nSource: %#v", err, obj2)
return nil
}
return obj3
}
func TestSetDefaultReplicationController(t *testing.T) {
tests := []struct {
rc *versioned.ReplicationController
expectLabels bool
expectSelector bool
}{
{
rc: &versioned.ReplicationController{
DesiredState: versioned.ReplicationControllerState{
PodTemplate: versioned.PodTemplate{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
expectLabels: true,
expectSelector: true,
},
{
rc: &versioned.ReplicationController{
Labels: map[string]string{
"bar": "foo",
},
DesiredState: versioned.ReplicationControllerState{
PodTemplate: versioned.PodTemplate{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
expectLabels: false,
expectSelector: true,
},
{
rc: &versioned.ReplicationController{
Labels: map[string]string{
"bar": "foo",
},
DesiredState: versioned.ReplicationControllerState{
ReplicaSelector: map[string]string{
"some": "other",
},
PodTemplate: versioned.PodTemplate{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
expectLabels: false,
expectSelector: false,
},
{
rc: &versioned.ReplicationController{
DesiredState: versioned.ReplicationControllerState{
ReplicaSelector: map[string]string{
"some": "other",
},
PodTemplate: versioned.PodTemplate{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
expectLabels: true,
expectSelector: false,
},
}
for _, test := range tests {
rc := test.rc
obj2 := roundTrip(t, runtime.Object(rc))
rc2, ok := obj2.(*versioned.ReplicationController)
if !ok {
t.Errorf("unexpected object: %v", rc2)
t.FailNow()
}
if test.expectSelector != reflect.DeepEqual(rc2.DesiredState.ReplicaSelector, rc2.DesiredState.PodTemplate.Labels) {
if test.expectSelector {
t.Errorf("expected: %v, got: %v", rc2.DesiredState.PodTemplate.Labels, rc2.DesiredState.ReplicaSelector)
} else {
t.Errorf("unexpected equality: %v", rc2.DesiredState.PodTemplate.Labels)
}
}
if test.expectLabels != reflect.DeepEqual(rc2.Labels, rc2.DesiredState.PodTemplate.Labels) {
if test.expectLabels {
t.Errorf("expected: %v, got: %v", rc2.DesiredState.PodTemplate.Labels, rc2.Labels)
} else {
t.Errorf("unexpected equality: %v", rc2.DesiredState.PodTemplate.Labels)
}
}
}
}
func TestSetDefaultService(t *testing.T) {
svc := &versioned.Service{}
obj2 := roundTrip(t, runtime.Object(svc))
svc2 := obj2.(*versioned.Service)
if svc2.Protocol != versioned.ProtocolTCP {
t.Errorf("Expected default protocol :%s, got: %s", versioned.ProtocolTCP, svc2.Protocol)
}
if svc2.SessionAffinity != versioned.ServiceAffinityNone {
t.Errorf("Expected default session affinity type:%s, got: %s", versioned.ServiceAffinityNone, svc2.SessionAffinity)
}
if svc2.Type != versioned.ServiceTypeClusterIP {
t.Errorf("Expected default type:%s, got: %s", versioned.ServiceTypeClusterIP, svc2.Type)
}
}
func TestSetDefaultServiceWithLoadbalancer(t *testing.T) {
svc := &versioned.Service{}
svc.CreateExternalLoadBalancer = true
obj2 := roundTrip(t, runtime.Object(svc))
svc2 := obj2.(*versioned.Service)
if svc2.Type != versioned.ServiceTypeLoadBalancer {
t.Errorf("Expected default type:%s, got: %s", versioned.ServiceTypeLoadBalancer, svc2.Type)
}
}
func TestSetDefaultPersistentVolume(t *testing.T) {
pv := &versioned.PersistentVolume{}
obj2 := roundTrip(t, runtime.Object(pv))
pv2 := obj2.(*versioned.PersistentVolume)
if pv2.Status.Phase != versioned.VolumePending {
t.Errorf("Expected volume phase %v, got %v", versioned.VolumePending, pv2.Status.Phase)
}
}
func TestSetDefaultPersistentVolumeClaim(t *testing.T) {
pvc := &versioned.PersistentVolumeClaim{}
obj2 := roundTrip(t, runtime.Object(pvc))
pvc2 := obj2.(*versioned.PersistentVolumeClaim)
if pvc2.Status.Phase != versioned.ClaimPending {
t.Errorf("Expected claim phase %v, got %v", versioned.ClaimPending, pvc2.Status.Phase)
}
}
func TestSetDefaultSecret(t *testing.T) {
s := &versioned.Secret{}
obj2 := roundTrip(t, runtime.Object(s))
s2 := obj2.(*versioned.Secret)
if s2.Type != versioned.SecretTypeOpaque {
t.Errorf("Expected secret type %v, got %v", versioned.SecretTypeOpaque, s2.Type)
}
}
func TestSetDefaulEndpointsLegacy(t *testing.T) {
in := &versioned.Endpoints{
Protocol: "UDP",
Endpoints: []string{"1.2.3.4:93", "5.6.7.8:76"},
TargetRefs: []versioned.EndpointObjectReference{{Endpoint: "1.2.3.4:93", ObjectReference: versioned.ObjectReference{ID: "foo"}}},
}
obj := roundTrip(t, runtime.Object(in))
out := obj.(*versioned.Endpoints)
if len(out.Subsets) != 2 {
t.Errorf("Expected 2 EndpointSubsets, got %d (%#v)", len(out.Subsets), out.Subsets)
}
expected := []versioned.EndpointSubset{
{
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4", TargetRef: &versioned.ObjectReference{ID: "foo"}}},
Ports: []versioned.EndpointPort{{Protocol: versioned.ProtocolUDP, Port: 93}},
},
{
Addresses: []versioned.EndpointAddress{{IP: "5.6.7.8"}},
Ports: []versioned.EndpointPort{{Protocol: versioned.ProtocolUDP, Port: 76}},
},
}
if !reflect.DeepEqual(out.Subsets, expected) {
t.Errorf("Expected %#v, got %#v", expected, out.Subsets)
}
}
func TestSetDefaulEndpointsProtocol(t *testing.T) {
in := &versioned.Endpoints{Subsets: []versioned.EndpointSubset{
{Ports: []versioned.EndpointPort{{}, {Protocol: "UDP"}, {}}},
}}
obj := roundTrip(t, runtime.Object(in))
out := obj.(*versioned.Endpoints)
if out.Protocol != versioned.ProtocolTCP {
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Protocol)
}
for i := range out.Subsets {
for j := range out.Subsets[i].Ports {
if in.Subsets[i].Ports[j].Protocol == "" {
if out.Subsets[i].Ports[j].Protocol != versioned.ProtocolTCP {
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Subsets[i].Ports[j].Protocol)
}
} else {
if out.Subsets[i].Ports[j].Protocol != in.Subsets[i].Ports[j].Protocol {
t.Errorf("Expected protocol %s, got %s", in.Subsets[i].Ports[j].Protocol, out.Subsets[i].Ports[j].Protocol)
}
}
}
}
}
func TestSetDefaultNamespace(t *testing.T) {
s := &versioned.Namespace{}
obj2 := roundTrip(t, runtime.Object(s))
s2 := obj2.(*versioned.Namespace)
if s2.Status.Phase != versioned.NamespaceActive {
t.Errorf("Expected phase %v, got %v", versioned.NamespaceActive, s2.Status.Phase)
}
}
func TestSetDefaultContainerManifestHostNetwork(t *testing.T) {
portNum := 8080
s := versioned.ContainerManifest{}
s.HostNetwork = true
s.Containers = []versioned.Container{
{
Ports: []versioned.ContainerPort{
{
ContainerPort: portNum,
},
},
},
}
obj2 := roundTrip(t, runtime.Object(&versioned.ContainerManifestList{
Items: []versioned.ContainerManifest{s},
}))
sList2 := obj2.(*versioned.ContainerManifestList)
s2 := sList2.Items[0]
hostPortNum := s2.Containers[0].Ports[0].HostPort
if hostPortNum != portNum {
t.Errorf("Expected container port to be defaulted, was made %d instead of %d", hostPortNum, portNum)
}
}
func TestSetDefaultServicePort(t *testing.T) {
// Unchanged if set.
in := &versioned.Service{Ports: []versioned.ServicePort{{Protocol: "UDP", Port: 9376, ContainerPort: util.NewIntOrStringFromInt(118)}}}
out := roundTrip(t, runtime.Object(in)).(*versioned.Service)
if out.Ports[0].Protocol != versioned.ProtocolUDP {
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolUDP, out.Ports[0].Protocol)
}
if out.Ports[0].ContainerPort != in.Ports[0].ContainerPort {
t.Errorf("Expected port %d, got %d", in.Ports[0].ContainerPort, out.Ports[0].ContainerPort)
}
// Defaulted.
in = &versioned.Service{Ports: []versioned.ServicePort{{Protocol: "", Port: 9376, ContainerPort: util.NewIntOrStringFromInt(0)}}}
out = roundTrip(t, runtime.Object(in)).(*versioned.Service)
if out.Ports[0].Protocol != versioned.ProtocolTCP {
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Ports[0].Protocol)
}
if out.Ports[0].ContainerPort != util.NewIntOrStringFromInt(in.Ports[0].Port) {
t.Errorf("Expected port %d, got %v", in.Ports[0].Port, out.Ports[0].ContainerPort)
}
// Defaulted.
in = &versioned.Service{Ports: []versioned.ServicePort{{Protocol: "", Port: 9376, ContainerPort: util.NewIntOrStringFromString("")}}}
out = roundTrip(t, runtime.Object(in)).(*versioned.Service)
if out.Ports[0].Protocol != versioned.ProtocolTCP {
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Ports[0].Protocol)
}
if out.Ports[0].ContainerPort != util.NewIntOrStringFromInt(in.Ports[0].Port) {
t.Errorf("Expected port %d, got %v", in.Ports[0].Port, out.Ports[0].ContainerPort)
}
}
func TestSetDefaultMinionExternalID(t *testing.T) {
name := "node0"
m := &versioned.Minion{}
m.ID = name
obj2 := roundTrip(t, runtime.Object(m))
m2 := obj2.(*versioned.Minion)
if m2.ExternalID != name {
t.Errorf("Expected default External ID: %s, got: %s", name, m2.ExternalID)
}
if m2.ProviderID != "" {
t.Errorf("Expected empty default Cloud Provider ID, got: %s", m2.ProviderID)
}
}
func TestSetDefaultObjectFieldSelectorAPIVersion(t *testing.T) {
s := versioned.ContainerManifest{
Containers: []versioned.Container{
{
Env: []versioned.EnvVar{
{
ValueFrom: &versioned.EnvVarSource{
FieldRef: &versioned.ObjectFieldSelector{},
},
},
},
},
},
}
obj2 := roundTrip(t, runtime.Object(&versioned.ContainerManifestList{
Items: []versioned.ContainerManifest{s},
}))
sList2 := obj2.(*versioned.ContainerManifestList)
s2 := sList2.Items[0]
apiVersion := s2.Containers[0].Env[0].ValueFrom.FieldRef.APIVersion
if apiVersion != "v1beta2" {
t.Errorf("Expected default APIVersion v1beta2, got: %v", apiVersion)
}
}
func TestSetDefaultSecurityContext(t *testing.T) {
priv := false
privTrue := true
testCases := map[string]struct {
c versioned.Container
}{
"downward defaulting caps": {
c: versioned.Container{
Privileged: false,
Capabilities: versioned.Capabilities{
Add: []versioned.Capability{"foo"},
Drop: []versioned.Capability{"bar"},
},
SecurityContext: &versioned.SecurityContext{
Privileged: &priv,
},
},
},
"downward defaulting priv": {
c: versioned.Container{
Privileged: false,
Capabilities: versioned.Capabilities{
Add: []versioned.Capability{"foo"},
Drop: []versioned.Capability{"bar"},
},
SecurityContext: &versioned.SecurityContext{
Capabilities: &versioned.Capabilities{
Add: []versioned.Capability{"foo"},
Drop: []versioned.Capability{"bar"},
},
},
},
},
"upward defaulting caps": {
c: versioned.Container{
Privileged: false,
SecurityContext: &versioned.SecurityContext{
Privileged: &priv,
Capabilities: &versioned.Capabilities{
Add: []versioned.Capability{"biz"},
Drop: []versioned.Capability{"baz"},
},
},
},
},
"upward defaulting priv": {
c: versioned.Container{
Capabilities: versioned.Capabilities{
Add: []versioned.Capability{"foo"},
Drop: []versioned.Capability{"bar"},
},
SecurityContext: &versioned.SecurityContext{
Privileged: &privTrue,
Capabilities: &versioned.Capabilities{
Add: []versioned.Capability{"foo"},
Drop: []versioned.Capability{"bar"},
},
},
},
},
}
pod := &versioned.Pod{
DesiredState: versioned.PodState{
Manifest: versioned.ContainerManifest{},
},
}
for k, v := range testCases {
pod.DesiredState.Manifest.Containers = []versioned.Container{v.c}
obj := roundTrip(t, runtime.Object(pod))
defaultedPod := obj.(*versioned.Pod)
c := defaultedPod.DesiredState.Manifest.Containers[0]
if isEqual, issues := areSecurityContextAndContainerEqual(&c); !isEqual {
t.Errorf("test case %s expected the security context to have the same values as the container but found %#v", k, issues)
}
}
}
func areSecurityContextAndContainerEqual(c *versioned.Container) (bool, []string) {
issues := make([]string, 0)
equal := true
if c.SecurityContext == nil || c.SecurityContext.Privileged == nil || c.SecurityContext.Capabilities == nil {
equal = false
issues = append(issues, "Expected non nil settings for SecurityContext")
return equal, issues
}
if *c.SecurityContext.Privileged != c.Privileged {
equal = false
issues = append(issues, "The defaulted SecurityContext.Privileged value did not match the container value")
}
if !reflect.DeepEqual(c.Capabilities.Add, c.Capabilities.Add) {
equal = false
issues = append(issues, "The defaulted SecurityContext.Capabilities.Add did not match the container settings")
}
if !reflect.DeepEqual(c.Capabilities.Drop, c.Capabilities.Drop) {
equal = false
issues = append(issues, "The defaulted SecurityContext.Capabilities.Drop did not match the container settings")
}
return equal, issues
}

View File

@@ -1,18 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package v1beta2 is the v1beta2 version of the API.
package v1beta2

View File

@@ -1,138 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta2
import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/registered"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)
// Codec encodes internal objects to the v1beta2 scheme
var Codec = runtime.CodecFor(api.Scheme, "v1beta2")
// Dependency does nothing but give a hook for other packages to force a
// compile-time error when this API version is eventually removed. This is
// useful, for example, to clean up things that are implicitly tied to
// semantics of older APIs.
const Dependency = true
func init() {
// Check if v1beta2 is in the list of supported API versions.
if !registered.IsRegisteredAPIVersion("v1beta2") {
return
}
// Register the API.
addKnownTypes()
addConversionFuncs()
addDefaultingFuncs()
}
// Adds the list of known types to api.Scheme.
func addKnownTypes() {
api.Scheme.AddKnownTypes("v1beta2",
&Pod{},
&PodStatusResult{},
&PodList{},
&ReplicationController{},
&ReplicationControllerList{},
&Service{},
&ServiceList{},
&Endpoints{},
&EndpointsList{},
&Minion{},
&NodeInfo{},
&MinionList{},
&Binding{},
&Status{},
&Event{},
&EventList{},
&ContainerManifest{},
&ContainerManifestList{},
&List{},
&LimitRange{},
&LimitRangeList{},
&ResourceQuota{},
&ResourceQuotaList{},
&Namespace{},
&NamespaceList{},
&Secret{},
&SecretList{},
&ServiceAccount{},
&ServiceAccountList{},
&PersistentVolume{},
&PersistentVolumeList{},
&PersistentVolumeClaim{},
&PersistentVolumeClaimList{},
&DeleteOptions{},
&ListOptions{},
&PodLogOptions{},
&PodExecOptions{},
&PodProxyOptions{},
&ComponentStatus{},
&ComponentStatusList{},
&SerializedReference{},
&RangeAllocation{},
)
// Future names are supported
api.Scheme.AddKnownTypeWithName("v1beta2", "Node", &Minion{})
api.Scheme.AddKnownTypeWithName("v1beta2", "NodeList", &MinionList{})
}
func (*Pod) IsAnAPIObject() {}
func (*PodStatusResult) IsAnAPIObject() {}
func (*PodList) IsAnAPIObject() {}
func (*ReplicationController) IsAnAPIObject() {}
func (*ReplicationControllerList) IsAnAPIObject() {}
func (*Service) IsAnAPIObject() {}
func (*ServiceList) IsAnAPIObject() {}
func (*Endpoints) IsAnAPIObject() {}
func (*EndpointsList) IsAnAPIObject() {}
func (*Minion) IsAnAPIObject() {}
func (*NodeInfo) IsAnAPIObject() {}
func (*MinionList) IsAnAPIObject() {}
func (*Binding) IsAnAPIObject() {}
func (*Status) IsAnAPIObject() {}
func (*Event) IsAnAPIObject() {}
func (*EventList) IsAnAPIObject() {}
func (*ContainerManifest) IsAnAPIObject() {}
func (*ContainerManifestList) IsAnAPIObject() {}
func (*List) IsAnAPIObject() {}
func (*LimitRange) IsAnAPIObject() {}
func (*LimitRangeList) IsAnAPIObject() {}
func (*ResourceQuota) IsAnAPIObject() {}
func (*ResourceQuotaList) IsAnAPIObject() {}
func (*Namespace) IsAnAPIObject() {}
func (*NamespaceList) IsAnAPIObject() {}
func (*Secret) IsAnAPIObject() {}
func (*SecretList) IsAnAPIObject() {}
func (*ServiceAccount) IsAnAPIObject() {}
func (*ServiceAccountList) IsAnAPIObject() {}
func (*PersistentVolume) IsAnAPIObject() {}
func (*PersistentVolumeList) IsAnAPIObject() {}
func (*PersistentVolumeClaim) IsAnAPIObject() {}
func (*PersistentVolumeClaimList) IsAnAPIObject() {}
func (*DeleteOptions) IsAnAPIObject() {}
func (*ListOptions) IsAnAPIObject() {}
func (*PodLogOptions) IsAnAPIObject() {}
func (*PodExecOptions) IsAnAPIObject() {}
func (*PodProxyOptions) IsAnAPIObject() {}
func (*ComponentStatus) IsAnAPIObject() {}
func (*ComponentStatusList) IsAnAPIObject() {}
func (*SerializedReference) IsAnAPIObject() {}
func (*RangeAllocation) IsAnAPIObject() {}

File diff suppressed because it is too large Load Diff