Merge pull request #8917 from krousey/delete_deprecated_apis

Delete deprecated apis
pull/6/head
Eric Tune 2015-06-01 08:49:33 -07:00
commit c1fa82837e
55 changed files with 3449 additions and 37462 deletions

View File

@ -6,7 +6,7 @@ matrix:
include:
- go: 1.4
env:
- KUBE_TEST_API_VERSIONS="v1beta1"
- KUBE_TEST_API_VERSIONS="v1beta3"
KUBE_TEST_ETCD_PREFIXES="registry"
- go: 1.3
env:

View File

@ -23,5 +23,6 @@
}
]
}
]
],
"models": {}
}

View File

@ -1,14 +1,14 @@
{
"swaggerVersion": "1.2",
"apis": [
{
"path": "/api",
"description": "get available API versions"
},
{
"path": "/api/v1beta3",
"description": "API at /api/v1beta3 version v1beta3"
},
{
"path": "/api",
"description": "get available API versions"
},
{
"path": "/version",
"description": "git code version from which this is built"
@ -19,4 +19,4 @@
"title": "",
"description": ""
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -23,5 +23,6 @@
}
]
}
]
],
"models": {}
}

View File

@ -16,7 +16,7 @@ spec:
kubernetes.io/cluster-service: "true"
spec:
containers:
- image: gcr.io/google_containers/heapster:v0.12.1
- image: gcr.io/google_containers/heapster:v0.13.0
name: heapster
command:
- /heapster

View File

@ -16,7 +16,7 @@ spec:
kubernetes.io/cluster-service: "true"
spec:
containers:
- image: gcr.io/google_containers/heapster:v0.12.1
- image: gcr.io/google_containers/heapster:v0.13.0
name: heapster
command:
- /heapster

View File

@ -23,8 +23,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
_ "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"
pkg_runtime "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"

View File

@ -24,8 +24,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
_ "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"
pkg_runtime "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"

View File

@ -605,23 +605,6 @@ func runPatchTest(c *client.Client) {
RemoveLabelBody []byte
RemoveAllLabelsBody []byte
}{
"v1beta1": {
api.JSONPatchType: {
[]byte(`[{"op":"add","path":"/labels","value":{"foo":"bar","baz":"qux"}}]`),
[]byte(`[{"op":"remove","path":"/labels/foo"}]`),
[]byte(`[{"op":"remove","path":"/labels"}]`),
},
api.MergePatchType: {
[]byte(`{"labels":{"foo":"bar","baz":"qux"}}`),
[]byte(`{"labels":{"foo":null}}`),
[]byte(`{"labels":null}`),
},
api.StrategicMergePatchType: {
[]byte(`{"labels":{"foo":"bar","baz":"qux"}}`),
[]byte(`{"labels":{"foo":null}}`),
[]byte(`{"labels":{"$patch":"replace"}}`),
},
},
"v1beta3": {
api.JSONPatchType: {
[]byte(`[{"op":"add","path":"/metadata/labels","value":{"foo":"bar","baz":"qux"}}]`),
@ -938,7 +921,7 @@ func main() {
glog.Infof("Running tests for APIVersion: %s", apiVersion)
firstManifestURL := ServeCachedManifestFile(testPodSpecFile)
secondManifestURL := ServeCachedManifestFile(testManifestFile)
secondManifestURL := ServeCachedManifestFile(testPodSpecFile)
apiServerURL, _ := startComponents(firstManifestURL, secondManifestURL, apiVersion)
// Ok. we're good to go.
@ -1059,27 +1042,3 @@ const (
}
}`
)
const (
// This is copied from, and should be kept in sync with:
// https://raw.githubusercontent.com/GoogleCloudPlatform/container-vm-guestbook-redis-python/master/manifest.yaml
// Note that kubelet complains about these containers not having a self link.
testManifestFile = `version: v1beta2
id: container-vm-guestbook-manifest
containers:
- name: redis
image: redis
volumeMounts:
- name: redis-data
mountPath: /data
- name: guestbook
image: google/guestbook-python-redis
ports:
- name: www
hostPort: 80
containerPort: 80
volumes:
- name: redis-data`
)

View File

@ -1,23 +0,0 @@
{
"id": "nginx-controller",
"apiVersion": "v1beta1",
"kind": "ReplicationController",
"desiredState": {
"replicas": 2,
"replicaSelector": {"name": "nginx"},
"podTemplate": {
"desiredState": {
"manifest": {
"version": "v1beta1",
"id": "nginx-controller",
"containers": [{
"name": "nginx",
"image": "nginx",
"ports": [{"containerPort": 80}]
}]
}
},
"labels": {"name": "nginx"}
}},
"labels": {"name": "nginx"}
}

View File

@ -264,16 +264,7 @@ func (s *APIServer) Run(_ []string) error {
if ok && legacyAPIFlagValue == "false" {
disableLegacyAPIs = true
}
// "api/v1beta1={true|false} allows users to enable/disable v1beta1 API.
// This takes preference over api/all and api/legacy, if specified.
disableV1beta1 := disableAllAPIs || disableLegacyAPIs
disableV1beta1 = !s.getRuntimeConfigValue("api/v1beta1", !disableV1beta1)
// "api/v1beta2={true|false} allows users to enable/disable v1beta2 API.
// This takes preference over api/all and api/legacy, if specified.
disableV1beta2 := disableAllAPIs || disableLegacyAPIs
disableV1beta2 = !s.getRuntimeConfigValue("api/v1beta2", !disableV1beta2)
_ = disableLegacyAPIs // hush the compiler while we don't have legacy APIs to disable.
// "api/v1beta3={true|false} allows users to enable/disable v1beta3 API.
// This takes preference over api/all and api/legacy, if specified.
@ -369,8 +360,6 @@ func (s *APIServer) Run(_ []string) error {
SupportsBasicAuth: len(s.BasicAuthFile) > 0,
Authorizer: authorizer,
AdmissionControl: admissionController,
DisableV1Beta1: disableV1beta1,
DisableV1Beta2: disableV1beta2,
DisableV1Beta3: disableV1beta3,
EnableV1: enableV1,
MasterServiceNamespace: s.MasterServiceNamespace,

View File

@ -28,8 +28,6 @@ import (
"runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
_ "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/util"

View File

@ -121,7 +121,6 @@ func walkJSONFiles(inDir string, fn func(name, path string, data []byte)) error
func TestExampleObjectSchemas(t *testing.T) {
cases := map[string]map[string]runtime.Object{
"../cmd/integration": {
"v1beta1-controller": &api.ReplicationController{},
"v1beta3-controller": &api.ReplicationController{},
},
"../examples/guestbook": {

View File

@ -114,8 +114,6 @@ PATH="${KUBE_OUTPUT_HOSTBIN}":$PATH
kube_api_versions=(
""
v1beta1
v1beta2
v1beta3
)
for version in "${kube_api_versions[@]}"; do

View File

@ -52,7 +52,7 @@ KUBE_RACE=${KUBE_RACE:-} # use KUBE_RACE="-race" to enable race testing
# Set to the goveralls binary path to report coverage results to Coveralls.io.
KUBE_GOVERALLS_BIN=${KUBE_GOVERALLS_BIN:-}
# Comma separated list of API Versions that should be tested.
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1beta1,v1beta3"}
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1beta3"}
# Run tests with the standard (registry) and a custom etcd prefix
# (kubernetes.io/registry).
KUBE_TEST_ETCD_PREFIXES=${KUBE_TEST_ETCD_PREFIXES:-"registry,kubernetes.io/registry"}

View File

@ -25,7 +25,7 @@ set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
source "${KUBE_ROOT}/hack/lib/init.sh"
# Comma separated list of API Versions that should be tested.
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1beta1,v1beta3"}
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1beta3"}
KUBE_INTEGRATION_TEST_MAX_CONCURRENCY=${KUBE_INTEGRATION_TEST_MAX_CONCURRENCY:-"-1"}
LOG_LEVEL=${LOG_LEVEL:-2}

View File

@ -24,9 +24,10 @@ KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
source "${KUBE_ROOT}/hack/lib/init.sh"
# The api version in which objects are currently stored in etcd.
KUBE_OLD_API_VERSION=${KUBE_OLD_API_VERSION:-"v1beta1"}
KUBE_OLD_API_VERSION=${KUBE_OLD_API_VERSION:-"v1beta3"}
# The api version in which our etcd objects should be converted to.
# The new api version
# TODO change this to v1 when it's ready.
KUBE_NEW_API_VERSION=${KUBE_NEW_API_VERSION:-"v1beta3"}
ETCD_HOST=${ETCD_HOST:-127.0.0.1}

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

View File

@ -37,8 +37,6 @@ import (
apierrs "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
@ -55,20 +53,13 @@ func convert(obj runtime.Object) (runtime.Object, error) {
return obj, nil
}
// This creates a fake API version, similar to api/latest.go for a v1beta1 equivalent api. It is distinct
// from the Kubernetes API versions to allow clients to properly distinguish the two.
// This creates fake API versions, similar to api/latest.go.
const testVersion = "version"
const newVersion = "version2"
// The equivalent of the Kubernetes v1beta3 API.
const testVersion2 = "version2"
var versions = []string{testVersion, testVersion2}
var legacyCodec = runtime.CodecFor(api.Scheme, testVersion)
var codec = runtime.CodecFor(api.Scheme, testVersion2)
// these codecs reflect ListOptions/DeleteOptions coming from the serverAPIversion
var versionServerCodec = runtime.CodecFor(api.Scheme, "v1beta1")
var version2ServerCodec = runtime.CodecFor(api.Scheme, "v1beta3")
var versions = []string{testVersion, newVersion}
var codec = runtime.CodecFor(api.Scheme, testVersion)
var newCodec = runtime.CodecFor(api.Scheme, newVersion)
var accessor = meta.NewAccessor()
var versioner runtime.ResourceVersioner = accessor
@ -81,13 +72,13 @@ func interfacesFor(version string) (*meta.VersionInterfaces, error) {
switch version {
case testVersion:
return &meta.VersionInterfaces{
Codec: legacyCodec,
Codec: codec,
ObjectConvertor: api.Scheme,
MetadataAccessor: accessor,
}, nil
case testVersion2:
case newVersion:
return &meta.VersionInterfaces{
Codec: codec,
Codec: newCodec,
ObjectConvertor: api.Scheme,
MetadataAccessor: accessor,
}, nil
@ -109,26 +100,44 @@ func newMapper() *meta.DefaultRESTMapper {
)
}
func addTestTypes() {
type ListOptions struct {
runtime.Object
api.TypeMeta `json:",inline"`
LabelSelector string `json:"labels,omitempty"`
FieldSelector string `json:"fields,omitempty"`
Watch bool `json:"watch,omitempty"`
ResourceVersion string `json:"resourceVersion,omitempty"`
}
api.Scheme.AddKnownTypes(testVersion, &Simple{}, &SimpleList{}, &api.Status{}, &ListOptions{}, &api.DeleteOptions{}, &SimpleGetOptions{}, &SimpleRoot{})
}
func addNewTestTypes() {
type ListOptions struct {
runtime.Object
api.TypeMeta `json:",inline"`
LabelSelector string `json:"labelSelector,omitempty"`
FieldSelector string `json:"fieldSelector,omitempty"`
Watch bool `json:"watch,omitempty"`
ResourceVersion string `json:"resourceVersion,omitempty"`
}
api.Scheme.AddKnownTypes(newVersion, &Simple{}, &SimpleList{}, &api.Status{}, &ListOptions{}, &api.DeleteOptions{}, &SimpleGetOptions{}, &SimpleRoot{})
}
func init() {
// Certain API objects are returned regardless of the contents of storage:
// api.Status is returned in errors
// "internal" version
api.Scheme.AddKnownTypes("", &Simple{}, &SimpleList{}, &api.Status{}, &api.ListOptions{}, &SimpleGetOptions{}, &SimpleRoot{})
// "version" version
// TODO: Use versioned api objects?
api.Scheme.AddKnownTypes(testVersion, &Simple{}, &SimpleList{}, &v1beta1.Status{}, &SimpleGetOptions{}, &SimpleRoot{})
// "version2" version
// TODO: Use versioned api objects?
api.Scheme.AddKnownTypes(testVersion2, &Simple{}, &SimpleList{}, &v1beta3.Status{}, &SimpleGetOptions{}, &SimpleRoot{})
// Register SimpleGetOptions with the server versions to convert query params to it
api.Scheme.AddKnownTypes("v1beta1", &SimpleGetOptions{})
api.Scheme.AddKnownTypes("v1beta3", &SimpleGetOptions{})
addTestTypes()
addNewTestTypes()
nsMapper := newMapper()
legacyNsMapper := newMapper()
// enumerate all supported versions, get the kinds, and register with the mapper how to address our resources
// enumerate all supported versions, get the kinds, and register with
// the mapper how to address our resources
for _, version := range versions {
for kind := range api.Scheme.KnownTypes(version) {
mixedCase := true
@ -149,13 +158,12 @@ func init() {
admissionControl = admit.NewAlwaysAdmit()
requestContextMapper = api.NewRequestContextMapper()
//mapper.(*meta.DefaultRESTMapper).Add(meta.RESTScopeNamespaceLegacy, "Simple", testVersion, false)
api.Scheme.AddFieldLabelConversionFunc(testVersion, "Simple",
func(label, value string) (string, string, error) {
return label, value, nil
},
)
api.Scheme.AddFieldLabelConversionFunc(testVersion2, "Simple",
api.Scheme.AddFieldLabelConversionFunc(newVersion, "Simple",
func(label, value string) (string, string, error) {
return label, value, nil
},
@ -210,13 +218,13 @@ func handleInternal(legacy bool, storage map[string]rest.Storage, admissionContr
}
if legacy {
group.Version = testVersion
group.ServerVersion = "v1beta1"
group.Codec = legacyCodec
group.ServerVersion = testVersion
group.Codec = codec
group.Mapper = legacyNamespaceMapper
} else {
group.Version = testVersion2
group.ServerVersion = "v1beta3"
group.Codec = codec
group.Version = newVersion
group.ServerVersion = newVersion
group.Codec = newCodec
group.Mapper = namespaceMapper
}
@ -757,7 +765,7 @@ func TestList(t *testing.T) {
selfLink: "/api/version/simple?namespace=",
legacy: true,
},
// list items in a namespace, v1beta3+
// list items in a namespace in the path
{
url: "/api/version2/namespaces/default/simple",
namespace: "default",
@ -1378,7 +1386,7 @@ func TestDeleteWithOptions(t *testing.T) {
item := &api.DeleteOptions{
GracePeriodSeconds: &grace,
}
body, err := versionServerCodec.Encode(item)
body, err := codec.Encode(item)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -1439,7 +1447,7 @@ func TestLegacyDeleteIgnoresOptions(t *testing.T) {
defer server.Close()
item := api.NewDeleteOptions(300)
body, err := versionServerCodec.Encode(item)
body, err := codec.Encode(item)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -1888,9 +1896,9 @@ func TestParentResourceIsRequired(t *testing.T) {
Context: requestContextMapper,
Mapper: namespaceMapper,
Version: testVersion2,
ServerVersion: "v1beta3",
Codec: codec,
Version: newVersion,
ServerVersion: newVersion,
Codec: newCodec,
}
container := restful.NewContainer()
if err := group.InstallREST(container); err == nil {
@ -1916,9 +1924,9 @@ func TestParentResourceIsRequired(t *testing.T) {
Context: requestContextMapper,
Mapper: namespaceMapper,
Version: testVersion2,
ServerVersion: "v1beta3",
Codec: codec,
Version: newVersion,
ServerVersion: newVersion,
Codec: newCodec,
}
container = restful.NewContainer()
if err := group.InstallREST(container); err != nil {

View File

@ -303,7 +303,7 @@ func TestWatchHTTPTimeout(t *testing.T) {
// Setup a new watchserver
watchServer := &WatchServer{
watcher,
version2ServerCodec,
newCodec,
func(obj runtime.Object) {},
&fakeTimeoutFactory{timeoutCh, done},
}
@ -315,13 +315,13 @@ func TestWatchHTTPTimeout(t *testing.T) {
// Setup a client
dest, _ := url.Parse(s.URL)
dest.Path = "/api/version/watch/resource"
dest.RawQuery = ""
dest.Path = "/api/" + newVersion + "/simple"
dest.RawQuery = "watch=true"
req, _ := http.NewRequest("GET", dest.String(), nil)
client := http.Client{}
resp, err := client.Do(req)
watcher.Add(&api.Pod{TypeMeta: api.TypeMeta{APIVersion: "v1beta3"}})
watcher.Add(&Simple{TypeMeta: api.TypeMeta{APIVersion: newVersion}})
// Make sure we can actually watch an endpoint
decoder := json.NewDecoder(resp.Body)

View File

@ -106,14 +106,6 @@ func TestExec(t *testing.T) {
pod *api.Pod
execErr bool
}{
{
name: "v1beta1 - pod exec",
version: "v1beta1",
podPath: "/api/v1beta1/pods/foo",
execPath: "/api/v1beta1/pods/foo/exec",
nsInQuery: true,
pod: execPod(),
},
{
name: "v1beta3 - pod exec",
version: "v1beta3",

View File

@ -155,10 +155,10 @@ func TestGetUnknownSchemaObjectListGeneric(t *testing.T) {
obj2 string
}{
"handles specific version": {
output: "v1beta3",
list: "v1beta3",
output: "v1",
list: "v1",
obj1: "unlikelyversion",
obj2: "v1beta3",
obj2: "v1",
},
"handles second specific version": {
output: "unlikelyversion",
@ -167,14 +167,14 @@ func TestGetUnknownSchemaObjectListGeneric(t *testing.T) {
obj2: "v1beta3", // version of the API response
},
"handles common version": {
output: "v1beta1",
list: "v1beta1",
output: "v1beta3",
list: "v1beta3",
obj1: "unlikelyversion", // because test scheme defaults to unlikelyversion
obj2: "v1beta1",
obj2: "v1beta3",
},
}
for k, test := range testCases {
apiCodec := runtime.CodecFor(api.Scheme, "v1beta1")
apiCodec := runtime.CodecFor(api.Scheme, "v1beta3")
regularClient := &client.FakeRESTClient{
Codec: apiCodec,
Client: client.HTTPClientFunc(func(req *http.Request) (*http.Response, error) {

View File

@ -156,14 +156,6 @@ func TestLog(t *testing.T) {
nsInQuery bool
pod *api.Pod
}{
{
name: "v1beta1 - pod log",
version: "v1beta1",
podPath: "/api/v1beta1/pods/foo",
logPath: "/api/v1beta1/pods/foo/log",
nsInQuery: true,
pod: testPod(),
},
{
name: "v1beta3 - pod log",
version: "v1beta3",

View File

@ -45,14 +45,6 @@ func TestPortForward(t *testing.T) {
pod *api.Pod
pfErr bool
}{
{
name: "v1beta1 - pod portforward",
version: "v1beta1",
podPath: "/api/v1beta1/pods/foo",
pfPath: "/api/v1beta1/pods/foo/portforward",
nsInQuery: true,
pod: execPod(),
},
{
name: "v1beta3 - pod portforward",
version: "v1beta3",

View File

@ -43,7 +43,7 @@ func TestMerge(t *testing.T) {
Name: "foo",
},
},
fragment: `{ "apiVersion": "v1beta1" }`,
fragment: `{ "apiVersion": "v1beta3" }`,
expected: &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "foo",
@ -94,25 +94,6 @@ func TestMerge(t *testing.T) {
},
},
}, */
{
kind: "Pod",
obj: &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "foo",
},
},
fragment: `{ "apiVersion": "v1beta1", "id": "baz", "desiredState": { "host": "bar" } }`,
expected: &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "baz",
},
Spec: api.PodSpec{
NodeName: "bar",
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
},
},
},
{
kind: "Pod",
obj: &api.Pod{
@ -148,24 +129,6 @@ func TestMerge(t *testing.T) {
expected: &api.Pod{},
expectErr: true,
},
{
kind: "Pod",
obj: &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "foo",
},
},
fragment: `{ "apiVersion": "v1beta1", "id": null}`,
expected: &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "",
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
},
},
},
{
kind: "Service",
obj: &api.Service{},
@ -177,11 +140,17 @@ func TestMerge(t *testing.T) {
obj: &api.Service{
Spec: api.ServiceSpec{},
},
fragment: `{ "apiVersion": "v1beta1", "port": 0 }`,
fragment: `{ "apiVersion": "v1beta3", "spec": { "ports": [ { "port": 0 } ] } }`,
expected: &api.Service{
Spec: api.ServiceSpec{
SessionAffinity: "None",
Type: api.ServiceTypeClusterIP,
Ports: []api.ServicePort{
{
Protocol: api.ProtocolTCP,
Port: 0,
},
},
},
},
},
@ -194,7 +163,7 @@ func TestMerge(t *testing.T) {
},
},
},
fragment: `{ "apiVersion": "v1beta1", "selector": { "version": "v2" } }`,
fragment: `{ "apiVersion": "v1beta3", "spec": { "selector": { "version": "v2" } } }`,
expected: &api.Service{
Spec: api.ServiceSpec{
SessionAffinity: "None",

View File

@ -24,14 +24,12 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet"
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
utilyaml "github.com/GoogleCloudPlatform/kubernetes/pkg/util/yaml"
"github.com/ghodss/yaml"
"github.com/golang/glog"
)
@ -144,68 +142,3 @@ func tryDecodePodList(data []byte, defaultFn defaultFunc) (parsed bool, pods api
}
return true, *newPods, err
}
func tryDecodeSingleManifest(data []byte, defaultFn defaultFunc) (parsed bool, manifest v1beta1.ContainerManifest, pod *api.Pod, err error) {
// TODO: should be api.Scheme.Decode
// This is awful. DecodeInto() expects to find an APIObject, which
// Manifest is not. We keep reading manifest for now for compat, but
// we will eventually change it to read Pod (at which point this all
// becomes nicer). Until then, we assert that the ContainerManifest
// structure on disk is always v1beta1. Read that, convert it to a
// "current" ContainerManifest (should be ~identical), then convert
// that to a Pod (which is a well-understood conversion). This
// avoids writing a v1beta1.ContainerManifest -> api.Pod
// conversion which would be identical to the api.ContainerManifest ->
// api.Pod conversion.
pod = new(api.Pod)
if err = yaml.Unmarshal(data, &manifest); err != nil {
return false, manifest, pod, err
}
newManifest := api.ContainerManifest{}
if err = api.Scheme.Convert(&manifest, &newManifest); err != nil {
return false, manifest, pod, err
}
if errs := validation.ValidateManifest(&newManifest); len(errs) > 0 {
err = fmt.Errorf("invalid manifest: %v", errs)
return false, manifest, pod, err
}
if err = api.Scheme.Convert(&newManifest, pod); err != nil {
return true, manifest, pod, err
}
if err := defaultFn(pod); err != nil {
return true, manifest, pod, err
}
// Success.
return true, manifest, pod, nil
}
func tryDecodeManifestList(data []byte, defaultFn defaultFunc) (parsed bool, manifests []v1beta1.ContainerManifest, pods api.PodList, err error) {
// TODO: should be api.Scheme.Decode
// See the comment in tryDecodeSingle().
if err = yaml.Unmarshal(data, &manifests); err != nil {
return false, manifests, pods, err
}
newManifests := []api.ContainerManifest{}
if err = api.Scheme.Convert(&manifests, &newManifests); err != nil {
return false, manifests, pods, err
}
for i := range newManifests {
manifest := &newManifests[i]
if errs := validation.ValidateManifest(manifest); len(errs) > 0 {
err = fmt.Errorf("invalid manifest: %v", errs)
return false, manifests, pods, err
}
}
list := api.ContainerManifestList{Items: newManifests}
if err = api.Scheme.Convert(&list, &pods); err != nil {
return true, manifests, pods, err
}
for i := range pods.Items {
pod := &pods.Items[i]
if err := defaultFn(pod); err != nil {
return true, manifests, pods, err
}
}
// Success.
return true, manifests, pods, nil
}

View File

@ -148,15 +148,6 @@ func (s *sourceFile) extractFromFile(filename string) (pod *api.Pod, err error)
return s.applyDefaults(pod, filename)
}
parsed, _, pod, manifestErr := tryDecodeSingleManifest(data, defaultFn)
if parsed {
if manifestErr != nil {
// It parsed but could not be used.
return pod, manifestErr
}
return pod, nil
}
parsed, pod, podErr := tryDecodeSinglePod(data, defaultFn)
if parsed {
if podErr != nil {
@ -165,7 +156,6 @@ func (s *sourceFile) extractFromFile(filename string) (pod *api.Pod, err error)
return pod, nil
}
return pod, fmt.Errorf("%v: read '%v', but couldn't parse as neither "+
"manifest (%v) nor pod (%v).\n",
filename, string(data), manifestErr, podErr)
return pod, fmt.Errorf("%v: read '%v', but couldn't parse as pod(%v).\n",
filename, string(data), podErr)
}

View File

@ -17,22 +17,18 @@ limitations under the License.
package config
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"sort"
"testing"
"time"
"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/validation"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/securitycontext"
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
)
func TestExtractFromNonExistentFile(t *testing.T) {
@ -339,111 +335,3 @@ func TestExtractFromEmptyDir(t *testing.T) {
t.Errorf("Expected %#v, Got %#v", expected, update)
}
}
func exampleManifestAndPod(id string) (v1beta1.ContainerManifest, *api.Pod) {
hostname := "an-example-host"
manifest := v1beta1.ContainerManifest{
Version: "v1beta1",
ID: id,
UUID: types.UID(id),
Containers: []v1beta1.Container{
{
Name: "c" + id,
Image: "foo",
TerminationMessagePath: "/somepath",
},
},
Volumes: []v1beta1.Volume{
{
Name: "host-dir",
Source: v1beta1.VolumeSource{
HostDir: &v1beta1.HostPathVolumeSource{"/dir/path"},
},
},
},
}
expectedPod := &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: id + "-" + hostname,
UID: types.UID(id),
Namespace: kubelet.NamespaceDefault,
SelfLink: getSelfLink(id+"-"+hostname, kubelet.NamespaceDefault),
},
Spec: api.PodSpec{
NodeName: hostname,
Containers: []api.Container{
{
Name: "c" + id,
Image: "foo",
},
},
Volumes: []api.Volume{
{
Name: "host-dir",
VolumeSource: api.VolumeSource{
HostPath: &api.HostPathVolumeSource{"/dir/path"},
},
},
},
},
}
return manifest, expectedPod
}
func TestExtractFromDir(t *testing.T) {
if !api.PreV1Beta3(testapi.Version()) {
return
}
manifest, expectedPod := exampleManifestAndPod("1")
manifest2, expectedPod2 := exampleManifestAndPod("2")
manifests := []v1beta1.ContainerManifest{manifest, manifest2}
pods := []*api.Pod{expectedPod, expectedPod2}
files := make([]*os.File, len(manifests))
dirName, err := ioutil.TempDir("", "foo")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
for i, manifest := range manifests {
data, err := json.Marshal(manifest)
if err != nil {
t.Errorf("Unexpected error: %v", err)
continue
}
file, err := ioutil.TempFile(dirName, manifest.ID)
if err != nil {
t.Errorf("Unexpected error: %v", err)
continue
}
name := file.Name()
if err := file.Close(); err != nil {
t.Errorf("Unexpected error: %v", err)
continue
}
ioutil.WriteFile(name, data, 0755)
files[i] = file
}
ch := make(chan interface{}, 1)
c := sourceFile{dirName, "an-example-host", ch}
err = c.extractFromPath()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
update := (<-ch).(kubelet.PodUpdate)
expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, pods...)
sort.Sort(sortedPods(update.Pods))
sort.Sort(sortedPods(expected.Pods))
if !api.Semantic.DeepDerivative(expected, update) {
t.Fatalf("Expected %#v, Got %#v", expected, update)
}
for _, pod := range update.Pods {
if errs := validation.ValidatePod(pod); len(errs) != 0 {
t.Errorf("Expected no validation errors on %#v, Got %q", pod, errs)
}
}
}

View File

@ -77,50 +77,12 @@ func (s *sourceURL) extractFromURL() error {
s.updates <- kubelet.PodUpdate{[]*api.Pod{}, kubelet.SET, kubelet.HTTPSource}
return fmt.Errorf("zero-length data received from %v", s.url)
}
// Short circuit if the manifest has not changed since the last time it was read.
// Short circuit if the data has not changed since the last time it was read.
if bytes.Compare(data, s.data) == 0 {
return nil
}
s.data = data
// First try as if it's a single manifest
parsed, manifest, pod, singleErr := tryDecodeSingleManifest(data, s.applyDefaults)
if parsed {
if singleErr != nil {
// It parsed but could not be used.
return singleErr
}
// It parsed!
s.updates <- kubelet.PodUpdate{[]*api.Pod{pod}, kubelet.SET, kubelet.HTTPSource}
return nil
}
// That didn't work, so try an array of manifests.
parsed, manifests, podList, multiErr := tryDecodeManifestList(data, s.applyDefaults)
if parsed {
if multiErr != nil {
// It parsed but could not be used.
return multiErr
}
// A single manifest that did not pass semantic validation will yield an empty
// array of manifests (and no error) when unmarshaled as such. In that case,
// if the single manifest at least had a Version, we return the single-manifest
// error (if any).
if len(manifests) == 0 && len(manifest.Version) != 0 {
return singleErr
}
// It parsed!
pods := make([]*api.Pod, 0)
for i := range podList.Items {
pods = append(pods, &podList.Items[i])
}
s.updates <- kubelet.PodUpdate{pods, kubelet.SET, kubelet.HTTPSource}
return nil
}
// Parsing it as ContainerManifest(s) failed.
// Try to parse it as Pod(s).
// First try as it is a single pod.
parsed, pod, singlePodErr := tryDecodeSinglePod(data, s.applyDefaults)
if parsed {
@ -147,9 +109,7 @@ func (s *sourceURL) extractFromURL() error {
return nil
}
return fmt.Errorf("%v: received '%v', but couldn't parse as neither "+
"single (%v: %+v) or multiple manifests (%v: %+v) nor "+
return fmt.Errorf("%v: received '%v', but couldn't parse as "+
"single (%v) or multiple pods (%v).\n",
s.url, string(data), singleErr, manifest, multiErr, manifests,
singlePodErr, multiPodErr)
s.url, string(data), singlePodErr, multiPodErr)
}

View File

@ -24,7 +24,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/validation"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
@ -118,195 +117,6 @@ func TestExtractInvalidManifest(t *testing.T) {
}
}
func TestExtractManifestFromHTTP(t *testing.T) {
hostname := "random-hostname"
// ContainerManifests are not supported v1beta3 onwards.
if api.PreV1Beta3(testapi.Version()) {
return
}
var testCases = []struct {
desc string
manifests interface{}
expected kubelet.PodUpdate
}{
{
desc: "Single manifest",
manifests: v1beta1.ContainerManifest{Version: "v1beta1", ID: "foo", UUID: "111",
Containers: []v1beta1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1beta1.PullAlways}}},
expected: CreatePodUpdate(kubelet.SET,
kubelet.HTTPSource,
&api.Pod{
ObjectMeta: api.ObjectMeta{
UID: "111",
Name: "foo" + "-" + hostname,
Namespace: "foobar",
SelfLink: getSelfLink("foo-"+hostname, kubelet.NamespaceDefault),
},
Spec: api.PodSpec{
NodeName: hostname,
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{
Name: "1",
Image: "foo",
TerminationMessagePath: "/dev/termination-log",
ImagePullPolicy: "Always",
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
},
}),
},
{
desc: "Single manifest without ID",
manifests: v1beta1.ContainerManifest{Version: "v1beta1", UUID: "111",
Containers: []v1beta1.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}},
expected: CreatePodUpdate(kubelet.SET,
kubelet.HTTPSource,
&api.Pod{
ObjectMeta: api.ObjectMeta{
UID: "111",
Name: "111" + "-" + hostname,
Namespace: "foobar",
SelfLink: getSelfLink("111-"+hostname, kubelet.NamespaceDefault),
},
Spec: api.PodSpec{
NodeName: hostname,
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{
Name: "ctr",
Image: "image",
TerminationMessagePath: "/dev/termination-log",
ImagePullPolicy: "IfNotPresent",
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
},
}),
},
{
desc: "Single manifest with v1beta2",
manifests: v1beta1.ContainerManifest{Version: "v1beta2", ID: "foo", UUID: "111",
Containers: []v1beta1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1beta1.PullAlways}}},
expected: CreatePodUpdate(kubelet.SET,
kubelet.HTTPSource,
&api.Pod{
ObjectMeta: api.ObjectMeta{
UID: "111",
Name: "foo" + "-" + hostname,
Namespace: "foobar",
SelfLink: getSelfLink("foo-"+hostname, kubelet.NamespaceDefault),
},
Spec: api.PodSpec{
NodeName: hostname,
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{
Name: "1",
Image: "foo",
TerminationMessagePath: "/dev/termination-log",
ImagePullPolicy: "Always",
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
},
}),
},
{
desc: "Multiple manifests",
manifests: []v1beta1.ContainerManifest{
{Version: "v1beta1", ID: "foo", UUID: "111",
Containers: []v1beta1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1beta1.PullAlways}}},
{Version: "v1beta1", ID: "bar", UUID: "222",
Containers: []v1beta1.Container{{Name: "1", Image: "foo", ImagePullPolicy: ""}}},
},
expected: CreatePodUpdate(kubelet.SET,
kubelet.HTTPSource,
&api.Pod{
ObjectMeta: api.ObjectMeta{
UID: "111",
Name: "foo" + "-" + hostname,
Namespace: "foobar",
SelfLink: getSelfLink("foo-"+hostname, kubelet.NamespaceDefault),
},
Spec: api.PodSpec{
NodeName: hostname,
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{
Name: "1",
Image: "foo",
TerminationMessagePath: "/dev/termination-log",
ImagePullPolicy: "Always",
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
},
},
&api.Pod{
ObjectMeta: api.ObjectMeta{
UID: "222",
Name: "bar" + "-" + hostname,
Namespace: "foobar",
SelfLink: getSelfLink("bar-"+hostname, kubelet.NamespaceDefault),
},
Spec: api.PodSpec{
NodeName: hostname,
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
Containers: []api.Container{{
Name: "1",
Image: "foo",
TerminationMessagePath: "/dev/termination-log",
ImagePullPolicy: "IfNotPresent",
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
},
}),
},
{
desc: "Empty Array",
manifests: []v1beta1.ContainerManifest{},
expected: CreatePodUpdate(kubelet.SET, kubelet.HTTPSource),
},
}
for _, testCase := range testCases {
data, err := json.Marshal(testCase.manifests)
if err != nil {
t.Fatalf("%s: Some weird json problem: %v", testCase.desc, err)
}
fakeHandler := util.FakeHandler{
StatusCode: 200,
ResponseBody: string(data),
}
testServer := httptest.NewServer(&fakeHandler)
defer testServer.Close()
ch := make(chan interface{}, 1)
c := sourceURL{testServer.URL, hostname, ch, nil}
if err := c.extractFromURL(); err != nil {
t.Errorf("%s: Unexpected error: %v", testCase.desc, err)
continue
}
update := (<-ch).(kubelet.PodUpdate)
for i := range update.Pods {
// There's no way to provide namespace in ContainerManifest, so
// it will be defaulted.
if update.Pods[i].Namespace != kubelet.NamespaceDefault {
t.Errorf("Unexpected namespace: %s", update.Pods[0].Namespace)
}
update.Pods[i].ObjectMeta.Namespace = "foobar"
}
if !api.Semantic.DeepEqual(testCase.expected, update) {
t.Errorf("%s: Expected: %#v, Got: %#v", testCase.desc, testCase.expected, update)
}
for _, pod := range update.Pods {
if errs := validation.ValidatePod(pod); len(errs) != 0 {
t.Errorf("%s: Expected no validation errors on %#v, Got %v", testCase.desc, pod, errors.NewAggregate(errs))
}
}
}
}
func TestExtractPodsFromHTTP(t *testing.T) {
hostname := "different-value"

View File

@ -33,8 +33,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
"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/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator"
@ -91,10 +89,6 @@ type Config struct {
EnableUISupport bool
// allow downstream consumers to disable swagger
EnableSwaggerSupport bool
// allow v1beta1 to be conditionally disabled
DisableV1Beta1 bool
// allow v1beta2 to be conditionally disabled
DisableV1Beta2 bool
// allow v1beta3 to be conditionally disabled
DisableV1Beta3 bool
// allow v1 to be conditionally enabled
@ -170,8 +164,6 @@ type Master struct {
authorizer authorizer.Authorizer
admissionControl admission.Interface
masterCount int
v1beta1 bool
v1beta2 bool
v1beta3 bool
v1 bool
requestContextMapper api.RequestContextMapper
@ -328,8 +320,6 @@ func New(c *Config) *Master {
authenticator: c.Authenticator,
authorizer: c.Authorizer,
admissionControl: c.AdmissionControl,
v1beta1: !c.DisableV1Beta1,
v1beta2: !c.DisableV1Beta2,
v1beta3: !c.DisableV1Beta3,
v1: c.EnableV1,
requestContextMapper: c.RequestContextMapper,
@ -501,18 +491,6 @@ func (m *Master) init(c *Config) {
}
apiVersions := []string{}
if m.v1beta1 {
if err := m.api_v1beta1().InstallREST(m.handlerContainer); err != nil {
glog.Fatalf("Unable to setup API v1beta1: %v", err)
}
apiVersions = append(apiVersions, "v1beta1")
}
if m.v1beta2 {
if err := m.api_v1beta2().InstallREST(m.handlerContainer); err != nil {
glog.Fatalf("Unable to setup API v1beta2: %v", err)
}
apiVersions = append(apiVersions, "v1beta2")
}
if m.v1beta3 {
if err := m.api_v1beta3().InstallREST(m.handlerContainer); err != nil {
glog.Fatalf("Unable to setup API v1beta3: %v", err)
@ -718,38 +696,6 @@ func (m *Master) defaultAPIGroupVersion() *apiserver.APIGroupVersion {
}
}
// api_v1beta1 returns the resources and codec for API version v1beta1.
func (m *Master) api_v1beta1() *apiserver.APIGroupVersion {
storage := make(map[string]rest.Storage)
for k, v := range m.storage {
if k == "podTemplates" {
continue
}
storage[k] = v
}
version := m.defaultAPIGroupVersion()
version.Storage = storage
version.Version = "v1beta1"
version.Codec = v1beta1.Codec
return version
}
// api_v1beta2 returns the resources and codec for API version v1beta2.
func (m *Master) api_v1beta2() *apiserver.APIGroupVersion {
storage := make(map[string]rest.Storage)
for k, v := range m.storage {
if k == "podTemplates" {
continue
}
storage[k] = v
}
version := m.defaultAPIGroupVersion()
version.Storage = storage
version.Version = "v1beta2"
version.Codec = v1beta2.Codec
return version
}
// api_v1beta3 returns the resources and codec for API version v1beta3.
func (m *Master) api_v1beta3() *apiserver.APIGroupVersion {
storage := make(map[string]rest.Storage)

View File

@ -24,8 +24,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/endpoints"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
"github.com/GoogleCloudPlatform/kubernetes/pkg/controller/framework"
@ -302,12 +300,6 @@ func (e *EndpointController) syncService(key string) {
for i := range service.Spec.Ports {
servicePort := &service.Spec.Ports[i]
// TODO: Once v1beta1 and v1beta2 are EOL'ed,
// this can safely assume that TargetPort is
// populated, and findPort() can be removed.
_ = v1beta1.Dependency
_ = v1beta2.Dependency
portName := servicePort.Name
portProto := servicePort.Protocol
portNum, err := findPort(pod, servicePort)
@ -398,32 +390,14 @@ func (e *EndpointController) checkLeftoverEndpoints() {
}
}
func findDefaultPort(pod *api.Pod, servicePort int, proto api.Protocol) int {
for _, container := range pod.Spec.Containers {
for _, port := range container.Ports {
if port.Protocol == proto {
return port.ContainerPort
}
}
}
return servicePort
}
// findPort locates the container port for the given manifest and portName.
// If the targetPort is a non-zero number, use that. If the targetPort is 0 or
// not specified, use the first defined port with the same protocol. If no port
// is defined, use the service's port. If the targetPort is an empty string use
// the first defined port with the same protocol. If no port is defined, use
// the service's port. If the targetPort is a non-empty string, look that
// findPort locates the container port for the given pod and portName. If the
// targetPort is a number, use that. If the targetPort is a string, look that
// string up in all named ports in all containers in the target pod. If no
// match is found, fail.
func findPort(pod *api.Pod, svcPort *api.ServicePort) (int, error) {
portName := svcPort.TargetPort
switch portName.Kind {
case util.IntstrString:
if len(portName.StrVal) == 0 {
return findDefaultPort(pod, svcPort.Port, svcPort.Protocol), nil
}
name := portName.StrVal
for _, container := range pod.Spec.Containers {
for _, port := range container.Ports {
@ -433,9 +407,6 @@ func findPort(pod *api.Pod, svcPort *api.ServicePort) (int, error) {
}
}
case util.IntstrInt:
if portName.IntVal == 0 {
return findDefaultPort(pod, svcPort.Port, svcPort.Protocol), nil
}
return portName.IntVal, nil
}

View File

@ -63,7 +63,6 @@ func addPods(store cache.Store, namespace string, nPods int, nPorts int) {
}
func TestFindPort(t *testing.T) {
servicePort := 999
testCases := []struct {
name string
containers []api.Container
@ -90,74 +89,6 @@ func TestFindPort(t *testing.T) {
port: util.NewIntOrStringFromInt(93),
expected: 93,
pass: true,
}, {
name: "zero int, no ports",
containers: []api.Container{{}},
port: util.NewIntOrStringFromInt(0),
expected: servicePort,
pass: true,
}, {
name: "zero int, one ctr with ports",
containers: []api.Container{{Ports: []api.ContainerPort{{
Name: "",
ContainerPort: 11,
Protocol: "UDP",
}, {
Name: "p",
ContainerPort: 22,
Protocol: "TCP",
}}}},
port: util.NewIntOrStringFromInt(0),
expected: 22,
pass: true,
}, {
name: "zero int, two ctr with ports",
containers: []api.Container{{}, {Ports: []api.ContainerPort{{
Name: "",
ContainerPort: 11,
Protocol: "UDP",
}, {
Name: "p",
ContainerPort: 22,
Protocol: "TCP",
}}}},
port: util.NewIntOrStringFromInt(0),
expected: 22,
pass: true,
}, {
name: "empty str, no ports",
containers: []api.Container{{}},
port: util.NewIntOrStringFromString(""),
expected: servicePort,
pass: true,
}, {
name: "empty str, one ctr with ports",
containers: []api.Container{{Ports: []api.ContainerPort{{
Name: "",
ContainerPort: 11,
Protocol: "UDP",
}, {
Name: "p",
ContainerPort: 22,
Protocol: "TCP",
}}}},
port: util.NewIntOrStringFromString(""),
expected: 22,
pass: true,
}, {
name: "empty str, two ctr with ports",
containers: []api.Container{{}, {Ports: []api.ContainerPort{{
Name: "",
ContainerPort: 11,
Protocol: "UDP",
}, {
Name: "p",
ContainerPort: 22,
Protocol: "TCP",
}}}},
port: util.NewIntOrStringFromString(""),
expected: 22,
pass: true,
}, {
name: "valid str, no ports",
containers: []api.Container{{}},
@ -204,7 +135,7 @@ func TestFindPort(t *testing.T) {
for _, tc := range testCases {
port, err := findPort(&api.Pod{Spec: api.PodSpec{Containers: tc.containers}},
&api.ServicePort{Protocol: "TCP", Port: servicePort, TargetPort: tc.port})
&api.ServicePort{Protocol: "TCP", TargetPort: tc.port})
if err != nil && tc.pass {
t.Errorf("unexpected error for %s: %v", tc.name, err)
}

View File

@ -8,7 +8,7 @@ matrix:
include:
- go: 1.4
env:
- KUBE_TEST_API_VERSIONS=v1beta1 KUBE_TEST_ETCD_PREFIXES=registry
- KUBE_TEST_API_VERSIONS=v1beta3 KUBE_TEST_ETCD_PREFIXES=registry
- go: 1.3
env:
- KUBE_TEST_API_VERSIONS=v1beta3 KUBE_TEST_ETCD_PREFIXES=kubernetes.io/registry