mirror of https://github.com/k3s-io/k3s
commit
c1fa82837e
|
@ -6,7 +6,7 @@ matrix:
|
|||
include:
|
||||
- go: 1.4
|
||||
env:
|
||||
- KUBE_TEST_API_VERSIONS="v1beta1"
|
||||
- KUBE_TEST_API_VERSIONS="v1beta3"
|
||||
KUBE_TEST_ETCD_PREFIXES="registry"
|
||||
- go: 1.3
|
||||
env:
|
||||
|
|
|
@ -23,5 +23,6 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"models": {}
|
||||
}
|
|
@ -1,14 +1,14 @@
|
|||
{
|
||||
"swaggerVersion": "1.2",
|
||||
"apis": [
|
||||
{
|
||||
"path": "/api",
|
||||
"description": "get available API versions"
|
||||
},
|
||||
{
|
||||
"path": "/api/v1beta3",
|
||||
"description": "API at /api/v1beta3 version v1beta3"
|
||||
},
|
||||
{
|
||||
"path": "/api",
|
||||
"description": "get available API versions"
|
||||
},
|
||||
{
|
||||
"path": "/version",
|
||||
"description": "git code version from which this is built"
|
||||
|
@ -19,4 +19,4 @@
|
|||
"title": "",
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -23,5 +23,6 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"models": {}
|
||||
}
|
|
@ -16,7 +16,7 @@ spec:
|
|||
kubernetes.io/cluster-service: "true"
|
||||
spec:
|
||||
containers:
|
||||
- image: gcr.io/google_containers/heapster:v0.12.1
|
||||
- image: gcr.io/google_containers/heapster:v0.13.0
|
||||
name: heapster
|
||||
command:
|
||||
- /heapster
|
||||
|
|
|
@ -16,7 +16,7 @@ spec:
|
|||
kubernetes.io/cluster-service: "true"
|
||||
spec:
|
||||
containers:
|
||||
- image: gcr.io/google_containers/heapster:v0.12.1
|
||||
- image: gcr.io/google_containers/heapster:v0.13.0
|
||||
name: heapster
|
||||
command:
|
||||
- /heapster
|
||||
|
|
|
@ -23,8 +23,6 @@ import (
|
|||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
|
||||
pkg_runtime "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
|
||||
|
|
|
@ -24,8 +24,6 @@ import (
|
|||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
|
||||
pkg_runtime "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
|
||||
|
|
|
@ -605,23 +605,6 @@ func runPatchTest(c *client.Client) {
|
|||
RemoveLabelBody []byte
|
||||
RemoveAllLabelsBody []byte
|
||||
}{
|
||||
"v1beta1": {
|
||||
api.JSONPatchType: {
|
||||
[]byte(`[{"op":"add","path":"/labels","value":{"foo":"bar","baz":"qux"}}]`),
|
||||
[]byte(`[{"op":"remove","path":"/labels/foo"}]`),
|
||||
[]byte(`[{"op":"remove","path":"/labels"}]`),
|
||||
},
|
||||
api.MergePatchType: {
|
||||
[]byte(`{"labels":{"foo":"bar","baz":"qux"}}`),
|
||||
[]byte(`{"labels":{"foo":null}}`),
|
||||
[]byte(`{"labels":null}`),
|
||||
},
|
||||
api.StrategicMergePatchType: {
|
||||
[]byte(`{"labels":{"foo":"bar","baz":"qux"}}`),
|
||||
[]byte(`{"labels":{"foo":null}}`),
|
||||
[]byte(`{"labels":{"$patch":"replace"}}`),
|
||||
},
|
||||
},
|
||||
"v1beta3": {
|
||||
api.JSONPatchType: {
|
||||
[]byte(`[{"op":"add","path":"/metadata/labels","value":{"foo":"bar","baz":"qux"}}]`),
|
||||
|
@ -938,7 +921,7 @@ func main() {
|
|||
glog.Infof("Running tests for APIVersion: %s", apiVersion)
|
||||
|
||||
firstManifestURL := ServeCachedManifestFile(testPodSpecFile)
|
||||
secondManifestURL := ServeCachedManifestFile(testManifestFile)
|
||||
secondManifestURL := ServeCachedManifestFile(testPodSpecFile)
|
||||
apiServerURL, _ := startComponents(firstManifestURL, secondManifestURL, apiVersion)
|
||||
|
||||
// Ok. we're good to go.
|
||||
|
@ -1059,27 +1042,3 @@ const (
|
|||
}
|
||||
}`
|
||||
)
|
||||
|
||||
const (
|
||||
// This is copied from, and should be kept in sync with:
|
||||
// https://raw.githubusercontent.com/GoogleCloudPlatform/container-vm-guestbook-redis-python/master/manifest.yaml
|
||||
// Note that kubelet complains about these containers not having a self link.
|
||||
testManifestFile = `version: v1beta2
|
||||
id: container-vm-guestbook-manifest
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis
|
||||
volumeMounts:
|
||||
- name: redis-data
|
||||
mountPath: /data
|
||||
|
||||
- name: guestbook
|
||||
image: google/guestbook-python-redis
|
||||
ports:
|
||||
- name: www
|
||||
hostPort: 80
|
||||
containerPort: 80
|
||||
|
||||
volumes:
|
||||
- name: redis-data`
|
||||
)
|
||||
|
|
|
@ -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" {
|
||||
disableLegacyAPIs = true
|
||||
}
|
||||
|
||||
// "api/v1beta1={true|false} allows users to enable/disable v1beta1 API.
|
||||
// This takes preference over api/all and api/legacy, if specified.
|
||||
disableV1beta1 := disableAllAPIs || disableLegacyAPIs
|
||||
disableV1beta1 = !s.getRuntimeConfigValue("api/v1beta1", !disableV1beta1)
|
||||
|
||||
// "api/v1beta2={true|false} allows users to enable/disable v1beta2 API.
|
||||
// This takes preference over api/all and api/legacy, if specified.
|
||||
disableV1beta2 := disableAllAPIs || disableLegacyAPIs
|
||||
disableV1beta2 = !s.getRuntimeConfigValue("api/v1beta2", !disableV1beta2)
|
||||
_ = disableLegacyAPIs // hush the compiler while we don't have legacy APIs to disable.
|
||||
|
||||
// "api/v1beta3={true|false} allows users to enable/disable v1beta3 API.
|
||||
// This takes preference over api/all and api/legacy, if specified.
|
||||
|
@ -369,8 +360,6 @@ func (s *APIServer) Run(_ []string) error {
|
|||
SupportsBasicAuth: len(s.BasicAuthFile) > 0,
|
||||
Authorizer: authorizer,
|
||||
AdmissionControl: admissionController,
|
||||
DisableV1Beta1: disableV1beta1,
|
||||
DisableV1Beta2: disableV1beta2,
|
||||
DisableV1Beta3: disableV1beta3,
|
||||
EnableV1: enableV1,
|
||||
MasterServiceNamespace: s.MasterServiceNamespace,
|
||||
|
|
|
@ -28,8 +28,6 @@ import (
|
|||
"runtime"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
|
||||
|
|
|
@ -121,7 +121,6 @@ func walkJSONFiles(inDir string, fn func(name, path string, data []byte)) error
|
|||
func TestExampleObjectSchemas(t *testing.T) {
|
||||
cases := map[string]map[string]runtime.Object{
|
||||
"../cmd/integration": {
|
||||
"v1beta1-controller": &api.ReplicationController{},
|
||||
"v1beta3-controller": &api.ReplicationController{},
|
||||
},
|
||||
"../examples/guestbook": {
|
||||
|
|
|
@ -114,8 +114,6 @@ PATH="${KUBE_OUTPUT_HOSTBIN}":$PATH
|
|||
|
||||
kube_api_versions=(
|
||||
""
|
||||
v1beta1
|
||||
v1beta2
|
||||
v1beta3
|
||||
)
|
||||
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.
|
||||
KUBE_GOVERALLS_BIN=${KUBE_GOVERALLS_BIN:-}
|
||||
# Comma separated list of API Versions that should be tested.
|
||||
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1beta1,v1beta3"}
|
||||
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1beta3"}
|
||||
# Run tests with the standard (registry) and a custom etcd prefix
|
||||
# (kubernetes.io/registry).
|
||||
KUBE_TEST_ETCD_PREFIXES=${KUBE_TEST_ETCD_PREFIXES:-"registry,kubernetes.io/registry"}
|
||||
|
|
|
@ -25,7 +25,7 @@ set -o pipefail
|
|||
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
|
||||
source "${KUBE_ROOT}/hack/lib/init.sh"
|
||||
# Comma separated list of API Versions that should be tested.
|
||||
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1beta1,v1beta3"}
|
||||
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1beta3"}
|
||||
KUBE_INTEGRATION_TEST_MAX_CONCURRENCY=${KUBE_INTEGRATION_TEST_MAX_CONCURRENCY:-"-1"}
|
||||
LOG_LEVEL=${LOG_LEVEL:-2}
|
||||
|
||||
|
|
|
@ -24,9 +24,10 @@ KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
|
|||
source "${KUBE_ROOT}/hack/lib/init.sh"
|
||||
|
||||
# The api version in which objects are currently stored in etcd.
|
||||
KUBE_OLD_API_VERSION=${KUBE_OLD_API_VERSION:-"v1beta1"}
|
||||
KUBE_OLD_API_VERSION=${KUBE_OLD_API_VERSION:-"v1beta3"}
|
||||
# The api version in which our etcd objects should be converted to.
|
||||
# The new api version
|
||||
# TODO change this to v1 when it's ready.
|
||||
KUBE_NEW_API_VERSION=${KUBE_NEW_API_VERSION:-"v1beta3"}
|
||||
|
||||
ETCD_HOST=${ETCD_HOST:-127.0.0.1}
|
||||
|
|
|
@ -22,8 +22,6 @@ import (
|
|||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
|
||||
)
|
||||
|
||||
|
|
|
@ -24,8 +24,6 @@ import (
|
|||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/registered"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
|
@ -36,7 +34,7 @@ var Version string
|
|||
|
||||
// OldestVersion is the string that represents the oldest server version supported,
|
||||
// for client code that wants to hardcode the lowest common denominator.
|
||||
const OldestVersion = "v1beta1"
|
||||
const OldestVersion = "v1beta3"
|
||||
|
||||
// Versions is the list of versions that are recognized in code. The order provided
|
||||
// may be assumed to be least feature rich to most feature rich, and clients may
|
||||
|
@ -88,20 +86,6 @@ func init() {
|
|||
},
|
||||
)
|
||||
|
||||
// versions that used mixed case URL formats
|
||||
versionMixedCase := map[string]bool{
|
||||
"v1beta1": true,
|
||||
"v1beta2": true,
|
||||
}
|
||||
|
||||
// backwards compatibility, prior to v1beta3, we identified the namespace as a query parameter
|
||||
versionToNamespaceScope := map[string]meta.RESTScope{
|
||||
"v1beta1": meta.RESTScopeNamespaceLegacy,
|
||||
"v1beta2": meta.RESTScopeNamespaceLegacy,
|
||||
"v1beta3": meta.RESTScopeNamespace,
|
||||
"v1": meta.RESTScopeNamespace,
|
||||
}
|
||||
|
||||
// the list of kinds that are scoped at the root of the api hierarchy
|
||||
// if a kind is not enumerated here, it is assumed to have a namespace scope
|
||||
kindToRootScope := map[string]bool{
|
||||
|
@ -130,16 +114,11 @@ func init() {
|
|||
if ignoredKinds.Has(kind) {
|
||||
continue
|
||||
}
|
||||
mixedCase, found := versionMixedCase[version]
|
||||
if !found {
|
||||
mixedCase = false
|
||||
}
|
||||
scope := versionToNamespaceScope[version]
|
||||
_, found = kindToRootScope[kind]
|
||||
if found {
|
||||
scope := meta.RESTScopeNamespace
|
||||
if kindToRootScope[kind] {
|
||||
scope = meta.RESTScopeRoot
|
||||
}
|
||||
mapper.Add(scope, kind, version, mixedCase)
|
||||
mapper.Add(scope, kind, version, false)
|
||||
}
|
||||
}
|
||||
RESTMapper = mapper
|
||||
|
@ -149,18 +128,6 @@ func init() {
|
|||
// string, or an error if the version is not known.
|
||||
func InterfacesFor(version string) (*meta.VersionInterfaces, error) {
|
||||
switch version {
|
||||
case "v1beta1":
|
||||
return &meta.VersionInterfaces{
|
||||
Codec: v1beta1.Codec,
|
||||
ObjectConvertor: api.Scheme,
|
||||
MetadataAccessor: accessor,
|
||||
}, nil
|
||||
case "v1beta2":
|
||||
return &meta.VersionInterfaces{
|
||||
Codec: v1beta2.Codec,
|
||||
ObjectConvertor: api.Scheme,
|
||||
MetadataAccessor: accessor,
|
||||
}, nil
|
||||
case "v1beta3":
|
||||
return &meta.VersionInterfaces{
|
||||
Codec: v1beta3.Codec,
|
||||
|
|
|
@ -21,8 +21,6 @@ import (
|
|||
"testing"
|
||||
|
||||
internal "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
||||
)
|
||||
|
||||
func TestResourceVersioner(t *testing.T) {
|
||||
|
|
|
@ -31,13 +31,11 @@ var RegisteredVersions []string
|
|||
func init() {
|
||||
validAPIVersions := map[string]bool{
|
||||
"v1": true,
|
||||
"v1beta1": true,
|
||||
"v1beta2": true,
|
||||
"v1beta3": true,
|
||||
}
|
||||
|
||||
// The default list of supported api versions, in order of most preferred to the least.
|
||||
defaultSupportedVersions := "v1beta3,v1beta1,v1beta2,v1"
|
||||
defaultSupportedVersions := "v1beta3,v1"
|
||||
// Env var KUBE_API_VERSIONS is a comma separated list of API versions that should be registered in the scheme.
|
||||
// The versions should be in the order of most preferred to the least.
|
||||
supportedVersions := os.Getenv("KUBE_API_VERSIONS")
|
||||
|
|
|
@ -27,8 +27,6 @@ import (
|
|||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
||||
apitesting "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testing"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
|
@ -89,12 +87,6 @@ func roundTripSame(t *testing.T, item runtime.Object, except ...string) {
|
|||
set := util.NewStringSet(except...)
|
||||
seed := rand.Int63()
|
||||
fuzzInternalObject(t, "", item, seed)
|
||||
if !set.Has("v1beta1") {
|
||||
roundTrip(t, v1beta1.Codec, item)
|
||||
}
|
||||
if !set.Has("v1beta2") {
|
||||
roundTrip(t, v1beta2.Codec, item)
|
||||
}
|
||||
if !set.Has("v1beta3") {
|
||||
fuzzInternalObject(t, "v1beta3", item, seed)
|
||||
roundTrip(t, v1beta3.Codec, item)
|
||||
|
@ -103,8 +95,6 @@ func roundTripSame(t *testing.T, item runtime.Object, except ...string) {
|
|||
|
||||
func roundTripAll(t *testing.T, item runtime.Object) {
|
||||
seed := rand.Int63()
|
||||
roundTrip(t, v1beta1.Codec, fuzzInternalObject(t, "v1beta1", item, seed))
|
||||
roundTrip(t, v1beta2.Codec, fuzzInternalObject(t, "v1beta2", item, seed))
|
||||
roundTrip(t, v1beta3.Codec, fuzzInternalObject(t, "v1beta3", item, seed))
|
||||
}
|
||||
|
||||
|
@ -137,10 +127,7 @@ func TestList(t *testing.T) {
|
|||
|
||||
var nonRoundTrippableTypes = util.NewStringSet("ContainerManifest", "ContainerManifestList")
|
||||
var nonInternalRoundTrippableTypes = util.NewStringSet("List", "ListOptions", "PodExecOptions")
|
||||
var nonRoundTrippableTypesByVersion = map[string][]string{
|
||||
"PodTemplate": {"v1beta1", "v1beta2"},
|
||||
"PodTemplateList": {"v1beta1", "v1beta2"},
|
||||
}
|
||||
var nonRoundTrippableTypesByVersion = map[string][]string{}
|
||||
|
||||
func TestRoundTripTypes(t *testing.T) {
|
||||
// api.Scheme.Log(t)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
|
@ -55,20 +53,13 @@ func convert(obj runtime.Object) (runtime.Object, error) {
|
|||
return obj, nil
|
||||
}
|
||||
|
||||
// This creates a fake API version, similar to api/latest.go for a v1beta1 equivalent api. It is distinct
|
||||
// from the Kubernetes API versions to allow clients to properly distinguish the two.
|
||||
// This creates fake API versions, similar to api/latest.go.
|
||||
const testVersion = "version"
|
||||
const newVersion = "version2"
|
||||
|
||||
// The equivalent of the Kubernetes v1beta3 API.
|
||||
const testVersion2 = "version2"
|
||||
|
||||
var versions = []string{testVersion, testVersion2}
|
||||
var legacyCodec = runtime.CodecFor(api.Scheme, testVersion)
|
||||
var codec = runtime.CodecFor(api.Scheme, testVersion2)
|
||||
|
||||
// these codecs reflect ListOptions/DeleteOptions coming from the serverAPIversion
|
||||
var versionServerCodec = runtime.CodecFor(api.Scheme, "v1beta1")
|
||||
var version2ServerCodec = runtime.CodecFor(api.Scheme, "v1beta3")
|
||||
var versions = []string{testVersion, newVersion}
|
||||
var codec = runtime.CodecFor(api.Scheme, testVersion)
|
||||
var newCodec = runtime.CodecFor(api.Scheme, newVersion)
|
||||
|
||||
var accessor = meta.NewAccessor()
|
||||
var versioner runtime.ResourceVersioner = accessor
|
||||
|
@ -81,13 +72,13 @@ func interfacesFor(version string) (*meta.VersionInterfaces, error) {
|
|||
switch version {
|
||||
case testVersion:
|
||||
return &meta.VersionInterfaces{
|
||||
Codec: legacyCodec,
|
||||
Codec: codec,
|
||||
ObjectConvertor: api.Scheme,
|
||||
MetadataAccessor: accessor,
|
||||
}, nil
|
||||
case testVersion2:
|
||||
case newVersion:
|
||||
return &meta.VersionInterfaces{
|
||||
Codec: codec,
|
||||
Codec: newCodec,
|
||||
ObjectConvertor: api.Scheme,
|
||||
MetadataAccessor: accessor,
|
||||
}, nil
|
||||
|
@ -109,26 +100,44 @@ func newMapper() *meta.DefaultRESTMapper {
|
|||
)
|
||||
}
|
||||
|
||||
func addTestTypes() {
|
||||
type ListOptions struct {
|
||||
runtime.Object
|
||||
api.TypeMeta `json:",inline"`
|
||||
LabelSelector string `json:"labels,omitempty"`
|
||||
FieldSelector string `json:"fields,omitempty"`
|
||||
Watch bool `json:"watch,omitempty"`
|
||||
ResourceVersion string `json:"resourceVersion,omitempty"`
|
||||
}
|
||||
api.Scheme.AddKnownTypes(testVersion, &Simple{}, &SimpleList{}, &api.Status{}, &ListOptions{}, &api.DeleteOptions{}, &SimpleGetOptions{}, &SimpleRoot{})
|
||||
}
|
||||
|
||||
func addNewTestTypes() {
|
||||
type ListOptions struct {
|
||||
runtime.Object
|
||||
api.TypeMeta `json:",inline"`
|
||||
LabelSelector string `json:"labelSelector,omitempty"`
|
||||
FieldSelector string `json:"fieldSelector,omitempty"`
|
||||
Watch bool `json:"watch,omitempty"`
|
||||
ResourceVersion string `json:"resourceVersion,omitempty"`
|
||||
}
|
||||
api.Scheme.AddKnownTypes(newVersion, &Simple{}, &SimpleList{}, &api.Status{}, &ListOptions{}, &api.DeleteOptions{}, &SimpleGetOptions{}, &SimpleRoot{})
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Certain API objects are returned regardless of the contents of storage:
|
||||
// api.Status is returned in errors
|
||||
|
||||
// "internal" version
|
||||
api.Scheme.AddKnownTypes("", &Simple{}, &SimpleList{}, &api.Status{}, &api.ListOptions{}, &SimpleGetOptions{}, &SimpleRoot{})
|
||||
// "version" version
|
||||
// TODO: Use versioned api objects?
|
||||
api.Scheme.AddKnownTypes(testVersion, &Simple{}, &SimpleList{}, &v1beta1.Status{}, &SimpleGetOptions{}, &SimpleRoot{})
|
||||
// "version2" version
|
||||
// TODO: Use versioned api objects?
|
||||
api.Scheme.AddKnownTypes(testVersion2, &Simple{}, &SimpleList{}, &v1beta3.Status{}, &SimpleGetOptions{}, &SimpleRoot{})
|
||||
|
||||
// Register SimpleGetOptions with the server versions to convert query params to it
|
||||
api.Scheme.AddKnownTypes("v1beta1", &SimpleGetOptions{})
|
||||
api.Scheme.AddKnownTypes("v1beta3", &SimpleGetOptions{})
|
||||
addTestTypes()
|
||||
addNewTestTypes()
|
||||
|
||||
nsMapper := newMapper()
|
||||
legacyNsMapper := newMapper()
|
||||
// enumerate all supported versions, get the kinds, and register with the mapper how to address our resources
|
||||
|
||||
// enumerate all supported versions, get the kinds, and register with
|
||||
// the mapper how to address our resources
|
||||
for _, version := range versions {
|
||||
for kind := range api.Scheme.KnownTypes(version) {
|
||||
mixedCase := true
|
||||
|
@ -149,13 +158,12 @@ func init() {
|
|||
admissionControl = admit.NewAlwaysAdmit()
|
||||
requestContextMapper = api.NewRequestContextMapper()
|
||||
|
||||
//mapper.(*meta.DefaultRESTMapper).Add(meta.RESTScopeNamespaceLegacy, "Simple", testVersion, false)
|
||||
api.Scheme.AddFieldLabelConversionFunc(testVersion, "Simple",
|
||||
func(label, value string) (string, string, error) {
|
||||
return label, value, nil
|
||||
},
|
||||
)
|
||||
api.Scheme.AddFieldLabelConversionFunc(testVersion2, "Simple",
|
||||
api.Scheme.AddFieldLabelConversionFunc(newVersion, "Simple",
|
||||
func(label, value string) (string, string, error) {
|
||||
return label, value, nil
|
||||
},
|
||||
|
@ -210,13 +218,13 @@ func handleInternal(legacy bool, storage map[string]rest.Storage, admissionContr
|
|||
}
|
||||
if legacy {
|
||||
group.Version = testVersion
|
||||
group.ServerVersion = "v1beta1"
|
||||
group.Codec = legacyCodec
|
||||
group.ServerVersion = testVersion
|
||||
group.Codec = codec
|
||||
group.Mapper = legacyNamespaceMapper
|
||||
} else {
|
||||
group.Version = testVersion2
|
||||
group.ServerVersion = "v1beta3"
|
||||
group.Codec = codec
|
||||
group.Version = newVersion
|
||||
group.ServerVersion = newVersion
|
||||
group.Codec = newCodec
|
||||
group.Mapper = namespaceMapper
|
||||
}
|
||||
|
||||
|
@ -757,7 +765,7 @@ func TestList(t *testing.T) {
|
|||
selfLink: "/api/version/simple?namespace=",
|
||||
legacy: true,
|
||||
},
|
||||
// list items in a namespace, v1beta3+
|
||||
// list items in a namespace in the path
|
||||
{
|
||||
url: "/api/version2/namespaces/default/simple",
|
||||
namespace: "default",
|
||||
|
@ -1378,7 +1386,7 @@ func TestDeleteWithOptions(t *testing.T) {
|
|||
item := &api.DeleteOptions{
|
||||
GracePeriodSeconds: &grace,
|
||||
}
|
||||
body, err := versionServerCodec.Encode(item)
|
||||
body, err := codec.Encode(item)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
@ -1439,7 +1447,7 @@ func TestLegacyDeleteIgnoresOptions(t *testing.T) {
|
|||
defer server.Close()
|
||||
|
||||
item := api.NewDeleteOptions(300)
|
||||
body, err := versionServerCodec.Encode(item)
|
||||
body, err := codec.Encode(item)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
@ -1888,9 +1896,9 @@ func TestParentResourceIsRequired(t *testing.T) {
|
|||
Context: requestContextMapper,
|
||||
Mapper: namespaceMapper,
|
||||
|
||||
Version: testVersion2,
|
||||
ServerVersion: "v1beta3",
|
||||
Codec: codec,
|
||||
Version: newVersion,
|
||||
ServerVersion: newVersion,
|
||||
Codec: newCodec,
|
||||
}
|
||||
container := restful.NewContainer()
|
||||
if err := group.InstallREST(container); err == nil {
|
||||
|
@ -1916,9 +1924,9 @@ func TestParentResourceIsRequired(t *testing.T) {
|
|||
Context: requestContextMapper,
|
||||
Mapper: namespaceMapper,
|
||||
|
||||
Version: testVersion2,
|
||||
ServerVersion: "v1beta3",
|
||||
Codec: codec,
|
||||
Version: newVersion,
|
||||
ServerVersion: newVersion,
|
||||
Codec: newCodec,
|
||||
}
|
||||
container = restful.NewContainer()
|
||||
if err := group.InstallREST(container); err != nil {
|
||||
|
|
|
@ -303,7 +303,7 @@ func TestWatchHTTPTimeout(t *testing.T) {
|
|||
// Setup a new watchserver
|
||||
watchServer := &WatchServer{
|
||||
watcher,
|
||||
version2ServerCodec,
|
||||
newCodec,
|
||||
func(obj runtime.Object) {},
|
||||
&fakeTimeoutFactory{timeoutCh, done},
|
||||
}
|
||||
|
@ -315,13 +315,13 @@ func TestWatchHTTPTimeout(t *testing.T) {
|
|||
|
||||
// Setup a client
|
||||
dest, _ := url.Parse(s.URL)
|
||||
dest.Path = "/api/version/watch/resource"
|
||||
dest.RawQuery = ""
|
||||
dest.Path = "/api/" + newVersion + "/simple"
|
||||
dest.RawQuery = "watch=true"
|
||||
|
||||
req, _ := http.NewRequest("GET", dest.String(), nil)
|
||||
client := http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
watcher.Add(&api.Pod{TypeMeta: api.TypeMeta{APIVersion: "v1beta3"}})
|
||||
watcher.Add(&Simple{TypeMeta: api.TypeMeta{APIVersion: newVersion}})
|
||||
|
||||
// Make sure we can actually watch an endpoint
|
||||
decoder := json.NewDecoder(resp.Body)
|
||||
|
|
|
@ -106,14 +106,6 @@ func TestExec(t *testing.T) {
|
|||
pod *api.Pod
|
||||
execErr bool
|
||||
}{
|
||||
{
|
||||
name: "v1beta1 - pod exec",
|
||||
version: "v1beta1",
|
||||
podPath: "/api/v1beta1/pods/foo",
|
||||
execPath: "/api/v1beta1/pods/foo/exec",
|
||||
nsInQuery: true,
|
||||
pod: execPod(),
|
||||
},
|
||||
{
|
||||
name: "v1beta3 - pod exec",
|
||||
version: "v1beta3",
|
||||
|
|
|
@ -155,10 +155,10 @@ func TestGetUnknownSchemaObjectListGeneric(t *testing.T) {
|
|||
obj2 string
|
||||
}{
|
||||
"handles specific version": {
|
||||
output: "v1beta3",
|
||||
list: "v1beta3",
|
||||
output: "v1",
|
||||
list: "v1",
|
||||
obj1: "unlikelyversion",
|
||||
obj2: "v1beta3",
|
||||
obj2: "v1",
|
||||
},
|
||||
"handles second specific version": {
|
||||
output: "unlikelyversion",
|
||||
|
@ -167,14 +167,14 @@ func TestGetUnknownSchemaObjectListGeneric(t *testing.T) {
|
|||
obj2: "v1beta3", // version of the API response
|
||||
},
|
||||
"handles common version": {
|
||||
output: "v1beta1",
|
||||
list: "v1beta1",
|
||||
output: "v1beta3",
|
||||
list: "v1beta3",
|
||||
obj1: "unlikelyversion", // because test scheme defaults to unlikelyversion
|
||||
obj2: "v1beta1",
|
||||
obj2: "v1beta3",
|
||||
},
|
||||
}
|
||||
for k, test := range testCases {
|
||||
apiCodec := runtime.CodecFor(api.Scheme, "v1beta1")
|
||||
apiCodec := runtime.CodecFor(api.Scheme, "v1beta3")
|
||||
regularClient := &client.FakeRESTClient{
|
||||
Codec: apiCodec,
|
||||
Client: client.HTTPClientFunc(func(req *http.Request) (*http.Response, error) {
|
||||
|
|
|
@ -156,14 +156,6 @@ func TestLog(t *testing.T) {
|
|||
nsInQuery bool
|
||||
pod *api.Pod
|
||||
}{
|
||||
{
|
||||
name: "v1beta1 - pod log",
|
||||
version: "v1beta1",
|
||||
podPath: "/api/v1beta1/pods/foo",
|
||||
logPath: "/api/v1beta1/pods/foo/log",
|
||||
nsInQuery: true,
|
||||
pod: testPod(),
|
||||
},
|
||||
{
|
||||
name: "v1beta3 - pod log",
|
||||
version: "v1beta3",
|
||||
|
|
|
@ -45,14 +45,6 @@ func TestPortForward(t *testing.T) {
|
|||
pod *api.Pod
|
||||
pfErr bool
|
||||
}{
|
||||
{
|
||||
name: "v1beta1 - pod portforward",
|
||||
version: "v1beta1",
|
||||
podPath: "/api/v1beta1/pods/foo",
|
||||
pfPath: "/api/v1beta1/pods/foo/portforward",
|
||||
nsInQuery: true,
|
||||
pod: execPod(),
|
||||
},
|
||||
{
|
||||
name: "v1beta3 - pod portforward",
|
||||
version: "v1beta3",
|
||||
|
|
|
@ -43,7 +43,7 @@ func TestMerge(t *testing.T) {
|
|||
Name: "foo",
|
||||
},
|
||||
},
|
||||
fragment: `{ "apiVersion": "v1beta1" }`,
|
||||
fragment: `{ "apiVersion": "v1beta3" }`,
|
||||
expected: &api.Pod{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo",
|
||||
|
@ -94,25 +94,6 @@ func TestMerge(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}, */
|
||||
{
|
||||
kind: "Pod",
|
||||
obj: &api.Pod{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
fragment: `{ "apiVersion": "v1beta1", "id": "baz", "desiredState": { "host": "bar" } }`,
|
||||
expected: &api.Pod{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "baz",
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
NodeName: "bar",
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: "Pod",
|
||||
obj: &api.Pod{
|
||||
|
@ -148,24 +129,6 @@ func TestMerge(t *testing.T) {
|
|||
expected: &api.Pod{},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
kind: "Pod",
|
||||
obj: &api.Pod{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
fragment: `{ "apiVersion": "v1beta1", "id": null}`,
|
||||
expected: &api.Pod{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "",
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: "Service",
|
||||
obj: &api.Service{},
|
||||
|
@ -177,11 +140,17 @@ func TestMerge(t *testing.T) {
|
|||
obj: &api.Service{
|
||||
Spec: api.ServiceSpec{},
|
||||
},
|
||||
fragment: `{ "apiVersion": "v1beta1", "port": 0 }`,
|
||||
fragment: `{ "apiVersion": "v1beta3", "spec": { "ports": [ { "port": 0 } ] } }`,
|
||||
expected: &api.Service{
|
||||
Spec: api.ServiceSpec{
|
||||
SessionAffinity: "None",
|
||||
Type: api.ServiceTypeClusterIP,
|
||||
Ports: []api.ServicePort{
|
||||
{
|
||||
Protocol: api.ProtocolTCP,
|
||||
Port: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -194,7 +163,7 @@ func TestMerge(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
fragment: `{ "apiVersion": "v1beta1", "selector": { "version": "v2" } }`,
|
||||
fragment: `{ "apiVersion": "v1beta3", "spec": { "selector": { "version": "v2" } } }`,
|
||||
expected: &api.Service{
|
||||
Spec: api.ServiceSpec{
|
||||
SessionAffinity: "None",
|
||||
|
|
|
@ -24,14 +24,12 @@ import (
|
|||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
utilyaml "github.com/GoogleCloudPlatform/kubernetes/pkg/util/yaml"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
|
@ -144,68 +142,3 @@ func tryDecodePodList(data []byte, defaultFn defaultFunc) (parsed bool, pods api
|
|||
}
|
||||
return true, *newPods, err
|
||||
}
|
||||
|
||||
func tryDecodeSingleManifest(data []byte, defaultFn defaultFunc) (parsed bool, manifest v1beta1.ContainerManifest, pod *api.Pod, err error) {
|
||||
// TODO: should be api.Scheme.Decode
|
||||
// This is awful. DecodeInto() expects to find an APIObject, which
|
||||
// Manifest is not. We keep reading manifest for now for compat, but
|
||||
// we will eventually change it to read Pod (at which point this all
|
||||
// becomes nicer). Until then, we assert that the ContainerManifest
|
||||
// structure on disk is always v1beta1. Read that, convert it to a
|
||||
// "current" ContainerManifest (should be ~identical), then convert
|
||||
// that to a Pod (which is a well-understood conversion). This
|
||||
// avoids writing a v1beta1.ContainerManifest -> api.Pod
|
||||
// conversion which would be identical to the api.ContainerManifest ->
|
||||
// api.Pod conversion.
|
||||
pod = new(api.Pod)
|
||||
if err = yaml.Unmarshal(data, &manifest); err != nil {
|
||||
return false, manifest, pod, err
|
||||
}
|
||||
newManifest := api.ContainerManifest{}
|
||||
if err = api.Scheme.Convert(&manifest, &newManifest); err != nil {
|
||||
return false, manifest, pod, err
|
||||
}
|
||||
if errs := validation.ValidateManifest(&newManifest); len(errs) > 0 {
|
||||
err = fmt.Errorf("invalid manifest: %v", errs)
|
||||
return false, manifest, pod, err
|
||||
}
|
||||
if err = api.Scheme.Convert(&newManifest, pod); err != nil {
|
||||
return true, manifest, pod, err
|
||||
}
|
||||
if err := defaultFn(pod); err != nil {
|
||||
return true, manifest, pod, err
|
||||
}
|
||||
// Success.
|
||||
return true, manifest, pod, nil
|
||||
}
|
||||
|
||||
func tryDecodeManifestList(data []byte, defaultFn defaultFunc) (parsed bool, manifests []v1beta1.ContainerManifest, pods api.PodList, err error) {
|
||||
// TODO: should be api.Scheme.Decode
|
||||
// See the comment in tryDecodeSingle().
|
||||
if err = yaml.Unmarshal(data, &manifests); err != nil {
|
||||
return false, manifests, pods, err
|
||||
}
|
||||
newManifests := []api.ContainerManifest{}
|
||||
if err = api.Scheme.Convert(&manifests, &newManifests); err != nil {
|
||||
return false, manifests, pods, err
|
||||
}
|
||||
for i := range newManifests {
|
||||
manifest := &newManifests[i]
|
||||
if errs := validation.ValidateManifest(manifest); len(errs) > 0 {
|
||||
err = fmt.Errorf("invalid manifest: %v", errs)
|
||||
return false, manifests, pods, err
|
||||
}
|
||||
}
|
||||
list := api.ContainerManifestList{Items: newManifests}
|
||||
if err = api.Scheme.Convert(&list, &pods); err != nil {
|
||||
return true, manifests, pods, err
|
||||
}
|
||||
for i := range pods.Items {
|
||||
pod := &pods.Items[i]
|
||||
if err := defaultFn(pod); err != nil {
|
||||
return true, manifests, pods, err
|
||||
}
|
||||
}
|
||||
// Success.
|
||||
return true, manifests, pods, nil
|
||||
}
|
||||
|
|
|
@ -148,15 +148,6 @@ func (s *sourceFile) extractFromFile(filename string) (pod *api.Pod, err error)
|
|||
return s.applyDefaults(pod, filename)
|
||||
}
|
||||
|
||||
parsed, _, pod, manifestErr := tryDecodeSingleManifest(data, defaultFn)
|
||||
if parsed {
|
||||
if manifestErr != nil {
|
||||
// It parsed but could not be used.
|
||||
return pod, manifestErr
|
||||
}
|
||||
return pod, nil
|
||||
}
|
||||
|
||||
parsed, pod, podErr := tryDecodeSinglePod(data, defaultFn)
|
||||
if parsed {
|
||||
if podErr != nil {
|
||||
|
@ -165,7 +156,6 @@ func (s *sourceFile) extractFromFile(filename string) (pod *api.Pod, err error)
|
|||
return pod, nil
|
||||
}
|
||||
|
||||
return pod, fmt.Errorf("%v: read '%v', but couldn't parse as neither "+
|
||||
"manifest (%v) nor pod (%v).\n",
|
||||
filename, string(data), manifestErr, podErr)
|
||||
return pod, fmt.Errorf("%v: read '%v', but couldn't parse as pod(%v).\n",
|
||||
filename, string(data), podErr)
|
||||
}
|
||||
|
|
|
@ -17,22 +17,18 @@ limitations under the License.
|
|||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/securitycontext"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
||||
)
|
||||
|
||||
func TestExtractFromNonExistentFile(t *testing.T) {
|
||||
|
@ -339,111 +335,3 @@ func TestExtractFromEmptyDir(t *testing.T) {
|
|||
t.Errorf("Expected %#v, Got %#v", expected, update)
|
||||
}
|
||||
}
|
||||
|
||||
func exampleManifestAndPod(id string) (v1beta1.ContainerManifest, *api.Pod) {
|
||||
hostname := "an-example-host"
|
||||
|
||||
manifest := v1beta1.ContainerManifest{
|
||||
Version: "v1beta1",
|
||||
ID: id,
|
||||
UUID: types.UID(id),
|
||||
Containers: []v1beta1.Container{
|
||||
{
|
||||
Name: "c" + id,
|
||||
Image: "foo",
|
||||
TerminationMessagePath: "/somepath",
|
||||
},
|
||||
},
|
||||
Volumes: []v1beta1.Volume{
|
||||
{
|
||||
Name: "host-dir",
|
||||
Source: v1beta1.VolumeSource{
|
||||
HostDir: &v1beta1.HostPathVolumeSource{"/dir/path"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
expectedPod := &api.Pod{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: id + "-" + hostname,
|
||||
UID: types.UID(id),
|
||||
Namespace: kubelet.NamespaceDefault,
|
||||
SelfLink: getSelfLink(id+"-"+hostname, kubelet.NamespaceDefault),
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
NodeName: hostname,
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "c" + id,
|
||||
Image: "foo",
|
||||
},
|
||||
},
|
||||
Volumes: []api.Volume{
|
||||
{
|
||||
Name: "host-dir",
|
||||
VolumeSource: api.VolumeSource{
|
||||
HostPath: &api.HostPathVolumeSource{"/dir/path"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return manifest, expectedPod
|
||||
}
|
||||
|
||||
func TestExtractFromDir(t *testing.T) {
|
||||
if !api.PreV1Beta3(testapi.Version()) {
|
||||
return
|
||||
}
|
||||
manifest, expectedPod := exampleManifestAndPod("1")
|
||||
manifest2, expectedPod2 := exampleManifestAndPod("2")
|
||||
|
||||
manifests := []v1beta1.ContainerManifest{manifest, manifest2}
|
||||
pods := []*api.Pod{expectedPod, expectedPod2}
|
||||
files := make([]*os.File, len(manifests))
|
||||
|
||||
dirName, err := ioutil.TempDir("", "foo")
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
for i, manifest := range manifests {
|
||||
data, err := json.Marshal(manifest)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
continue
|
||||
}
|
||||
file, err := ioutil.TempFile(dirName, manifest.ID)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
continue
|
||||
}
|
||||
name := file.Name()
|
||||
if err := file.Close(); err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
continue
|
||||
}
|
||||
ioutil.WriteFile(name, data, 0755)
|
||||
files[i] = file
|
||||
}
|
||||
|
||||
ch := make(chan interface{}, 1)
|
||||
c := sourceFile{dirName, "an-example-host", ch}
|
||||
err = c.extractFromPath()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
update := (<-ch).(kubelet.PodUpdate)
|
||||
expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, pods...)
|
||||
sort.Sort(sortedPods(update.Pods))
|
||||
sort.Sort(sortedPods(expected.Pods))
|
||||
if !api.Semantic.DeepDerivative(expected, update) {
|
||||
t.Fatalf("Expected %#v, Got %#v", expected, update)
|
||||
}
|
||||
for _, pod := range update.Pods {
|
||||
if errs := validation.ValidatePod(pod); len(errs) != 0 {
|
||||
t.Errorf("Expected no validation errors on %#v, Got %q", pod, errs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,50 +77,12 @@ func (s *sourceURL) extractFromURL() error {
|
|||
s.updates <- kubelet.PodUpdate{[]*api.Pod{}, kubelet.SET, kubelet.HTTPSource}
|
||||
return fmt.Errorf("zero-length data received from %v", s.url)
|
||||
}
|
||||
// Short circuit if the manifest has not changed since the last time it was read.
|
||||
// Short circuit if the data has not changed since the last time it was read.
|
||||
if bytes.Compare(data, s.data) == 0 {
|
||||
return nil
|
||||
}
|
||||
s.data = data
|
||||
|
||||
// First try as if it's a single manifest
|
||||
parsed, manifest, pod, singleErr := tryDecodeSingleManifest(data, s.applyDefaults)
|
||||
if parsed {
|
||||
if singleErr != nil {
|
||||
// It parsed but could not be used.
|
||||
return singleErr
|
||||
}
|
||||
// It parsed!
|
||||
s.updates <- kubelet.PodUpdate{[]*api.Pod{pod}, kubelet.SET, kubelet.HTTPSource}
|
||||
return nil
|
||||
}
|
||||
|
||||
// That didn't work, so try an array of manifests.
|
||||
parsed, manifests, podList, multiErr := tryDecodeManifestList(data, s.applyDefaults)
|
||||
if parsed {
|
||||
if multiErr != nil {
|
||||
// It parsed but could not be used.
|
||||
return multiErr
|
||||
}
|
||||
// A single manifest that did not pass semantic validation will yield an empty
|
||||
// array of manifests (and no error) when unmarshaled as such. In that case,
|
||||
// if the single manifest at least had a Version, we return the single-manifest
|
||||
// error (if any).
|
||||
if len(manifests) == 0 && len(manifest.Version) != 0 {
|
||||
return singleErr
|
||||
}
|
||||
// It parsed!
|
||||
pods := make([]*api.Pod, 0)
|
||||
for i := range podList.Items {
|
||||
pods = append(pods, &podList.Items[i])
|
||||
}
|
||||
s.updates <- kubelet.PodUpdate{pods, kubelet.SET, kubelet.HTTPSource}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parsing it as ContainerManifest(s) failed.
|
||||
// Try to parse it as Pod(s).
|
||||
|
||||
// First try as it is a single pod.
|
||||
parsed, pod, singlePodErr := tryDecodeSinglePod(data, s.applyDefaults)
|
||||
if parsed {
|
||||
|
@ -147,9 +109,7 @@ func (s *sourceURL) extractFromURL() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("%v: received '%v', but couldn't parse as neither "+
|
||||
"single (%v: %+v) or multiple manifests (%v: %+v) nor "+
|
||||
return fmt.Errorf("%v: received '%v', but couldn't parse as "+
|
||||
"single (%v) or multiple pods (%v).\n",
|
||||
s.url, string(data), singleErr, manifest, multiErr, manifests,
|
||||
singlePodErr, multiPodErr)
|
||||
s.url, string(data), singlePodErr, multiPodErr)
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import (
|
|||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
|
@ -118,195 +117,6 @@ func TestExtractInvalidManifest(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestExtractManifestFromHTTP(t *testing.T) {
|
||||
hostname := "random-hostname"
|
||||
// ContainerManifests are not supported v1beta3 onwards.
|
||||
if api.PreV1Beta3(testapi.Version()) {
|
||||
return
|
||||
}
|
||||
|
||||
var testCases = []struct {
|
||||
desc string
|
||||
manifests interface{}
|
||||
expected kubelet.PodUpdate
|
||||
}{
|
||||
{
|
||||
desc: "Single manifest",
|
||||
manifests: v1beta1.ContainerManifest{Version: "v1beta1", ID: "foo", UUID: "111",
|
||||
Containers: []v1beta1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1beta1.PullAlways}}},
|
||||
expected: CreatePodUpdate(kubelet.SET,
|
||||
kubelet.HTTPSource,
|
||||
&api.Pod{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
UID: "111",
|
||||
Name: "foo" + "-" + hostname,
|
||||
Namespace: "foobar",
|
||||
|
||||
SelfLink: getSelfLink("foo-"+hostname, kubelet.NamespaceDefault),
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
NodeName: hostname,
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{
|
||||
Name: "1",
|
||||
Image: "foo",
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
ImagePullPolicy: "Always",
|
||||
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
desc: "Single manifest without ID",
|
||||
manifests: v1beta1.ContainerManifest{Version: "v1beta1", UUID: "111",
|
||||
Containers: []v1beta1.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}},
|
||||
expected: CreatePodUpdate(kubelet.SET,
|
||||
kubelet.HTTPSource,
|
||||
&api.Pod{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
UID: "111",
|
||||
Name: "111" + "-" + hostname,
|
||||
Namespace: "foobar",
|
||||
|
||||
SelfLink: getSelfLink("111-"+hostname, kubelet.NamespaceDefault),
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
NodeName: hostname,
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{
|
||||
Name: "ctr",
|
||||
Image: "image",
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
desc: "Single manifest with v1beta2",
|
||||
manifests: v1beta1.ContainerManifest{Version: "v1beta2", ID: "foo", UUID: "111",
|
||||
Containers: []v1beta1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1beta1.PullAlways}}},
|
||||
expected: CreatePodUpdate(kubelet.SET,
|
||||
kubelet.HTTPSource,
|
||||
&api.Pod{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
UID: "111",
|
||||
Name: "foo" + "-" + hostname,
|
||||
Namespace: "foobar",
|
||||
|
||||
SelfLink: getSelfLink("foo-"+hostname, kubelet.NamespaceDefault),
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
NodeName: hostname,
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{
|
||||
Name: "1",
|
||||
Image: "foo",
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
ImagePullPolicy: "Always",
|
||||
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
desc: "Multiple manifests",
|
||||
manifests: []v1beta1.ContainerManifest{
|
||||
{Version: "v1beta1", ID: "foo", UUID: "111",
|
||||
Containers: []v1beta1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1beta1.PullAlways}}},
|
||||
{Version: "v1beta1", ID: "bar", UUID: "222",
|
||||
Containers: []v1beta1.Container{{Name: "1", Image: "foo", ImagePullPolicy: ""}}},
|
||||
},
|
||||
expected: CreatePodUpdate(kubelet.SET,
|
||||
kubelet.HTTPSource,
|
||||
&api.Pod{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
UID: "111",
|
||||
Name: "foo" + "-" + hostname,
|
||||
Namespace: "foobar",
|
||||
|
||||
SelfLink: getSelfLink("foo-"+hostname, kubelet.NamespaceDefault),
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
NodeName: hostname,
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{
|
||||
Name: "1",
|
||||
Image: "foo",
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
ImagePullPolicy: "Always",
|
||||
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
|
||||
},
|
||||
},
|
||||
&api.Pod{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
UID: "222",
|
||||
Name: "bar" + "-" + hostname,
|
||||
Namespace: "foobar",
|
||||
|
||||
SelfLink: getSelfLink("bar-"+hostname, kubelet.NamespaceDefault),
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
NodeName: hostname,
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{
|
||||
Name: "1",
|
||||
Image: "foo",
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
ImagePullPolicy: "IfNotPresent",
|
||||
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
desc: "Empty Array",
|
||||
manifests: []v1beta1.ContainerManifest{},
|
||||
expected: CreatePodUpdate(kubelet.SET, kubelet.HTTPSource),
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
data, err := json.Marshal(testCase.manifests)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: Some weird json problem: %v", testCase.desc, err)
|
||||
}
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(data),
|
||||
}
|
||||
testServer := httptest.NewServer(&fakeHandler)
|
||||
defer testServer.Close()
|
||||
ch := make(chan interface{}, 1)
|
||||
c := sourceURL{testServer.URL, hostname, ch, nil}
|
||||
if err := c.extractFromURL(); err != nil {
|
||||
t.Errorf("%s: Unexpected error: %v", testCase.desc, err)
|
||||
continue
|
||||
}
|
||||
update := (<-ch).(kubelet.PodUpdate)
|
||||
|
||||
for i := range update.Pods {
|
||||
// There's no way to provide namespace in ContainerManifest, so
|
||||
// it will be defaulted.
|
||||
if update.Pods[i].Namespace != kubelet.NamespaceDefault {
|
||||
t.Errorf("Unexpected namespace: %s", update.Pods[0].Namespace)
|
||||
}
|
||||
update.Pods[i].ObjectMeta.Namespace = "foobar"
|
||||
}
|
||||
if !api.Semantic.DeepEqual(testCase.expected, update) {
|
||||
t.Errorf("%s: Expected: %#v, Got: %#v", testCase.desc, testCase.expected, update)
|
||||
}
|
||||
for _, pod := range update.Pods {
|
||||
if errs := validation.ValidatePod(pod); len(errs) != 0 {
|
||||
t.Errorf("%s: Expected no validation errors on %#v, Got %v", testCase.desc, pod, errors.NewAggregate(errs))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractPodsFromHTTP(t *testing.T) {
|
||||
hostname := "different-value"
|
||||
|
||||
|
|
|
@ -33,8 +33,6 @@ import (
|
|||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authenticator"
|
||||
|
@ -91,10 +89,6 @@ type Config struct {
|
|||
EnableUISupport bool
|
||||
// allow downstream consumers to disable swagger
|
||||
EnableSwaggerSupport bool
|
||||
// allow v1beta1 to be conditionally disabled
|
||||
DisableV1Beta1 bool
|
||||
// allow v1beta2 to be conditionally disabled
|
||||
DisableV1Beta2 bool
|
||||
// allow v1beta3 to be conditionally disabled
|
||||
DisableV1Beta3 bool
|
||||
// allow v1 to be conditionally enabled
|
||||
|
@ -170,8 +164,6 @@ type Master struct {
|
|||
authorizer authorizer.Authorizer
|
||||
admissionControl admission.Interface
|
||||
masterCount int
|
||||
v1beta1 bool
|
||||
v1beta2 bool
|
||||
v1beta3 bool
|
||||
v1 bool
|
||||
requestContextMapper api.RequestContextMapper
|
||||
|
@ -328,8 +320,6 @@ func New(c *Config) *Master {
|
|||
authenticator: c.Authenticator,
|
||||
authorizer: c.Authorizer,
|
||||
admissionControl: c.AdmissionControl,
|
||||
v1beta1: !c.DisableV1Beta1,
|
||||
v1beta2: !c.DisableV1Beta2,
|
||||
v1beta3: !c.DisableV1Beta3,
|
||||
v1: c.EnableV1,
|
||||
requestContextMapper: c.RequestContextMapper,
|
||||
|
@ -501,18 +491,6 @@ func (m *Master) init(c *Config) {
|
|||
}
|
||||
|
||||
apiVersions := []string{}
|
||||
if m.v1beta1 {
|
||||
if err := m.api_v1beta1().InstallREST(m.handlerContainer); err != nil {
|
||||
glog.Fatalf("Unable to setup API v1beta1: %v", err)
|
||||
}
|
||||
apiVersions = append(apiVersions, "v1beta1")
|
||||
}
|
||||
if m.v1beta2 {
|
||||
if err := m.api_v1beta2().InstallREST(m.handlerContainer); err != nil {
|
||||
glog.Fatalf("Unable to setup API v1beta2: %v", err)
|
||||
}
|
||||
apiVersions = append(apiVersions, "v1beta2")
|
||||
}
|
||||
if m.v1beta3 {
|
||||
if err := m.api_v1beta3().InstallREST(m.handlerContainer); err != nil {
|
||||
glog.Fatalf("Unable to setup API v1beta3: %v", err)
|
||||
|
@ -718,38 +696,6 @@ func (m *Master) defaultAPIGroupVersion() *apiserver.APIGroupVersion {
|
|||
}
|
||||
}
|
||||
|
||||
// api_v1beta1 returns the resources and codec for API version v1beta1.
|
||||
func (m *Master) api_v1beta1() *apiserver.APIGroupVersion {
|
||||
storage := make(map[string]rest.Storage)
|
||||
for k, v := range m.storage {
|
||||
if k == "podTemplates" {
|
||||
continue
|
||||
}
|
||||
storage[k] = v
|
||||
}
|
||||
version := m.defaultAPIGroupVersion()
|
||||
version.Storage = storage
|
||||
version.Version = "v1beta1"
|
||||
version.Codec = v1beta1.Codec
|
||||
return version
|
||||
}
|
||||
|
||||
// api_v1beta2 returns the resources and codec for API version v1beta2.
|
||||
func (m *Master) api_v1beta2() *apiserver.APIGroupVersion {
|
||||
storage := make(map[string]rest.Storage)
|
||||
for k, v := range m.storage {
|
||||
if k == "podTemplates" {
|
||||
continue
|
||||
}
|
||||
storage[k] = v
|
||||
}
|
||||
version := m.defaultAPIGroupVersion()
|
||||
version.Storage = storage
|
||||
version.Version = "v1beta2"
|
||||
version.Codec = v1beta2.Codec
|
||||
return version
|
||||
}
|
||||
|
||||
// api_v1beta3 returns the resources and codec for API version v1beta3.
|
||||
func (m *Master) api_v1beta3() *apiserver.APIGroupVersion {
|
||||
storage := make(map[string]rest.Storage)
|
||||
|
|
|
@ -24,8 +24,6 @@ import (
|
|||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/endpoints"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/controller/framework"
|
||||
|
@ -302,12 +300,6 @@ func (e *EndpointController) syncService(key string) {
|
|||
for i := range service.Spec.Ports {
|
||||
servicePort := &service.Spec.Ports[i]
|
||||
|
||||
// TODO: Once v1beta1 and v1beta2 are EOL'ed,
|
||||
// this can safely assume that TargetPort is
|
||||
// populated, and findPort() can be removed.
|
||||
_ = v1beta1.Dependency
|
||||
_ = v1beta2.Dependency
|
||||
|
||||
portName := servicePort.Name
|
||||
portProto := servicePort.Protocol
|
||||
portNum, err := findPort(pod, servicePort)
|
||||
|
@ -398,32 +390,14 @@ func (e *EndpointController) checkLeftoverEndpoints() {
|
|||
}
|
||||
}
|
||||
|
||||
func findDefaultPort(pod *api.Pod, servicePort int, proto api.Protocol) int {
|
||||
for _, container := range pod.Spec.Containers {
|
||||
for _, port := range container.Ports {
|
||||
if port.Protocol == proto {
|
||||
return port.ContainerPort
|
||||
}
|
||||
}
|
||||
}
|
||||
return servicePort
|
||||
}
|
||||
|
||||
// findPort locates the container port for the given manifest and portName.
|
||||
// If the targetPort is a non-zero number, use that. If the targetPort is 0 or
|
||||
// not specified, use the first defined port with the same protocol. If no port
|
||||
// is defined, use the service's port. If the targetPort is an empty string use
|
||||
// the first defined port with the same protocol. If no port is defined, use
|
||||
// the service's port. If the targetPort is a non-empty string, look that
|
||||
// findPort locates the container port for the given pod and portName. If the
|
||||
// targetPort is a number, use that. If the targetPort is a string, look that
|
||||
// string up in all named ports in all containers in the target pod. If no
|
||||
// match is found, fail.
|
||||
func findPort(pod *api.Pod, svcPort *api.ServicePort) (int, error) {
|
||||
portName := svcPort.TargetPort
|
||||
switch portName.Kind {
|
||||
case util.IntstrString:
|
||||
if len(portName.StrVal) == 0 {
|
||||
return findDefaultPort(pod, svcPort.Port, svcPort.Protocol), nil
|
||||
}
|
||||
name := portName.StrVal
|
||||
for _, container := range pod.Spec.Containers {
|
||||
for _, port := range container.Ports {
|
||||
|
@ -433,9 +407,6 @@ func findPort(pod *api.Pod, svcPort *api.ServicePort) (int, error) {
|
|||
}
|
||||
}
|
||||
case util.IntstrInt:
|
||||
if portName.IntVal == 0 {
|
||||
return findDefaultPort(pod, svcPort.Port, svcPort.Protocol), nil
|
||||
}
|
||||
return portName.IntVal, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,6 @@ func addPods(store cache.Store, namespace string, nPods int, nPorts int) {
|
|||
}
|
||||
|
||||
func TestFindPort(t *testing.T) {
|
||||
servicePort := 999
|
||||
testCases := []struct {
|
||||
name string
|
||||
containers []api.Container
|
||||
|
@ -90,74 +89,6 @@ func TestFindPort(t *testing.T) {
|
|||
port: util.NewIntOrStringFromInt(93),
|
||||
expected: 93,
|
||||
pass: true,
|
||||
}, {
|
||||
name: "zero int, no ports",
|
||||
containers: []api.Container{{}},
|
||||
port: util.NewIntOrStringFromInt(0),
|
||||
expected: servicePort,
|
||||
pass: true,
|
||||
}, {
|
||||
name: "zero int, one ctr with ports",
|
||||
containers: []api.Container{{Ports: []api.ContainerPort{{
|
||||
Name: "",
|
||||
ContainerPort: 11,
|
||||
Protocol: "UDP",
|
||||
}, {
|
||||
Name: "p",
|
||||
ContainerPort: 22,
|
||||
Protocol: "TCP",
|
||||
}}}},
|
||||
port: util.NewIntOrStringFromInt(0),
|
||||
expected: 22,
|
||||
pass: true,
|
||||
}, {
|
||||
name: "zero int, two ctr with ports",
|
||||
containers: []api.Container{{}, {Ports: []api.ContainerPort{{
|
||||
Name: "",
|
||||
ContainerPort: 11,
|
||||
Protocol: "UDP",
|
||||
}, {
|
||||
Name: "p",
|
||||
ContainerPort: 22,
|
||||
Protocol: "TCP",
|
||||
}}}},
|
||||
port: util.NewIntOrStringFromInt(0),
|
||||
expected: 22,
|
||||
pass: true,
|
||||
}, {
|
||||
name: "empty str, no ports",
|
||||
containers: []api.Container{{}},
|
||||
port: util.NewIntOrStringFromString(""),
|
||||
expected: servicePort,
|
||||
pass: true,
|
||||
}, {
|
||||
name: "empty str, one ctr with ports",
|
||||
containers: []api.Container{{Ports: []api.ContainerPort{{
|
||||
Name: "",
|
||||
ContainerPort: 11,
|
||||
Protocol: "UDP",
|
||||
}, {
|
||||
Name: "p",
|
||||
ContainerPort: 22,
|
||||
Protocol: "TCP",
|
||||
}}}},
|
||||
port: util.NewIntOrStringFromString(""),
|
||||
expected: 22,
|
||||
pass: true,
|
||||
}, {
|
||||
name: "empty str, two ctr with ports",
|
||||
containers: []api.Container{{}, {Ports: []api.ContainerPort{{
|
||||
Name: "",
|
||||
ContainerPort: 11,
|
||||
Protocol: "UDP",
|
||||
}, {
|
||||
Name: "p",
|
||||
ContainerPort: 22,
|
||||
Protocol: "TCP",
|
||||
}}}},
|
||||
port: util.NewIntOrStringFromString(""),
|
||||
expected: 22,
|
||||
pass: true,
|
||||
}, {
|
||||
name: "valid str, no ports",
|
||||
containers: []api.Container{{}},
|
||||
|
@ -204,7 +135,7 @@ func TestFindPort(t *testing.T) {
|
|||
|
||||
for _, tc := range testCases {
|
||||
port, err := findPort(&api.Pod{Spec: api.PodSpec{Containers: tc.containers}},
|
||||
&api.ServicePort{Protocol: "TCP", Port: servicePort, TargetPort: tc.port})
|
||||
&api.ServicePort{Protocol: "TCP", TargetPort: tc.port})
|
||||
if err != nil && tc.pass {
|
||||
t.Errorf("unexpected error for %s: %v", tc.name, err)
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ matrix:
|
|||
include:
|
||||
- go: 1.4
|
||||
env:
|
||||
- KUBE_TEST_API_VERSIONS=v1beta1 KUBE_TEST_ETCD_PREFIXES=registry
|
||||
- KUBE_TEST_API_VERSIONS=v1beta3 KUBE_TEST_ETCD_PREFIXES=registry
|
||||
- go: 1.3
|
||||
env:
|
||||
- KUBE_TEST_API_VERSIONS=v1beta3 KUBE_TEST_ETCD_PREFIXES=kubernetes.io/registry
|
||||
|
|
Loading…
Reference in New Issue