mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-26 21:17:23 +00:00
Delete deprecated API versions
pkg/service: There were a couple of references here just as a reminder to change the behavior of findPort. As of v1beta3, TargetPort was always defaulted, so we could remove findDefaultPort and related tests. pkg/apiserver: The tests were using versioned API codecs for some of their encoding tests. Necessary API types had to be written and registered with the fake versioned codecs. pkg/kubectl: Some tests were converted to current versions where it made sense.
This commit is contained in:
parent
f3b4b1aa31
commit
f4e2c738f6
@ -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 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"models": {}
|
||||||
}
|
}
|
@ -1,14 +1,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 @@
|
|||||||
"title": "",
|
"title": "",
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -23,5 +23,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"models": {}
|
||||||
}
|
}
|
@ -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:
|
|||||||
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 (
|
|||||||
|
|
||||||
"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 (
|
|||||||
|
|
||||||
"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) {
|
|||||||
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() {
|
|||||||
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 (
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
)
|
)
|
||||||
|
|
||||||
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`
|
|
||||||
)
|
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"id": "nginx-controller",
|
|
||||||
"apiVersion": "v1beta1",
|
|
||||||
"kind": "ReplicationController",
|
|
||||||
"desiredState": {
|
|
||||||
"replicas": 2,
|
|
||||||
"replicaSelector": {"name": "nginx"},
|
|
||||||
"podTemplate": {
|
|
||||||
"desiredState": {
|
|
||||||
"manifest": {
|
|
||||||
"version": "v1beta1",
|
|
||||||
"id": "nginx-controller",
|
|
||||||
"containers": [{
|
|
||||||
"name": "nginx",
|
|
||||||
"image": "nginx",
|
|
||||||
"ports": [{"containerPort": 80}]
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"labels": {"name": "nginx"}
|
|
||||||
}},
|
|
||||||
"labels": {"name": "nginx"}
|
|
||||||
}
|
|
@ -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 {
|
|||||||
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 (
|
|||||||
"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
|
|||||||
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
|
|||||||
|
|
||||||
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
|
|||||||
# 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
|
|||||||
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}")/..
|
|||||||
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 (
|
|||||||
|
|
||||||
"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 (
|
|||||||
"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
|
|||||||
|
|
||||||
// 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() {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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() {
|
|||||||
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() {
|
|||||||
// 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 (
|
|||||||
"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
|
|||||||
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 (
|
|||||||
"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) {
|
|||||||
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) {
|
|||||||
|
|
||||||
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) {
|
|||||||
|
|
||||||
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)
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,811 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 The Kubernetes Authors All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package v1beta1_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
|
||||||
versioned "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
var Convert = api.Scheme.Convert
|
|
||||||
|
|
||||||
func TestEmptyObjectConversion(t *testing.T) {
|
|
||||||
s, err := versioned.Codec.Encode(&versioned.LimitRange{})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
// DeletionTimestamp is not included, while CreationTimestamp is (would always be set)
|
|
||||||
if string(s) != `{"kind":"LimitRange","creationTimestamp":null,"apiVersion":"v1beta1","spec":{"limits":null}}` {
|
|
||||||
t.Errorf("unexpected empty object: %s", string(s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNodeConversion(t *testing.T) {
|
|
||||||
version, kind, err := api.Scheme.ObjectVersionAndKind(&versioned.Minion{})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if version != "v1beta1" || kind != "Minion" {
|
|
||||||
t.Errorf("unexpected version and kind: %s %s", version, kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
api.Scheme.Log(t)
|
|
||||||
obj, err := versioned.Codec.Decode([]byte(`{"kind":"Node","apiVersion":"v1beta1"}`))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if _, ok := obj.(*api.Node); !ok {
|
|
||||||
t.Errorf("unexpected type: %#v", obj)
|
|
||||||
}
|
|
||||||
|
|
||||||
obj, err = versioned.Codec.Decode([]byte(`{"kind":"NodeList","apiVersion":"v1beta1"}`))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if _, ok := obj.(*api.NodeList); !ok {
|
|
||||||
t.Errorf("unexpected type: %#v", obj)
|
|
||||||
}
|
|
||||||
|
|
||||||
obj = &api.Node{}
|
|
||||||
if err := versioned.Codec.DecodeInto([]byte(`{"kind":"Node","apiVersion":"v1beta1"}`), obj); err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
obj = &api.Node{}
|
|
||||||
data, err := versioned.Codec.Encode(obj)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
m := map[string]interface{}{}
|
|
||||||
if err := json.Unmarshal(data, &m); err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if m["kind"] != "Minion" {
|
|
||||||
t.Errorf("unexpected encoding: %s - %#v", m["kind"], string(data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEnvConversion(t *testing.T) {
|
|
||||||
nonCanonical := []versioned.EnvVar{
|
|
||||||
{Key: "EV"},
|
|
||||||
{Key: "EV", Name: "EX"},
|
|
||||||
}
|
|
||||||
canonical := []api.EnvVar{
|
|
||||||
{Name: "EV"},
|
|
||||||
{Name: "EX"},
|
|
||||||
}
|
|
||||||
for i := range nonCanonical {
|
|
||||||
var got api.EnvVar
|
|
||||||
err := Convert(&nonCanonical[i], &got)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if e, a := canonical[i], got; !reflect.DeepEqual(e, a) {
|
|
||||||
t.Errorf("expected %v, got %v", e, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test conversion the other way, too.
|
|
||||||
for i := range canonical {
|
|
||||||
var got versioned.EnvVar
|
|
||||||
err := Convert(&canonical[i], &got)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if e, a := canonical[i].Name, got.Key; e != a {
|
|
||||||
t.Errorf("expected %v, got %v", e, a)
|
|
||||||
}
|
|
||||||
if e, a := canonical[i].Name, got.Name; e != a {
|
|
||||||
t.Errorf("expected %v, got %v", e, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVolumeMountConversionToOld(t *testing.T) {
|
|
||||||
table := []struct {
|
|
||||||
in api.VolumeMount
|
|
||||||
out versioned.VolumeMount
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
in: api.VolumeMount{Name: "foo", MountPath: "/dev/foo", ReadOnly: true},
|
|
||||||
out: versioned.VolumeMount{Name: "foo", MountPath: "/dev/foo", Path: "/dev/foo", ReadOnly: true},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, item := range table {
|
|
||||||
got := versioned.VolumeMount{}
|
|
||||||
err := Convert(&item.in, &got)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if e, a := item.out, got; !reflect.DeepEqual(e, a) {
|
|
||||||
t.Errorf("Expected: %#v, got %#v", e, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVolumeMountConversionToNew(t *testing.T) {
|
|
||||||
table := []struct {
|
|
||||||
in versioned.VolumeMount
|
|
||||||
out api.VolumeMount
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
in: versioned.VolumeMount{Name: "foo", MountPath: "/dev/foo", ReadOnly: true},
|
|
||||||
out: api.VolumeMount{Name: "foo", MountPath: "/dev/foo", ReadOnly: true},
|
|
||||||
}, {
|
|
||||||
in: versioned.VolumeMount{Name: "foo", MountPath: "/dev/foo", Path: "/dev/bar", ReadOnly: true},
|
|
||||||
out: api.VolumeMount{Name: "foo", MountPath: "/dev/foo", ReadOnly: true},
|
|
||||||
}, {
|
|
||||||
in: versioned.VolumeMount{Name: "foo", Path: "/dev/bar", ReadOnly: true},
|
|
||||||
out: api.VolumeMount{Name: "foo", MountPath: "/dev/bar", ReadOnly: true},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, item := range table {
|
|
||||||
got := api.VolumeMount{}
|
|
||||||
err := Convert(&item.in, &got)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if e, a := item.out, got; !reflect.DeepEqual(e, a) {
|
|
||||||
t.Errorf("Expected: %#v, got %#v", e, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMinionListConversionToNew(t *testing.T) {
|
|
||||||
oldMinion := func(id string) versioned.Minion {
|
|
||||||
return versioned.Minion{
|
|
||||||
TypeMeta: versioned.TypeMeta{ID: id},
|
|
||||||
ExternalID: id}
|
|
||||||
}
|
|
||||||
newNode := func(id string) api.Node {
|
|
||||||
return api.Node{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: id},
|
|
||||||
Spec: api.NodeSpec{ExternalID: id},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
oldMinions := []versioned.Minion{
|
|
||||||
oldMinion("foo"),
|
|
||||||
oldMinion("bar"),
|
|
||||||
}
|
|
||||||
newMinions := []api.Node{
|
|
||||||
newNode("foo"),
|
|
||||||
newNode("bar"),
|
|
||||||
}
|
|
||||||
|
|
||||||
table := []struct {
|
|
||||||
oldML *versioned.MinionList
|
|
||||||
newML *api.NodeList
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
oldML: &versioned.MinionList{Items: oldMinions},
|
|
||||||
newML: &api.NodeList{Items: newMinions},
|
|
||||||
}, {
|
|
||||||
oldML: &versioned.MinionList{Minions: oldMinions},
|
|
||||||
newML: &api.NodeList{Items: newMinions},
|
|
||||||
}, {
|
|
||||||
oldML: &versioned.MinionList{
|
|
||||||
Items: oldMinions,
|
|
||||||
Minions: []versioned.Minion{oldMinion("baz")},
|
|
||||||
},
|
|
||||||
newML: &api.NodeList{Items: newMinions},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, item := range table {
|
|
||||||
got := &api.NodeList{}
|
|
||||||
err := Convert(item.oldML, got)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if e, a := item.newML, got; !api.Semantic.DeepEqual(e, a) {
|
|
||||||
t.Errorf("Expected: %#v, got %#v", e, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMinionListConversionToOld(t *testing.T) {
|
|
||||||
oldMinion := func(id string) versioned.Minion {
|
|
||||||
return versioned.Minion{TypeMeta: versioned.TypeMeta{ID: id}}
|
|
||||||
}
|
|
||||||
newNode := func(id string) api.Node {
|
|
||||||
return api.Node{ObjectMeta: api.ObjectMeta{Name: id}}
|
|
||||||
}
|
|
||||||
oldMinions := []versioned.Minion{
|
|
||||||
oldMinion("foo"),
|
|
||||||
oldMinion("bar"),
|
|
||||||
}
|
|
||||||
newMinions := []api.Node{
|
|
||||||
newNode("foo"),
|
|
||||||
newNode("bar"),
|
|
||||||
}
|
|
||||||
|
|
||||||
newML := &api.NodeList{Items: newMinions}
|
|
||||||
oldML := &versioned.MinionList{
|
|
||||||
Items: oldMinions,
|
|
||||||
Minions: oldMinions,
|
|
||||||
}
|
|
||||||
|
|
||||||
got := &versioned.MinionList{}
|
|
||||||
err := Convert(newML, got)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if e, a := oldML, got; !api.Semantic.DeepEqual(e, a) {
|
|
||||||
t.Errorf("Expected: %#v, got %#v", e, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServiceEmptySelector(t *testing.T) {
|
|
||||||
// Nil map should be preserved
|
|
||||||
svc := &versioned.Service{Selector: nil}
|
|
||||||
data, err := api.Scheme.EncodeToVersion(svc, "v1beta1")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
obj, err := api.Scheme.Decode(data)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
selector := obj.(*api.Service).Spec.Selector
|
|
||||||
if selector != nil {
|
|
||||||
t.Errorf("unexpected selector: %#v", obj)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Empty map should be preserved
|
|
||||||
svc2 := &versioned.Service{Selector: map[string]string{}}
|
|
||||||
data, err = api.Scheme.EncodeToVersion(svc2, "v1beta1")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
obj, err = api.Scheme.Decode(data)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
selector = obj.(*api.Service).Spec.Selector
|
|
||||||
if selector == nil || len(selector) != 0 {
|
|
||||||
t.Errorf("unexpected selector: %#v", obj)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServicePorts(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
given versioned.Service
|
|
||||||
expected api.Service
|
|
||||||
roundtrip versioned.Service
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
given: versioned.Service{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "legacy-with-defaults",
|
|
||||||
},
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
},
|
|
||||||
expected: api.Service{
|
|
||||||
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
|
|
||||||
Port: 111,
|
|
||||||
Protocol: api.ProtocolTCP,
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
roundtrip: versioned.Service{
|
|
||||||
Ports: []versioned.ServicePort{{
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
given: versioned.Service{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "legacy-full",
|
|
||||||
},
|
|
||||||
PortName: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromString("p"),
|
|
||||||
},
|
|
||||||
expected: api.Service{
|
|
||||||
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
|
|
||||||
Name: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: api.ProtocolTCP,
|
|
||||||
TargetPort: util.NewIntOrStringFromString("p"),
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
roundtrip: versioned.Service{
|
|
||||||
Ports: []versioned.ServicePort{{
|
|
||||||
Name: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromString("p"),
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
given: versioned.Service{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "both",
|
|
||||||
},
|
|
||||||
PortName: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromString("p"),
|
|
||||||
Ports: []versioned.ServicePort{{
|
|
||||||
Name: "q",
|
|
||||||
Port: 222,
|
|
||||||
Protocol: versioned.ProtocolUDP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
expected: api.Service{
|
|
||||||
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
|
|
||||||
Name: "q",
|
|
||||||
Port: 222,
|
|
||||||
Protocol: api.ProtocolUDP,
|
|
||||||
TargetPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
roundtrip: versioned.Service{
|
|
||||||
Ports: []versioned.ServicePort{{
|
|
||||||
Name: "q",
|
|
||||||
Port: 222,
|
|
||||||
Protocol: versioned.ProtocolUDP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
given: versioned.Service{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "one",
|
|
||||||
},
|
|
||||||
Ports: []versioned.ServicePort{{
|
|
||||||
Name: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolUDP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
expected: api.Service{
|
|
||||||
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
|
|
||||||
Name: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: api.ProtocolUDP,
|
|
||||||
TargetPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
roundtrip: versioned.Service{
|
|
||||||
Ports: []versioned.ServicePort{{
|
|
||||||
Name: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolUDP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
given: versioned.Service{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "two",
|
|
||||||
},
|
|
||||||
Ports: []versioned.ServicePort{{
|
|
||||||
Name: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolUDP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}, {
|
|
||||||
Name: "q",
|
|
||||||
Port: 222,
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromInt(76),
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
expected: api.Service{
|
|
||||||
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
|
|
||||||
Name: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: api.ProtocolUDP,
|
|
||||||
TargetPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}, {
|
|
||||||
Name: "q",
|
|
||||||
Port: 222,
|
|
||||||
Protocol: api.ProtocolTCP,
|
|
||||||
TargetPort: util.NewIntOrStringFromInt(76),
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
roundtrip: versioned.Service{
|
|
||||||
Ports: []versioned.ServicePort{{
|
|
||||||
Name: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolUDP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}, {
|
|
||||||
Name: "q",
|
|
||||||
Port: 222,
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromInt(76),
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range testCases {
|
|
||||||
// Convert versioned -> internal.
|
|
||||||
got := api.Service{}
|
|
||||||
if err := Convert(&tc.given, &got); err != nil {
|
|
||||||
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(got.Spec.Ports, tc.expected.Spec.Ports) {
|
|
||||||
t.Errorf("[Case: %d] Expected %v, got %v", i, tc.expected.Spec.Ports, got.Spec.Ports)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert internal -> versioned.
|
|
||||||
got2 := versioned.Service{}
|
|
||||||
if err := Convert(&got, &got2); err != nil {
|
|
||||||
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(got2.Ports, tc.roundtrip.Ports) {
|
|
||||||
t.Errorf("[Case: %d] Expected %v, got %v", i, tc.roundtrip.Ports, got2.Ports)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPullPolicyConversion(t *testing.T) {
|
|
||||||
table := []struct {
|
|
||||||
versioned versioned.PullPolicy
|
|
||||||
internal api.PullPolicy
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
versioned: versioned.PullAlways,
|
|
||||||
internal: api.PullAlways,
|
|
||||||
}, {
|
|
||||||
versioned: versioned.PullNever,
|
|
||||||
internal: api.PullNever,
|
|
||||||
}, {
|
|
||||||
versioned: versioned.PullIfNotPresent,
|
|
||||||
internal: api.PullIfNotPresent,
|
|
||||||
}, {
|
|
||||||
versioned: "",
|
|
||||||
internal: "",
|
|
||||||
}, {
|
|
||||||
versioned: "invalid value",
|
|
||||||
internal: "invalid value",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, item := range table {
|
|
||||||
var got api.PullPolicy
|
|
||||||
err := Convert(&item.versioned, &got)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if e, a := item.internal, got; e != a {
|
|
||||||
t.Errorf("Expected: %q, got %q", e, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, item := range table {
|
|
||||||
var got versioned.PullPolicy
|
|
||||||
err := Convert(&item.internal, &got)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if e, a := item.versioned, got; e != a {
|
|
||||||
t.Errorf("Expected: %q, got %q", e, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getResourceRequirements(cpu, memory resource.Quantity) versioned.ResourceRequirements {
|
|
||||||
res := versioned.ResourceRequirements{}
|
|
||||||
res.Limits = versioned.ResourceList{}
|
|
||||||
if cpu.Value() > 0 {
|
|
||||||
res.Limits[versioned.ResourceCPU] = util.NewIntOrStringFromInt(int(cpu.Value()))
|
|
||||||
}
|
|
||||||
if memory.Value() > 0 {
|
|
||||||
res.Limits[versioned.ResourceMemory] = util.NewIntOrStringFromInt(int(memory.Value()))
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestContainerConversion(t *testing.T) {
|
|
||||||
cpuLimit := resource.MustParse("10")
|
|
||||||
memoryLimit := resource.MustParse("10M")
|
|
||||||
null := resource.Quantity{}
|
|
||||||
testCases := []versioned.Container{
|
|
||||||
{
|
|
||||||
Name: "container",
|
|
||||||
Resources: getResourceRequirements(cpuLimit, memoryLimit),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "container",
|
|
||||||
CPU: int(cpuLimit.MilliValue()),
|
|
||||||
Resources: getResourceRequirements(null, memoryLimit),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "container",
|
|
||||||
Memory: memoryLimit.Value(),
|
|
||||||
Resources: getResourceRequirements(cpuLimit, null),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "container",
|
|
||||||
CPU: int(cpuLimit.MilliValue()),
|
|
||||||
Memory: memoryLimit.Value(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "container",
|
|
||||||
Memory: memoryLimit.Value(),
|
|
||||||
Resources: getResourceRequirements(cpuLimit, resource.MustParse("100M")),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "container",
|
|
||||||
CPU: int(cpuLimit.MilliValue()),
|
|
||||||
Resources: getResourceRequirements(resource.MustParse("500"), memoryLimit),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range testCases {
|
|
||||||
got := api.Container{}
|
|
||||||
if err := Convert(&tc, &got); err != nil {
|
|
||||||
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if cpu := got.Resources.Limits.Cpu(); cpu.Value() != cpuLimit.Value() {
|
|
||||||
t.Errorf("[Case: %d] Expected cpu: %v, got: %v", i, cpuLimit, *cpu)
|
|
||||||
}
|
|
||||||
if memory := got.Resources.Limits.Memory(); memory.Value() != memoryLimit.Value() {
|
|
||||||
t.Errorf("[Case: %d] Expected memory: %v, got: %v", i, memoryLimit, *memory)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEndpointsConversion(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
given versioned.Endpoints
|
|
||||||
expected api.Endpoints
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
given: versioned.Endpoints{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "empty",
|
|
||||||
},
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
Endpoints: []string{},
|
|
||||||
},
|
|
||||||
expected: api.Endpoints{
|
|
||||||
Subsets: []api.EndpointSubset{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
given: versioned.Endpoints{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "one legacy",
|
|
||||||
},
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
Endpoints: []string{"1.2.3.4:88"},
|
|
||||||
},
|
|
||||||
expected: api.Endpoints{
|
|
||||||
Subsets: []api.EndpointSubset{{
|
|
||||||
Ports: []api.EndpointPort{{Name: "", Port: 88, Protocol: api.ProtocolTCP}},
|
|
||||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
given: versioned.Endpoints{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "several legacy",
|
|
||||||
},
|
|
||||||
Protocol: versioned.ProtocolUDP,
|
|
||||||
Endpoints: []string{"1.2.3.4:88", "1.2.3.4:89", "1.2.3.4:90"},
|
|
||||||
},
|
|
||||||
expected: api.Endpoints{
|
|
||||||
Subsets: []api.EndpointSubset{
|
|
||||||
{
|
|
||||||
Ports: []api.EndpointPort{{Name: "", Port: 88, Protocol: api.ProtocolUDP}},
|
|
||||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Ports: []api.EndpointPort{{Name: "", Port: 89, Protocol: api.ProtocolUDP}},
|
|
||||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Ports: []api.EndpointPort{{Name: "", Port: 90, Protocol: api.ProtocolUDP}},
|
|
||||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
given: versioned.Endpoints{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "one subset",
|
|
||||||
},
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
Endpoints: []string{"1.2.3.4:88"},
|
|
||||||
Subsets: []versioned.EndpointSubset{{
|
|
||||||
Ports: []versioned.EndpointPort{{Name: "", Port: 88, Protocol: versioned.ProtocolTCP}},
|
|
||||||
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4"}},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
expected: api.Endpoints{
|
|
||||||
Subsets: []api.EndpointSubset{{
|
|
||||||
Ports: []api.EndpointPort{{Name: "", Port: 88, Protocol: api.ProtocolTCP}},
|
|
||||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
given: versioned.Endpoints{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "several subset",
|
|
||||||
},
|
|
||||||
Protocol: versioned.ProtocolUDP,
|
|
||||||
Endpoints: []string{"1.2.3.4:88", "5.6.7.8:88", "1.2.3.4:89", "5.6.7.8:89"},
|
|
||||||
Subsets: []versioned.EndpointSubset{
|
|
||||||
{
|
|
||||||
Ports: []versioned.EndpointPort{{Name: "", Port: 88, Protocol: versioned.ProtocolUDP}},
|
|
||||||
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Ports: []versioned.EndpointPort{{Name: "", Port: 89, Protocol: versioned.ProtocolUDP}},
|
|
||||||
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Ports: []versioned.EndpointPort{{Name: "named", Port: 90, Protocol: versioned.ProtocolUDP}},
|
|
||||||
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expected: api.Endpoints{
|
|
||||||
Subsets: []api.EndpointSubset{
|
|
||||||
{
|
|
||||||
Ports: []api.EndpointPort{{Name: "", Port: 88, Protocol: api.ProtocolUDP}},
|
|
||||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Ports: []api.EndpointPort{{Name: "", Port: 89, Protocol: api.ProtocolUDP}},
|
|
||||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Ports: []api.EndpointPort{{Name: "named", Port: 90, Protocol: api.ProtocolUDP}},
|
|
||||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range testCases {
|
|
||||||
// Convert versioned -> internal.
|
|
||||||
got := api.Endpoints{}
|
|
||||||
if err := Convert(&tc.given, &got); err != nil {
|
|
||||||
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !api.Semantic.DeepEqual(got.Subsets, tc.expected.Subsets) {
|
|
||||||
t.Errorf("[Case: %d] Expected %#v, got %#v", i, tc.expected.Subsets, got.Subsets)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert internal -> versioned.
|
|
||||||
got2 := versioned.Endpoints{}
|
|
||||||
if err := Convert(&got, &got2); err != nil {
|
|
||||||
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if got2.Protocol != tc.given.Protocol || !api.Semantic.DeepEqual(got2.Endpoints, tc.given.Endpoints) {
|
|
||||||
t.Errorf("[Case: %d] Expected %s %#v, got %s %#v", i, tc.given.Protocol, tc.given.Endpoints, got2.Protocol, got2.Endpoints)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSecretVolumeSourceConversion(t *testing.T) {
|
|
||||||
given := versioned.SecretVolumeSource{
|
|
||||||
Target: versioned.ObjectReference{
|
|
||||||
ID: "foo",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := api.SecretVolumeSource{
|
|
||||||
SecretName: "foo",
|
|
||||||
}
|
|
||||||
|
|
||||||
got := api.SecretVolumeSource{}
|
|
||||||
if err := Convert(&given, &got); err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if got.SecretName != expected.SecretName {
|
|
||||||
t.Errorf("Expected %v; got %v", expected, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
got2 := versioned.SecretVolumeSource{}
|
|
||||||
if err := Convert(&got, &got2); err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if got2.Target.ID != given.Target.ID {
|
|
||||||
t.Errorf("Expected %v; got %v", given, got2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBadSecurityContextConversion(t *testing.T) {
|
|
||||||
priv := false
|
|
||||||
testCases := map[string]struct {
|
|
||||||
c *versioned.Container
|
|
||||||
err string
|
|
||||||
}{
|
|
||||||
// this use case must use true for the container and false for the sc. Otherwise the defaulter
|
|
||||||
// will assume privileged was left undefined (since it is the default value) and copy the
|
|
||||||
// sc setting upwards
|
|
||||||
"mismatched privileged": {
|
|
||||||
c: &versioned.Container{
|
|
||||||
Privileged: true,
|
|
||||||
SecurityContext: &versioned.SecurityContext{
|
|
||||||
Privileged: &priv,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
err: "container privileged settings do not match security context settings, cannot convert",
|
|
||||||
},
|
|
||||||
"mismatched caps add": {
|
|
||||||
c: &versioned.Container{
|
|
||||||
Capabilities: versioned.Capabilities{
|
|
||||||
Add: []versioned.Capability{"foo"},
|
|
||||||
},
|
|
||||||
SecurityContext: &versioned.SecurityContext{
|
|
||||||
Capabilities: &versioned.Capabilities{
|
|
||||||
Add: []versioned.Capability{"bar"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
err: "container capability settings do not match security context settings, cannot convert",
|
|
||||||
},
|
|
||||||
"mismatched caps drop": {
|
|
||||||
c: &versioned.Container{
|
|
||||||
Capabilities: versioned.Capabilities{
|
|
||||||
Drop: []versioned.Capability{"foo"},
|
|
||||||
},
|
|
||||||
SecurityContext: &versioned.SecurityContext{
|
|
||||||
Capabilities: &versioned.Capabilities{
|
|
||||||
Drop: []versioned.Capability{"bar"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
err: "container capability settings do not match security context settings, cannot convert",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range testCases {
|
|
||||||
got := api.Container{}
|
|
||||||
err := Convert(v.c, &got)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("expected error for case %s but got none", k)
|
|
||||||
} else {
|
|
||||||
if err.Error() != v.err {
|
|
||||||
t.Errorf("unexpected error for case %s. Expected: %s but got: %s", k, v.err, err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,242 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 The Kubernetes Authors All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package v1beta1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
|
||||||
"github.com/golang/glog"
|
|
||||||
)
|
|
||||||
|
|
||||||
func addDefaultingFuncs() {
|
|
||||||
api.Scheme.AddDefaultingFuncs(
|
|
||||||
func(obj *ReplicationController) {
|
|
||||||
if len(obj.DesiredState.ReplicaSelector) == 0 {
|
|
||||||
obj.DesiredState.ReplicaSelector = obj.DesiredState.PodTemplate.Labels
|
|
||||||
}
|
|
||||||
if len(obj.Labels) == 0 {
|
|
||||||
obj.Labels = obj.DesiredState.PodTemplate.Labels
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *Volume) {
|
|
||||||
if util.AllPtrFieldsNil(&obj.Source) {
|
|
||||||
obj.Source = VolumeSource{
|
|
||||||
EmptyDir: &EmptyDirVolumeSource{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *ContainerPort) {
|
|
||||||
if obj.Protocol == "" {
|
|
||||||
obj.Protocol = ProtocolTCP
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *Container) {
|
|
||||||
if obj.ImagePullPolicy == "" {
|
|
||||||
// TODO(dchen1107): Move ParseImageName code to pkg/util
|
|
||||||
parts := strings.Split(obj.Image, ":")
|
|
||||||
// Check image tag
|
|
||||||
if parts[len(parts)-1] == "latest" {
|
|
||||||
obj.ImagePullPolicy = PullAlways
|
|
||||||
} else {
|
|
||||||
obj.ImagePullPolicy = PullIfNotPresent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if obj.TerminationMessagePath == "" {
|
|
||||||
obj.TerminationMessagePath = TerminationMessagePathDefault
|
|
||||||
}
|
|
||||||
defaultSecurityContext(obj)
|
|
||||||
},
|
|
||||||
func(obj *RestartPolicy) {
|
|
||||||
if util.AllPtrFieldsNil(obj) {
|
|
||||||
obj.Always = &RestartPolicyAlways{}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *Service) {
|
|
||||||
if obj.Protocol == "" {
|
|
||||||
obj.Protocol = ProtocolTCP
|
|
||||||
}
|
|
||||||
if obj.SessionAffinity == "" {
|
|
||||||
obj.SessionAffinity = ServiceAffinityNone
|
|
||||||
}
|
|
||||||
if obj.Type == "" {
|
|
||||||
if obj.CreateExternalLoadBalancer {
|
|
||||||
obj.Type = ServiceTypeLoadBalancer
|
|
||||||
} else {
|
|
||||||
obj.Type = ServiceTypeClusterIP
|
|
||||||
}
|
|
||||||
} else if obj.Type == ServiceTypeLoadBalancer {
|
|
||||||
obj.CreateExternalLoadBalancer = true
|
|
||||||
}
|
|
||||||
for i := range obj.Ports {
|
|
||||||
sp := &obj.Ports[i]
|
|
||||||
if sp.Protocol == "" {
|
|
||||||
sp.Protocol = ProtocolTCP
|
|
||||||
}
|
|
||||||
if sp.ContainerPort == util.NewIntOrStringFromInt(0) || sp.ContainerPort == util.NewIntOrStringFromString("") {
|
|
||||||
sp.ContainerPort = util.NewIntOrStringFromInt(sp.Port)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *PodSpec) {
|
|
||||||
if obj.DNSPolicy == "" {
|
|
||||||
obj.DNSPolicy = DNSClusterFirst
|
|
||||||
}
|
|
||||||
if obj.HostNetwork {
|
|
||||||
defaultHostNetworkPorts(&obj.Containers)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *ContainerManifest) {
|
|
||||||
if obj.DNSPolicy == "" {
|
|
||||||
obj.DNSPolicy = DNSClusterFirst
|
|
||||||
}
|
|
||||||
if obj.HostNetwork {
|
|
||||||
defaultHostNetworkPorts(&obj.Containers)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *LivenessProbe) {
|
|
||||||
if obj.TimeoutSeconds == 0 {
|
|
||||||
obj.TimeoutSeconds = 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *Secret) {
|
|
||||||
if obj.Type == "" {
|
|
||||||
obj.Type = SecretTypeOpaque
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *PersistentVolume) {
|
|
||||||
if obj.Status.Phase == "" {
|
|
||||||
obj.Status.Phase = VolumePending
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *PersistentVolumeClaim) {
|
|
||||||
if obj.Status.Phase == "" {
|
|
||||||
obj.Status.Phase = ClaimPending
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *Endpoints) {
|
|
||||||
if obj.Protocol == "" {
|
|
||||||
obj.Protocol = ProtocolTCP
|
|
||||||
}
|
|
||||||
if len(obj.Subsets) == 0 && len(obj.Endpoints) > 0 {
|
|
||||||
// Must be a legacy-style object - populate
|
|
||||||
// Subsets from the older fields. Do this the
|
|
||||||
// simplest way, which is dumb (but valid).
|
|
||||||
for i := range obj.Endpoints {
|
|
||||||
host, portStr, err := net.SplitHostPort(obj.Endpoints[i])
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("failed to SplitHostPort(%q)", obj.Endpoints[i])
|
|
||||||
}
|
|
||||||
var tgtRef *ObjectReference
|
|
||||||
for j := range obj.TargetRefs {
|
|
||||||
if obj.TargetRefs[j].Endpoint == obj.Endpoints[i] {
|
|
||||||
tgtRef = &ObjectReference{}
|
|
||||||
*tgtRef = obj.TargetRefs[j].ObjectReference
|
|
||||||
}
|
|
||||||
}
|
|
||||||
port, err := strconv.Atoi(portStr)
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("failed to Atoi(%q)", portStr)
|
|
||||||
}
|
|
||||||
obj.Subsets = append(obj.Subsets, EndpointSubset{
|
|
||||||
Addresses: []EndpointAddress{{IP: host, TargetRef: tgtRef}},
|
|
||||||
Ports: []EndpointPort{{Protocol: obj.Protocol, Port: port}},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i := range obj.Subsets {
|
|
||||||
ss := &obj.Subsets[i]
|
|
||||||
for i := range ss.Ports {
|
|
||||||
ep := &ss.Ports[i]
|
|
||||||
if ep.Protocol == "" {
|
|
||||||
ep.Protocol = ProtocolTCP
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *HTTPGetAction) {
|
|
||||||
if obj.Path == "" {
|
|
||||||
obj.Path = "/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *NamespaceStatus) {
|
|
||||||
if obj.Phase == "" {
|
|
||||||
obj.Phase = NamespaceActive
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *Minion) {
|
|
||||||
if obj.ExternalID == "" {
|
|
||||||
obj.ExternalID = obj.ID
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *ObjectFieldSelector) {
|
|
||||||
if obj.APIVersion == "" {
|
|
||||||
obj.APIVersion = "v1beta1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// With host networking default all host ports to container ports.
|
|
||||||
func defaultHostNetworkPorts(containers *[]Container) {
|
|
||||||
for i := range *containers {
|
|
||||||
for j := range (*containers)[i].Ports {
|
|
||||||
if (*containers)[i].Ports[j].HostPort == 0 {
|
|
||||||
(*containers)[i].Ports[j].HostPort = (*containers)[i].Ports[j].ContainerPort
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// defaultSecurityContext performs the downward and upward merges of a pod definition
|
|
||||||
func defaultSecurityContext(container *Container) {
|
|
||||||
if container.SecurityContext == nil {
|
|
||||||
glog.V(5).Infof("creating security context for container %s", container.Name)
|
|
||||||
container.SecurityContext = &SecurityContext{}
|
|
||||||
}
|
|
||||||
// if there are no capabilities defined on the SecurityContext then copy the container settings
|
|
||||||
if container.SecurityContext.Capabilities == nil {
|
|
||||||
container.SecurityContext.Capabilities = &container.Capabilities
|
|
||||||
} else {
|
|
||||||
// if there are capabilities defined on the security context and the container setting is
|
|
||||||
// empty then assume that it was left off the pod definition and ensure that the container
|
|
||||||
// settings match the security context settings (checked by the convert functions). If
|
|
||||||
// there are settings in both then don't touch it, the converter will error if they don't
|
|
||||||
// match
|
|
||||||
if len(container.Capabilities.Add) == 0 {
|
|
||||||
container.Capabilities.Add = container.SecurityContext.Capabilities.Add
|
|
||||||
}
|
|
||||||
if len(container.Capabilities.Drop) == 0 {
|
|
||||||
container.Capabilities.Drop = container.SecurityContext.Capabilities.Drop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if there are no privileged settings on the security context then copy the container settings
|
|
||||||
if container.SecurityContext.Privileged == nil {
|
|
||||||
container.SecurityContext.Privileged = &container.Privileged
|
|
||||||
} else {
|
|
||||||
// we don't have a good way to know if container.Privileged was set or just defaulted to false
|
|
||||||
// so the best we can do here is check if the securityContext is set to true and the
|
|
||||||
// container is set to false and assume that the Privileged field was left off the container
|
|
||||||
// definition and not an intentional mismatch
|
|
||||||
if *container.SecurityContext.Privileged && !container.Privileged {
|
|
||||||
container.Privileged = *container.SecurityContext.Privileged
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,461 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package v1beta1_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
versioned "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
|
|
||||||
data, err := versioned.Codec.Encode(obj)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%v\n %#v", err, obj)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
obj2, err := api.Codec.Decode(data)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), obj)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
obj3 := reflect.New(reflect.TypeOf(obj).Elem()).Interface().(runtime.Object)
|
|
||||||
err = api.Scheme.Convert(obj2, obj3)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%v\nSource: %#v", err, obj2)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return obj3
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultReplicationController(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
rc *versioned.ReplicationController
|
|
||||||
expectLabels bool
|
|
||||||
expectSelector bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
rc: &versioned.ReplicationController{
|
|
||||||
DesiredState: versioned.ReplicationControllerState{
|
|
||||||
PodTemplate: versioned.PodTemplate{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"foo": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectLabels: true,
|
|
||||||
expectSelector: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rc: &versioned.ReplicationController{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"bar": "foo",
|
|
||||||
},
|
|
||||||
DesiredState: versioned.ReplicationControllerState{
|
|
||||||
PodTemplate: versioned.PodTemplate{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"foo": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectLabels: false,
|
|
||||||
expectSelector: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rc: &versioned.ReplicationController{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"bar": "foo",
|
|
||||||
},
|
|
||||||
DesiredState: versioned.ReplicationControllerState{
|
|
||||||
ReplicaSelector: map[string]string{
|
|
||||||
"some": "other",
|
|
||||||
},
|
|
||||||
PodTemplate: versioned.PodTemplate{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"foo": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectLabels: false,
|
|
||||||
expectSelector: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rc: &versioned.ReplicationController{
|
|
||||||
DesiredState: versioned.ReplicationControllerState{
|
|
||||||
ReplicaSelector: map[string]string{
|
|
||||||
"some": "other",
|
|
||||||
},
|
|
||||||
PodTemplate: versioned.PodTemplate{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"foo": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectLabels: true,
|
|
||||||
expectSelector: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
rc := test.rc
|
|
||||||
obj2 := roundTrip(t, runtime.Object(rc))
|
|
||||||
rc2, ok := obj2.(*versioned.ReplicationController)
|
|
||||||
if !ok {
|
|
||||||
t.Errorf("unexpected object: %v", rc2)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
if test.expectSelector != reflect.DeepEqual(rc2.DesiredState.ReplicaSelector, rc2.DesiredState.PodTemplate.Labels) {
|
|
||||||
if test.expectSelector {
|
|
||||||
t.Errorf("expected: %v, got: %v", rc2.DesiredState.PodTemplate.Labels, rc2.DesiredState.ReplicaSelector)
|
|
||||||
} else {
|
|
||||||
t.Errorf("unexpected equality: %v", rc2.DesiredState.PodTemplate.Labels)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if test.expectLabels != reflect.DeepEqual(rc2.Labels, rc2.DesiredState.PodTemplate.Labels) {
|
|
||||||
if test.expectLabels {
|
|
||||||
t.Errorf("expected: %v, got: %v", rc2.DesiredState.PodTemplate.Labels, rc2.Labels)
|
|
||||||
} else {
|
|
||||||
t.Errorf("unexpected equality: %v", rc2.DesiredState.PodTemplate.Labels)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultService(t *testing.T) {
|
|
||||||
svc := &versioned.Service{}
|
|
||||||
obj2 := roundTrip(t, runtime.Object(svc))
|
|
||||||
svc2 := obj2.(*versioned.Service)
|
|
||||||
if svc2.Protocol != versioned.ProtocolTCP {
|
|
||||||
t.Errorf("Expected default protocol :%s, got: %s", versioned.ProtocolTCP, svc2.Protocol)
|
|
||||||
}
|
|
||||||
if svc2.SessionAffinity != versioned.ServiceAffinityNone {
|
|
||||||
t.Errorf("Expected default session affinity type:%s, got: %s", versioned.ServiceAffinityNone, svc2.SessionAffinity)
|
|
||||||
}
|
|
||||||
if svc2.Type != versioned.ServiceTypeClusterIP {
|
|
||||||
t.Errorf("Expected default type:%s, got: %s", versioned.ServiceTypeClusterIP, svc2.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultServiceWithLoadbalancer(t *testing.T) {
|
|
||||||
svc := &versioned.Service{}
|
|
||||||
svc.CreateExternalLoadBalancer = true
|
|
||||||
obj2 := roundTrip(t, runtime.Object(svc))
|
|
||||||
svc2 := obj2.(*versioned.Service)
|
|
||||||
if svc2.Type != versioned.ServiceTypeLoadBalancer {
|
|
||||||
t.Errorf("Expected default type:%s, got: %s", versioned.ServiceTypeLoadBalancer, svc2.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultSecret(t *testing.T) {
|
|
||||||
s := &versioned.Secret{}
|
|
||||||
obj2 := roundTrip(t, runtime.Object(s))
|
|
||||||
s2 := obj2.(*versioned.Secret)
|
|
||||||
|
|
||||||
if s2.Type != versioned.SecretTypeOpaque {
|
|
||||||
t.Errorf("Expected secret type %v, got %v", versioned.SecretTypeOpaque, s2.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultPersistentVolume(t *testing.T) {
|
|
||||||
pv := &versioned.PersistentVolume{}
|
|
||||||
obj2 := roundTrip(t, runtime.Object(pv))
|
|
||||||
pv2 := obj2.(*versioned.PersistentVolume)
|
|
||||||
|
|
||||||
if pv2.Status.Phase != versioned.VolumePending {
|
|
||||||
t.Errorf("Expected volume phase %v, got %v", versioned.VolumePending, pv2.Status.Phase)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultPersistentVolumeClaim(t *testing.T) {
|
|
||||||
pvc := &versioned.PersistentVolumeClaim{}
|
|
||||||
obj2 := roundTrip(t, runtime.Object(pvc))
|
|
||||||
pvc2 := obj2.(*versioned.PersistentVolumeClaim)
|
|
||||||
|
|
||||||
if pvc2.Status.Phase != versioned.ClaimPending {
|
|
||||||
t.Errorf("Expected claim phase %v, got %v", versioned.ClaimPending, pvc2.Status.Phase)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that we use "legacy" fields if "modern" fields are not provided.
|
|
||||||
func TestSetDefaulEndpointsLegacy(t *testing.T) {
|
|
||||||
in := &versioned.Endpoints{
|
|
||||||
Protocol: "UDP",
|
|
||||||
Endpoints: []string{"1.2.3.4:93", "5.6.7.8:76"},
|
|
||||||
TargetRefs: []versioned.EndpointObjectReference{{Endpoint: "1.2.3.4:93", ObjectReference: versioned.ObjectReference{ID: "foo"}}},
|
|
||||||
}
|
|
||||||
obj := roundTrip(t, runtime.Object(in))
|
|
||||||
out := obj.(*versioned.Endpoints)
|
|
||||||
|
|
||||||
if len(out.Subsets) != 2 {
|
|
||||||
t.Errorf("Expected 2 EndpointSubsets, got %d (%#v)", len(out.Subsets), out.Subsets)
|
|
||||||
}
|
|
||||||
expected := []versioned.EndpointSubset{
|
|
||||||
{
|
|
||||||
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4", TargetRef: &versioned.ObjectReference{ID: "foo"}}},
|
|
||||||
Ports: []versioned.EndpointPort{{Protocol: versioned.ProtocolUDP, Port: 93}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Addresses: []versioned.EndpointAddress{{IP: "5.6.7.8"}},
|
|
||||||
Ports: []versioned.EndpointPort{{Protocol: versioned.ProtocolUDP, Port: 76}},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(out.Subsets, expected) {
|
|
||||||
t.Errorf("Expected %#v, got %#v", expected, out.Subsets)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaulEndpointsProtocol(t *testing.T) {
|
|
||||||
in := &versioned.Endpoints{Subsets: []versioned.EndpointSubset{
|
|
||||||
{Ports: []versioned.EndpointPort{{}, {Protocol: "UDP"}, {}}},
|
|
||||||
}}
|
|
||||||
obj := roundTrip(t, runtime.Object(in))
|
|
||||||
out := obj.(*versioned.Endpoints)
|
|
||||||
|
|
||||||
if out.Protocol != versioned.ProtocolTCP {
|
|
||||||
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Protocol)
|
|
||||||
}
|
|
||||||
for i := range out.Subsets {
|
|
||||||
for j := range out.Subsets[i].Ports {
|
|
||||||
if in.Subsets[i].Ports[j].Protocol == "" {
|
|
||||||
if out.Subsets[i].Ports[j].Protocol != versioned.ProtocolTCP {
|
|
||||||
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Subsets[i].Ports[j].Protocol)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if out.Subsets[i].Ports[j].Protocol != in.Subsets[i].Ports[j].Protocol {
|
|
||||||
t.Errorf("Expected protocol %s, got %s", in.Subsets[i].Ports[j].Protocol, out.Subsets[i].Ports[j].Protocol)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultNamespace(t *testing.T) {
|
|
||||||
s := &versioned.Namespace{}
|
|
||||||
obj2 := roundTrip(t, runtime.Object(s))
|
|
||||||
s2 := obj2.(*versioned.Namespace)
|
|
||||||
|
|
||||||
if s2.Status.Phase != versioned.NamespaceActive {
|
|
||||||
t.Errorf("Expected phase %v, got %v", versioned.NamespaceActive, s2.Status.Phase)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultContainerManifestHostNetwork(t *testing.T) {
|
|
||||||
portNum := 8080
|
|
||||||
s := versioned.ContainerManifest{}
|
|
||||||
s.HostNetwork = true
|
|
||||||
s.Containers = []versioned.Container{
|
|
||||||
{
|
|
||||||
Ports: []versioned.ContainerPort{
|
|
||||||
{
|
|
||||||
ContainerPort: portNum,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
obj2 := roundTrip(t, runtime.Object(&versioned.ContainerManifestList{
|
|
||||||
Items: []versioned.ContainerManifest{s},
|
|
||||||
}))
|
|
||||||
sList2 := obj2.(*versioned.ContainerManifestList)
|
|
||||||
s2 := sList2.Items[0]
|
|
||||||
|
|
||||||
hostPortNum := s2.Containers[0].Ports[0].HostPort
|
|
||||||
if hostPortNum != portNum {
|
|
||||||
t.Errorf("Expected container port to be defaulted, was made %d instead of %d", hostPortNum, portNum)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultServicePort(t *testing.T) {
|
|
||||||
// Unchanged if set.
|
|
||||||
in := &versioned.Service{Ports: []versioned.ServicePort{{Protocol: "UDP", Port: 9376, ContainerPort: util.NewIntOrStringFromInt(118)}}}
|
|
||||||
out := roundTrip(t, runtime.Object(in)).(*versioned.Service)
|
|
||||||
if out.Ports[0].Protocol != versioned.ProtocolUDP {
|
|
||||||
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolUDP, out.Ports[0].Protocol)
|
|
||||||
}
|
|
||||||
if out.Ports[0].ContainerPort != in.Ports[0].ContainerPort {
|
|
||||||
t.Errorf("Expected port %d, got %d", in.Ports[0].ContainerPort, out.Ports[0].ContainerPort)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defaulted.
|
|
||||||
in = &versioned.Service{Ports: []versioned.ServicePort{{Protocol: "", Port: 9376, ContainerPort: util.NewIntOrStringFromInt(0)}}}
|
|
||||||
out = roundTrip(t, runtime.Object(in)).(*versioned.Service)
|
|
||||||
if out.Ports[0].Protocol != versioned.ProtocolTCP {
|
|
||||||
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Ports[0].Protocol)
|
|
||||||
}
|
|
||||||
if out.Ports[0].ContainerPort != util.NewIntOrStringFromInt(in.Ports[0].Port) {
|
|
||||||
t.Errorf("Expected port %d, got %v", in.Ports[0].Port, out.Ports[0].ContainerPort)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defaulted.
|
|
||||||
in = &versioned.Service{Ports: []versioned.ServicePort{{Protocol: "", Port: 9376, ContainerPort: util.NewIntOrStringFromString("")}}}
|
|
||||||
out = roundTrip(t, runtime.Object(in)).(*versioned.Service)
|
|
||||||
if out.Ports[0].Protocol != versioned.ProtocolTCP {
|
|
||||||
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Ports[0].Protocol)
|
|
||||||
}
|
|
||||||
if out.Ports[0].ContainerPort != util.NewIntOrStringFromInt(in.Ports[0].Port) {
|
|
||||||
t.Errorf("Expected port %d, got %v", in.Ports[0].Port, out.Ports[0].ContainerPort)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultMinionExternalID(t *testing.T) {
|
|
||||||
name := "node0"
|
|
||||||
m := &versioned.Minion{}
|
|
||||||
m.ID = name
|
|
||||||
obj2 := roundTrip(t, runtime.Object(m))
|
|
||||||
m2 := obj2.(*versioned.Minion)
|
|
||||||
if m2.ExternalID != name {
|
|
||||||
t.Errorf("Expected default External ID: %s, got: %s", name, m2.ExternalID)
|
|
||||||
}
|
|
||||||
if m2.ProviderID != "" {
|
|
||||||
t.Errorf("Expected empty default Cloud Provider ID, got: %s", m2.ProviderID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultObjectFieldSelectorAPIVersion(t *testing.T) {
|
|
||||||
s := versioned.ContainerManifest{
|
|
||||||
Containers: []versioned.Container{
|
|
||||||
{
|
|
||||||
Env: []versioned.EnvVar{
|
|
||||||
{
|
|
||||||
ValueFrom: &versioned.EnvVarSource{
|
|
||||||
FieldRef: &versioned.ObjectFieldSelector{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
obj2 := roundTrip(t, runtime.Object(&versioned.ContainerManifestList{
|
|
||||||
Items: []versioned.ContainerManifest{s},
|
|
||||||
}))
|
|
||||||
sList2 := obj2.(*versioned.ContainerManifestList)
|
|
||||||
s2 := sList2.Items[0]
|
|
||||||
|
|
||||||
apiVersion := s2.Containers[0].Env[0].ValueFrom.FieldRef.APIVersion
|
|
||||||
if apiVersion != "v1beta1" {
|
|
||||||
t.Errorf("Expected default APIVersion v1beta1, got: %v", apiVersion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultSecurityContext(t *testing.T) {
|
|
||||||
priv := false
|
|
||||||
privTrue := true
|
|
||||||
testCases := map[string]struct {
|
|
||||||
c versioned.Container
|
|
||||||
}{
|
|
||||||
"downward defaulting caps": {
|
|
||||||
c: versioned.Container{
|
|
||||||
Privileged: false,
|
|
||||||
Capabilities: versioned.Capabilities{
|
|
||||||
Add: []versioned.Capability{"foo"},
|
|
||||||
Drop: []versioned.Capability{"bar"},
|
|
||||||
},
|
|
||||||
SecurityContext: &versioned.SecurityContext{
|
|
||||||
Privileged: &priv,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"downward defaulting priv": {
|
|
||||||
c: versioned.Container{
|
|
||||||
Privileged: false,
|
|
||||||
Capabilities: versioned.Capabilities{
|
|
||||||
Add: []versioned.Capability{"foo"},
|
|
||||||
Drop: []versioned.Capability{"bar"},
|
|
||||||
},
|
|
||||||
SecurityContext: &versioned.SecurityContext{
|
|
||||||
Capabilities: &versioned.Capabilities{
|
|
||||||
Add: []versioned.Capability{"foo"},
|
|
||||||
Drop: []versioned.Capability{"bar"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"upward defaulting caps": {
|
|
||||||
c: versioned.Container{
|
|
||||||
Privileged: false,
|
|
||||||
SecurityContext: &versioned.SecurityContext{
|
|
||||||
Privileged: &priv,
|
|
||||||
Capabilities: &versioned.Capabilities{
|
|
||||||
Add: []versioned.Capability{"biz"},
|
|
||||||
Drop: []versioned.Capability{"baz"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"upward defaulting priv": {
|
|
||||||
c: versioned.Container{
|
|
||||||
Capabilities: versioned.Capabilities{
|
|
||||||
Add: []versioned.Capability{"foo"},
|
|
||||||
Drop: []versioned.Capability{"bar"},
|
|
||||||
},
|
|
||||||
SecurityContext: &versioned.SecurityContext{
|
|
||||||
Privileged: &privTrue,
|
|
||||||
Capabilities: &versioned.Capabilities{
|
|
||||||
Add: []versioned.Capability{"foo"},
|
|
||||||
Drop: []versioned.Capability{"bar"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
pod := &versioned.Pod{
|
|
||||||
DesiredState: versioned.PodState{
|
|
||||||
Manifest: versioned.ContainerManifest{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range testCases {
|
|
||||||
pod.DesiredState.Manifest.Containers = []versioned.Container{v.c}
|
|
||||||
obj := roundTrip(t, runtime.Object(pod))
|
|
||||||
defaultedPod := obj.(*versioned.Pod)
|
|
||||||
c := defaultedPod.DesiredState.Manifest.Containers[0]
|
|
||||||
if isEqual, issues := areSecurityContextAndContainerEqual(&c); !isEqual {
|
|
||||||
t.Errorf("test case %s expected the security context to have the same values as the container but found %#v", k, issues)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func areSecurityContextAndContainerEqual(c *versioned.Container) (bool, []string) {
|
|
||||||
issues := make([]string, 0)
|
|
||||||
equal := true
|
|
||||||
|
|
||||||
if c.SecurityContext == nil || c.SecurityContext.Privileged == nil || c.SecurityContext.Capabilities == nil {
|
|
||||||
equal = false
|
|
||||||
issues = append(issues, "Expected non nil settings for SecurityContext")
|
|
||||||
return equal, issues
|
|
||||||
}
|
|
||||||
if *c.SecurityContext.Privileged != c.Privileged {
|
|
||||||
equal = false
|
|
||||||
issues = append(issues, "The defaulted SecurityContext.Privileged value did not match the container value")
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(c.Capabilities.Add, c.Capabilities.Add) {
|
|
||||||
equal = false
|
|
||||||
issues = append(issues, "The defaulted SecurityContext.Capabilities.Add did not match the container settings")
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(c.Capabilities.Drop, c.Capabilities.Drop) {
|
|
||||||
equal = false
|
|
||||||
issues = append(issues, "The defaulted SecurityContext.Capabilities.Drop did not match the container settings")
|
|
||||||
}
|
|
||||||
return equal, issues
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 The Kubernetes Authors All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Package v1beta1 is the v1beta1 version of the API.
|
|
||||||
package v1beta1
|
|
@ -1,138 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 The Kubernetes Authors All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package v1beta1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/registered"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Codec encodes internal objects to the v1beta1 scheme
|
|
||||||
var Codec = runtime.CodecFor(api.Scheme, "v1beta1")
|
|
||||||
|
|
||||||
// Dependency does nothing but give a hook for other packages to force a
|
|
||||||
// compile-time error when this API version is eventually removed. This is
|
|
||||||
// useful, for example, to clean up things that are implicitly tied to
|
|
||||||
// semantics of older APIs.
|
|
||||||
const Dependency = true
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Check if v1beta1 is in the list of supported API versions.
|
|
||||||
if !registered.IsRegisteredAPIVersion("v1beta1") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the API.
|
|
||||||
addKnownTypes()
|
|
||||||
addConversionFuncs()
|
|
||||||
addDefaultingFuncs()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adds the list of known types to api.Scheme.
|
|
||||||
func addKnownTypes() {
|
|
||||||
api.Scheme.AddKnownTypes("v1beta1",
|
|
||||||
&Pod{},
|
|
||||||
&PodStatusResult{},
|
|
||||||
&PodList{},
|
|
||||||
&ReplicationController{},
|
|
||||||
&ReplicationControllerList{},
|
|
||||||
&Service{},
|
|
||||||
&ServiceList{},
|
|
||||||
&Endpoints{},
|
|
||||||
&EndpointsList{},
|
|
||||||
&Minion{},
|
|
||||||
&MinionList{},
|
|
||||||
&NodeInfo{},
|
|
||||||
&Binding{},
|
|
||||||
&Status{},
|
|
||||||
&Event{},
|
|
||||||
&EventList{},
|
|
||||||
&ContainerManifest{},
|
|
||||||
&ContainerManifestList{},
|
|
||||||
&List{},
|
|
||||||
&LimitRange{},
|
|
||||||
&LimitRangeList{},
|
|
||||||
&ResourceQuota{},
|
|
||||||
&ResourceQuotaList{},
|
|
||||||
&Namespace{},
|
|
||||||
&NamespaceList{},
|
|
||||||
&Secret{},
|
|
||||||
&SecretList{},
|
|
||||||
&ServiceAccount{},
|
|
||||||
&ServiceAccountList{},
|
|
||||||
&PersistentVolume{},
|
|
||||||
&PersistentVolumeList{},
|
|
||||||
&PersistentVolumeClaim{},
|
|
||||||
&PersistentVolumeClaimList{},
|
|
||||||
&DeleteOptions{},
|
|
||||||
&ListOptions{},
|
|
||||||
&PodLogOptions{},
|
|
||||||
&PodExecOptions{},
|
|
||||||
&PodProxyOptions{},
|
|
||||||
&ComponentStatus{},
|
|
||||||
&ComponentStatusList{},
|
|
||||||
&SerializedReference{},
|
|
||||||
&RangeAllocation{},
|
|
||||||
)
|
|
||||||
// Future names are supported
|
|
||||||
api.Scheme.AddKnownTypeWithName("v1beta1", "Node", &Minion{})
|
|
||||||
api.Scheme.AddKnownTypeWithName("v1beta1", "NodeList", &MinionList{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Pod) IsAnAPIObject() {}
|
|
||||||
func (*PodStatusResult) IsAnAPIObject() {}
|
|
||||||
func (*PodList) IsAnAPIObject() {}
|
|
||||||
func (*ReplicationController) IsAnAPIObject() {}
|
|
||||||
func (*ReplicationControllerList) IsAnAPIObject() {}
|
|
||||||
func (*Service) IsAnAPIObject() {}
|
|
||||||
func (*ServiceList) IsAnAPIObject() {}
|
|
||||||
func (*Endpoints) IsAnAPIObject() {}
|
|
||||||
func (*EndpointsList) IsAnAPIObject() {}
|
|
||||||
func (*Minion) IsAnAPIObject() {}
|
|
||||||
func (*NodeInfo) IsAnAPIObject() {}
|
|
||||||
func (*MinionList) IsAnAPIObject() {}
|
|
||||||
func (*Binding) IsAnAPIObject() {}
|
|
||||||
func (*Status) IsAnAPIObject() {}
|
|
||||||
func (*Event) IsAnAPIObject() {}
|
|
||||||
func (*EventList) IsAnAPIObject() {}
|
|
||||||
func (*ContainerManifest) IsAnAPIObject() {}
|
|
||||||
func (*ContainerManifestList) IsAnAPIObject() {}
|
|
||||||
func (*List) IsAnAPIObject() {}
|
|
||||||
func (*LimitRange) IsAnAPIObject() {}
|
|
||||||
func (*LimitRangeList) IsAnAPIObject() {}
|
|
||||||
func (*ResourceQuota) IsAnAPIObject() {}
|
|
||||||
func (*ResourceQuotaList) IsAnAPIObject() {}
|
|
||||||
func (*Namespace) IsAnAPIObject() {}
|
|
||||||
func (*NamespaceList) IsAnAPIObject() {}
|
|
||||||
func (*Secret) IsAnAPIObject() {}
|
|
||||||
func (*SecretList) IsAnAPIObject() {}
|
|
||||||
func (*ServiceAccount) IsAnAPIObject() {}
|
|
||||||
func (*ServiceAccountList) IsAnAPIObject() {}
|
|
||||||
func (*PersistentVolume) IsAnAPIObject() {}
|
|
||||||
func (*PersistentVolumeList) IsAnAPIObject() {}
|
|
||||||
func (*PersistentVolumeClaim) IsAnAPIObject() {}
|
|
||||||
func (*PersistentVolumeClaimList) IsAnAPIObject() {}
|
|
||||||
func (*DeleteOptions) IsAnAPIObject() {}
|
|
||||||
func (*ListOptions) IsAnAPIObject() {}
|
|
||||||
func (*PodLogOptions) IsAnAPIObject() {}
|
|
||||||
func (*PodExecOptions) IsAnAPIObject() {}
|
|
||||||
func (*PodProxyOptions) IsAnAPIObject() {}
|
|
||||||
func (*ComponentStatus) IsAnAPIObject() {}
|
|
||||||
func (*ComponentStatusList) IsAnAPIObject() {}
|
|
||||||
func (*SerializedReference) IsAnAPIObject() {}
|
|
||||||
func (*RangeAllocation) IsAnAPIObject() {}
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,626 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 The Kubernetes Authors All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package v1beta2_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
|
||||||
versioned "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestServiceEmptySelector(t *testing.T) {
|
|
||||||
// Nil map should be preserved
|
|
||||||
svc := &versioned.Service{Selector: nil}
|
|
||||||
data, err := api.Scheme.EncodeToVersion(svc, "v1beta2")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
obj, err := api.Scheme.Decode(data)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
selector := obj.(*api.Service).Spec.Selector
|
|
||||||
if selector != nil {
|
|
||||||
t.Errorf("unexpected selector: %#v", obj)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Empty map should be preserved
|
|
||||||
svc2 := &versioned.Service{Selector: map[string]string{}}
|
|
||||||
data, err = api.Scheme.EncodeToVersion(svc2, "v1beta2")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
obj, err = api.Scheme.Decode(data)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
selector = obj.(*api.Service).Spec.Selector
|
|
||||||
if selector == nil || len(selector) != 0 {
|
|
||||||
t.Errorf("unexpected selector: %#v", obj)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServicePorts(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
given versioned.Service
|
|
||||||
expected api.Service
|
|
||||||
roundtrip versioned.Service
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
given: versioned.Service{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "legacy-with-defaults",
|
|
||||||
},
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
},
|
|
||||||
expected: api.Service{
|
|
||||||
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
|
|
||||||
Port: 111,
|
|
||||||
Protocol: api.ProtocolTCP,
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
roundtrip: versioned.Service{
|
|
||||||
Ports: []versioned.ServicePort{{
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
given: versioned.Service{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "legacy-full",
|
|
||||||
},
|
|
||||||
PortName: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromString("p"),
|
|
||||||
},
|
|
||||||
expected: api.Service{
|
|
||||||
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
|
|
||||||
Name: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: api.ProtocolTCP,
|
|
||||||
TargetPort: util.NewIntOrStringFromString("p"),
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
roundtrip: versioned.Service{
|
|
||||||
Ports: []versioned.ServicePort{{
|
|
||||||
Name: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromString("p"),
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
given: versioned.Service{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "both",
|
|
||||||
},
|
|
||||||
PortName: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromString("p"),
|
|
||||||
Ports: []versioned.ServicePort{{
|
|
||||||
Name: "q",
|
|
||||||
Port: 222,
|
|
||||||
Protocol: versioned.ProtocolUDP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
expected: api.Service{
|
|
||||||
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
|
|
||||||
Name: "q",
|
|
||||||
Port: 222,
|
|
||||||
Protocol: api.ProtocolUDP,
|
|
||||||
TargetPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
roundtrip: versioned.Service{
|
|
||||||
Ports: []versioned.ServicePort{{
|
|
||||||
Name: "q",
|
|
||||||
Port: 222,
|
|
||||||
Protocol: versioned.ProtocolUDP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
given: versioned.Service{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "one",
|
|
||||||
},
|
|
||||||
Ports: []versioned.ServicePort{{
|
|
||||||
Name: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolUDP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
expected: api.Service{
|
|
||||||
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
|
|
||||||
Name: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: api.ProtocolUDP,
|
|
||||||
TargetPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
roundtrip: versioned.Service{
|
|
||||||
Ports: []versioned.ServicePort{{
|
|
||||||
Name: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolUDP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
given: versioned.Service{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "two",
|
|
||||||
},
|
|
||||||
Ports: []versioned.ServicePort{{
|
|
||||||
Name: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolUDP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}, {
|
|
||||||
Name: "q",
|
|
||||||
Port: 222,
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromInt(76),
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
expected: api.Service{
|
|
||||||
Spec: api.ServiceSpec{Ports: []api.ServicePort{{
|
|
||||||
Name: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: api.ProtocolUDP,
|
|
||||||
TargetPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}, {
|
|
||||||
Name: "q",
|
|
||||||
Port: 222,
|
|
||||||
Protocol: api.ProtocolTCP,
|
|
||||||
TargetPort: util.NewIntOrStringFromInt(76),
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
roundtrip: versioned.Service{
|
|
||||||
Ports: []versioned.ServicePort{{
|
|
||||||
Name: "p",
|
|
||||||
Port: 111,
|
|
||||||
Protocol: versioned.ProtocolUDP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromInt(93),
|
|
||||||
}, {
|
|
||||||
Name: "q",
|
|
||||||
Port: 222,
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
ContainerPort: util.NewIntOrStringFromInt(76),
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range testCases {
|
|
||||||
// Convert versioned -> internal.
|
|
||||||
got := api.Service{}
|
|
||||||
if err := api.Scheme.Convert(&tc.given, &got); err != nil {
|
|
||||||
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(got.Spec.Ports, tc.expected.Spec.Ports) {
|
|
||||||
t.Errorf("[Case: %d] Expected %v, got %v", i, tc.expected.Spec.Ports, got.Spec.Ports)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert internal -> versioned.
|
|
||||||
got2 := versioned.Service{}
|
|
||||||
if err := api.Scheme.Convert(&got, &got2); err != nil {
|
|
||||||
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(got2.Ports, tc.roundtrip.Ports) {
|
|
||||||
t.Errorf("[Case: %d] Expected %v, got %v", i, tc.roundtrip.Ports, got2.Ports)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNodeConversion(t *testing.T) {
|
|
||||||
version, kind, err := api.Scheme.ObjectVersionAndKind(&versioned.Minion{})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if version != "v1beta2" || kind != "Minion" {
|
|
||||||
t.Errorf("unexpected version and kind: %s %s", version, kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
api.Scheme.Log(t)
|
|
||||||
obj, err := versioned.Codec.Decode([]byte(`{"kind":"Node","apiVersion":"v1beta2"}`))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if _, ok := obj.(*api.Node); !ok {
|
|
||||||
t.Errorf("unexpected type: %#v", obj)
|
|
||||||
}
|
|
||||||
|
|
||||||
obj, err = versioned.Codec.Decode([]byte(`{"kind":"NodeList","apiVersion":"v1beta2"}`))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if _, ok := obj.(*api.NodeList); !ok {
|
|
||||||
t.Errorf("unexpected type: %#v", obj)
|
|
||||||
}
|
|
||||||
|
|
||||||
obj = &api.Node{}
|
|
||||||
if err := versioned.Codec.DecodeInto([]byte(`{"kind":"Node","apiVersion":"v1beta2"}`), obj); err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
obj = &api.Node{}
|
|
||||||
data, err := versioned.Codec.Encode(obj)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
m := map[string]interface{}{}
|
|
||||||
if err := json.Unmarshal(data, &m); err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if m["kind"] != "Minion" {
|
|
||||||
t.Errorf("unexpected encoding: %s - %#v", m["kind"], string(data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPullPolicyConversion(t *testing.T) {
|
|
||||||
table := []struct {
|
|
||||||
versioned versioned.PullPolicy
|
|
||||||
internal api.PullPolicy
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
versioned: versioned.PullAlways,
|
|
||||||
internal: api.PullAlways,
|
|
||||||
}, {
|
|
||||||
versioned: versioned.PullNever,
|
|
||||||
internal: api.PullNever,
|
|
||||||
}, {
|
|
||||||
versioned: versioned.PullIfNotPresent,
|
|
||||||
internal: api.PullIfNotPresent,
|
|
||||||
}, {
|
|
||||||
versioned: "",
|
|
||||||
internal: "",
|
|
||||||
}, {
|
|
||||||
versioned: "invalid value",
|
|
||||||
internal: "invalid value",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, item := range table {
|
|
||||||
var got api.PullPolicy
|
|
||||||
err := api.Scheme.Convert(&item.versioned, &got)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if e, a := item.internal, got; e != a {
|
|
||||||
t.Errorf("Expected: %q, got %q", e, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, item := range table {
|
|
||||||
var got versioned.PullPolicy
|
|
||||||
err := api.Scheme.Convert(&item.internal, &got)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if e, a := item.versioned, got; e != a {
|
|
||||||
t.Errorf("Expected: %q, got %q", e, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getResourceRequirements(cpu, memory resource.Quantity) versioned.ResourceRequirements {
|
|
||||||
res := versioned.ResourceRequirements{}
|
|
||||||
res.Limits = versioned.ResourceList{}
|
|
||||||
if cpu.Value() > 0 {
|
|
||||||
res.Limits[versioned.ResourceCPU] = util.NewIntOrStringFromInt(int(cpu.Value()))
|
|
||||||
}
|
|
||||||
if memory.Value() > 0 {
|
|
||||||
res.Limits[versioned.ResourceMemory] = util.NewIntOrStringFromInt(int(memory.Value()))
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestContainerConversion(t *testing.T) {
|
|
||||||
cpuLimit := resource.MustParse("10")
|
|
||||||
memoryLimit := resource.MustParse("10M")
|
|
||||||
null := resource.Quantity{}
|
|
||||||
testCases := []versioned.Container{
|
|
||||||
{
|
|
||||||
Name: "container",
|
|
||||||
Resources: getResourceRequirements(cpuLimit, memoryLimit),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "container",
|
|
||||||
CPU: int(cpuLimit.MilliValue()),
|
|
||||||
Resources: getResourceRequirements(null, memoryLimit),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "container",
|
|
||||||
Memory: memoryLimit.Value(),
|
|
||||||
Resources: getResourceRequirements(cpuLimit, null),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "container",
|
|
||||||
CPU: int(cpuLimit.MilliValue()),
|
|
||||||
Memory: memoryLimit.Value(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "container",
|
|
||||||
Memory: memoryLimit.Value(),
|
|
||||||
Resources: getResourceRequirements(cpuLimit, resource.MustParse("100M")),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "container",
|
|
||||||
CPU: int(cpuLimit.MilliValue()),
|
|
||||||
Resources: getResourceRequirements(resource.MustParse("500"), memoryLimit),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range testCases {
|
|
||||||
got := api.Container{}
|
|
||||||
if err := api.Scheme.Convert(&tc, &got); err != nil {
|
|
||||||
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if cpu := got.Resources.Limits.Cpu(); cpu.Value() != cpuLimit.Value() {
|
|
||||||
t.Errorf("[Case: %d] Expected cpu: %v, got: %v", i, cpuLimit, *cpu)
|
|
||||||
}
|
|
||||||
if memory := got.Resources.Limits.Memory(); memory.Value() != memoryLimit.Value() {
|
|
||||||
t.Errorf("[Case: %d] Expected memory: %v, got: %v", i, memoryLimit, *memory)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEndpointsConversion(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
given versioned.Endpoints
|
|
||||||
expected api.Endpoints
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
given: versioned.Endpoints{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "empty",
|
|
||||||
},
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
Endpoints: []string{},
|
|
||||||
},
|
|
||||||
expected: api.Endpoints{
|
|
||||||
Subsets: []api.EndpointSubset{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
given: versioned.Endpoints{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "one legacy",
|
|
||||||
},
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
Endpoints: []string{"1.2.3.4:88"},
|
|
||||||
},
|
|
||||||
expected: api.Endpoints{
|
|
||||||
Subsets: []api.EndpointSubset{{
|
|
||||||
Ports: []api.EndpointPort{{Name: "", Port: 88, Protocol: api.ProtocolTCP}},
|
|
||||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
given: versioned.Endpoints{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "several legacy",
|
|
||||||
},
|
|
||||||
Protocol: versioned.ProtocolUDP,
|
|
||||||
Endpoints: []string{"1.2.3.4:88", "1.2.3.4:89", "1.2.3.4:90"},
|
|
||||||
},
|
|
||||||
expected: api.Endpoints{
|
|
||||||
Subsets: []api.EndpointSubset{
|
|
||||||
{
|
|
||||||
Ports: []api.EndpointPort{{Name: "", Port: 88, Protocol: api.ProtocolUDP}},
|
|
||||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Ports: []api.EndpointPort{{Name: "", Port: 89, Protocol: api.ProtocolUDP}},
|
|
||||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Ports: []api.EndpointPort{{Name: "", Port: 90, Protocol: api.ProtocolUDP}},
|
|
||||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
given: versioned.Endpoints{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "one subset",
|
|
||||||
},
|
|
||||||
Protocol: versioned.ProtocolTCP,
|
|
||||||
Endpoints: []string{"1.2.3.4:88"},
|
|
||||||
Subsets: []versioned.EndpointSubset{{
|
|
||||||
Ports: []versioned.EndpointPort{{Name: "", Port: 88, Protocol: versioned.ProtocolTCP}},
|
|
||||||
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4"}},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
expected: api.Endpoints{
|
|
||||||
Subsets: []api.EndpointSubset{{
|
|
||||||
Ports: []api.EndpointPort{{Name: "", Port: 88, Protocol: api.ProtocolTCP}},
|
|
||||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
given: versioned.Endpoints{
|
|
||||||
TypeMeta: versioned.TypeMeta{
|
|
||||||
ID: "several subset",
|
|
||||||
},
|
|
||||||
Protocol: versioned.ProtocolUDP,
|
|
||||||
Endpoints: []string{"1.2.3.4:88", "5.6.7.8:88", "1.2.3.4:89", "5.6.7.8:89"},
|
|
||||||
Subsets: []versioned.EndpointSubset{
|
|
||||||
{
|
|
||||||
Ports: []versioned.EndpointPort{{Name: "", Port: 88, Protocol: versioned.ProtocolUDP}},
|
|
||||||
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Ports: []versioned.EndpointPort{{Name: "", Port: 89, Protocol: versioned.ProtocolUDP}},
|
|
||||||
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Ports: []versioned.EndpointPort{{Name: "named", Port: 90, Protocol: versioned.ProtocolUDP}},
|
|
||||||
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expected: api.Endpoints{
|
|
||||||
Subsets: []api.EndpointSubset{
|
|
||||||
{
|
|
||||||
Ports: []api.EndpointPort{{Name: "", Port: 88, Protocol: api.ProtocolUDP}},
|
|
||||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Ports: []api.EndpointPort{{Name: "", Port: 89, Protocol: api.ProtocolUDP}},
|
|
||||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Ports: []api.EndpointPort{{Name: "named", Port: 90, Protocol: api.ProtocolUDP}},
|
|
||||||
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range testCases {
|
|
||||||
// Convert versioned -> internal.
|
|
||||||
got := api.Endpoints{}
|
|
||||||
if err := api.Scheme.Convert(&tc.given, &got); err != nil {
|
|
||||||
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !api.Semantic.DeepEqual(got.Subsets, tc.expected.Subsets) {
|
|
||||||
t.Errorf("[Case: %d] Expected %#v, got %#v", i, tc.expected.Subsets, got.Subsets)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert internal -> versioned.
|
|
||||||
got2 := versioned.Endpoints{}
|
|
||||||
if err := api.Scheme.Convert(&got, &got2); err != nil {
|
|
||||||
t.Errorf("[Case: %d] Unexpected error: %v", i, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if got2.Protocol != tc.given.Protocol || !api.Semantic.DeepEqual(got2.Endpoints, tc.given.Endpoints) {
|
|
||||||
t.Errorf("[Case: %d] Expected %#v, got %#v", i, tc.given.Endpoints, got2.Endpoints)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSecretVolumeSourceConversion(t *testing.T) {
|
|
||||||
given := versioned.SecretVolumeSource{
|
|
||||||
Target: versioned.ObjectReference{
|
|
||||||
ID: "foo",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := api.SecretVolumeSource{
|
|
||||||
SecretName: "foo",
|
|
||||||
}
|
|
||||||
|
|
||||||
got := api.SecretVolumeSource{}
|
|
||||||
if err := api.Scheme.Convert(&given, &got); err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if got.SecretName != expected.SecretName {
|
|
||||||
t.Errorf("Expected %v; got %v", expected, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
got2 := versioned.SecretVolumeSource{}
|
|
||||||
if err := api.Scheme.Convert(&got, &got2); err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if got2.Target.ID != given.Target.ID {
|
|
||||||
t.Errorf("Expected %v; got %v", given, got2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBadSecurityContextConversion(t *testing.T) {
|
|
||||||
priv := false
|
|
||||||
testCases := map[string]struct {
|
|
||||||
c *versioned.Container
|
|
||||||
err string
|
|
||||||
}{
|
|
||||||
// this use case must use true for the container and false for the sc. Otherwise the defaulter
|
|
||||||
// will assume privileged was left undefined (since it is the default value) and copy the
|
|
||||||
// sc setting upwards
|
|
||||||
"mismatched privileged": {
|
|
||||||
c: &versioned.Container{
|
|
||||||
Privileged: true,
|
|
||||||
SecurityContext: &versioned.SecurityContext{
|
|
||||||
Privileged: &priv,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
err: "container privileged settings do not match security context settings, cannot convert",
|
|
||||||
},
|
|
||||||
"mismatched caps add": {
|
|
||||||
c: &versioned.Container{
|
|
||||||
Capabilities: versioned.Capabilities{
|
|
||||||
Add: []versioned.Capability{"foo"},
|
|
||||||
},
|
|
||||||
SecurityContext: &versioned.SecurityContext{
|
|
||||||
Capabilities: &versioned.Capabilities{
|
|
||||||
Add: []versioned.Capability{"bar"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
err: "container capability settings do not match security context settings, cannot convert",
|
|
||||||
},
|
|
||||||
"mismatched caps drop": {
|
|
||||||
c: &versioned.Container{
|
|
||||||
Capabilities: versioned.Capabilities{
|
|
||||||
Drop: []versioned.Capability{"foo"},
|
|
||||||
},
|
|
||||||
SecurityContext: &versioned.SecurityContext{
|
|
||||||
Capabilities: &versioned.Capabilities{
|
|
||||||
Drop: []versioned.Capability{"bar"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
err: "container capability settings do not match security context settings, cannot convert",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range testCases {
|
|
||||||
got := api.Container{}
|
|
||||||
err := api.Scheme.Convert(v.c, &got)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("expected error for case %s but got none", k)
|
|
||||||
} else {
|
|
||||||
if err.Error() != v.err {
|
|
||||||
t.Errorf("unexpected error for case %s. Expected: %s but got: %s", k, v.err, err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,243 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 The Kubernetes Authors All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package v1beta2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
|
||||||
"github.com/golang/glog"
|
|
||||||
)
|
|
||||||
|
|
||||||
func addDefaultingFuncs() {
|
|
||||||
api.Scheme.AddDefaultingFuncs(
|
|
||||||
func(obj *ReplicationController) {
|
|
||||||
if len(obj.DesiredState.ReplicaSelector) == 0 {
|
|
||||||
obj.DesiredState.ReplicaSelector = obj.DesiredState.PodTemplate.Labels
|
|
||||||
}
|
|
||||||
if len(obj.Labels) == 0 {
|
|
||||||
obj.Labels = obj.DesiredState.PodTemplate.Labels
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *Volume) {
|
|
||||||
if util.AllPtrFieldsNil(&obj.Source) {
|
|
||||||
glog.Errorf("Defaulting volume source for %v", obj)
|
|
||||||
obj.Source = VolumeSource{
|
|
||||||
EmptyDir: &EmptyDirVolumeSource{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *ContainerPort) {
|
|
||||||
if obj.Protocol == "" {
|
|
||||||
obj.Protocol = ProtocolTCP
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *Container) {
|
|
||||||
if obj.ImagePullPolicy == "" {
|
|
||||||
// TODO(dchen1107): Move ParseImageName code to pkg/util
|
|
||||||
parts := strings.Split(obj.Image, ":")
|
|
||||||
// Check image tag
|
|
||||||
if parts[len(parts)-1] == "latest" {
|
|
||||||
obj.ImagePullPolicy = PullAlways
|
|
||||||
} else {
|
|
||||||
obj.ImagePullPolicy = PullIfNotPresent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if obj.TerminationMessagePath == "" {
|
|
||||||
obj.TerminationMessagePath = TerminationMessagePathDefault
|
|
||||||
}
|
|
||||||
defaultSecurityContext(obj)
|
|
||||||
},
|
|
||||||
func(obj *RestartPolicy) {
|
|
||||||
if util.AllPtrFieldsNil(obj) {
|
|
||||||
obj.Always = &RestartPolicyAlways{}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *Service) {
|
|
||||||
if obj.Protocol == "" {
|
|
||||||
obj.Protocol = ProtocolTCP
|
|
||||||
}
|
|
||||||
if obj.SessionAffinity == "" {
|
|
||||||
obj.SessionAffinity = ServiceAffinityNone
|
|
||||||
}
|
|
||||||
if obj.Type == "" {
|
|
||||||
if obj.CreateExternalLoadBalancer {
|
|
||||||
obj.Type = ServiceTypeLoadBalancer
|
|
||||||
} else {
|
|
||||||
obj.Type = ServiceTypeClusterIP
|
|
||||||
}
|
|
||||||
} else if obj.Type == ServiceTypeLoadBalancer {
|
|
||||||
obj.CreateExternalLoadBalancer = true
|
|
||||||
}
|
|
||||||
for i := range obj.Ports {
|
|
||||||
sp := &obj.Ports[i]
|
|
||||||
if sp.Protocol == "" {
|
|
||||||
sp.Protocol = ProtocolTCP
|
|
||||||
}
|
|
||||||
if sp.ContainerPort == util.NewIntOrStringFromInt(0) || sp.ContainerPort == util.NewIntOrStringFromString("") {
|
|
||||||
sp.ContainerPort = util.NewIntOrStringFromInt(sp.Port)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *PodSpec) {
|
|
||||||
if obj.DNSPolicy == "" {
|
|
||||||
obj.DNSPolicy = DNSClusterFirst
|
|
||||||
}
|
|
||||||
if obj.HostNetwork {
|
|
||||||
defaultHostNetworkPorts(&obj.Containers)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *ContainerManifest) {
|
|
||||||
if obj.DNSPolicy == "" {
|
|
||||||
obj.DNSPolicy = DNSClusterFirst
|
|
||||||
}
|
|
||||||
if obj.HostNetwork {
|
|
||||||
defaultHostNetworkPorts(&obj.Containers)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *LivenessProbe) {
|
|
||||||
if obj.TimeoutSeconds == 0 {
|
|
||||||
obj.TimeoutSeconds = 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *Secret) {
|
|
||||||
if obj.Type == "" {
|
|
||||||
obj.Type = SecretTypeOpaque
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *PersistentVolume) {
|
|
||||||
if obj.Status.Phase == "" {
|
|
||||||
obj.Status.Phase = VolumePending
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *PersistentVolumeClaim) {
|
|
||||||
if obj.Status.Phase == "" {
|
|
||||||
obj.Status.Phase = ClaimPending
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *Endpoints) {
|
|
||||||
if obj.Protocol == "" {
|
|
||||||
obj.Protocol = ProtocolTCP
|
|
||||||
}
|
|
||||||
if len(obj.Subsets) == 0 && len(obj.Endpoints) > 0 {
|
|
||||||
// Must be a legacy-style object - populate
|
|
||||||
// Subsets from the older fields. Do this the
|
|
||||||
// simplest way, which is dumb (but valid).
|
|
||||||
for i := range obj.Endpoints {
|
|
||||||
host, portStr, err := net.SplitHostPort(obj.Endpoints[i])
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("failed to SplitHostPort(%q)", obj.Endpoints[i])
|
|
||||||
}
|
|
||||||
var tgtRef *ObjectReference
|
|
||||||
for j := range obj.TargetRefs {
|
|
||||||
if obj.TargetRefs[j].Endpoint == obj.Endpoints[i] {
|
|
||||||
tgtRef = &ObjectReference{}
|
|
||||||
*tgtRef = obj.TargetRefs[j].ObjectReference
|
|
||||||
}
|
|
||||||
}
|
|
||||||
port, err := strconv.Atoi(portStr)
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("failed to Atoi(%q)", portStr)
|
|
||||||
}
|
|
||||||
obj.Subsets = append(obj.Subsets, EndpointSubset{
|
|
||||||
Addresses: []EndpointAddress{{IP: host, TargetRef: tgtRef}},
|
|
||||||
Ports: []EndpointPort{{Protocol: obj.Protocol, Port: port}},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i := range obj.Subsets {
|
|
||||||
ss := &obj.Subsets[i]
|
|
||||||
for i := range ss.Ports {
|
|
||||||
ep := &ss.Ports[i]
|
|
||||||
if ep.Protocol == "" {
|
|
||||||
ep.Protocol = ProtocolTCP
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *HTTPGetAction) {
|
|
||||||
if obj.Path == "" {
|
|
||||||
obj.Path = "/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *NamespaceStatus) {
|
|
||||||
if obj.Phase == "" {
|
|
||||||
obj.Phase = NamespaceActive
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *Minion) {
|
|
||||||
if obj.ExternalID == "" {
|
|
||||||
obj.ExternalID = obj.ID
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *ObjectFieldSelector) {
|
|
||||||
if obj.APIVersion == "" {
|
|
||||||
obj.APIVersion = "v1beta2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// With host networking default all container ports to host ports.
|
|
||||||
func defaultHostNetworkPorts(containers *[]Container) {
|
|
||||||
for i := range *containers {
|
|
||||||
for j := range (*containers)[i].Ports {
|
|
||||||
if (*containers)[i].Ports[j].HostPort == 0 {
|
|
||||||
(*containers)[i].Ports[j].HostPort = (*containers)[i].Ports[j].ContainerPort
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// defaultSecurityContext performs the downward and upward merges of a pod definition
|
|
||||||
func defaultSecurityContext(container *Container) {
|
|
||||||
if container.SecurityContext == nil {
|
|
||||||
glog.V(5).Infof("creating security context for container %s", container.Name)
|
|
||||||
container.SecurityContext = &SecurityContext{}
|
|
||||||
}
|
|
||||||
// if there are no capabilities defined on the SecurityContext then copy the container settings
|
|
||||||
if container.SecurityContext.Capabilities == nil {
|
|
||||||
container.SecurityContext.Capabilities = &container.Capabilities
|
|
||||||
} else {
|
|
||||||
// if there are capabilities defined on the security context and the container setting is
|
|
||||||
// empty then assume that it was left off the pod definition and ensure that the container
|
|
||||||
// settings match the security context settings (checked by the convert functions). If
|
|
||||||
// there are settings in both then don't touch it, the converter will error if they don't
|
|
||||||
// match
|
|
||||||
if len(container.Capabilities.Add) == 0 {
|
|
||||||
container.Capabilities.Add = container.SecurityContext.Capabilities.Add
|
|
||||||
}
|
|
||||||
if len(container.Capabilities.Drop) == 0 {
|
|
||||||
container.Capabilities.Drop = container.SecurityContext.Capabilities.Drop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if there are no privileged settings on the security context then copy the container settings
|
|
||||||
if container.SecurityContext.Privileged == nil {
|
|
||||||
container.SecurityContext.Privileged = &container.Privileged
|
|
||||||
} else {
|
|
||||||
// we don't have a good way to know if container.Privileged was set or just defaulted to false
|
|
||||||
// so the best we can do here is check if the securityContext is set to true and the
|
|
||||||
// container is set to false and assume that the Privileged field was left off the container
|
|
||||||
// definition and not an intentional mismatch
|
|
||||||
if *container.SecurityContext.Privileged && !container.Privileged {
|
|
||||||
container.Privileged = *container.SecurityContext.Privileged
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,460 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package v1beta2_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
versioned "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
|
|
||||||
data, err := versioned.Codec.Encode(obj)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%v\n %#v", err, obj)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
obj2, err := api.Codec.Decode(data)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), obj)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
obj3 := reflect.New(reflect.TypeOf(obj).Elem()).Interface().(runtime.Object)
|
|
||||||
err = api.Scheme.Convert(obj2, obj3)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%v\nSource: %#v", err, obj2)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return obj3
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultReplicationController(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
rc *versioned.ReplicationController
|
|
||||||
expectLabels bool
|
|
||||||
expectSelector bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
rc: &versioned.ReplicationController{
|
|
||||||
DesiredState: versioned.ReplicationControllerState{
|
|
||||||
PodTemplate: versioned.PodTemplate{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"foo": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectLabels: true,
|
|
||||||
expectSelector: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rc: &versioned.ReplicationController{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"bar": "foo",
|
|
||||||
},
|
|
||||||
DesiredState: versioned.ReplicationControllerState{
|
|
||||||
PodTemplate: versioned.PodTemplate{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"foo": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectLabels: false,
|
|
||||||
expectSelector: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rc: &versioned.ReplicationController{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"bar": "foo",
|
|
||||||
},
|
|
||||||
DesiredState: versioned.ReplicationControllerState{
|
|
||||||
ReplicaSelector: map[string]string{
|
|
||||||
"some": "other",
|
|
||||||
},
|
|
||||||
PodTemplate: versioned.PodTemplate{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"foo": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectLabels: false,
|
|
||||||
expectSelector: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rc: &versioned.ReplicationController{
|
|
||||||
DesiredState: versioned.ReplicationControllerState{
|
|
||||||
ReplicaSelector: map[string]string{
|
|
||||||
"some": "other",
|
|
||||||
},
|
|
||||||
PodTemplate: versioned.PodTemplate{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"foo": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectLabels: true,
|
|
||||||
expectSelector: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
rc := test.rc
|
|
||||||
obj2 := roundTrip(t, runtime.Object(rc))
|
|
||||||
rc2, ok := obj2.(*versioned.ReplicationController)
|
|
||||||
if !ok {
|
|
||||||
t.Errorf("unexpected object: %v", rc2)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
if test.expectSelector != reflect.DeepEqual(rc2.DesiredState.ReplicaSelector, rc2.DesiredState.PodTemplate.Labels) {
|
|
||||||
if test.expectSelector {
|
|
||||||
t.Errorf("expected: %v, got: %v", rc2.DesiredState.PodTemplate.Labels, rc2.DesiredState.ReplicaSelector)
|
|
||||||
} else {
|
|
||||||
t.Errorf("unexpected equality: %v", rc2.DesiredState.PodTemplate.Labels)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if test.expectLabels != reflect.DeepEqual(rc2.Labels, rc2.DesiredState.PodTemplate.Labels) {
|
|
||||||
if test.expectLabels {
|
|
||||||
t.Errorf("expected: %v, got: %v", rc2.DesiredState.PodTemplate.Labels, rc2.Labels)
|
|
||||||
} else {
|
|
||||||
t.Errorf("unexpected equality: %v", rc2.DesiredState.PodTemplate.Labels)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultService(t *testing.T) {
|
|
||||||
svc := &versioned.Service{}
|
|
||||||
obj2 := roundTrip(t, runtime.Object(svc))
|
|
||||||
svc2 := obj2.(*versioned.Service)
|
|
||||||
if svc2.Protocol != versioned.ProtocolTCP {
|
|
||||||
t.Errorf("Expected default protocol :%s, got: %s", versioned.ProtocolTCP, svc2.Protocol)
|
|
||||||
}
|
|
||||||
if svc2.SessionAffinity != versioned.ServiceAffinityNone {
|
|
||||||
t.Errorf("Expected default session affinity type:%s, got: %s", versioned.ServiceAffinityNone, svc2.SessionAffinity)
|
|
||||||
}
|
|
||||||
if svc2.Type != versioned.ServiceTypeClusterIP {
|
|
||||||
t.Errorf("Expected default type:%s, got: %s", versioned.ServiceTypeClusterIP, svc2.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultServiceWithLoadbalancer(t *testing.T) {
|
|
||||||
svc := &versioned.Service{}
|
|
||||||
svc.CreateExternalLoadBalancer = true
|
|
||||||
obj2 := roundTrip(t, runtime.Object(svc))
|
|
||||||
svc2 := obj2.(*versioned.Service)
|
|
||||||
if svc2.Type != versioned.ServiceTypeLoadBalancer {
|
|
||||||
t.Errorf("Expected default type:%s, got: %s", versioned.ServiceTypeLoadBalancer, svc2.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultPersistentVolume(t *testing.T) {
|
|
||||||
pv := &versioned.PersistentVolume{}
|
|
||||||
obj2 := roundTrip(t, runtime.Object(pv))
|
|
||||||
pv2 := obj2.(*versioned.PersistentVolume)
|
|
||||||
|
|
||||||
if pv2.Status.Phase != versioned.VolumePending {
|
|
||||||
t.Errorf("Expected volume phase %v, got %v", versioned.VolumePending, pv2.Status.Phase)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultPersistentVolumeClaim(t *testing.T) {
|
|
||||||
pvc := &versioned.PersistentVolumeClaim{}
|
|
||||||
obj2 := roundTrip(t, runtime.Object(pvc))
|
|
||||||
pvc2 := obj2.(*versioned.PersistentVolumeClaim)
|
|
||||||
|
|
||||||
if pvc2.Status.Phase != versioned.ClaimPending {
|
|
||||||
t.Errorf("Expected claim phase %v, got %v", versioned.ClaimPending, pvc2.Status.Phase)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultSecret(t *testing.T) {
|
|
||||||
s := &versioned.Secret{}
|
|
||||||
obj2 := roundTrip(t, runtime.Object(s))
|
|
||||||
s2 := obj2.(*versioned.Secret)
|
|
||||||
|
|
||||||
if s2.Type != versioned.SecretTypeOpaque {
|
|
||||||
t.Errorf("Expected secret type %v, got %v", versioned.SecretTypeOpaque, s2.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaulEndpointsLegacy(t *testing.T) {
|
|
||||||
in := &versioned.Endpoints{
|
|
||||||
Protocol: "UDP",
|
|
||||||
Endpoints: []string{"1.2.3.4:93", "5.6.7.8:76"},
|
|
||||||
TargetRefs: []versioned.EndpointObjectReference{{Endpoint: "1.2.3.4:93", ObjectReference: versioned.ObjectReference{ID: "foo"}}},
|
|
||||||
}
|
|
||||||
obj := roundTrip(t, runtime.Object(in))
|
|
||||||
out := obj.(*versioned.Endpoints)
|
|
||||||
|
|
||||||
if len(out.Subsets) != 2 {
|
|
||||||
t.Errorf("Expected 2 EndpointSubsets, got %d (%#v)", len(out.Subsets), out.Subsets)
|
|
||||||
}
|
|
||||||
expected := []versioned.EndpointSubset{
|
|
||||||
{
|
|
||||||
Addresses: []versioned.EndpointAddress{{IP: "1.2.3.4", TargetRef: &versioned.ObjectReference{ID: "foo"}}},
|
|
||||||
Ports: []versioned.EndpointPort{{Protocol: versioned.ProtocolUDP, Port: 93}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Addresses: []versioned.EndpointAddress{{IP: "5.6.7.8"}},
|
|
||||||
Ports: []versioned.EndpointPort{{Protocol: versioned.ProtocolUDP, Port: 76}},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(out.Subsets, expected) {
|
|
||||||
t.Errorf("Expected %#v, got %#v", expected, out.Subsets)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaulEndpointsProtocol(t *testing.T) {
|
|
||||||
in := &versioned.Endpoints{Subsets: []versioned.EndpointSubset{
|
|
||||||
{Ports: []versioned.EndpointPort{{}, {Protocol: "UDP"}, {}}},
|
|
||||||
}}
|
|
||||||
obj := roundTrip(t, runtime.Object(in))
|
|
||||||
out := obj.(*versioned.Endpoints)
|
|
||||||
|
|
||||||
if out.Protocol != versioned.ProtocolTCP {
|
|
||||||
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Protocol)
|
|
||||||
}
|
|
||||||
for i := range out.Subsets {
|
|
||||||
for j := range out.Subsets[i].Ports {
|
|
||||||
if in.Subsets[i].Ports[j].Protocol == "" {
|
|
||||||
if out.Subsets[i].Ports[j].Protocol != versioned.ProtocolTCP {
|
|
||||||
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Subsets[i].Ports[j].Protocol)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if out.Subsets[i].Ports[j].Protocol != in.Subsets[i].Ports[j].Protocol {
|
|
||||||
t.Errorf("Expected protocol %s, got %s", in.Subsets[i].Ports[j].Protocol, out.Subsets[i].Ports[j].Protocol)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultNamespace(t *testing.T) {
|
|
||||||
s := &versioned.Namespace{}
|
|
||||||
obj2 := roundTrip(t, runtime.Object(s))
|
|
||||||
s2 := obj2.(*versioned.Namespace)
|
|
||||||
|
|
||||||
if s2.Status.Phase != versioned.NamespaceActive {
|
|
||||||
t.Errorf("Expected phase %v, got %v", versioned.NamespaceActive, s2.Status.Phase)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultContainerManifestHostNetwork(t *testing.T) {
|
|
||||||
portNum := 8080
|
|
||||||
s := versioned.ContainerManifest{}
|
|
||||||
s.HostNetwork = true
|
|
||||||
s.Containers = []versioned.Container{
|
|
||||||
{
|
|
||||||
Ports: []versioned.ContainerPort{
|
|
||||||
{
|
|
||||||
ContainerPort: portNum,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
obj2 := roundTrip(t, runtime.Object(&versioned.ContainerManifestList{
|
|
||||||
Items: []versioned.ContainerManifest{s},
|
|
||||||
}))
|
|
||||||
sList2 := obj2.(*versioned.ContainerManifestList)
|
|
||||||
s2 := sList2.Items[0]
|
|
||||||
|
|
||||||
hostPortNum := s2.Containers[0].Ports[0].HostPort
|
|
||||||
if hostPortNum != portNum {
|
|
||||||
t.Errorf("Expected container port to be defaulted, was made %d instead of %d", hostPortNum, portNum)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultServicePort(t *testing.T) {
|
|
||||||
// Unchanged if set.
|
|
||||||
in := &versioned.Service{Ports: []versioned.ServicePort{{Protocol: "UDP", Port: 9376, ContainerPort: util.NewIntOrStringFromInt(118)}}}
|
|
||||||
out := roundTrip(t, runtime.Object(in)).(*versioned.Service)
|
|
||||||
if out.Ports[0].Protocol != versioned.ProtocolUDP {
|
|
||||||
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolUDP, out.Ports[0].Protocol)
|
|
||||||
}
|
|
||||||
if out.Ports[0].ContainerPort != in.Ports[0].ContainerPort {
|
|
||||||
t.Errorf("Expected port %d, got %d", in.Ports[0].ContainerPort, out.Ports[0].ContainerPort)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defaulted.
|
|
||||||
in = &versioned.Service{Ports: []versioned.ServicePort{{Protocol: "", Port: 9376, ContainerPort: util.NewIntOrStringFromInt(0)}}}
|
|
||||||
out = roundTrip(t, runtime.Object(in)).(*versioned.Service)
|
|
||||||
if out.Ports[0].Protocol != versioned.ProtocolTCP {
|
|
||||||
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Ports[0].Protocol)
|
|
||||||
}
|
|
||||||
if out.Ports[0].ContainerPort != util.NewIntOrStringFromInt(in.Ports[0].Port) {
|
|
||||||
t.Errorf("Expected port %d, got %v", in.Ports[0].Port, out.Ports[0].ContainerPort)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defaulted.
|
|
||||||
in = &versioned.Service{Ports: []versioned.ServicePort{{Protocol: "", Port: 9376, ContainerPort: util.NewIntOrStringFromString("")}}}
|
|
||||||
out = roundTrip(t, runtime.Object(in)).(*versioned.Service)
|
|
||||||
if out.Ports[0].Protocol != versioned.ProtocolTCP {
|
|
||||||
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Ports[0].Protocol)
|
|
||||||
}
|
|
||||||
if out.Ports[0].ContainerPort != util.NewIntOrStringFromInt(in.Ports[0].Port) {
|
|
||||||
t.Errorf("Expected port %d, got %v", in.Ports[0].Port, out.Ports[0].ContainerPort)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultMinionExternalID(t *testing.T) {
|
|
||||||
name := "node0"
|
|
||||||
m := &versioned.Minion{}
|
|
||||||
m.ID = name
|
|
||||||
obj2 := roundTrip(t, runtime.Object(m))
|
|
||||||
m2 := obj2.(*versioned.Minion)
|
|
||||||
if m2.ExternalID != name {
|
|
||||||
t.Errorf("Expected default External ID: %s, got: %s", name, m2.ExternalID)
|
|
||||||
}
|
|
||||||
if m2.ProviderID != "" {
|
|
||||||
t.Errorf("Expected empty default Cloud Provider ID, got: %s", m2.ProviderID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultObjectFieldSelectorAPIVersion(t *testing.T) {
|
|
||||||
s := versioned.ContainerManifest{
|
|
||||||
Containers: []versioned.Container{
|
|
||||||
{
|
|
||||||
Env: []versioned.EnvVar{
|
|
||||||
{
|
|
||||||
ValueFrom: &versioned.EnvVarSource{
|
|
||||||
FieldRef: &versioned.ObjectFieldSelector{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
obj2 := roundTrip(t, runtime.Object(&versioned.ContainerManifestList{
|
|
||||||
Items: []versioned.ContainerManifest{s},
|
|
||||||
}))
|
|
||||||
sList2 := obj2.(*versioned.ContainerManifestList)
|
|
||||||
s2 := sList2.Items[0]
|
|
||||||
|
|
||||||
apiVersion := s2.Containers[0].Env[0].ValueFrom.FieldRef.APIVersion
|
|
||||||
if apiVersion != "v1beta2" {
|
|
||||||
t.Errorf("Expected default APIVersion v1beta2, got: %v", apiVersion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetDefaultSecurityContext(t *testing.T) {
|
|
||||||
priv := false
|
|
||||||
privTrue := true
|
|
||||||
testCases := map[string]struct {
|
|
||||||
c versioned.Container
|
|
||||||
}{
|
|
||||||
"downward defaulting caps": {
|
|
||||||
c: versioned.Container{
|
|
||||||
Privileged: false,
|
|
||||||
Capabilities: versioned.Capabilities{
|
|
||||||
Add: []versioned.Capability{"foo"},
|
|
||||||
Drop: []versioned.Capability{"bar"},
|
|
||||||
},
|
|
||||||
SecurityContext: &versioned.SecurityContext{
|
|
||||||
Privileged: &priv,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"downward defaulting priv": {
|
|
||||||
c: versioned.Container{
|
|
||||||
Privileged: false,
|
|
||||||
Capabilities: versioned.Capabilities{
|
|
||||||
Add: []versioned.Capability{"foo"},
|
|
||||||
Drop: []versioned.Capability{"bar"},
|
|
||||||
},
|
|
||||||
SecurityContext: &versioned.SecurityContext{
|
|
||||||
Capabilities: &versioned.Capabilities{
|
|
||||||
Add: []versioned.Capability{"foo"},
|
|
||||||
Drop: []versioned.Capability{"bar"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"upward defaulting caps": {
|
|
||||||
c: versioned.Container{
|
|
||||||
Privileged: false,
|
|
||||||
SecurityContext: &versioned.SecurityContext{
|
|
||||||
Privileged: &priv,
|
|
||||||
Capabilities: &versioned.Capabilities{
|
|
||||||
Add: []versioned.Capability{"biz"},
|
|
||||||
Drop: []versioned.Capability{"baz"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"upward defaulting priv": {
|
|
||||||
c: versioned.Container{
|
|
||||||
Capabilities: versioned.Capabilities{
|
|
||||||
Add: []versioned.Capability{"foo"},
|
|
||||||
Drop: []versioned.Capability{"bar"},
|
|
||||||
},
|
|
||||||
SecurityContext: &versioned.SecurityContext{
|
|
||||||
Privileged: &privTrue,
|
|
||||||
Capabilities: &versioned.Capabilities{
|
|
||||||
Add: []versioned.Capability{"foo"},
|
|
||||||
Drop: []versioned.Capability{"bar"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
pod := &versioned.Pod{
|
|
||||||
DesiredState: versioned.PodState{
|
|
||||||
Manifest: versioned.ContainerManifest{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range testCases {
|
|
||||||
pod.DesiredState.Manifest.Containers = []versioned.Container{v.c}
|
|
||||||
obj := roundTrip(t, runtime.Object(pod))
|
|
||||||
defaultedPod := obj.(*versioned.Pod)
|
|
||||||
c := defaultedPod.DesiredState.Manifest.Containers[0]
|
|
||||||
if isEqual, issues := areSecurityContextAndContainerEqual(&c); !isEqual {
|
|
||||||
t.Errorf("test case %s expected the security context to have the same values as the container but found %#v", k, issues)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func areSecurityContextAndContainerEqual(c *versioned.Container) (bool, []string) {
|
|
||||||
issues := make([]string, 0)
|
|
||||||
equal := true
|
|
||||||
|
|
||||||
if c.SecurityContext == nil || c.SecurityContext.Privileged == nil || c.SecurityContext.Capabilities == nil {
|
|
||||||
equal = false
|
|
||||||
issues = append(issues, "Expected non nil settings for SecurityContext")
|
|
||||||
return equal, issues
|
|
||||||
}
|
|
||||||
if *c.SecurityContext.Privileged != c.Privileged {
|
|
||||||
equal = false
|
|
||||||
issues = append(issues, "The defaulted SecurityContext.Privileged value did not match the container value")
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(c.Capabilities.Add, c.Capabilities.Add) {
|
|
||||||
equal = false
|
|
||||||
issues = append(issues, "The defaulted SecurityContext.Capabilities.Add did not match the container settings")
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(c.Capabilities.Drop, c.Capabilities.Drop) {
|
|
||||||
equal = false
|
|
||||||
issues = append(issues, "The defaulted SecurityContext.Capabilities.Drop did not match the container settings")
|
|
||||||
}
|
|
||||||
return equal, issues
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 The Kubernetes Authors All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Package v1beta2 is the v1beta2 version of the API.
|
|
||||||
package v1beta2
|
|
@ -1,138 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 The Kubernetes Authors All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package v1beta2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/registered"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Codec encodes internal objects to the v1beta2 scheme
|
|
||||||
var Codec = runtime.CodecFor(api.Scheme, "v1beta2")
|
|
||||||
|
|
||||||
// Dependency does nothing but give a hook for other packages to force a
|
|
||||||
// compile-time error when this API version is eventually removed. This is
|
|
||||||
// useful, for example, to clean up things that are implicitly tied to
|
|
||||||
// semantics of older APIs.
|
|
||||||
const Dependency = true
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Check if v1beta2 is in the list of supported API versions.
|
|
||||||
if !registered.IsRegisteredAPIVersion("v1beta2") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the API.
|
|
||||||
addKnownTypes()
|
|
||||||
addConversionFuncs()
|
|
||||||
addDefaultingFuncs()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adds the list of known types to api.Scheme.
|
|
||||||
func addKnownTypes() {
|
|
||||||
api.Scheme.AddKnownTypes("v1beta2",
|
|
||||||
&Pod{},
|
|
||||||
&PodStatusResult{},
|
|
||||||
&PodList{},
|
|
||||||
&ReplicationController{},
|
|
||||||
&ReplicationControllerList{},
|
|
||||||
&Service{},
|
|
||||||
&ServiceList{},
|
|
||||||
&Endpoints{},
|
|
||||||
&EndpointsList{},
|
|
||||||
&Minion{},
|
|
||||||
&NodeInfo{},
|
|
||||||
&MinionList{},
|
|
||||||
&Binding{},
|
|
||||||
&Status{},
|
|
||||||
&Event{},
|
|
||||||
&EventList{},
|
|
||||||
&ContainerManifest{},
|
|
||||||
&ContainerManifestList{},
|
|
||||||
&List{},
|
|
||||||
&LimitRange{},
|
|
||||||
&LimitRangeList{},
|
|
||||||
&ResourceQuota{},
|
|
||||||
&ResourceQuotaList{},
|
|
||||||
&Namespace{},
|
|
||||||
&NamespaceList{},
|
|
||||||
&Secret{},
|
|
||||||
&SecretList{},
|
|
||||||
&ServiceAccount{},
|
|
||||||
&ServiceAccountList{},
|
|
||||||
&PersistentVolume{},
|
|
||||||
&PersistentVolumeList{},
|
|
||||||
&PersistentVolumeClaim{},
|
|
||||||
&PersistentVolumeClaimList{},
|
|
||||||
&DeleteOptions{},
|
|
||||||
&ListOptions{},
|
|
||||||
&PodLogOptions{},
|
|
||||||
&PodExecOptions{},
|
|
||||||
&PodProxyOptions{},
|
|
||||||
&ComponentStatus{},
|
|
||||||
&ComponentStatusList{},
|
|
||||||
&SerializedReference{},
|
|
||||||
&RangeAllocation{},
|
|
||||||
)
|
|
||||||
// Future names are supported
|
|
||||||
api.Scheme.AddKnownTypeWithName("v1beta2", "Node", &Minion{})
|
|
||||||
api.Scheme.AddKnownTypeWithName("v1beta2", "NodeList", &MinionList{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Pod) IsAnAPIObject() {}
|
|
||||||
func (*PodStatusResult) IsAnAPIObject() {}
|
|
||||||
func (*PodList) IsAnAPIObject() {}
|
|
||||||
func (*ReplicationController) IsAnAPIObject() {}
|
|
||||||
func (*ReplicationControllerList) IsAnAPIObject() {}
|
|
||||||
func (*Service) IsAnAPIObject() {}
|
|
||||||
func (*ServiceList) IsAnAPIObject() {}
|
|
||||||
func (*Endpoints) IsAnAPIObject() {}
|
|
||||||
func (*EndpointsList) IsAnAPIObject() {}
|
|
||||||
func (*Minion) IsAnAPIObject() {}
|
|
||||||
func (*NodeInfo) IsAnAPIObject() {}
|
|
||||||
func (*MinionList) IsAnAPIObject() {}
|
|
||||||
func (*Binding) IsAnAPIObject() {}
|
|
||||||
func (*Status) IsAnAPIObject() {}
|
|
||||||
func (*Event) IsAnAPIObject() {}
|
|
||||||
func (*EventList) IsAnAPIObject() {}
|
|
||||||
func (*ContainerManifest) IsAnAPIObject() {}
|
|
||||||
func (*ContainerManifestList) IsAnAPIObject() {}
|
|
||||||
func (*List) IsAnAPIObject() {}
|
|
||||||
func (*LimitRange) IsAnAPIObject() {}
|
|
||||||
func (*LimitRangeList) IsAnAPIObject() {}
|
|
||||||
func (*ResourceQuota) IsAnAPIObject() {}
|
|
||||||
func (*ResourceQuotaList) IsAnAPIObject() {}
|
|
||||||
func (*Namespace) IsAnAPIObject() {}
|
|
||||||
func (*NamespaceList) IsAnAPIObject() {}
|
|
||||||
func (*Secret) IsAnAPIObject() {}
|
|
||||||
func (*SecretList) IsAnAPIObject() {}
|
|
||||||
func (*ServiceAccount) IsAnAPIObject() {}
|
|
||||||
func (*ServiceAccountList) IsAnAPIObject() {}
|
|
||||||
func (*PersistentVolume) IsAnAPIObject() {}
|
|
||||||
func (*PersistentVolumeList) IsAnAPIObject() {}
|
|
||||||
func (*PersistentVolumeClaim) IsAnAPIObject() {}
|
|
||||||
func (*PersistentVolumeClaimList) IsAnAPIObject() {}
|
|
||||||
func (*DeleteOptions) IsAnAPIObject() {}
|
|
||||||
func (*ListOptions) IsAnAPIObject() {}
|
|
||||||
func (*PodLogOptions) IsAnAPIObject() {}
|
|
||||||
func (*PodExecOptions) IsAnAPIObject() {}
|
|
||||||
func (*PodProxyOptions) IsAnAPIObject() {}
|
|
||||||
func (*ComponentStatus) IsAnAPIObject() {}
|
|
||||||
func (*ComponentStatusList) IsAnAPIObject() {}
|
|
||||||
func (*SerializedReference) IsAnAPIObject() {}
|
|
||||||
func (*RangeAllocation) IsAnAPIObject() {}
|
|
File diff suppressed because it is too large
Load Diff
@ -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) {
|
|||||||
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) {
|
|||||||
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 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
|||||||
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
|
|||||||
}
|
}
|
||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
// 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) {
|
|||||||
|
|
||||||
// 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)
|
||||||
|
@ -106,14 +106,6 @@ func TestExec(t *testing.T) {
|
|||||||
pod *api.Pod
|
pod *api.Pod
|
||||||
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",
|
||||||
|
@ -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) {
|
|||||||
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) {
|
||||||
|
@ -156,14 +156,6 @@ func TestLog(t *testing.T) {
|
|||||||
nsInQuery bool
|
nsInQuery bool
|
||||||
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",
|
||||||
|
@ -45,14 +45,6 @@ func TestPortForward(t *testing.T) {
|
|||||||
pod *api.Pod
|
pod *api.Pod
|
||||||
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",
|
||||||
|
@ -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",
|
||||||
@ -94,25 +94,6 @@ func TestMerge(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, */
|
}, */
|
||||||
{
|
|
||||||
kind: "Pod",
|
|
||||||
obj: &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "foo",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
fragment: `{ "apiVersion": "v1beta1", "id": "baz", "desiredState": { "host": "bar" } }`,
|
|
||||||
expected: &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "baz",
|
|
||||||
},
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
NodeName: "bar",
|
|
||||||
RestartPolicy: api.RestartPolicyAlways,
|
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
kind: "Pod",
|
kind: "Pod",
|
||||||
obj: &api.Pod{
|
obj: &api.Pod{
|
||||||
@ -148,24 +129,6 @@ func TestMerge(t *testing.T) {
|
|||||||
expected: &api.Pod{},
|
expected: &api.Pod{},
|
||||||
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{},
|
||||||
@ -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) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
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 (
|
|||||||
|
|
||||||
"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
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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)
|
|||||||
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.
|
|||||||
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) {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 (
|
|||||||
|
|
||||||
"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) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 (
|
|||||||
"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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 (
|
|||||||
"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) {
|
|||||||
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() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
@ -90,74 +89,6 @@ func TestFindPort(t *testing.T) {
|
|||||||
port: util.NewIntOrStringFromInt(93),
|
port: util.NewIntOrStringFromInt(93),
|
||||||
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{{}},
|
||||||
@ -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:
|
|||||||
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
|
||||||
|
Loading…
Reference in New Issue
Block a user