Commit c1fa8283 authored by Eric Tune's avatar Eric Tune

Merge pull request #8917 from krousey/delete_deprecated_apis

Delete deprecated apis
parents 0bb78fe6 f4e2c738
...@@ -6,7 +6,7 @@ matrix: ...@@ -6,7 +6,7 @@ matrix:
include: include:
- go: 1.4 - go: 1.4
env: env:
- KUBE_TEST_API_VERSIONS="v1beta1" - KUBE_TEST_API_VERSIONS="v1beta3"
KUBE_TEST_ETCD_PREFIXES="registry" KUBE_TEST_ETCD_PREFIXES="registry"
- go: 1.3 - go: 1.3
env: env:
......
...@@ -23,5 +23,6 @@ ...@@ -23,5 +23,6 @@
} }
] ]
} }
] ],
"models": {}
} }
\ No newline at end of file
...@@ -2,14 +2,14 @@ ...@@ -2,14 +2,14 @@
"swaggerVersion": "1.2", "swaggerVersion": "1.2",
"apis": [ "apis": [
{ {
"path": "/api",
"description": "get available API versions"
},
{
"path": "/api/v1beta3", "path": "/api/v1beta3",
"description": "API at /api/v1beta3 version v1beta3" "description": "API at /api/v1beta3 version v1beta3"
}, },
{ {
"path": "/api",
"description": "get available API versions"
},
{
"path": "/version", "path": "/version",
"description": "git code version from which this is built" "description": "git code version from which this is built"
} }
...@@ -19,4 +19,4 @@ ...@@ -19,4 +19,4 @@
"title": "", "title": "",
"description": "" "description": ""
} }
} }
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -23,5 +23,6 @@ ...@@ -23,5 +23,6 @@
} }
] ]
} }
] ],
"models": {}
} }
\ No newline at end of file
...@@ -16,7 +16,7 @@ spec: ...@@ -16,7 +16,7 @@ spec:
kubernetes.io/cluster-service: "true" kubernetes.io/cluster-service: "true"
spec: spec:
containers: containers:
- image: gcr.io/google_containers/heapster:v0.12.1 - image: gcr.io/google_containers/heapster:v0.13.0
name: heapster name: heapster
command: command:
- /heapster - /heapster
......
...@@ -16,7 +16,7 @@ spec: ...@@ -16,7 +16,7 @@ spec:
kubernetes.io/cluster-service: "true" kubernetes.io/cluster-service: "true"
spec: spec:
containers: containers:
- image: gcr.io/google_containers/heapster:v0.12.1 - image: gcr.io/google_containers/heapster:v0.13.0
name: heapster name: heapster
command: command:
- /heapster - /heapster
......
...@@ -23,8 +23,6 @@ import ( ...@@ -23,8 +23,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1" _ "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/api/v1beta3"
pkg_runtime "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" pkg_runtime "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
......
...@@ -24,8 +24,6 @@ import ( ...@@ -24,8 +24,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1" _ "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/api/v1beta3"
pkg_runtime "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" pkg_runtime "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
......
...@@ -605,23 +605,6 @@ func runPatchTest(c *client.Client) { ...@@ -605,23 +605,6 @@ func runPatchTest(c *client.Client) {
RemoveLabelBody []byte RemoveLabelBody []byte
RemoveAllLabelsBody []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": { "v1beta3": {
api.JSONPatchType: { api.JSONPatchType: {
[]byte(`[{"op":"add","path":"/metadata/labels","value":{"foo":"bar","baz":"qux"}}]`), []byte(`[{"op":"add","path":"/metadata/labels","value":{"foo":"bar","baz":"qux"}}]`),
...@@ -938,7 +921,7 @@ func main() { ...@@ -938,7 +921,7 @@ func main() {
glog.Infof("Running tests for APIVersion: %s", apiVersion) glog.Infof("Running tests for APIVersion: %s", apiVersion)
firstManifestURL := ServeCachedManifestFile(testPodSpecFile) firstManifestURL := ServeCachedManifestFile(testPodSpecFile)
secondManifestURL := ServeCachedManifestFile(testManifestFile) secondManifestURL := ServeCachedManifestFile(testPodSpecFile)
apiServerURL, _ := startComponents(firstManifestURL, secondManifestURL, apiVersion) apiServerURL, _ := startComponents(firstManifestURL, secondManifestURL, apiVersion)
// Ok. we're good to go. // Ok. we're good to go.
...@@ -1059,27 +1042,3 @@ const ( ...@@ -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`
)
{
"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"}
}
...@@ -264,16 +264,7 @@ func (s *APIServer) Run(_ []string) error { ...@@ -264,16 +264,7 @@ func (s *APIServer) Run(_ []string) error {
if ok && legacyAPIFlagValue == "false" { if ok && legacyAPIFlagValue == "false" {
disableLegacyAPIs = true disableLegacyAPIs = true
} }
_ = disableLegacyAPIs // hush the compiler while we don't have legacy APIs to disable.
// "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)
// "api/v1beta3={true|false} allows users to enable/disable v1beta3 API. // "api/v1beta3={true|false} allows users to enable/disable v1beta3 API.
// This takes preference over api/all and api/legacy, if specified. // This takes preference over api/all and api/legacy, if specified.
...@@ -369,8 +360,6 @@ func (s *APIServer) Run(_ []string) error { ...@@ -369,8 +360,6 @@ func (s *APIServer) Run(_ []string) error {
SupportsBasicAuth: len(s.BasicAuthFile) > 0, SupportsBasicAuth: len(s.BasicAuthFile) > 0,
Authorizer: authorizer, Authorizer: authorizer,
AdmissionControl: admissionController, AdmissionControl: admissionController,
DisableV1Beta1: disableV1beta1,
DisableV1Beta2: disableV1beta2,
DisableV1Beta3: disableV1beta3, DisableV1Beta3: disableV1beta3,
EnableV1: enableV1, EnableV1: enableV1,
MasterServiceNamespace: s.MasterServiceNamespace, MasterServiceNamespace: s.MasterServiceNamespace,
......
...@@ -28,8 +28,6 @@ import ( ...@@ -28,8 +28,6 @@ import (
"runtime" "runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "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/api/v1beta3"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
......
...@@ -121,7 +121,6 @@ func walkJSONFiles(inDir string, fn func(name, path string, data []byte)) error ...@@ -121,7 +121,6 @@ func walkJSONFiles(inDir string, fn func(name, path string, data []byte)) error
func TestExampleObjectSchemas(t *testing.T) { func TestExampleObjectSchemas(t *testing.T) {
cases := map[string]map[string]runtime.Object{ cases := map[string]map[string]runtime.Object{
"../cmd/integration": { "../cmd/integration": {
"v1beta1-controller": &api.ReplicationController{},
"v1beta3-controller": &api.ReplicationController{}, "v1beta3-controller": &api.ReplicationController{},
}, },
"../examples/guestbook": { "../examples/guestbook": {
......
...@@ -114,8 +114,6 @@ PATH="${KUBE_OUTPUT_HOSTBIN}":$PATH ...@@ -114,8 +114,6 @@ PATH="${KUBE_OUTPUT_HOSTBIN}":$PATH
kube_api_versions=( kube_api_versions=(
"" ""
v1beta1
v1beta2
v1beta3 v1beta3
) )
for version in "${kube_api_versions[@]}"; do for version in "${kube_api_versions[@]}"; do
......
...@@ -52,7 +52,7 @@ KUBE_RACE=${KUBE_RACE:-} # use KUBE_RACE="-race" to enable race testing ...@@ -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. # Set to the goveralls binary path to report coverage results to Coveralls.io.
KUBE_GOVERALLS_BIN=${KUBE_GOVERALLS_BIN:-} KUBE_GOVERALLS_BIN=${KUBE_GOVERALLS_BIN:-}
# Comma separated list of API Versions that should be tested. # 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 # Run tests with the standard (registry) and a custom etcd prefix
# (kubernetes.io/registry). # (kubernetes.io/registry).
KUBE_TEST_ETCD_PREFIXES=${KUBE_TEST_ETCD_PREFIXES:-"registry,kubernetes.io/registry"} KUBE_TEST_ETCD_PREFIXES=${KUBE_TEST_ETCD_PREFIXES:-"registry,kubernetes.io/registry"}
......
...@@ -25,7 +25,7 @@ set -o pipefail ...@@ -25,7 +25,7 @@ set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
source "${KUBE_ROOT}/hack/lib/init.sh" source "${KUBE_ROOT}/hack/lib/init.sh"
# Comma separated list of API Versions that should be tested. # 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"} KUBE_INTEGRATION_TEST_MAX_CONCURRENCY=${KUBE_INTEGRATION_TEST_MAX_CONCURRENCY:-"-1"}
LOG_LEVEL=${LOG_LEVEL:-2} LOG_LEVEL=${LOG_LEVEL:-2}
......
...@@ -24,9 +24,10 @@ KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. ...@@ -24,9 +24,10 @@ KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
source "${KUBE_ROOT}/hack/lib/init.sh" source "${KUBE_ROOT}/hack/lib/init.sh"
# The api version in which objects are currently stored in etcd. # 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 api version in which our etcd objects should be converted to.
# The new api version # The new api version
# TODO change this to v1 when it's ready.
KUBE_NEW_API_VERSION=${KUBE_NEW_API_VERSION:-"v1beta3"} KUBE_NEW_API_VERSION=${KUBE_NEW_API_VERSION:-"v1beta3"}
ETCD_HOST=${ETCD_HOST:-127.0.0.1} ETCD_HOST=${ETCD_HOST:-127.0.0.1}
......
...@@ -22,8 +22,6 @@ import ( ...@@ -22,8 +22,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "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" _ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
) )
......
...@@ -24,8 +24,6 @@ import ( ...@@ -24,8 +24,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/registered" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/registered"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1" "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/api/v1beta3"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
...@@ -36,7 +34,7 @@ var Version string ...@@ -36,7 +34,7 @@ var Version string
// OldestVersion is the string that represents the oldest server version supported, // OldestVersion is the string that represents the oldest server version supported,
// for client code that wants to hardcode the lowest common denominator. // 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 // 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 // may be assumed to be least feature rich to most feature rich, and clients may
...@@ -88,20 +86,6 @@ func init() { ...@@ -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 // 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 // if a kind is not enumerated here, it is assumed to have a namespace scope
kindToRootScope := map[string]bool{ kindToRootScope := map[string]bool{
...@@ -130,16 +114,11 @@ func init() { ...@@ -130,16 +114,11 @@ func init() {
if ignoredKinds.Has(kind) { if ignoredKinds.Has(kind) {
continue continue
} }
mixedCase, found := versionMixedCase[version] scope := meta.RESTScopeNamespace
if !found { if kindToRootScope[kind] {
mixedCase = false
}
scope := versionToNamespaceScope[version]
_, found = kindToRootScope[kind]
if found {
scope = meta.RESTScopeRoot scope = meta.RESTScopeRoot
} }
mapper.Add(scope, kind, version, mixedCase) mapper.Add(scope, kind, version, false)
} }
} }
RESTMapper = mapper RESTMapper = mapper
...@@ -149,18 +128,6 @@ func init() { ...@@ -149,18 +128,6 @@ func init() {
// string, or an error if the version is not known. // string, or an error if the version is not known.
func InterfacesFor(version string) (*meta.VersionInterfaces, error) { func InterfacesFor(version string) (*meta.VersionInterfaces, error) {
switch version { 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": case "v1beta3":
return &meta.VersionInterfaces{ return &meta.VersionInterfaces{
Codec: v1beta3.Codec, Codec: v1beta3.Codec,
......
...@@ -21,8 +21,6 @@ import ( ...@@ -21,8 +21,6 @@ import (
"testing" "testing"
internal "github.com/GoogleCloudPlatform/kubernetes/pkg/api" 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) { func TestResourceVersioner(t *testing.T) {
......
...@@ -31,13 +31,11 @@ var RegisteredVersions []string ...@@ -31,13 +31,11 @@ var RegisteredVersions []string
func init() { func init() {
validAPIVersions := map[string]bool{ validAPIVersions := map[string]bool{
"v1": true, "v1": true,
"v1beta1": true,
"v1beta2": true,
"v1beta3": true, "v1beta3": true,
} }
// The default list of supported api versions, in order of most preferred to the least. // 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. // 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. // The versions should be in the order of most preferred to the least.
supportedVersions := os.Getenv("KUBE_API_VERSIONS") supportedVersions := os.Getenv("KUBE_API_VERSIONS")
......
...@@ -27,8 +27,6 @@ import ( ...@@ -27,8 +27,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
apitesting "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testing" 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/api/v1beta3"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
...@@ -89,12 +87,6 @@ func roundTripSame(t *testing.T, item runtime.Object, except ...string) { ...@@ -89,12 +87,6 @@ func roundTripSame(t *testing.T, item runtime.Object, except ...string) {
set := util.NewStringSet(except...) set := util.NewStringSet(except...)
seed := rand.Int63() seed := rand.Int63()
fuzzInternalObject(t, "", item, seed) 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") { if !set.Has("v1beta3") {
fuzzInternalObject(t, "v1beta3", item, seed) fuzzInternalObject(t, "v1beta3", item, seed)
roundTrip(t, v1beta3.Codec, item) roundTrip(t, v1beta3.Codec, item)
...@@ -103,8 +95,6 @@ func roundTripSame(t *testing.T, item runtime.Object, except ...string) { ...@@ -103,8 +95,6 @@ func roundTripSame(t *testing.T, item runtime.Object, except ...string) {
func roundTripAll(t *testing.T, item runtime.Object) { func roundTripAll(t *testing.T, item runtime.Object) {
seed := rand.Int63() 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)) roundTrip(t, v1beta3.Codec, fuzzInternalObject(t, "v1beta3", item, seed))
} }
...@@ -137,10 +127,7 @@ func TestList(t *testing.T) { ...@@ -137,10 +127,7 @@ func TestList(t *testing.T) {
var nonRoundTrippableTypes = util.NewStringSet("ContainerManifest", "ContainerManifestList") var nonRoundTrippableTypes = util.NewStringSet("ContainerManifest", "ContainerManifestList")
var nonInternalRoundTrippableTypes = util.NewStringSet("List", "ListOptions", "PodExecOptions") var nonInternalRoundTrippableTypes = util.NewStringSet("List", "ListOptions", "PodExecOptions")
var nonRoundTrippableTypesByVersion = map[string][]string{ var nonRoundTrippableTypesByVersion = map[string][]string{}
"PodTemplate": {"v1beta1", "v1beta2"},
"PodTemplateList": {"v1beta1", "v1beta2"},
}
func TestRoundTripTypes(t *testing.T) { func TestRoundTripTypes(t *testing.T) {
// api.Scheme.Log(t) // api.Scheme.Log(t)
......
/*
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 (
"fmt"
"net"
"reflect"
"strconv"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
func addConversionFuncs() {
// Our TypeMeta was split into two different structs.
api.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", api.TypeMeta{}, "TypeMeta")
api.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", api.ObjectMeta{}, "ObjectMeta")
api.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", api.ListMeta{}, "ListMeta")
api.Scheme.AddStructFieldConversion(api.TypeMeta{}, "TypeMeta", TypeMeta{}, "TypeMeta")
api.Scheme.AddStructFieldConversion(api.ObjectMeta{}, "ObjectMeta", TypeMeta{}, "TypeMeta")
api.Scheme.AddStructFieldConversion(api.ListMeta{}, "ListMeta", TypeMeta{}, "TypeMeta")
api.Scheme.AddStructFieldConversion(api.Endpoints{}, "Endpoints", Endpoints{}, "Endpoints")
// TODO: scope this to a specific type once that becomes available and remove the Event conversion functions below
// api.Scheme.AddStructFieldConversion(string(""), "Status", string(""), "Condition")
// api.Scheme.AddStructFieldConversion(string(""), "Condition", string(""), "Status")
err := api.Scheme.AddConversionFuncs(
// TypeMeta must be split into two objects
func(in *api.TypeMeta, out *TypeMeta, s conversion.Scope) error {
out.Kind = in.Kind
out.APIVersion = in.APIVersion
return nil
},
func(in *TypeMeta, out *api.TypeMeta, s conversion.Scope) error {
out.Kind = in.Kind
out.APIVersion = in.APIVersion
return nil
},
// ListMeta must be converted to TypeMeta
func(in *api.ListMeta, out *TypeMeta, s conversion.Scope) error {
out.SelfLink = in.SelfLink
if len(in.ResourceVersion) > 0 {
v, err := strconv.ParseUint(in.ResourceVersion, 10, 64)
if err != nil {
return err
}
out.ResourceVersion = v
}
return nil
},
func(in *TypeMeta, out *api.ListMeta, s conversion.Scope) error {
out.SelfLink = in.SelfLink
if in.ResourceVersion != 0 {
out.ResourceVersion = strconv.FormatUint(in.ResourceVersion, 10)
} else {
out.ResourceVersion = ""
}
return nil
},
// ObjectMeta must be converted to TypeMeta
func(in *api.ObjectMeta, out *TypeMeta, s conversion.Scope) error {
out.Namespace = in.Namespace
out.ID = in.Name
out.GenerateName = in.GenerateName
out.UID = in.UID
out.CreationTimestamp = in.CreationTimestamp
out.DeletionTimestamp = in.DeletionTimestamp
out.SelfLink = in.SelfLink
if len(in.ResourceVersion) > 0 {
v, err := strconv.ParseUint(in.ResourceVersion, 10, 64)
if err != nil {
return err
}
out.ResourceVersion = v
}
return s.Convert(&in.Annotations, &out.Annotations, 0)
},
func(in *TypeMeta, out *api.ObjectMeta, s conversion.Scope) error {
out.Namespace = in.Namespace
out.Name = in.ID
out.GenerateName = in.GenerateName
out.UID = in.UID
out.CreationTimestamp = in.CreationTimestamp
out.DeletionTimestamp = in.DeletionTimestamp
out.SelfLink = in.SelfLink
if in.ResourceVersion != 0 {
out.ResourceVersion = strconv.FormatUint(in.ResourceVersion, 10)
} else {
out.ResourceVersion = ""
}
return s.Convert(&in.Annotations, &out.Annotations, 0)
},
// EnvVar's Key is deprecated in favor of Name.
func(in *api.EnvVar, out *EnvVar, s conversion.Scope) error {
out.Value = in.Value
out.Key = in.Name
out.Name = in.Name
if err := s.Convert(&in.ValueFrom, &out.ValueFrom, 0); err != nil {
return err
}
return nil
},
func(in *EnvVar, out *api.EnvVar, s conversion.Scope) error {
out.Value = in.Value
if in.Name != "" {
out.Name = in.Name
} else {
out.Name = in.Key
}
if err := s.Convert(&in.ValueFrom, &out.ValueFrom, 0); err != nil {
return err
}
return nil
},
// Path & MountType are deprecated.
func(in *api.VolumeMount, out *VolumeMount, s conversion.Scope) error {
out.Name = in.Name
out.ReadOnly = in.ReadOnly
out.MountPath = in.MountPath
out.Path = in.MountPath
out.MountType = "" // MountType is ignored.
return nil
},
func(in *VolumeMount, out *api.VolumeMount, s conversion.Scope) error {
out.Name = in.Name
out.ReadOnly = in.ReadOnly
if in.MountPath == "" {
out.MountPath = in.Path
} else {
out.MountPath = in.MountPath
}
return nil
},
// MinionList.Items had a wrong name in v1beta1
func(in *api.NodeList, out *MinionList, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Items, &out.Items, 0); err != nil {
return err
}
out.Minions = out.Items
return nil
},
func(in *MinionList, out *api.NodeList, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil {
return err
}
if len(in.Items) == 0 {
if err := s.Convert(&in.Minions, &out.Items, 0); err != nil {
return err
}
} else {
if err := s.Convert(&in.Items, &out.Items, 0); err != nil {
return err
}
}
return nil
},
func(in *api.PodStatus, out *PodState, s conversion.Scope) error {
if err := s.Convert(&in.Phase, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.Conditions, &out.Conditions, 0); err != nil {
return err
}
if err := s.Convert(&in.ContainerStatuses, &out.Info, 0); err != nil {
return err
}
out.Message = in.Message
out.HostIP = in.HostIP
out.PodIP = in.PodIP
return nil
},
func(in *PodState, out *api.PodStatus, s conversion.Scope) error {
if err := s.Convert(&in.Status, &out.Phase, 0); err != nil {
return err
}
if err := s.Convert(&in.Conditions, &out.Conditions, 0); err != nil {
return err
}
if err := s.Convert(&in.Info, &out.ContainerStatuses, 0); err != nil {
return err
}
out.Message = in.Message
out.HostIP = in.HostIP
out.PodIP = in.PodIP
return nil
},
func(in *api.PodSpec, out *PodState, s conversion.Scope) error {
if err := s.Convert(&in, &out.Manifest, 0); err != nil {
return err
}
out.Host = in.NodeName
return nil
},
func(in *PodState, out *api.PodSpec, s conversion.Scope) error {
if err := s.Convert(&in.Manifest, &out, 0); err != nil {
return err
}
out.NodeName = in.Host
return nil
},
func(in *[]api.ContainerStatus, out *PodInfo, s conversion.Scope) error {
*out = make(map[string]ContainerStatus)
for _, st := range *in {
v := ContainerStatus{}
if err := s.Convert(&st, &v, 0); err != nil {
return err
}
(*out)[st.Name] = v
}
return nil
},
func(in *PodInfo, out *[]api.ContainerStatus, s conversion.Scope) error {
for k, v := range *in {
st := api.ContainerStatus{}
if err := s.Convert(&v, &st, 0); err != nil {
return err
}
st.Name = k
*out = append(*out, st)
}
return nil
},
func(in *api.ContainerStatus, out *ContainerStatus, s conversion.Scope) error {
if err := s.Convert(&in.State, &out.State, 0); err != nil {
return err
}
if err := s.Convert(&in.LastTerminationState, &out.LastTerminationState, 0); err != nil {
return err
}
if err := s.Convert(&in.Ready, &out.Ready, 0); err != nil {
return err
}
if err := s.Convert(&in.RestartCount, &out.RestartCount, 0); err != nil {
return err
}
if err := s.Convert(&in.Image, &out.Image, 0); err != nil {
return err
}
if err := s.Convert(&in.ImageID, &out.ImageID, 0); err != nil {
return err
}
if err := s.Convert(&in.ContainerID, &out.ContainerID, 0); err != nil {
return err
}
return nil
},
func(in *ContainerStatus, out *api.ContainerStatus, s conversion.Scope) error {
if err := s.Convert(&in.State, &out.State, 0); err != nil {
return err
}
if err := s.Convert(&in.LastTerminationState, &out.LastTerminationState, 0); err != nil {
return err
}
if err := s.Convert(&in.Ready, &out.Ready, 0); err != nil {
return err
}
if err := s.Convert(&in.RestartCount, &out.RestartCount, 0); err != nil {
return err
}
if err := s.Convert(&in.Image, &out.Image, 0); err != nil {
return err
}
if err := s.Convert(&in.ImageID, &out.ImageID, 0); err != nil {
return err
}
if err := s.Convert(&in.ContainerID, &out.ContainerID, 0); err != nil {
return err
}
return nil
},
// Convert all to the new PodPhase constants
func(in *api.PodPhase, out *PodStatus, s conversion.Scope) error {
switch *in {
case "":
*out = ""
case api.PodPending:
*out = PodWaiting
case api.PodRunning:
*out = PodRunning
case api.PodSucceeded:
*out = PodSucceeded
case api.PodFailed:
*out = PodTerminated
case api.PodUnknown:
*out = PodUnknown
default:
return &api.ConversionError{
In: in,
Out: out,
Message: "The string provided is not a valid PodPhase constant value",
}
}
return nil
},
func(in *PodStatus, out *api.PodPhase, s conversion.Scope) error {
switch *in {
case "":
*out = ""
case PodWaiting:
*out = api.PodPending
case PodRunning:
*out = api.PodRunning
case PodTerminated:
// Older API versions did not contain enough info to map to PodSucceeded
*out = api.PodFailed
case PodSucceeded:
*out = api.PodSucceeded
case PodUnknown:
*out = api.PodUnknown
default:
return &api.ConversionError{
In: in,
Out: out,
Message: "The string provided is not a valid PodPhase constant value",
}
}
return nil
},
// Convert all the standard objects
func(in *api.Pod, out *Pod, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
// TODO: Change this to use in.ObjectMeta.Labels.
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec, &out.DesiredState.Manifest, 0); err != nil {
return err
}
out.DesiredState.Host = in.Spec.NodeName
out.CurrentState.Host = in.Spec.NodeName
out.ServiceAccount = in.Spec.ServiceAccount
if err := s.Convert(&in.Status, &out.CurrentState, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec.NodeSelector, &out.NodeSelector, 0); err != nil {
return err
}
return nil
},
func(in *Pod, out *api.Pod, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.DesiredState.Manifest, &out.Spec, 0); err != nil {
return err
}
out.Spec.NodeName = in.DesiredState.Host
out.Spec.ServiceAccount = in.ServiceAccount
if err := s.Convert(&in.CurrentState, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.NodeSelector, &out.Spec.NodeSelector, 0); err != nil {
return err
}
return nil
},
func(in *api.PodStatusResult, out *PodStatusResult, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.State, 0); err != nil {
return err
}
return nil
},
func(in *PodStatusResult, out *api.PodStatusResult, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.State, &out.Status, 0); err != nil {
return err
}
return nil
},
func(in *api.ReplicationController, out *ReplicationController, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec, &out.DesiredState, 0); err != nil {
return err
}
out.CurrentState.Replicas = in.Status.Replicas
return nil
},
func(in *ReplicationController, out *api.ReplicationController, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.DesiredState, &out.Spec, 0); err != nil {
return err
}
out.Status.Replicas = in.CurrentState.Replicas
return nil
},
func(in *api.ReplicationControllerSpec, out *ReplicationControllerState, s conversion.Scope) error {
out.Replicas = in.Replicas
if err := s.Convert(&in.Selector, &out.ReplicaSelector, 0); err != nil {
return err
}
//if in.TemplateRef != nil && in.Template == nil {
// return &api.ConversionError{
// In: in,
// Out: out,
// Message: "objects with a template ref cannot be converted to older objects, must populate template",
// }
//}
if in.Template != nil {
if err := s.Convert(in.Template, &out.PodTemplate, 0); err != nil {
return err
}
}
return nil
},
func(in *ReplicationControllerState, out *api.ReplicationControllerSpec, s conversion.Scope) error {
out.Replicas = in.Replicas
if err := s.Convert(&in.ReplicaSelector, &out.Selector, 0); err != nil {
return err
}
out.Template = &api.PodTemplateSpec{}
if err := s.Convert(&in.PodTemplate, out.Template, 0); err != nil {
return err
}
return nil
},
func(in *api.PodTemplateSpec, out *PodTemplate, s conversion.Scope) error {
if err := s.Convert(&in.Spec, &out.DesiredState.Manifest, 0); err != nil {
return err
}
out.DesiredState.Host = in.Spec.NodeName
out.ServiceAccount = in.Spec.ServiceAccount
if err := s.Convert(&in.Spec.NodeSelector, &out.NodeSelector, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta.Labels, &out.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta.Annotations, &out.Annotations, 0); err != nil {
return err
}
return nil
},
func(in *PodTemplate, out *api.PodTemplateSpec, s conversion.Scope) error {
if err := s.Convert(&in.DesiredState.Manifest, &out.Spec, 0); err != nil {
return err
}
out.Spec.NodeName = in.DesiredState.Host
out.Spec.ServiceAccount = in.ServiceAccount
if err := s.Convert(&in.NodeSelector, &out.Spec.NodeSelector, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.Annotations, &out.ObjectMeta.Annotations, 0); err != nil {
return err
}
return nil
},
// Converts internal Container to v1beta1.Container.
// Fields 'CPU' and 'Memory' are not present in the internal Container object.
// Hence the need for a custom conversion function.
func(in *api.Container, out *Container, s conversion.Scope) error {
if err := s.Convert(&in.Name, &out.Name, 0); err != nil {
return err
}
if err := s.Convert(&in.Image, &out.Image, 0); err != nil {
return err
}
if err := s.Convert(&in.Command, &out.Entrypoint, 0); err != nil {
return err
}
if err := s.Convert(&in.Args, &out.Command, 0); err != nil {
return err
}
if err := s.Convert(&in.WorkingDir, &out.WorkingDir, 0); err != nil {
return err
}
if err := s.Convert(&in.Ports, &out.Ports, 0); err != nil {
return err
}
if err := s.Convert(&in.Env, &out.Env, 0); err != nil {
return err
}
if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil {
return err
}
if err := s.Convert(in.Resources.Limits.Cpu(), &out.CPU, 0); err != nil {
return err
}
if err := s.Convert(in.Resources.Limits.Memory(), &out.Memory, 0); err != nil {
return err
}
if err := s.Convert(&in.VolumeMounts, &out.VolumeMounts, 0); err != nil {
return err
}
if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil {
return err
}
if err := s.Convert(&in.ReadinessProbe, &out.ReadinessProbe, 0); err != nil {
return err
}
if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil {
return err
}
if err := s.Convert(&in.TerminationMessagePath, &out.TerminationMessagePath, 0); err != nil {
return err
}
if err := s.Convert(&in.ImagePullPolicy, &out.ImagePullPolicy, 0); err != nil {
return err
}
if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil {
return err
}
// now that we've converted set the container field from security context
if out.SecurityContext != nil && out.SecurityContext.Privileged != nil {
out.Privileged = *out.SecurityContext.Privileged
}
// now that we've converted set the container field from security context
if out.SecurityContext != nil && out.SecurityContext.Capabilities != nil {
out.Capabilities = *out.SecurityContext.Capabilities
}
return nil
},
// Internal API does not support CPU to be specified via an explicit field.
// Hence it must be stored in Container.Resources.
func(in *int, out *api.ResourceList, s conversion.Scope) error {
if *in <= 0 {
return nil
}
quantity := resource.Quantity{}
if err := s.Convert(in, &quantity, 0); err != nil {
return err
}
(*out)[api.ResourceCPU] = quantity
return nil
},
// Internal API does not support Memory to be specified via an explicit field.
// Hence it must be stored in Container.Resources.
func(in *int64, out *api.ResourceList, s conversion.Scope) error {
if *in <= 0 {
return nil
}
quantity := resource.Quantity{}
if err := s.Convert(in, &quantity, 0); err != nil {
return err
}
(*out)[api.ResourceMemory] = quantity
return nil
},
// Converts v1beta1.Container to internal Container.
// Fields 'CPU' and 'Memory' are not present in the internal Container object.
// Hence the need for a custom conversion function.
func(in *Container, out *api.Container, s conversion.Scope) error {
if err := s.Convert(&in.Name, &out.Name, 0); err != nil {
return err
}
if err := s.Convert(&in.Image, &out.Image, 0); err != nil {
return err
}
if err := s.Convert(&in.Command, &out.Args, 0); err != nil {
return err
}
if err := s.Convert(&in.Entrypoint, &out.Command, 0); err != nil {
return err
}
if err := s.Convert(&in.WorkingDir, &out.WorkingDir, 0); err != nil {
return err
}
if err := s.Convert(&in.Ports, &out.Ports, 0); err != nil {
return err
}
if err := s.Convert(&in.Env, &out.Env, 0); err != nil {
return err
}
if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil {
return err
}
if err := s.Convert(&in.CPU, &out.Resources.Limits, 0); err != nil {
return err
}
if err := s.Convert(&in.Memory, &out.Resources.Limits, 0); err != nil {
return err
}
if err := s.Convert(&in.VolumeMounts, &out.VolumeMounts, 0); err != nil {
return err
}
if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil {
return err
}
if err := s.Convert(&in.ReadinessProbe, &out.ReadinessProbe, 0); err != nil {
return err
}
if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil {
return err
}
if err := s.Convert(&in.TerminationMessagePath, &out.TerminationMessagePath, 0); err != nil {
return err
}
if err := s.Convert(&in.ImagePullPolicy, &out.ImagePullPolicy, 0); err != nil {
return err
}
if in.SecurityContext != nil {
if in.SecurityContext.Capabilities != nil {
if !reflect.DeepEqual(in.SecurityContext.Capabilities.Add, in.Capabilities.Add) ||
!reflect.DeepEqual(in.SecurityContext.Capabilities.Drop, in.Capabilities.Drop) {
return fmt.Errorf("container capability settings do not match security context settings, cannot convert")
}
}
if in.SecurityContext.Privileged != nil {
if in.Privileged != *in.SecurityContext.Privileged {
return fmt.Errorf("container privileged settings do not match security context settings, cannot convert")
}
}
}
if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil {
return err
}
return nil
},
func(in *api.PodSpec, out *ContainerManifest, s conversion.Scope) error {
if err := s.Convert(&in.Volumes, &out.Volumes, 0); err != nil {
return err
}
if err := s.Convert(&in.Containers, &out.Containers, 0); err != nil {
return err
}
if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil {
return err
}
if err := s.Convert(&in.ImagePullSecrets, &out.ImagePullSecrets, 0); err != nil {
return err
}
if in.TerminationGracePeriodSeconds != nil {
out.TerminationGracePeriodSeconds = new(int64)
*out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds
}
if in.ActiveDeadlineSeconds != nil {
out.ActiveDeadlineSeconds = new(int64)
*out.ActiveDeadlineSeconds = *in.ActiveDeadlineSeconds
}
out.DNSPolicy = DNSPolicy(in.DNSPolicy)
out.Version = "v1beta2"
out.HostNetwork = in.HostNetwork
return nil
},
func(in *ContainerManifest, out *api.PodSpec, s conversion.Scope) error {
if err := s.Convert(&in.Volumes, &out.Volumes, 0); err != nil {
return err
}
if err := s.Convert(&in.Containers, &out.Containers, 0); err != nil {
return err
}
if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil {
return err
}
if err := s.Convert(&in.ImagePullSecrets, &out.ImagePullSecrets, 0); err != nil {
return err
}
if in.TerminationGracePeriodSeconds != nil {
out.TerminationGracePeriodSeconds = new(int64)
*out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds
}
if in.ActiveDeadlineSeconds != nil {
out.ActiveDeadlineSeconds = new(int64)
*out.ActiveDeadlineSeconds = *in.ActiveDeadlineSeconds
}
out.DNSPolicy = api.DNSPolicy(in.DNSPolicy)
out.HostNetwork = in.HostNetwork
return nil
},
func(in *api.Service, out *Service, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
// Produce legacy fields.
out.Protocol = ProtocolTCP
if len(in.Spec.Ports) > 0 {
out.PortName = in.Spec.Ports[0].Name
out.Port = in.Spec.Ports[0].Port
out.Protocol = Protocol(in.Spec.Ports[0].Protocol)
out.ContainerPort = in.Spec.Ports[0].TargetPort
}
// Copy modern fields.
for i := range in.Spec.Ports {
out.Ports = append(out.Ports, ServicePort{
Name: in.Spec.Ports[i].Name,
Port: in.Spec.Ports[i].Port,
Protocol: Protocol(in.Spec.Ports[i].Protocol),
ContainerPort: in.Spec.Ports[i].TargetPort,
NodePort: in.Spec.Ports[i].NodePort,
})
}
if err := s.Convert(&in.Spec.Selector, &out.Selector, 0); err != nil {
return err
}
out.PublicIPs = in.Spec.DeprecatedPublicIPs
out.PortalIP = in.Spec.ClusterIP
if err := s.Convert(&in.Spec.SessionAffinity, &out.SessionAffinity, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.LoadBalancer, &out.LoadBalancerStatus, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec.Type, &out.Type, 0); err != nil {
return err
}
out.CreateExternalLoadBalancer = in.Spec.Type == api.ServiceTypeLoadBalancer
return nil
},
func(in *Service, out *api.Service, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
if len(in.Ports) == 0 && in.Port != 0 {
// Use legacy fields to produce modern fields.
out.Spec.Ports = append(out.Spec.Ports, api.ServicePort{
Name: in.PortName,
Port: in.Port,
Protocol: api.Protocol(in.Protocol),
TargetPort: in.ContainerPort,
})
} else {
// Use modern fields, ignore legacy.
for i := range in.Ports {
out.Spec.Ports = append(out.Spec.Ports, api.ServicePort{
Name: in.Ports[i].Name,
Port: in.Ports[i].Port,
Protocol: api.Protocol(in.Ports[i].Protocol),
TargetPort: in.Ports[i].ContainerPort,
NodePort: in.Ports[i].NodePort,
})
}
}
if err := s.Convert(&in.Selector, &out.Spec.Selector, 0); err != nil {
return err
}
out.Spec.DeprecatedPublicIPs = in.PublicIPs
out.Spec.ClusterIP = in.PortalIP
if err := s.Convert(&in.SessionAffinity, &out.Spec.SessionAffinity, 0); err != nil {
return err
}
if err := s.Convert(&in.LoadBalancerStatus, &out.Status.LoadBalancer, 0); err != nil {
return err
}
typeIn := in.Type
if typeIn == "" {
if in.CreateExternalLoadBalancer {
typeIn = ServiceTypeLoadBalancer
} else {
typeIn = ServiceTypeClusterIP
}
}
if err := s.Convert(&typeIn, &out.Spec.Type, 0); err != nil {
return err
}
return nil
},
func(in *api.Node, out *Minion, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta.Labels, &out.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.Phase, &out.Status.Phase, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.Conditions, &out.Status.Conditions, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.Addresses, &out.Status.Addresses, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.NodeInfo, &out.Status.NodeInfo, 0); err != nil {
return err
}
for _, address := range in.Status.Addresses {
if address.Type == api.NodeLegacyHostIP {
out.HostIP = address.Address
}
}
out.PodCIDR = in.Spec.PodCIDR
out.ExternalID = in.Spec.ExternalID
out.ProviderID = in.Spec.ProviderID
out.Unschedulable = in.Spec.Unschedulable
return s.Convert(&in.Status.Capacity, &out.NodeResources.Capacity, 0)
},
func(in *Minion, out *api.Node, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.Phase, &out.Status.Phase, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.Conditions, &out.Status.Conditions, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.Addresses, &out.Status.Addresses, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.NodeInfo, &out.Status.NodeInfo, 0); err != nil {
return err
}
if in.HostIP != "" {
api.AddToNodeAddresses(&out.Status.Addresses,
api.NodeAddress{Type: api.NodeLegacyHostIP, Address: in.HostIP})
}
out.Spec.PodCIDR = in.PodCIDR
out.Spec.ExternalID = in.ExternalID
out.Spec.ProviderID = in.ProviderID
out.Spec.Unschedulable = in.Unschedulable
return s.Convert(&in.NodeResources.Capacity, &out.Status.Capacity, 0)
},
func(in *api.LimitRange, out *LimitRange, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil {
return err
}
return nil
},
func(in *LimitRange, out *api.LimitRange, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil {
return err
}
return nil
},
func(in *Namespace, out *api.Namespace, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil {
return err
}
return nil
},
func(in *api.LimitRangeSpec, out *LimitRangeSpec, s conversion.Scope) error {
*out = LimitRangeSpec{}
out.Limits = make([]LimitRangeItem, len(in.Limits), len(in.Limits))
for i := range in.Limits {
if err := s.Convert(&in.Limits[i], &out.Limits[i], 0); err != nil {
return err
}
}
return nil
},
func(in *LimitRangeSpec, out *api.LimitRangeSpec, s conversion.Scope) error {
*out = api.LimitRangeSpec{}
out.Limits = make([]api.LimitRangeItem, len(in.Limits), len(in.Limits))
for i := range in.Limits {
if err := s.Convert(&in.Limits[i], &out.Limits[i], 0); err != nil {
return err
}
}
return nil
},
func(in *api.LimitRangeItem, out *LimitRangeItem, s conversion.Scope) error {
*out = LimitRangeItem{}
out.Type = LimitType(in.Type)
if err := s.Convert(&in.Max, &out.Max, 0); err != nil {
return err
}
if err := s.Convert(&in.Min, &out.Min, 0); err != nil {
return err
}
if err := s.Convert(&in.Default, &out.Default, 0); err != nil {
return err
}
return nil
},
func(in *LimitRangeItem, out *api.LimitRangeItem, s conversion.Scope) error {
*out = api.LimitRangeItem{}
out.Type = api.LimitType(in.Type)
if err := s.Convert(&in.Max, &out.Max, 0); err != nil {
return err
}
if err := s.Convert(&in.Min, &out.Min, 0); err != nil {
return err
}
if err := s.Convert(&in.Default, &out.Default, 0); err != nil {
return err
}
return nil
},
func(in *api.ResourceQuota, out *ResourceQuota, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
return nil
},
func(in *ResourceQuota, out *api.ResourceQuota, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil {
return err
}
return nil
},
func(in *api.ResourceQuotaSpec, out *ResourceQuotaSpec, s conversion.Scope) error {
*out = ResourceQuotaSpec{}
if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil {
return err
}
return nil
},
func(in *ResourceQuotaSpec, out *api.ResourceQuotaSpec, s conversion.Scope) error {
*out = api.ResourceQuotaSpec{}
if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil {
return err
}
return nil
},
func(in *api.ResourceQuotaStatus, out *ResourceQuotaStatus, s conversion.Scope) error {
*out = ResourceQuotaStatus{}
if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil {
return err
}
if err := s.Convert(&in.Used, &out.Used, 0); err != nil {
return err
}
return nil
},
func(in *ResourceQuotaStatus, out *api.ResourceQuotaStatus, s conversion.Scope) error {
*out = api.ResourceQuotaStatus{}
if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil {
return err
}
if err := s.Convert(&in.Used, &out.Used, 0); err != nil {
return err
}
return nil
},
// Object ID <-> Name
// TODO: amend the conversion package to allow overriding specific fields.
func(in *ObjectReference, out *api.ObjectReference, s conversion.Scope) error {
out.Kind = in.Kind
out.Namespace = in.Namespace
out.Name = in.ID
out.UID = in.UID
out.APIVersion = in.APIVersion
out.ResourceVersion = in.ResourceVersion
out.FieldPath = in.FieldPath
return nil
},
func(in *api.ObjectReference, out *ObjectReference, s conversion.Scope) error {
out.Kind = in.Kind
out.Namespace = in.Namespace
out.ID = in.Name
out.UID = in.UID
out.APIVersion = in.APIVersion
out.ResourceVersion = in.ResourceVersion
out.FieldPath = in.FieldPath
return nil
},
// Event Source <-> Source.Component
// Event Host <-> Source.Host
// TODO: remove this when it becomes possible to specify a field name conversion on a specific type
func(in *api.Event, out *Event, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
out.Reason = in.Reason
out.Message = in.Message
out.Source = in.Source.Component
out.Host = in.Source.Host
out.Timestamp = in.FirstTimestamp
out.FirstTimestamp = in.FirstTimestamp
out.LastTimestamp = in.LastTimestamp
out.Count = in.Count
return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0)
},
func(in *Event, out *api.Event, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
out.Reason = in.Reason
out.Message = in.Message
out.Source.Component = in.Source
out.Source.Host = in.Host
if in.FirstTimestamp.IsZero() {
// Assume this is an old event that does not specify FirstTimestamp/LastTimestamp/Count
out.FirstTimestamp = in.Timestamp
out.LastTimestamp = in.Timestamp
out.Count = 1
} else {
out.FirstTimestamp = in.FirstTimestamp
out.LastTimestamp = in.LastTimestamp
out.Count = in.Count
}
return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0)
},
// This is triggered for the Memory field of Container.
func(in *int64, out *resource.Quantity, s conversion.Scope) error {
out.Set(*in)
out.Format = resource.BinarySI
return nil
},
func(in *resource.Quantity, out *int64, s conversion.Scope) error {
*out = in.Value()
return nil
},
// This is triggered by the CPU field of Container.
// Note that if we add other int/Quantity conversions my
// simple hack (int64=Value(), int=MilliValue()) here won't work.
func(in *int, out *resource.Quantity, s conversion.Scope) error {
out.SetMilli(int64(*in))
out.Format = resource.DecimalSI
return nil
},
func(in *resource.Quantity, out *int, s conversion.Scope) error {
*out = int(in.MilliValue())
return nil
},
// Convert resource lists.
func(in *ResourceList, out *api.ResourceList, s conversion.Scope) error {
*out = api.ResourceList{}
for k, v := range *in {
fv, err := strconv.ParseFloat(v.String(), 64)
if err != nil {
return &api.ConversionError{
In: in, Out: out,
Message: fmt.Sprintf("value '%v' of '%v': %v", v, k, err),
}
}
if k == ResourceCPU {
(*out)[api.ResourceCPU] = *resource.NewMilliQuantity(int64(fv*1000), resource.DecimalSI)
} else {
(*out)[api.ResourceName(k)] = *resource.NewQuantity(int64(fv), resource.BinarySI)
}
}
return nil
},
func(in *api.ResourceList, out *ResourceList, s conversion.Scope) error {
*out = ResourceList{}
for k, v := range *in {
if k == api.ResourceCPU {
(*out)[ResourceCPU] = util.NewIntOrStringFromString(fmt.Sprintf("%v", float64(v.MilliValue())/1000))
} else {
(*out)[ResourceName(k)] = util.NewIntOrStringFromInt(int(v.Value()))
}
}
return nil
},
func(in *api.Volume, out *Volume, s conversion.Scope) error {
if err := s.Convert(&in.VolumeSource, &out.Source, 0); err != nil {
return err
}
out.Name = in.Name
return nil
},
func(in *Volume, out *api.Volume, s conversion.Scope) error {
if err := s.Convert(&in.Source, &out.VolumeSource, 0); err != nil {
return err
}
out.Name = in.Name
return nil
},
// VolumeSource's HostDir is deprecated in favor of HostPath.
// TODO: It would be great if I could just map field names to
// convert or else maybe say "convert all members of this
// struct" and then fix up only the stuff that changed.
func(in *api.VolumeSource, out *VolumeSource, s conversion.Scope) error {
if err := s.Convert(&in.EmptyDir, &out.EmptyDir, 0); err != nil {
return err
}
if err := s.Convert(&in.GitRepo, &out.GitRepo, 0); err != nil {
return err
}
if err := s.Convert(&in.GCEPersistentDisk, &out.GCEPersistentDisk, 0); err != nil {
return err
}
if err := s.Convert(&in.ISCSI, &out.ISCSI, 0); err != nil {
return err
}
if err := s.Convert(&in.AWSElasticBlockStore, &out.AWSElasticBlockStore, 0); err != nil {
return err
}
if err := s.Convert(&in.HostPath, &out.HostDir, 0); err != nil {
return err
}
if err := s.Convert(&in.Secret, &out.Secret, 0); err != nil {
return err
}
if err := s.Convert(&in.NFS, &out.NFS, 0); err != nil {
return err
}
if err := s.Convert(&in.Glusterfs, &out.Glusterfs, 0); err != nil {
return err
}
if err := s.Convert(&in.PersistentVolumeClaimVolumeSource, &out.PersistentVolumeClaimVolumeSource, 0); err != nil {
return err
}
if err := s.Convert(&in.RBD, &out.RBD, 0); err != nil {
return err
}
return nil
},
func(in *VolumeSource, out *api.VolumeSource, s conversion.Scope) error {
if err := s.Convert(&in.EmptyDir, &out.EmptyDir, 0); err != nil {
return err
}
if err := s.Convert(&in.GitRepo, &out.GitRepo, 0); err != nil {
return err
}
if err := s.Convert(&in.GCEPersistentDisk, &out.GCEPersistentDisk, 0); err != nil {
return err
}
if err := s.Convert(&in.ISCSI, &out.ISCSI, 0); err != nil {
return err
}
if err := s.Convert(&in.AWSElasticBlockStore, &out.AWSElasticBlockStore, 0); err != nil {
return err
}
if err := s.Convert(&in.HostDir, &out.HostPath, 0); err != nil {
return err
}
if err := s.Convert(&in.Secret, &out.Secret, 0); err != nil {
return err
}
if err := s.Convert(&in.NFS, &out.NFS, 0); err != nil {
return err
}
if err := s.Convert(&in.PersistentVolumeClaimVolumeSource, &out.PersistentVolumeClaimVolumeSource, 0); err != nil {
return err
}
if err := s.Convert(&in.Glusterfs, &out.Glusterfs, 0); err != nil {
return err
}
if err := s.Convert(&in.RBD, &out.RBD, 0); err != nil {
return err
}
return nil
},
func(in *api.PullPolicy, out *PullPolicy, s conversion.Scope) error {
switch *in {
case api.PullAlways:
*out = PullAlways
case api.PullNever:
*out = PullNever
case api.PullIfNotPresent:
*out = PullIfNotPresent
case "":
*out = ""
default:
// Let unknown values through - they will get caught by validation
*out = PullPolicy(*in)
}
return nil
},
func(in *PullPolicy, out *api.PullPolicy, s conversion.Scope) error {
switch *in {
case PullAlways:
*out = api.PullAlways
case PullNever:
*out = api.PullNever
case PullIfNotPresent:
*out = api.PullIfNotPresent
case "":
*out = ""
default:
// Let unknown values through - they will get caught by validation
*out = api.PullPolicy(*in)
}
return nil
},
func(in *api.RestartPolicy, out *RestartPolicy, s conversion.Scope) error {
switch *in {
case api.RestartPolicyAlways:
*out = RestartPolicy{Always: &RestartPolicyAlways{}}
case api.RestartPolicyNever:
*out = RestartPolicy{Never: &RestartPolicyNever{}}
case api.RestartPolicyOnFailure:
*out = RestartPolicy{OnFailure: &RestartPolicyOnFailure{}}
default:
*out = RestartPolicy{}
}
return nil
},
func(in *RestartPolicy, out *api.RestartPolicy, s conversion.Scope) error {
switch {
case in.Always != nil:
*out = api.RestartPolicyAlways
case in.Never != nil:
*out = api.RestartPolicyNever
case in.OnFailure != nil:
*out = api.RestartPolicyOnFailure
default:
*out = ""
}
return nil
},
func(in *api.Probe, out *LivenessProbe, s conversion.Scope) error {
if err := s.Convert(&in.Exec, &out.Exec, 0); err != nil {
return err
}
if err := s.Convert(&in.HTTPGet, &out.HTTPGet, 0); err != nil {
return err
}
if err := s.Convert(&in.TCPSocket, &out.TCPSocket, 0); err != nil {
return err
}
out.InitialDelaySeconds = in.InitialDelaySeconds
out.TimeoutSeconds = in.TimeoutSeconds
return nil
},
func(in *LivenessProbe, out *api.Probe, s conversion.Scope) error {
if err := s.Convert(&in.Exec, &out.Exec, 0); err != nil {
return err
}
if err := s.Convert(&in.HTTPGet, &out.HTTPGet, 0); err != nil {
return err
}
if err := s.Convert(&in.TCPSocket, &out.TCPSocket, 0); err != nil {
return err
}
out.InitialDelaySeconds = in.InitialDelaySeconds
out.TimeoutSeconds = in.TimeoutSeconds
return nil
},
func(in *api.Endpoints, out *Endpoints, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Subsets, &out.Subsets, 0); err != nil {
return err
}
// Produce back-compat fields.
firstPortName := ""
if len(in.Subsets) > 0 {
if len(in.Subsets[0].Ports) > 0 {
if err := s.Convert(&in.Subsets[0].Ports[0].Protocol, &out.Protocol, 0); err != nil {
return err
}
firstPortName = in.Subsets[0].Ports[0].Name
}
} else {
out.Protocol = ProtocolTCP
}
for i := range in.Subsets {
ss := &in.Subsets[i]
for j := range ss.Ports {
ssp := &ss.Ports[j]
if ssp.Name != firstPortName {
continue
}
for k := range ss.Addresses {
ssa := &ss.Addresses[k]
hostPort := net.JoinHostPort(ssa.IP, strconv.Itoa(ssp.Port))
out.Endpoints = append(out.Endpoints, hostPort)
if ssa.TargetRef != nil {
target := EndpointObjectReference{
Endpoint: hostPort,
}
if err := s.Convert(ssa.TargetRef, &target.ObjectReference, 0); err != nil {
return err
}
out.TargetRefs = append(out.TargetRefs, target)
}
}
}
}
return nil
},
func(in *Endpoints, out *api.Endpoints, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Subsets, &out.Subsets, 0); err != nil {
return err
}
// Back-compat fields are handled in the defaulting phase.
return nil
},
func(in *api.NodeCondition, out *NodeCondition, s conversion.Scope) error {
if err := s.Convert(&in.Type, &out.Kind, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.LastHeartbeatTime, &out.LastProbeTime, 0); err != nil {
return err
}
if err := s.Convert(&in.LastTransitionTime, &out.LastTransitionTime, 0); err != nil {
return err
}
if err := s.Convert(&in.Reason, &out.Reason, 0); err != nil {
return err
}
if err := s.Convert(&in.Message, &out.Message, 0); err != nil {
return err
}
return nil
},
func(in *NodeCondition, out *api.NodeCondition, s conversion.Scope) error {
if err := s.Convert(&in.Kind, &out.Type, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.LastProbeTime, &out.LastHeartbeatTime, 0); err != nil {
return err
}
if err := s.Convert(&in.LastTransitionTime, &out.LastTransitionTime, 0); err != nil {
return err
}
if err := s.Convert(&in.Reason, &out.Reason, 0); err != nil {
return err
}
if err := s.Convert(&in.Message, &out.Message, 0); err != nil {
return err
}
return nil
},
func(in *api.NodeConditionType, out *NodeConditionKind, s conversion.Scope) error {
switch *in {
case api.NodeReady:
*out = NodeReady
break
case "":
*out = ""
default:
*out = NodeConditionKind(*in)
break
}
return nil
},
func(in *NodeConditionKind, out *api.NodeConditionType, s conversion.Scope) error {
switch *in {
case NodeReady:
*out = api.NodeReady
break
case "":
*out = ""
default:
*out = api.NodeConditionType(*in)
break
}
return nil
},
func(in *api.ConditionStatus, out *ConditionStatus, s conversion.Scope) error {
switch *in {
case api.ConditionTrue:
*out = ConditionFull
break
case api.ConditionFalse:
*out = ConditionNone
break
default:
*out = ConditionStatus(*in)
break
}
return nil
},
func(in *ConditionStatus, out *api.ConditionStatus, s conversion.Scope) error {
switch *in {
case ConditionFull:
*out = api.ConditionTrue
break
case ConditionNone:
*out = api.ConditionFalse
break
default:
*out = api.ConditionStatus(*in)
break
}
return nil
},
func(in *api.PodCondition, out *PodCondition, s conversion.Scope) error {
if err := s.Convert(&in.Type, &out.Kind, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.Status, 0); err != nil {
return err
}
return nil
},
func(in *PodCondition, out *api.PodCondition, s conversion.Scope) error {
if err := s.Convert(&in.Kind, &out.Type, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.Status, 0); err != nil {
return err
}
return nil
},
func(in *api.PodConditionType, out *PodConditionKind, s conversion.Scope) error {
switch *in {
case api.PodReady:
*out = PodReady
break
case "":
*out = ""
default:
*out = PodConditionKind(*in)
break
}
return nil
},
func(in *PodConditionKind, out *api.PodConditionType, s conversion.Scope) error {
switch *in {
case PodReady:
*out = api.PodReady
break
case "":
*out = ""
default:
*out = api.PodConditionType(*in)
break
}
return nil
},
func(in *Binding, out *api.Binding, s conversion.Scope) error {
if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil {
return err
}
out.Target = api.ObjectReference{
Name: in.Host,
}
out.Name = in.PodID
return nil
},
func(in *api.Binding, out *Binding, s conversion.Scope) error {
if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil {
return err
}
out.Host = in.Target.Name
out.PodID = in.Name
return nil
},
func(in *api.SecretVolumeSource, out *SecretVolumeSource, s conversion.Scope) error {
out.Target.ID = in.SecretName
return nil
},
func(in *SecretVolumeSource, out *api.SecretVolumeSource, s conversion.Scope) error {
out.SecretName = in.Target.ID
return nil
},
func(in *api.ContainerState, out *ContainerState, s conversion.Scope) error {
if err := s.Convert(&in.Waiting, &out.Waiting, 0); err != nil {
return err
}
if err := s.Convert(&in.Running, &out.Running, 0); err != nil {
return err
}
if err := s.Convert(&in.Terminated, &out.Termination, 0); err != nil {
return err
}
return nil
},
func(in *ContainerState, out *api.ContainerState, s conversion.Scope) error {
if err := s.Convert(&in.Waiting, &out.Waiting, 0); err != nil {
return err
}
if err := s.Convert(&in.Running, &out.Running, 0); err != nil {
return err
}
if err := s.Convert(&in.Termination, &out.Terminated, 0); err != nil {
return err
}
return nil
},
)
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
panic(err)
}
// Add field conversion funcs.
err = api.Scheme.AddFieldLabelConversionFunc("v1beta1", "Pod",
func(label, value string) (string, string, error) {
switch label {
case "name":
return "metadata.name", value, nil
case "DesiredState.Host":
return "spec.host", value, nil
case "DesiredState.Status":
podStatus := PodStatus(value)
var internalValue api.PodPhase
api.Scheme.Convert(&podStatus, &internalValue)
return "status.phase", string(internalValue), nil
default:
return "", "", fmt.Errorf("field label not supported: %s", label)
}
})
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
panic(err)
}
err = api.Scheme.AddFieldLabelConversionFunc("v1beta1", "Node",
func(label, value string) (string, string, error) {
switch label {
case "name":
return "metadata.name", value, nil
case "unschedulable":
return "spec.unschedulable", value, nil
default:
return "", "", fmt.Errorf("field label not supported: %s", label)
}
})
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
panic(err)
}
err = api.Scheme.AddFieldLabelConversionFunc("v1beta1", "ReplicationController",
func(label, value string) (string, string, error) {
switch label {
case "name":
return "metadata.name", value, nil
case "currentState.replicas":
return "status.replicas", value, nil
default:
return "", "", fmt.Errorf("field label not supported: %s", label)
}
})
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
panic(err)
}
err = api.Scheme.AddFieldLabelConversionFunc("v1beta1", "Event",
func(label, value string) (string, string, error) {
switch label {
case "involvedObject.kind",
"involvedObject.namespace",
"involvedObject.uid",
"involvedObject.apiVersion",
"involvedObject.resourceVersion",
"involvedObject.fieldPath",
"reason",
"source":
return label, value, nil
case "involvedObject.id":
return "involvedObject.name", value, nil
default:
return "", "", fmt.Errorf("field label not supported: %s", label)
}
})
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
panic(err)
}
err = api.Scheme.AddFieldLabelConversionFunc("v1beta1", "Namespace",
func(label, value string) (string, string, error) {
switch label {
case "status.phase":
return label, value, nil
default:
return "", "", fmt.Errorf("field label not supported: %s", label)
}
})
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
panic(err)
}
err = api.Scheme.AddFieldLabelConversionFunc("v1beta1", "Secret",
func(label, value string) (string, string, error) {
switch label {
case "type":
return label, value, nil
default:
return "", "", fmt.Errorf("field label not supported: %s", label)
}
})
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
panic(err)
}
err = api.Scheme.AddFieldLabelConversionFunc("v1beta1", "ServiceAccount",
func(label, value string) (string, string, error) {
switch label {
case "name":
return "metadata.name", value, nil
default:
return "", "", fmt.Errorf("field label not supported: %s", label)
}
})
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
panic(err)
}
}
/*
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())
}
}
}
}
/*
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
}
}
}
/*
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
}
/*
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
/*
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() {}
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
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 (
"fmt"
"net"
"reflect"
"strconv"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
func addConversionFuncs() {
// Our TypeMeta was split into two different structs.
api.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", api.TypeMeta{}, "TypeMeta")
api.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", api.ObjectMeta{}, "ObjectMeta")
api.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", api.ListMeta{}, "ListMeta")
api.Scheme.AddStructFieldConversion(api.TypeMeta{}, "TypeMeta", TypeMeta{}, "TypeMeta")
api.Scheme.AddStructFieldConversion(api.ObjectMeta{}, "ObjectMeta", TypeMeta{}, "TypeMeta")
api.Scheme.AddStructFieldConversion(api.ListMeta{}, "ListMeta", TypeMeta{}, "TypeMeta")
api.Scheme.AddStructFieldConversion(api.Endpoints{}, "Endpoints", Endpoints{}, "Endpoints")
// TODO: scope this to a specific type once that becomes available and remove the Event conversion functions below
// api.Scheme.AddStructFieldConversion(string(""), "Status", string(""), "Condition")
// api.Scheme.AddStructFieldConversion(string(""), "Condition", string(""), "Status")
err := api.Scheme.AddConversionFuncs(
// TypeMeta must be split into two objects
func(in *api.TypeMeta, out *TypeMeta, s conversion.Scope) error {
out.Kind = in.Kind
out.APIVersion = in.APIVersion
return nil
},
func(in *TypeMeta, out *api.TypeMeta, s conversion.Scope) error {
out.Kind = in.Kind
out.APIVersion = in.APIVersion
return nil
},
// ListMeta must be converted to TypeMeta
func(in *api.ListMeta, out *TypeMeta, s conversion.Scope) error {
out.SelfLink = in.SelfLink
if len(in.ResourceVersion) > 0 {
v, err := strconv.ParseUint(in.ResourceVersion, 10, 64)
if err != nil {
return err
}
out.ResourceVersion = v
}
return nil
},
func(in *TypeMeta, out *api.ListMeta, s conversion.Scope) error {
out.SelfLink = in.SelfLink
if in.ResourceVersion != 0 {
out.ResourceVersion = strconv.FormatUint(in.ResourceVersion, 10)
} else {
out.ResourceVersion = ""
}
return nil
},
// ObjectMeta must be converted to TypeMeta
func(in *api.ObjectMeta, out *TypeMeta, s conversion.Scope) error {
out.Namespace = in.Namespace
out.ID = in.Name
out.GenerateName = in.GenerateName
out.UID = in.UID
out.CreationTimestamp = in.CreationTimestamp
out.DeletionTimestamp = in.DeletionTimestamp
out.SelfLink = in.SelfLink
if len(in.ResourceVersion) > 0 {
v, err := strconv.ParseUint(in.ResourceVersion, 10, 64)
if err != nil {
return err
}
out.ResourceVersion = v
}
return s.Convert(&in.Annotations, &out.Annotations, 0)
},
func(in *TypeMeta, out *api.ObjectMeta, s conversion.Scope) error {
out.Namespace = in.Namespace
out.Name = in.ID
out.GenerateName = in.GenerateName
out.UID = in.UID
out.CreationTimestamp = in.CreationTimestamp
out.DeletionTimestamp = in.DeletionTimestamp
out.SelfLink = in.SelfLink
if in.ResourceVersion != 0 {
out.ResourceVersion = strconv.FormatUint(in.ResourceVersion, 10)
} else {
out.ResourceVersion = ""
}
return s.Convert(&in.Annotations, &out.Annotations, 0)
},
// Convert all to the new PodPhase constants
func(in *api.PodPhase, out *PodStatus, s conversion.Scope) error {
switch *in {
case "":
*out = ""
case api.PodPending:
*out = PodWaiting
case api.PodRunning:
*out = PodRunning
case api.PodSucceeded:
*out = PodSucceeded
case api.PodFailed:
*out = PodTerminated
case api.PodUnknown:
*out = PodUnknown
default:
return &api.ConversionError{
In: in,
Out: out,
Message: "The string provided is not a valid PodPhase constant value",
}
}
return nil
},
func(in *PodStatus, out *api.PodPhase, s conversion.Scope) error {
switch *in {
case "":
*out = ""
case PodWaiting:
*out = api.PodPending
case PodRunning:
*out = api.PodRunning
case PodTerminated:
// Older API versions did not contain enough info to map to PodSucceeded
*out = api.PodFailed
case PodSucceeded:
*out = api.PodSucceeded
case PodUnknown:
*out = api.PodUnknown
default:
return &api.ConversionError{
In: in,
Out: out,
Message: "The string provided is not a valid PodPhase constant value",
}
}
return nil
},
// Convert all the standard objects
func(in *api.Pod, out *Pod, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
// TODO: Change this to use in.ObjectMeta.Labels.
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec, &out.DesiredState.Manifest, 0); err != nil {
return err
}
out.DesiredState.Host = in.Spec.NodeName
out.CurrentState.Host = in.Spec.NodeName
out.ServiceAccount = in.Spec.ServiceAccount
if err := s.Convert(&in.Status, &out.CurrentState, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec.NodeSelector, &out.NodeSelector, 0); err != nil {
return err
}
return nil
},
func(in *Pod, out *api.Pod, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.DesiredState.Manifest, &out.Spec, 0); err != nil {
return err
}
out.Spec.ServiceAccount = in.ServiceAccount
out.Spec.NodeName = in.DesiredState.Host
if err := s.Convert(&in.CurrentState, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.NodeSelector, &out.Spec.NodeSelector, 0); err != nil {
return err
}
return nil
},
func(in *api.ReplicationController, out *ReplicationController, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec, &out.DesiredState, 0); err != nil {
return err
}
out.CurrentState.Replicas = in.Status.Replicas
return nil
},
func(in *ReplicationController, out *api.ReplicationController, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.DesiredState, &out.Spec, 0); err != nil {
return err
}
out.Status.Replicas = in.CurrentState.Replicas
return nil
},
func(in *api.ReplicationControllerSpec, out *ReplicationControllerState, s conversion.Scope) error {
out.Replicas = in.Replicas
if err := s.Convert(&in.Selector, &out.ReplicaSelector, 0); err != nil {
return err
}
//if in.TemplateRef != nil && in.Template == nil {
// return &api.ConversionError{
// In: in,
// Out: out,
// Message: "objects with a template ref cannot be converted to older objects, must populate template",
// }
//}
if in.Template != nil {
if err := s.Convert(in.Template, &out.PodTemplate, 0); err != nil {
return err
}
}
return nil
},
func(in *ReplicationControllerState, out *api.ReplicationControllerSpec, s conversion.Scope) error {
out.Replicas = in.Replicas
if err := s.Convert(&in.ReplicaSelector, &out.Selector, 0); err != nil {
return err
}
out.Template = &api.PodTemplateSpec{}
if err := s.Convert(&in.PodTemplate, out.Template, 0); err != nil {
return err
}
return nil
},
func(in *api.PodTemplateSpec, out *PodTemplate, s conversion.Scope) error {
if err := s.Convert(&in.Spec, &out.DesiredState.Manifest, 0); err != nil {
return err
}
out.DesiredState.Host = in.Spec.NodeName
out.ServiceAccount = in.Spec.ServiceAccount
if err := s.Convert(&in.Spec.NodeSelector, &out.NodeSelector, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta.Labels, &out.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta.Annotations, &out.Annotations, 0); err != nil {
return err
}
return nil
},
func(in *PodTemplate, out *api.PodTemplateSpec, s conversion.Scope) error {
if err := s.Convert(&in.DesiredState.Manifest, &out.Spec, 0); err != nil {
return err
}
out.Spec.NodeName = in.DesiredState.Host
out.Spec.ServiceAccount = in.ServiceAccount
if err := s.Convert(&in.NodeSelector, &out.Spec.NodeSelector, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.Annotations, &out.ObjectMeta.Annotations, 0); err != nil {
return err
}
return nil
},
// Converts internal Container to v1beta2.Container.
// Fields 'CPU' and 'Memory' are not present in the internal Container object.
// Hence the need for a custom conversion function.
func(in *api.Container, out *Container, s conversion.Scope) error {
if err := s.Convert(&in.Name, &out.Name, 0); err != nil {
return err
}
if err := s.Convert(&in.Image, &out.Image, 0); err != nil {
return err
}
if err := s.Convert(&in.Command, &out.Entrypoint, 0); err != nil {
return err
}
if err := s.Convert(&in.Args, &out.Command, 0); err != nil {
return err
}
if err := s.Convert(&in.WorkingDir, &out.WorkingDir, 0); err != nil {
return err
}
if err := s.Convert(&in.Ports, &out.Ports, 0); err != nil {
return err
}
if err := s.Convert(&in.Env, &out.Env, 0); err != nil {
return err
}
if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil {
return err
}
if err := s.Convert(in.Resources.Limits.Cpu(), &out.CPU, 0); err != nil {
return err
}
if err := s.Convert(in.Resources.Limits.Memory(), &out.Memory, 0); err != nil {
return err
}
if err := s.Convert(&in.VolumeMounts, &out.VolumeMounts, 0); err != nil {
return err
}
if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil {
return err
}
if err := s.Convert(&in.ReadinessProbe, &out.ReadinessProbe, 0); err != nil {
return err
}
if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil {
return err
}
if err := s.Convert(&in.TerminationMessagePath, &out.TerminationMessagePath, 0); err != nil {
return err
}
if err := s.Convert(&in.ImagePullPolicy, &out.ImagePullPolicy, 0); err != nil {
return err
}
if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil {
return err
}
// now that we've converted set the container field from security context
if out.SecurityContext != nil && out.SecurityContext.Privileged != nil {
out.Privileged = *out.SecurityContext.Privileged
}
// now that we've converted set the container field from security context
if out.SecurityContext != nil && out.SecurityContext.Capabilities != nil {
out.Capabilities = *out.SecurityContext.Capabilities
}
return nil
},
// Internal API does not support CPU to be specified via an explicit field.
// Hence it must be stored in Container.Resources.
func(in *int, out *api.ResourceList, s conversion.Scope) error {
if *in == 0 {
return nil
}
quantity := resource.Quantity{}
if err := s.Convert(in, &quantity, 0); err != nil {
return err
}
(*out)[api.ResourceCPU] = quantity
return nil
},
// Internal API does not support Memory to be specified via an explicit field.
// Hence it must be stored in Container.Resources.
func(in *int64, out *api.ResourceList, s conversion.Scope) error {
if *in == 0 {
return nil
}
quantity := resource.Quantity{}
if err := s.Convert(in, &quantity, 0); err != nil {
return err
}
(*out)[api.ResourceMemory] = quantity
return nil
},
// Converts v1beta2.Container to internal api.Container.
// Fields 'CPU' and 'Memory' are not present in the internal api.Container object.
// Hence the need for a custom conversion function.
func(in *Container, out *api.Container, s conversion.Scope) error {
if err := s.Convert(&in.Name, &out.Name, 0); err != nil {
return err
}
if err := s.Convert(&in.Image, &out.Image, 0); err != nil {
return err
}
if err := s.Convert(&in.Command, &out.Args, 0); err != nil {
return err
}
if err := s.Convert(&in.Entrypoint, &out.Command, 0); err != nil {
return err
}
if err := s.Convert(&in.WorkingDir, &out.WorkingDir, 0); err != nil {
return err
}
if err := s.Convert(&in.Ports, &out.Ports, 0); err != nil {
return err
}
if err := s.Convert(&in.Env, &out.Env, 0); err != nil {
return err
}
if err := s.Convert(&in.Resources, &out.Resources, 0); err != nil {
return err
}
if err := s.Convert(&in.CPU, &out.Resources.Limits, 0); err != nil {
return err
}
if err := s.Convert(&in.Memory, &out.Resources.Limits, 0); err != nil {
return err
}
if err := s.Convert(&in.VolumeMounts, &out.VolumeMounts, 0); err != nil {
return err
}
if err := s.Convert(&in.LivenessProbe, &out.LivenessProbe, 0); err != nil {
return err
}
if err := s.Convert(&in.ReadinessProbe, &out.ReadinessProbe, 0); err != nil {
return err
}
if err := s.Convert(&in.Lifecycle, &out.Lifecycle, 0); err != nil {
return err
}
if err := s.Convert(&in.TerminationMessagePath, &out.TerminationMessagePath, 0); err != nil {
return err
}
if err := s.Convert(&in.ImagePullPolicy, &out.ImagePullPolicy, 0); err != nil {
return err
}
if in.SecurityContext != nil {
if in.SecurityContext.Capabilities != nil {
if !reflect.DeepEqual(in.SecurityContext.Capabilities.Add, in.Capabilities.Add) ||
!reflect.DeepEqual(in.SecurityContext.Capabilities.Drop, in.Capabilities.Drop) {
return fmt.Errorf("container capability settings do not match security context settings, cannot convert")
}
}
if in.SecurityContext.Privileged != nil {
if in.Privileged != *in.SecurityContext.Privileged {
return fmt.Errorf("container privileged settings do not match security context settings, cannot convert")
}
}
}
if err := s.Convert(&in.SecurityContext, &out.SecurityContext, 0); err != nil {
return err
}
return nil
},
func(in *api.PodSpec, out *ContainerManifest, s conversion.Scope) error {
if err := s.Convert(&in.Volumes, &out.Volumes, 0); err != nil {
return err
}
if err := s.Convert(&in.Containers, &out.Containers, 0); err != nil {
return err
}
if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil {
return err
}
if err := s.Convert(&in.ImagePullSecrets, &out.ImagePullSecrets, 0); err != nil {
return err
}
if in.TerminationGracePeriodSeconds != nil {
out.TerminationGracePeriodSeconds = new(int64)
*out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds
}
if in.ActiveDeadlineSeconds != nil {
out.ActiveDeadlineSeconds = new(int64)
*out.ActiveDeadlineSeconds = *in.ActiveDeadlineSeconds
}
out.DNSPolicy = DNSPolicy(in.DNSPolicy)
out.Version = "v1beta2"
out.HostNetwork = in.HostNetwork
return nil
},
func(in *ContainerManifest, out *api.PodSpec, s conversion.Scope) error {
if err := s.Convert(&in.Volumes, &out.Volumes, 0); err != nil {
return err
}
if err := s.Convert(&in.Containers, &out.Containers, 0); err != nil {
return err
}
if err := s.Convert(&in.RestartPolicy, &out.RestartPolicy, 0); err != nil {
return err
}
if err := s.Convert(&in.ImagePullSecrets, &out.ImagePullSecrets, 0); err != nil {
return err
}
if in.TerminationGracePeriodSeconds != nil {
out.TerminationGracePeriodSeconds = new(int64)
*out.TerminationGracePeriodSeconds = *in.TerminationGracePeriodSeconds
}
if in.ActiveDeadlineSeconds != nil {
out.ActiveDeadlineSeconds = new(int64)
*out.ActiveDeadlineSeconds = *in.ActiveDeadlineSeconds
}
out.DNSPolicy = api.DNSPolicy(in.DNSPolicy)
out.HostNetwork = in.HostNetwork
return nil
},
func(in *api.PodStatus, out *PodState, s conversion.Scope) error {
if err := s.Convert(&in.Phase, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.ContainerStatuses, &out.Info, 0); err != nil {
return err
}
if err := s.Convert(&in.Conditions, &out.Conditions, 0); err != nil {
return err
}
out.Message = in.Message
out.HostIP = in.HostIP
out.PodIP = in.PodIP
return nil
},
func(in *PodState, out *api.PodStatus, s conversion.Scope) error {
if err := s.Convert(&in.Status, &out.Phase, 0); err != nil {
return err
}
if err := s.Convert(&in.Info, &out.ContainerStatuses, 0); err != nil {
return err
}
if err := s.Convert(&in.Conditions, &out.Conditions, 0); err != nil {
return err
}
out.Message = in.Message
out.HostIP = in.HostIP
out.PodIP = in.PodIP
return nil
},
func(in *[]api.ContainerStatus, out *PodInfo, s conversion.Scope) error {
*out = make(map[string]ContainerStatus)
for _, st := range *in {
v := ContainerStatus{}
if err := s.Convert(&st, &v, 0); err != nil {
return err
}
(*out)[st.Name] = v
}
return nil
},
func(in *PodInfo, out *[]api.ContainerStatus, s conversion.Scope) error {
for k, v := range *in {
st := api.ContainerStatus{}
if err := s.Convert(&v, &st, 0); err != nil {
return err
}
st.Name = k
*out = append(*out, st)
}
return nil
},
func(in *api.ContainerStatus, out *ContainerStatus, s conversion.Scope) error {
if err := s.Convert(&in.State, &out.State, 0); err != nil {
return err
}
if err := s.Convert(&in.LastTerminationState, &out.LastTerminationState, 0); err != nil {
return err
}
if err := s.Convert(&in.Ready, &out.Ready, 0); err != nil {
return err
}
if err := s.Convert(&in.RestartCount, &out.RestartCount, 0); err != nil {
return err
}
if err := s.Convert(&in.Image, &out.Image, 0); err != nil {
return err
}
if err := s.Convert(&in.ImageID, &out.ImageID, 0); err != nil {
return err
}
if err := s.Convert(&in.ContainerID, &out.ContainerID, 0); err != nil {
return err
}
return nil
},
func(in *ContainerStatus, out *api.ContainerStatus, s conversion.Scope) error {
if err := s.Convert(&in.State, &out.State, 0); err != nil {
return err
}
if err := s.Convert(&in.LastTerminationState, &out.LastTerminationState, 0); err != nil {
return err
}
if err := s.Convert(&in.Ready, &out.Ready, 0); err != nil {
return err
}
if err := s.Convert(&in.RestartCount, &out.RestartCount, 0); err != nil {
return err
}
if err := s.Convert(&in.Image, &out.Image, 0); err != nil {
return err
}
if err := s.Convert(&in.ImageID, &out.ImageID, 0); err != nil {
return err
}
if err := s.Convert(&in.ContainerID, &out.ContainerID, 0); err != nil {
return err
}
return nil
},
func(in *api.PodStatusResult, out *PodStatusResult, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.State, 0); err != nil {
return err
}
return nil
},
func(in *PodStatusResult, out *api.PodStatusResult, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.State, &out.Status, 0); err != nil {
return err
}
return nil
},
func(in *api.PodSpec, out *PodState, s conversion.Scope) error {
if err := s.Convert(&in, &out.Manifest, 0); err != nil {
return err
}
out.Host = in.NodeName
return nil
},
func(in *PodState, out *api.PodSpec, s conversion.Scope) error {
if err := s.Convert(&in.Manifest, &out, 0); err != nil {
return err
}
out.NodeName = in.Host
return nil
},
func(in *api.Service, out *Service, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
// Produce legacy fields.
out.Protocol = ProtocolTCP
if len(in.Spec.Ports) > 0 {
out.PortName = in.Spec.Ports[0].Name
out.Port = in.Spec.Ports[0].Port
out.Protocol = Protocol(in.Spec.Ports[0].Protocol)
out.ContainerPort = in.Spec.Ports[0].TargetPort
}
// Copy modern fields.
for i := range in.Spec.Ports {
out.Ports = append(out.Ports, ServicePort{
Name: in.Spec.Ports[i].Name,
Port: in.Spec.Ports[i].Port,
Protocol: Protocol(in.Spec.Ports[i].Protocol),
ContainerPort: in.Spec.Ports[i].TargetPort,
NodePort: in.Spec.Ports[i].NodePort,
})
}
if err := s.Convert(&in.Spec.Selector, &out.Selector, 0); err != nil {
return err
}
out.PublicIPs = in.Spec.DeprecatedPublicIPs
out.PortalIP = in.Spec.ClusterIP
if err := s.Convert(&in.Spec.SessionAffinity, &out.SessionAffinity, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.LoadBalancer, &out.LoadBalancerStatus, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec.Type, &out.Type, 0); err != nil {
return err
}
out.CreateExternalLoadBalancer = in.Spec.Type == api.ServiceTypeLoadBalancer
return nil
},
func(in *Service, out *api.Service, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
if len(in.Ports) == 0 && in.Port != 0 {
// Use legacy fields to produce modern fields.
out.Spec.Ports = append(out.Spec.Ports, api.ServicePort{
Name: in.PortName,
Port: in.Port,
Protocol: api.Protocol(in.Protocol),
TargetPort: in.ContainerPort,
})
} else {
// Use modern fields, ignore legacy.
for i := range in.Ports {
out.Spec.Ports = append(out.Spec.Ports, api.ServicePort{
Name: in.Ports[i].Name,
Port: in.Ports[i].Port,
Protocol: api.Protocol(in.Ports[i].Protocol),
TargetPort: in.Ports[i].ContainerPort,
NodePort: in.Ports[i].NodePort,
})
}
}
if err := s.Convert(&in.Selector, &out.Spec.Selector, 0); err != nil {
return err
}
out.Spec.DeprecatedPublicIPs = in.PublicIPs
out.Spec.ClusterIP = in.PortalIP
if err := s.Convert(&in.SessionAffinity, &out.Spec.SessionAffinity, 0); err != nil {
return err
}
if err := s.Convert(&in.LoadBalancerStatus, &out.Status.LoadBalancer, 0); err != nil {
return err
}
typeIn := in.Type
if typeIn == "" {
if in.CreateExternalLoadBalancer {
typeIn = ServiceTypeLoadBalancer
} else {
typeIn = ServiceTypeClusterIP
}
}
if err := s.Convert(&typeIn, &out.Spec.Type, 0); err != nil {
return err
}
return nil
},
func(in *api.Node, out *Minion, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta.Labels, &out.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.Phase, &out.Status.Phase, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.Conditions, &out.Status.Conditions, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.Addresses, &out.Status.Addresses, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.NodeInfo, &out.Status.NodeInfo, 0); err != nil {
return err
}
for _, address := range in.Status.Addresses {
if address.Type == api.NodeLegacyHostIP {
out.HostIP = address.Address
}
}
out.PodCIDR = in.Spec.PodCIDR
out.ExternalID = in.Spec.ExternalID
out.ProviderID = in.Spec.ProviderID
out.Unschedulable = in.Spec.Unschedulable
return s.Convert(&in.Status.Capacity, &out.NodeResources.Capacity, 0)
},
func(in *Minion, out *api.Node, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.Phase, &out.Status.Phase, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.Conditions, &out.Status.Conditions, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.Addresses, &out.Status.Addresses, 0); err != nil {
return err
}
if err := s.Convert(&in.Status.NodeInfo, &out.Status.NodeInfo, 0); err != nil {
return err
}
if in.HostIP != "" {
api.AddToNodeAddresses(&out.Status.Addresses,
api.NodeAddress{Type: api.NodeLegacyHostIP, Address: in.HostIP})
}
out.Spec.PodCIDR = in.PodCIDR
out.Spec.ExternalID = in.ExternalID
out.Spec.ProviderID = in.ProviderID
out.Spec.Unschedulable = in.Unschedulable
return s.Convert(&in.NodeResources.Capacity, &out.Status.Capacity, 0)
},
func(in *api.LimitRange, out *LimitRange, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil {
return err
}
return nil
},
func(in *LimitRange, out *api.LimitRange, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil {
return err
}
return nil
},
func(in *Namespace, out *api.Namespace, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil {
return err
}
return nil
},
func(in *api.LimitRangeSpec, out *LimitRangeSpec, s conversion.Scope) error {
*out = LimitRangeSpec{}
out.Limits = make([]LimitRangeItem, len(in.Limits), len(in.Limits))
for i := range in.Limits {
if err := s.Convert(&in.Limits[i], &out.Limits[i], 0); err != nil {
return err
}
}
return nil
},
func(in *LimitRangeSpec, out *api.LimitRangeSpec, s conversion.Scope) error {
*out = api.LimitRangeSpec{}
out.Limits = make([]api.LimitRangeItem, len(in.Limits), len(in.Limits))
for i := range in.Limits {
if err := s.Convert(&in.Limits[i], &out.Limits[i], 0); err != nil {
return err
}
}
return nil
},
func(in *api.LimitRangeItem, out *LimitRangeItem, s conversion.Scope) error {
*out = LimitRangeItem{}
out.Type = LimitType(in.Type)
if err := s.Convert(&in.Max, &out.Max, 0); err != nil {
return err
}
if err := s.Convert(&in.Min, &out.Min, 0); err != nil {
return err
}
if err := s.Convert(&in.Default, &out.Default, 0); err != nil {
return err
}
return nil
},
func(in *LimitRangeItem, out *api.LimitRangeItem, s conversion.Scope) error {
*out = api.LimitRangeItem{}
out.Type = api.LimitType(in.Type)
if err := s.Convert(&in.Max, &out.Max, 0); err != nil {
return err
}
if err := s.Convert(&in.Min, &out.Min, 0); err != nil {
return err
}
if err := s.Convert(&in.Default, &out.Default, 0); err != nil {
return err
}
return nil
},
func(in *api.ResourceQuota, out *ResourceQuota, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil {
return err
}
return nil
},
func(in *ResourceQuota, out *api.ResourceQuota, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.Labels, &out.ObjectMeta.Labels, 0); err != nil {
return err
}
return nil
},
func(in *api.ResourceQuotaSpec, out *ResourceQuotaSpec, s conversion.Scope) error {
*out = ResourceQuotaSpec{}
if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil {
return err
}
return nil
},
func(in *ResourceQuotaSpec, out *api.ResourceQuotaSpec, s conversion.Scope) error {
*out = api.ResourceQuotaSpec{}
if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil {
return err
}
return nil
},
func(in *api.ResourceQuotaStatus, out *ResourceQuotaStatus, s conversion.Scope) error {
*out = ResourceQuotaStatus{}
if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil {
return err
}
if err := s.Convert(&in.Used, &out.Used, 0); err != nil {
return err
}
return nil
},
func(in *ResourceQuotaStatus, out *api.ResourceQuotaStatus, s conversion.Scope) error {
*out = api.ResourceQuotaStatus{}
if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil {
return err
}
if err := s.Convert(&in.Used, &out.Used, 0); err != nil {
return err
}
return nil
},
// Object ID <-> Name
// TODO: amend the conversion package to allow overriding specific fields.
func(in *ObjectReference, out *api.ObjectReference, s conversion.Scope) error {
out.Kind = in.Kind
out.Namespace = in.Namespace
out.Name = in.ID
out.UID = in.UID
out.APIVersion = in.APIVersion
out.ResourceVersion = in.ResourceVersion
out.FieldPath = in.FieldPath
return nil
},
func(in *api.ObjectReference, out *ObjectReference, s conversion.Scope) error {
out.Kind = in.Kind
out.Namespace = in.Namespace
out.ID = in.Name
out.UID = in.UID
out.APIVersion = in.APIVersion
out.ResourceVersion = in.ResourceVersion
out.FieldPath = in.FieldPath
return nil
},
// Event Status <-> Condition
// Event Source <-> Source.Component
// Event Host <-> Source.Host
// TODO: remove this when it becomes possible to specify a field name conversion on a specific type
func(in *api.Event, out *Event, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
out.Reason = in.Reason
out.Message = in.Message
out.Source = in.Source.Component
out.Host = in.Source.Host
out.Timestamp = in.FirstTimestamp
out.FirstTimestamp = in.FirstTimestamp
out.LastTimestamp = in.LastTimestamp
out.Count = in.Count
return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0)
},
func(in *Event, out *api.Event, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
out.Reason = in.Reason
out.Message = in.Message
out.Source.Component = in.Source
out.Source.Host = in.Host
if in.FirstTimestamp.IsZero() {
// Assume this is an old event that does not specify FirstTimestamp/LastTimestamp/Count
out.FirstTimestamp = in.Timestamp
out.LastTimestamp = in.Timestamp
out.Count = 1
} else {
out.FirstTimestamp = in.FirstTimestamp
out.LastTimestamp = in.LastTimestamp
out.Count = in.Count
}
return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0)
},
// This is triggered for the Memory field of Container.
func(in *int64, out *resource.Quantity, s conversion.Scope) error {
out.Set(*in)
out.Format = resource.BinarySI
return nil
},
func(in *resource.Quantity, out *int64, s conversion.Scope) error {
*out = in.Value()
return nil
},
// This is triggered by the CPU field of Container.
// Note that if we add other int/Quantity conversions my
// simple hack (int64=Value(), int=MilliValue()) here won't work.
func(in *int, out *resource.Quantity, s conversion.Scope) error {
out.SetMilli(int64(*in))
out.Format = resource.DecimalSI
return nil
},
func(in *resource.Quantity, out *int, s conversion.Scope) error {
*out = int(in.MilliValue())
return nil
},
// Convert resource lists.
func(in *ResourceList, out *api.ResourceList, s conversion.Scope) error {
*out = api.ResourceList{}
for k, v := range *in {
fv, err := strconv.ParseFloat(v.String(), 64)
if err != nil {
return &api.ConversionError{
In: in, Out: out,
Message: fmt.Sprintf("value '%v' of '%v': %v", v, k, err),
}
}
if k == ResourceCPU {
(*out)[api.ResourceCPU] = *resource.NewMilliQuantity(int64(fv*1000), resource.DecimalSI)
} else {
(*out)[api.ResourceName(k)] = *resource.NewQuantity(int64(fv), resource.BinarySI)
}
}
return nil
},
func(in *api.ResourceList, out *ResourceList, s conversion.Scope) error {
*out = ResourceList{}
for k, v := range *in {
if k == api.ResourceCPU {
(*out)[ResourceCPU] = util.NewIntOrStringFromString(fmt.Sprintf("%v", float64(v.MilliValue())/1000))
} else {
(*out)[ResourceName(k)] = util.NewIntOrStringFromInt(int(v.Value()))
}
}
return nil
},
func(in *api.Volume, out *Volume, s conversion.Scope) error {
if err := s.Convert(&in.VolumeSource, &out.Source, 0); err != nil {
return err
}
out.Name = in.Name
return nil
},
func(in *Volume, out *api.Volume, s conversion.Scope) error {
if err := s.Convert(&in.Source, &out.VolumeSource, 0); err != nil {
return err
}
out.Name = in.Name
return nil
},
func(in *api.VolumeSource, out *VolumeSource, s conversion.Scope) error {
if err := s.Convert(&in.EmptyDir, &out.EmptyDir, 0); err != nil {
return err
}
if err := s.Convert(&in.GitRepo, &out.GitRepo, 0); err != nil {
return err
}
if err := s.Convert(&in.ISCSI, &out.ISCSI, 0); err != nil {
return err
}
if err := s.Convert(&in.GCEPersistentDisk, &out.GCEPersistentDisk, 0); err != nil {
return err
}
if err := s.Convert(&in.AWSElasticBlockStore, &out.AWSElasticBlockStore, 0); err != nil {
return err
}
if err := s.Convert(&in.HostPath, &out.HostDir, 0); err != nil {
return err
}
if err := s.Convert(&in.Secret, &out.Secret, 0); err != nil {
return err
}
if err := s.Convert(&in.NFS, &out.NFS, 0); err != nil {
return err
}
if err := s.Convert(&in.Glusterfs, &out.Glusterfs, 0); err != nil {
return err
}
if err := s.Convert(&in.PersistentVolumeClaimVolumeSource, &out.PersistentVolumeClaimVolumeSource, 0); err != nil {
return err
}
if err := s.Convert(&in.RBD, &out.RBD, 0); err != nil {
return err
}
return nil
},
func(in *VolumeSource, out *api.VolumeSource, s conversion.Scope) error {
if err := s.Convert(&in.EmptyDir, &out.EmptyDir, 0); err != nil {
return err
}
if err := s.Convert(&in.GitRepo, &out.GitRepo, 0); err != nil {
return err
}
if err := s.Convert(&in.GCEPersistentDisk, &out.GCEPersistentDisk, 0); err != nil {
return err
}
if err := s.Convert(&in.AWSElasticBlockStore, &out.AWSElasticBlockStore, 0); err != nil {
return err
}
if err := s.Convert(&in.ISCSI, &out.ISCSI, 0); err != nil {
return err
}
if err := s.Convert(&in.HostDir, &out.HostPath, 0); err != nil {
return err
}
if err := s.Convert(&in.Secret, &out.Secret, 0); err != nil {
return err
}
if err := s.Convert(&in.NFS, &out.NFS, 0); err != nil {
return err
}
if err := s.Convert(&in.PersistentVolumeClaimVolumeSource, &out.PersistentVolumeClaimVolumeSource, 0); err != nil {
return err
}
if err := s.Convert(&in.Glusterfs, &out.Glusterfs, 0); err != nil {
return err
}
if err := s.Convert(&in.RBD, &out.RBD, 0); err != nil {
return err
}
return nil
},
func(in *api.PullPolicy, out *PullPolicy, s conversion.Scope) error {
switch *in {
case api.PullAlways:
*out = PullAlways
case api.PullNever:
*out = PullNever
case api.PullIfNotPresent:
*out = PullIfNotPresent
case "":
*out = ""
default:
// Let unknown values through - they will get caught by validation
*out = PullPolicy(*in)
}
return nil
},
func(in *PullPolicy, out *api.PullPolicy, s conversion.Scope) error {
switch *in {
case PullAlways:
*out = api.PullAlways
case PullNever:
*out = api.PullNever
case PullIfNotPresent:
*out = api.PullIfNotPresent
case "":
*out = ""
default:
// Let unknown values through - they will get caught by validation
*out = api.PullPolicy(*in)
}
return nil
},
func(in *api.RestartPolicy, out *RestartPolicy, s conversion.Scope) error {
switch *in {
case api.RestartPolicyAlways:
*out = RestartPolicy{Always: &RestartPolicyAlways{}}
case api.RestartPolicyNever:
*out = RestartPolicy{Never: &RestartPolicyNever{}}
case api.RestartPolicyOnFailure:
*out = RestartPolicy{OnFailure: &RestartPolicyOnFailure{}}
default:
*out = RestartPolicy{}
}
return nil
},
func(in *RestartPolicy, out *api.RestartPolicy, s conversion.Scope) error {
switch {
case in.Always != nil:
*out = api.RestartPolicyAlways
case in.Never != nil:
*out = api.RestartPolicyNever
case in.OnFailure != nil:
*out = api.RestartPolicyOnFailure
default:
*out = ""
}
return nil
},
func(in *api.Probe, out *LivenessProbe, s conversion.Scope) error {
if err := s.Convert(&in.Exec, &out.Exec, 0); err != nil {
return err
}
if err := s.Convert(&in.HTTPGet, &out.HTTPGet, 0); err != nil {
return err
}
if err := s.Convert(&in.TCPSocket, &out.TCPSocket, 0); err != nil {
return err
}
out.InitialDelaySeconds = in.InitialDelaySeconds
out.TimeoutSeconds = in.TimeoutSeconds
return nil
},
func(in *LivenessProbe, out *api.Probe, s conversion.Scope) error {
if err := s.Convert(&in.Exec, &out.Exec, 0); err != nil {
return err
}
if err := s.Convert(&in.HTTPGet, &out.HTTPGet, 0); err != nil {
return err
}
if err := s.Convert(&in.TCPSocket, &out.TCPSocket, 0); err != nil {
return err
}
out.InitialDelaySeconds = in.InitialDelaySeconds
out.TimeoutSeconds = in.TimeoutSeconds
return nil
},
func(in *api.Endpoints, out *Endpoints, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Subsets, &out.Subsets, 0); err != nil {
return err
}
// Produce back-compat fields.
firstPortName := ""
if len(in.Subsets) > 0 {
if len(in.Subsets[0].Ports) > 0 {
if err := s.Convert(&in.Subsets[0].Ports[0].Protocol, &out.Protocol, 0); err != nil {
return err
}
firstPortName = in.Subsets[0].Ports[0].Name
}
} else {
out.Protocol = ProtocolTCP
}
for i := range in.Subsets {
ss := &in.Subsets[i]
for j := range ss.Ports {
ssp := &ss.Ports[j]
if ssp.Name != firstPortName {
continue
}
for k := range ss.Addresses {
ssa := &ss.Addresses[k]
hostPort := net.JoinHostPort(ssa.IP, strconv.Itoa(ssp.Port))
out.Endpoints = append(out.Endpoints, hostPort)
if ssa.TargetRef != nil {
target := EndpointObjectReference{
Endpoint: hostPort,
}
if err := s.Convert(ssa.TargetRef, &target.ObjectReference, 0); err != nil {
return err
}
out.TargetRefs = append(out.TargetRefs, target)
}
}
}
}
return nil
},
func(in *Endpoints, out *api.Endpoints, s conversion.Scope) error {
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil {
return err
}
if err := s.Convert(&in.Subsets, &out.Subsets, 0); err != nil {
return err
}
// Back-compat fields are handled in the defaulting phase.
return nil
},
func(in *api.NodeCondition, out *NodeCondition, s conversion.Scope) error {
if err := s.Convert(&in.Type, &out.Kind, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.LastHeartbeatTime, &out.LastProbeTime, 0); err != nil {
return err
}
if err := s.Convert(&in.LastTransitionTime, &out.LastTransitionTime, 0); err != nil {
return err
}
if err := s.Convert(&in.Reason, &out.Reason, 0); err != nil {
return err
}
if err := s.Convert(&in.Message, &out.Message, 0); err != nil {
return err
}
return nil
},
func(in *NodeCondition, out *api.NodeCondition, s conversion.Scope) error {
if err := s.Convert(&in.Kind, &out.Type, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.Status, 0); err != nil {
return err
}
if err := s.Convert(&in.LastProbeTime, &out.LastHeartbeatTime, 0); err != nil {
return err
}
if err := s.Convert(&in.LastTransitionTime, &out.LastTransitionTime, 0); err != nil {
return err
}
if err := s.Convert(&in.Reason, &out.Reason, 0); err != nil {
return err
}
if err := s.Convert(&in.Message, &out.Message, 0); err != nil {
return err
}
return nil
},
func(in *api.NodeConditionType, out *NodeConditionKind, s conversion.Scope) error {
switch *in {
case api.NodeReady:
*out = NodeReady
break
case "":
*out = ""
default:
*out = NodeConditionKind(*in)
break
}
return nil
},
func(in *NodeConditionKind, out *api.NodeConditionType, s conversion.Scope) error {
switch *in {
case NodeReady:
*out = api.NodeReady
break
case "":
*out = ""
default:
*out = api.NodeConditionType(*in)
break
}
return nil
},
func(in *api.ConditionStatus, out *ConditionStatus, s conversion.Scope) error {
switch *in {
case api.ConditionTrue:
*out = ConditionFull
break
case api.ConditionFalse:
*out = ConditionNone
break
default:
*out = ConditionStatus(*in)
break
}
return nil
},
func(in *ConditionStatus, out *api.ConditionStatus, s conversion.Scope) error {
switch *in {
case ConditionFull:
*out = api.ConditionTrue
break
case ConditionNone:
*out = api.ConditionFalse
break
default:
*out = api.ConditionStatus(*in)
break
}
return nil
},
func(in *api.PodCondition, out *PodCondition, s conversion.Scope) error {
if err := s.Convert(&in.Type, &out.Kind, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.Status, 0); err != nil {
return err
}
return nil
},
func(in *PodCondition, out *api.PodCondition, s conversion.Scope) error {
if err := s.Convert(&in.Kind, &out.Type, 0); err != nil {
return err
}
if err := s.Convert(&in.Status, &out.Status, 0); err != nil {
return err
}
return nil
},
func(in *api.PodConditionType, out *PodConditionKind, s conversion.Scope) error {
switch *in {
case api.PodReady:
*out = PodReady
break
case "":
*out = ""
default:
*out = PodConditionKind(*in)
break
}
return nil
},
func(in *PodConditionKind, out *api.PodConditionType, s conversion.Scope) error {
switch *in {
case PodReady:
*out = api.PodReady
break
case "":
*out = ""
default:
*out = api.PodConditionType(*in)
break
}
return nil
},
func(in *Binding, out *api.Binding, s conversion.Scope) error {
if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil {
return err
}
out.Target = api.ObjectReference{
Name: in.Host,
}
out.Name = in.PodID
return nil
},
func(in *api.Binding, out *Binding, s conversion.Scope) error {
if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil {
return err
}
out.Host = in.Target.Name
out.PodID = in.Name
return nil
},
func(in *api.SecretVolumeSource, out *SecretVolumeSource, s conversion.Scope) error {
out.Target.ID = in.SecretName
return nil
},
func(in *SecretVolumeSource, out *api.SecretVolumeSource, s conversion.Scope) error {
out.SecretName = in.Target.ID
return nil
},
func(in *api.ContainerState, out *ContainerState, s conversion.Scope) error {
if err := s.Convert(&in.Waiting, &out.Waiting, 0); err != nil {
return err
}
if err := s.Convert(&in.Running, &out.Running, 0); err != nil {
return err
}
if err := s.Convert(&in.Terminated, &out.Termination, 0); err != nil {
return err
}
return nil
},
func(in *ContainerState, out *api.ContainerState, s conversion.Scope) error {
if err := s.Convert(&in.Waiting, &out.Waiting, 0); err != nil {
return err
}
if err := s.Convert(&in.Running, &out.Running, 0); err != nil {
return err
}
if err := s.Convert(&in.Termination, &out.Terminated, 0); err != nil {
return err
}
return nil
},
)
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
panic(err)
}
// Add field conversion funcs.
err = api.Scheme.AddFieldLabelConversionFunc("v1beta2", "Pod",
func(label, value string) (string, string, error) {
switch label {
case "name":
return "metadata.name", value, nil
case "DesiredState.Host":
return "spec.host", value, nil
case "DesiredState.Status":
podStatus := PodStatus(value)
var internalValue api.PodPhase
api.Scheme.Convert(&podStatus, &internalValue)
return "status.phase", string(internalValue), nil
default:
return "", "", fmt.Errorf("field label not supported: %s", label)
}
})
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
panic(err)
}
err = api.Scheme.AddFieldLabelConversionFunc("v1beta2", "Node",
func(label, value string) (string, string, error) {
switch label {
case "name":
return "metadata.name", value, nil
case "unschedulable":
return "spec.unschedulable", value, nil
default:
return "", "", fmt.Errorf("field label not supported: %s", label)
}
})
if err != nil {
// if one of the conversion functions is malformed, detect it immediately.
panic(err)
}
err = api.Scheme.AddFieldLabelConversionFunc("v1beta2", "ReplicationController",
func(label, value string) (string, string, error) {
switch label {
case "name":
return "metadata.name", value, nil
case "currentState.replicas":
return "status.replicas", value, nil
default:
return "", "", fmt.Errorf("field label not supported: %s", label)
}
})
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
panic(err)
}
err = api.Scheme.AddFieldLabelConversionFunc("v1beta2", "Event",
func(label, value string) (string, string, error) {
switch label {
case "involvedObject.kind",
"involvedObject.namespace",
"involvedObject.uid",
"involvedObject.apiVersion",
"involvedObject.resourceVersion",
"involvedObject.fieldPath",
"reason",
"source":
return label, value, nil
case "involvedObject.id":
return "involvedObject.name", value, nil
default:
return "", "", fmt.Errorf("field label not supported: %s", label)
}
})
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
panic(err)
}
err = api.Scheme.AddFieldLabelConversionFunc("v1beta2", "Namespace",
func(label, value string) (string, string, error) {
switch label {
case "status.phase":
return label, value, nil
default:
return "", "", fmt.Errorf("field label not supported: %s", label)
}
})
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
panic(err)
}
err = api.Scheme.AddFieldLabelConversionFunc("v1beta2", "Secret",
func(label, value string) (string, string, error) {
switch label {
case "type":
return label, value, nil
default:
return "", "", fmt.Errorf("field label not supported: %s", label)
}
})
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
panic(err)
}
err = api.Scheme.AddFieldLabelConversionFunc("v1beta2", "ServiceAccount",
func(label, value string) (string, string, error) {
switch label {
case "name":
return "metadata.name", value, nil
default:
return "", "", fmt.Errorf("field label not supported: %s", label)
}
})
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
panic(err)
}
}
/*
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())
}
}
}
}
/*
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
}
}
}
/*
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
}
/*
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
/*
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() {}
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -37,8 +37,6 @@ import ( ...@@ -37,8 +37,6 @@ import (
apierrs "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" apierrs "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest" "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/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
...@@ -55,20 +53,13 @@ func convert(obj runtime.Object) (runtime.Object, error) { ...@@ -55,20 +53,13 @@ func convert(obj runtime.Object) (runtime.Object, error) {
return obj, nil return obj, nil
} }
// This creates a fake API version, similar to api/latest.go for a v1beta1 equivalent api. It is distinct // This creates fake API versions, similar to api/latest.go.
// from the Kubernetes API versions to allow clients to properly distinguish the two.
const testVersion = "version" const testVersion = "version"
const newVersion = "version2"
// The equivalent of the Kubernetes v1beta3 API. var versions = []string{testVersion, newVersion}
const testVersion2 = "version2" var codec = runtime.CodecFor(api.Scheme, testVersion)
var newCodec = runtime.CodecFor(api.Scheme, newVersion)
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 accessor = meta.NewAccessor() var accessor = meta.NewAccessor()
var versioner runtime.ResourceVersioner = accessor var versioner runtime.ResourceVersioner = accessor
...@@ -81,13 +72,13 @@ func interfacesFor(version string) (*meta.VersionInterfaces, error) { ...@@ -81,13 +72,13 @@ func interfacesFor(version string) (*meta.VersionInterfaces, error) {
switch version { switch version {
case testVersion: case testVersion:
return &meta.VersionInterfaces{ return &meta.VersionInterfaces{
Codec: legacyCodec, Codec: codec,
ObjectConvertor: api.Scheme, ObjectConvertor: api.Scheme,
MetadataAccessor: accessor, MetadataAccessor: accessor,
}, nil }, nil
case testVersion2: case newVersion:
return &meta.VersionInterfaces{ return &meta.VersionInterfaces{
Codec: codec, Codec: newCodec,
ObjectConvertor: api.Scheme, ObjectConvertor: api.Scheme,
MetadataAccessor: accessor, MetadataAccessor: accessor,
}, nil }, nil
...@@ -109,26 +100,44 @@ func newMapper() *meta.DefaultRESTMapper { ...@@ -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() { func init() {
// Certain API objects are returned regardless of the contents of storage: // Certain API objects are returned regardless of the contents of storage:
// api.Status is returned in errors // api.Status is returned in errors
// "internal" version // "internal" version
api.Scheme.AddKnownTypes("", &Simple{}, &SimpleList{}, &api.Status{}, &api.ListOptions{}, &SimpleGetOptions{}, &SimpleRoot{}) api.Scheme.AddKnownTypes("", &Simple{}, &SimpleList{}, &api.Status{}, &api.ListOptions{}, &SimpleGetOptions{}, &SimpleRoot{})
// "version" version addTestTypes()
// TODO: Use versioned api objects? addNewTestTypes()
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{})
nsMapper := newMapper() nsMapper := newMapper()
legacyNsMapper := 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 _, version := range versions {
for kind := range api.Scheme.KnownTypes(version) { for kind := range api.Scheme.KnownTypes(version) {
mixedCase := true mixedCase := true
...@@ -149,13 +158,12 @@ func init() { ...@@ -149,13 +158,12 @@ func init() {
admissionControl = admit.NewAlwaysAdmit() admissionControl = admit.NewAlwaysAdmit()
requestContextMapper = api.NewRequestContextMapper() requestContextMapper = api.NewRequestContextMapper()
//mapper.(*meta.DefaultRESTMapper).Add(meta.RESTScopeNamespaceLegacy, "Simple", testVersion, false)
api.Scheme.AddFieldLabelConversionFunc(testVersion, "Simple", api.Scheme.AddFieldLabelConversionFunc(testVersion, "Simple",
func(label, value string) (string, string, error) { func(label, value string) (string, string, error) {
return label, value, nil return label, value, nil
}, },
) )
api.Scheme.AddFieldLabelConversionFunc(testVersion2, "Simple", api.Scheme.AddFieldLabelConversionFunc(newVersion, "Simple",
func(label, value string) (string, string, error) { func(label, value string) (string, string, error) {
return label, value, nil return label, value, nil
}, },
...@@ -210,13 +218,13 @@ func handleInternal(legacy bool, storage map[string]rest.Storage, admissionContr ...@@ -210,13 +218,13 @@ func handleInternal(legacy bool, storage map[string]rest.Storage, admissionContr
} }
if legacy { if legacy {
group.Version = testVersion group.Version = testVersion
group.ServerVersion = "v1beta1" group.ServerVersion = testVersion
group.Codec = legacyCodec group.Codec = codec
group.Mapper = legacyNamespaceMapper group.Mapper = legacyNamespaceMapper
} else { } else {
group.Version = testVersion2 group.Version = newVersion
group.ServerVersion = "v1beta3" group.ServerVersion = newVersion
group.Codec = codec group.Codec = newCodec
group.Mapper = namespaceMapper group.Mapper = namespaceMapper
} }
...@@ -757,7 +765,7 @@ func TestList(t *testing.T) { ...@@ -757,7 +765,7 @@ func TestList(t *testing.T) {
selfLink: "/api/version/simple?namespace=", selfLink: "/api/version/simple?namespace=",
legacy: true, legacy: true,
}, },
// list items in a namespace, v1beta3+ // list items in a namespace in the path
{ {
url: "/api/version2/namespaces/default/simple", url: "/api/version2/namespaces/default/simple",
namespace: "default", namespace: "default",
...@@ -1378,7 +1386,7 @@ func TestDeleteWithOptions(t *testing.T) { ...@@ -1378,7 +1386,7 @@ func TestDeleteWithOptions(t *testing.T) {
item := &api.DeleteOptions{ item := &api.DeleteOptions{
GracePeriodSeconds: &grace, GracePeriodSeconds: &grace,
} }
body, err := versionServerCodec.Encode(item) body, err := codec.Encode(item)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -1439,7 +1447,7 @@ func TestLegacyDeleteIgnoresOptions(t *testing.T) { ...@@ -1439,7 +1447,7 @@ func TestLegacyDeleteIgnoresOptions(t *testing.T) {
defer server.Close() defer server.Close()
item := api.NewDeleteOptions(300) item := api.NewDeleteOptions(300)
body, err := versionServerCodec.Encode(item) body, err := codec.Encode(item)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -1888,9 +1896,9 @@ func TestParentResourceIsRequired(t *testing.T) { ...@@ -1888,9 +1896,9 @@ func TestParentResourceIsRequired(t *testing.T) {
Context: requestContextMapper, Context: requestContextMapper,
Mapper: namespaceMapper, Mapper: namespaceMapper,
Version: testVersion2, Version: newVersion,
ServerVersion: "v1beta3", ServerVersion: newVersion,
Codec: codec, Codec: newCodec,
} }
container := restful.NewContainer() container := restful.NewContainer()
if err := group.InstallREST(container); err == nil { if err := group.InstallREST(container); err == nil {
...@@ -1916,9 +1924,9 @@ func TestParentResourceIsRequired(t *testing.T) { ...@@ -1916,9 +1924,9 @@ func TestParentResourceIsRequired(t *testing.T) {
Context: requestContextMapper, Context: requestContextMapper,
Mapper: namespaceMapper, Mapper: namespaceMapper,
Version: testVersion2, Version: newVersion,
ServerVersion: "v1beta3", ServerVersion: newVersion,
Codec: codec, Codec: newCodec,
} }
container = restful.NewContainer() container = restful.NewContainer()
if err := group.InstallREST(container); err != nil { if err := group.InstallREST(container); err != nil {
......
...@@ -303,7 +303,7 @@ func TestWatchHTTPTimeout(t *testing.T) { ...@@ -303,7 +303,7 @@ func TestWatchHTTPTimeout(t *testing.T) {
// Setup a new watchserver // Setup a new watchserver
watchServer := &WatchServer{ watchServer := &WatchServer{
watcher, watcher,
version2ServerCodec, newCodec,
func(obj runtime.Object) {}, func(obj runtime.Object) {},
&fakeTimeoutFactory{timeoutCh, done}, &fakeTimeoutFactory{timeoutCh, done},
} }
...@@ -315,13 +315,13 @@ func TestWatchHTTPTimeout(t *testing.T) { ...@@ -315,13 +315,13 @@ func TestWatchHTTPTimeout(t *testing.T) {
// Setup a client // Setup a client
dest, _ := url.Parse(s.URL) dest, _ := url.Parse(s.URL)
dest.Path = "/api/version/watch/resource" dest.Path = "/api/" + newVersion + "/simple"
dest.RawQuery = "" dest.RawQuery = "watch=true"
req, _ := http.NewRequest("GET", dest.String(), nil) req, _ := http.NewRequest("GET", dest.String(), nil)
client := http.Client{} client := http.Client{}
resp, err := client.Do(req) 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 // Make sure we can actually watch an endpoint
decoder := json.NewDecoder(resp.Body) decoder := json.NewDecoder(resp.Body)
......
...@@ -107,14 +107,6 @@ func TestExec(t *testing.T) { ...@@ -107,14 +107,6 @@ func TestExec(t *testing.T) {
execErr bool 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", name: "v1beta3 - pod exec",
version: "v1beta3", version: "v1beta3",
podPath: "/api/v1beta3/namespaces/test/pods/foo", podPath: "/api/v1beta3/namespaces/test/pods/foo",
......
...@@ -155,10 +155,10 @@ func TestGetUnknownSchemaObjectListGeneric(t *testing.T) { ...@@ -155,10 +155,10 @@ func TestGetUnknownSchemaObjectListGeneric(t *testing.T) {
obj2 string obj2 string
}{ }{
"handles specific version": { "handles specific version": {
output: "v1beta3", output: "v1",
list: "v1beta3", list: "v1",
obj1: "unlikelyversion", obj1: "unlikelyversion",
obj2: "v1beta3", obj2: "v1",
}, },
"handles second specific version": { "handles second specific version": {
output: "unlikelyversion", output: "unlikelyversion",
...@@ -167,14 +167,14 @@ func TestGetUnknownSchemaObjectListGeneric(t *testing.T) { ...@@ -167,14 +167,14 @@ func TestGetUnknownSchemaObjectListGeneric(t *testing.T) {
obj2: "v1beta3", // version of the API response obj2: "v1beta3", // version of the API response
}, },
"handles common version": { "handles common version": {
output: "v1beta1", output: "v1beta3",
list: "v1beta1", list: "v1beta3",
obj1: "unlikelyversion", // because test scheme defaults to unlikelyversion obj1: "unlikelyversion", // because test scheme defaults to unlikelyversion
obj2: "v1beta1", obj2: "v1beta3",
}, },
} }
for k, test := range testCases { for k, test := range testCases {
apiCodec := runtime.CodecFor(api.Scheme, "v1beta1") apiCodec := runtime.CodecFor(api.Scheme, "v1beta3")
regularClient := &client.FakeRESTClient{ regularClient := &client.FakeRESTClient{
Codec: apiCodec, Codec: apiCodec,
Client: client.HTTPClientFunc(func(req *http.Request) (*http.Response, error) { Client: client.HTTPClientFunc(func(req *http.Request) (*http.Response, error) {
......
...@@ -157,14 +157,6 @@ func TestLog(t *testing.T) { ...@@ -157,14 +157,6 @@ func TestLog(t *testing.T) {
pod *api.Pod 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", name: "v1beta3 - pod log",
version: "v1beta3", version: "v1beta3",
podPath: "/api/v1beta3/namespaces/test/pods/foo", podPath: "/api/v1beta3/namespaces/test/pods/foo",
......
...@@ -46,14 +46,6 @@ func TestPortForward(t *testing.T) { ...@@ -46,14 +46,6 @@ func TestPortForward(t *testing.T) {
pfErr bool 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", name: "v1beta3 - pod portforward",
version: "v1beta3", version: "v1beta3",
podPath: "/api/v1beta3/namespaces/test/pods/foo", podPath: "/api/v1beta3/namespaces/test/pods/foo",
......
...@@ -43,7 +43,7 @@ func TestMerge(t *testing.T) { ...@@ -43,7 +43,7 @@ func TestMerge(t *testing.T) {
Name: "foo", Name: "foo",
}, },
}, },
fragment: `{ "apiVersion": "v1beta1" }`, fragment: `{ "apiVersion": "v1beta3" }`,
expected: &api.Pod{ expected: &api.Pod{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "foo", Name: "foo",
...@@ -101,25 +101,6 @@ func TestMerge(t *testing.T) { ...@@ -101,25 +101,6 @@ func TestMerge(t *testing.T) {
Name: "foo", 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{
ObjectMeta: api.ObjectMeta{
Name: "foo",
},
},
fragment: `{ "apiVersion": "v1beta3", "spec": { "volumes": [ {"name": "v1"}, {"name": "v2"} ] } }`, fragment: `{ "apiVersion": "v1beta3", "spec": { "volumes": [ {"name": "v1"}, {"name": "v2"} ] } }`,
expected: &api.Pod{ expected: &api.Pod{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
...@@ -149,24 +130,6 @@ func TestMerge(t *testing.T) { ...@@ -149,24 +130,6 @@ func TestMerge(t *testing.T) {
expectErr: true, 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", kind: "Service",
obj: &api.Service{}, obj: &api.Service{},
fragment: `{ "apiVersion": "badVersion" }`, fragment: `{ "apiVersion": "badVersion" }`,
...@@ -177,11 +140,17 @@ func TestMerge(t *testing.T) { ...@@ -177,11 +140,17 @@ func TestMerge(t *testing.T) {
obj: &api.Service{ obj: &api.Service{
Spec: api.ServiceSpec{}, Spec: api.ServiceSpec{},
}, },
fragment: `{ "apiVersion": "v1beta1", "port": 0 }`, fragment: `{ "apiVersion": "v1beta3", "spec": { "ports": [ { "port": 0 } ] } }`,
expected: &api.Service{ expected: &api.Service{
Spec: api.ServiceSpec{ Spec: api.ServiceSpec{
SessionAffinity: "None", SessionAffinity: "None",
Type: api.ServiceTypeClusterIP, Type: api.ServiceTypeClusterIP,
Ports: []api.ServicePort{
{
Protocol: api.ProtocolTCP,
Port: 0,
},
},
}, },
}, },
}, },
...@@ -194,7 +163,7 @@ func TestMerge(t *testing.T) { ...@@ -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{ expected: &api.Service{
Spec: api.ServiceSpec{ Spec: api.ServiceSpec{
SessionAffinity: "None", SessionAffinity: "None",
......
...@@ -24,14 +24,12 @@ import ( ...@@ -24,14 +24,12 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "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/api/validation"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet"
"github.com/GoogleCloudPlatform/kubernetes/pkg/types" "github.com/GoogleCloudPlatform/kubernetes/pkg/types"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
utilyaml "github.com/GoogleCloudPlatform/kubernetes/pkg/util/yaml" utilyaml "github.com/GoogleCloudPlatform/kubernetes/pkg/util/yaml"
"github.com/ghodss/yaml"
"github.com/golang/glog" "github.com/golang/glog"
) )
...@@ -144,68 +142,3 @@ func tryDecodePodList(data []byte, defaultFn defaultFunc) (parsed bool, pods api ...@@ -144,68 +142,3 @@ func tryDecodePodList(data []byte, defaultFn defaultFunc) (parsed bool, pods api
} }
return true, *newPods, err 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
}
...@@ -148,15 +148,6 @@ func (s *sourceFile) extractFromFile(filename string) (pod *api.Pod, err error) ...@@ -148,15 +148,6 @@ func (s *sourceFile) extractFromFile(filename string) (pod *api.Pod, err error)
return s.applyDefaults(pod, filename) 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) parsed, pod, podErr := tryDecodeSinglePod(data, defaultFn)
if parsed { if parsed {
if podErr != nil { if podErr != nil {
...@@ -165,7 +156,6 @@ func (s *sourceFile) extractFromFile(filename string) (pod *api.Pod, err error) ...@@ -165,7 +156,6 @@ func (s *sourceFile) extractFromFile(filename string) (pod *api.Pod, err error)
return pod, nil return pod, nil
} }
return pod, fmt.Errorf("%v: read '%v', but couldn't parse as neither "+ return pod, fmt.Errorf("%v: read '%v', but couldn't parse as pod(%v).\n",
"manifest (%v) nor pod (%v).\n", filename, string(data), podErr)
filename, string(data), manifestErr, podErr)
} }
...@@ -17,22 +17,18 @@ limitations under the License. ...@@ -17,22 +17,18 @@ limitations under the License.
package config package config
import ( import (
"encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"sort"
"testing" "testing"
"time" "time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "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/api/validation"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/securitycontext" "github.com/GoogleCloudPlatform/kubernetes/pkg/securitycontext"
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
) )
func TestExtractFromNonExistentFile(t *testing.T) { func TestExtractFromNonExistentFile(t *testing.T) {
...@@ -339,111 +335,3 @@ func TestExtractFromEmptyDir(t *testing.T) { ...@@ -339,111 +335,3 @@ func TestExtractFromEmptyDir(t *testing.T) {
t.Errorf("Expected %#v, Got %#v", expected, update) 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)
}
}
}
...@@ -77,50 +77,12 @@ func (s *sourceURL) extractFromURL() error { ...@@ -77,50 +77,12 @@ func (s *sourceURL) extractFromURL() error {
s.updates <- kubelet.PodUpdate{[]*api.Pod{}, kubelet.SET, kubelet.HTTPSource} s.updates <- kubelet.PodUpdate{[]*api.Pod{}, kubelet.SET, kubelet.HTTPSource}
return fmt.Errorf("zero-length data received from %v", s.url) 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 { if bytes.Compare(data, s.data) == 0 {
return nil return nil
} }
s.data = data 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. // First try as it is a single pod.
parsed, pod, singlePodErr := tryDecodeSinglePod(data, s.applyDefaults) parsed, pod, singlePodErr := tryDecodeSinglePod(data, s.applyDefaults)
if parsed { if parsed {
...@@ -147,9 +109,7 @@ func (s *sourceURL) extractFromURL() error { ...@@ -147,9 +109,7 @@ func (s *sourceURL) extractFromURL() error {
return nil return nil
} }
return fmt.Errorf("%v: received '%v', but couldn't parse as neither "+ return fmt.Errorf("%v: received '%v', but couldn't parse as "+
"single (%v: %+v) or multiple manifests (%v: %+v) nor "+
"single (%v) or multiple pods (%v).\n", "single (%v) or multiple pods (%v).\n",
s.url, string(data), singleErr, manifest, multiErr, manifests, s.url, string(data), singlePodErr, multiPodErr)
singlePodErr, multiPodErr)
} }
...@@ -24,7 +24,6 @@ import ( ...@@ -24,7 +24,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "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/api/validation"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
...@@ -118,195 +117,6 @@ func TestExtractInvalidManifest(t *testing.T) { ...@@ -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) { func TestExtractPodsFromHTTP(t *testing.T) {
hostname := "different-value" hostname := "different-value"
......
...@@ -33,8 +33,6 @@ import ( ...@@ -33,8 +33,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1" "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/api/v1beta3"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator" "github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator"
...@@ -91,10 +89,6 @@ type Config struct { ...@@ -91,10 +89,6 @@ type Config struct {
EnableUISupport bool EnableUISupport bool
// allow downstream consumers to disable swagger // allow downstream consumers to disable swagger
EnableSwaggerSupport bool EnableSwaggerSupport bool
// allow v1beta1 to be conditionally disabled
DisableV1Beta1 bool
// allow v1beta2 to be conditionally disabled
DisableV1Beta2 bool
// allow v1beta3 to be conditionally disabled // allow v1beta3 to be conditionally disabled
DisableV1Beta3 bool DisableV1Beta3 bool
// allow v1 to be conditionally enabled // allow v1 to be conditionally enabled
...@@ -170,8 +164,6 @@ type Master struct { ...@@ -170,8 +164,6 @@ type Master struct {
authorizer authorizer.Authorizer authorizer authorizer.Authorizer
admissionControl admission.Interface admissionControl admission.Interface
masterCount int masterCount int
v1beta1 bool
v1beta2 bool
v1beta3 bool v1beta3 bool
v1 bool v1 bool
requestContextMapper api.RequestContextMapper requestContextMapper api.RequestContextMapper
...@@ -328,8 +320,6 @@ func New(c *Config) *Master { ...@@ -328,8 +320,6 @@ func New(c *Config) *Master {
authenticator: c.Authenticator, authenticator: c.Authenticator,
authorizer: c.Authorizer, authorizer: c.Authorizer,
admissionControl: c.AdmissionControl, admissionControl: c.AdmissionControl,
v1beta1: !c.DisableV1Beta1,
v1beta2: !c.DisableV1Beta2,
v1beta3: !c.DisableV1Beta3, v1beta3: !c.DisableV1Beta3,
v1: c.EnableV1, v1: c.EnableV1,
requestContextMapper: c.RequestContextMapper, requestContextMapper: c.RequestContextMapper,
...@@ -501,18 +491,6 @@ func (m *Master) init(c *Config) { ...@@ -501,18 +491,6 @@ func (m *Master) init(c *Config) {
} }
apiVersions := []string{} 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 m.v1beta3 {
if err := m.api_v1beta3().InstallREST(m.handlerContainer); err != nil { if err := m.api_v1beta3().InstallREST(m.handlerContainer); err != nil {
glog.Fatalf("Unable to setup API v1beta3: %v", err) glog.Fatalf("Unable to setup API v1beta3: %v", err)
...@@ -718,38 +696,6 @@ func (m *Master) defaultAPIGroupVersion() *apiserver.APIGroupVersion { ...@@ -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. // api_v1beta3 returns the resources and codec for API version v1beta3.
func (m *Master) api_v1beta3() *apiserver.APIGroupVersion { func (m *Master) api_v1beta3() *apiserver.APIGroupVersion {
storage := make(map[string]rest.Storage) storage := make(map[string]rest.Storage)
......
...@@ -24,8 +24,6 @@ import ( ...@@ -24,8 +24,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/endpoints" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/endpoints"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "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"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache" "github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
"github.com/GoogleCloudPlatform/kubernetes/pkg/controller/framework" "github.com/GoogleCloudPlatform/kubernetes/pkg/controller/framework"
...@@ -302,12 +300,6 @@ func (e *EndpointController) syncService(key string) { ...@@ -302,12 +300,6 @@ func (e *EndpointController) syncService(key string) {
for i := range service.Spec.Ports { for i := range service.Spec.Ports {
servicePort := &service.Spec.Ports[i] 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 portName := servicePort.Name
portProto := servicePort.Protocol portProto := servicePort.Protocol
portNum, err := findPort(pod, servicePort) portNum, err := findPort(pod, servicePort)
...@@ -398,32 +390,14 @@ func (e *EndpointController) checkLeftoverEndpoints() { ...@@ -398,32 +390,14 @@ func (e *EndpointController) checkLeftoverEndpoints() {
} }
} }
func findDefaultPort(pod *api.Pod, servicePort int, proto api.Protocol) int { // findPort locates the container port for the given pod and portName. If the
for _, container := range pod.Spec.Containers { // targetPort is a number, use that. If the targetPort is a string, look that
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
// string up in all named ports in all containers in the target pod. If no // string up in all named ports in all containers in the target pod. If no
// match is found, fail. // match is found, fail.
func findPort(pod *api.Pod, svcPort *api.ServicePort) (int, error) { func findPort(pod *api.Pod, svcPort *api.ServicePort) (int, error) {
portName := svcPort.TargetPort portName := svcPort.TargetPort
switch portName.Kind { switch portName.Kind {
case util.IntstrString: case util.IntstrString:
if len(portName.StrVal) == 0 {
return findDefaultPort(pod, svcPort.Port, svcPort.Protocol), nil
}
name := portName.StrVal name := portName.StrVal
for _, container := range pod.Spec.Containers { for _, container := range pod.Spec.Containers {
for _, port := range container.Ports { for _, port := range container.Ports {
...@@ -433,9 +407,6 @@ func findPort(pod *api.Pod, svcPort *api.ServicePort) (int, error) { ...@@ -433,9 +407,6 @@ func findPort(pod *api.Pod, svcPort *api.ServicePort) (int, error) {
} }
} }
case util.IntstrInt: case util.IntstrInt:
if portName.IntVal == 0 {
return findDefaultPort(pod, svcPort.Port, svcPort.Protocol), nil
}
return portName.IntVal, nil return portName.IntVal, nil
} }
......
...@@ -63,7 +63,6 @@ func addPods(store cache.Store, namespace string, nPods int, nPorts int) { ...@@ -63,7 +63,6 @@ func addPods(store cache.Store, namespace string, nPods int, nPorts int) {
} }
func TestFindPort(t *testing.T) { func TestFindPort(t *testing.T) {
servicePort := 999
testCases := []struct { testCases := []struct {
name string name string
containers []api.Container containers []api.Container
...@@ -91,74 +90,6 @@ func TestFindPort(t *testing.T) { ...@@ -91,74 +90,6 @@ func TestFindPort(t *testing.T) {
expected: 93, expected: 93,
pass: true, 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", name: "valid str, no ports",
containers: []api.Container{{}}, containers: []api.Container{{}},
port: util.NewIntOrStringFromString("p"), port: util.NewIntOrStringFromString("p"),
...@@ -204,7 +135,7 @@ func TestFindPort(t *testing.T) { ...@@ -204,7 +135,7 @@ func TestFindPort(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
port, err := findPort(&api.Pod{Spec: api.PodSpec{Containers: tc.containers}}, 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 { if err != nil && tc.pass {
t.Errorf("unexpected error for %s: %v", tc.name, err) t.Errorf("unexpected error for %s: %v", tc.name, err)
} }
......
...@@ -8,7 +8,7 @@ matrix: ...@@ -8,7 +8,7 @@ matrix:
include: include:
- go: 1.4 - go: 1.4
env: env:
- KUBE_TEST_API_VERSIONS=v1beta1 KUBE_TEST_ETCD_PREFIXES=registry - KUBE_TEST_API_VERSIONS=v1beta3 KUBE_TEST_ETCD_PREFIXES=registry
- go: 1.3 - go: 1.3
env: env:
- KUBE_TEST_API_VERSIONS=v1beta3 KUBE_TEST_ETCD_PREFIXES=kubernetes.io/registry - KUBE_TEST_API_VERSIONS=v1beta3 KUBE_TEST_ETCD_PREFIXES=kubernetes.io/registry
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment