mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 04:33:26 +00:00
Factor out API defaulting from validation logic
Currently, the validation logic validates fields in an object and supply default values wherever applies. This change factors out defaulting to a set of defaulting callback functions for decoding (see #1502 for more discussion). * This change is based on pull request 2587. * Most defaulting has been migrated to defaults.go where the defaulting functions are added. * validation_test.go and converter_test.go have been adapted to not testing the default values. * Fixed all tests with that create invalid objects with the absence of defaulting logic.
This commit is contained in:
parent
1ddb68d8d7
commit
4a72addaeb
@ -319,6 +319,8 @@ func runSelfLinkTest(c *client.Client) {
|
|||||||
Selector: map[string]string{
|
Selector: map[string]string{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
},
|
},
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
).Do().Into(&svc)
|
).Do().Into(&svc)
|
||||||
@ -381,6 +383,8 @@ func runAtomicPutTest(c *client.Client) {
|
|||||||
Selector: map[string]string{
|
Selector: map[string]string{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
},
|
},
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
).Do().Into(&svc)
|
).Do().Into(&svc)
|
||||||
@ -521,8 +525,11 @@ func runServiceTest(client *client.Client) {
|
|||||||
Ports: []api.Port{
|
Ports: []api.Port{
|
||||||
{ContainerPort: 1234},
|
{ContainerPort: 1234},
|
||||||
},
|
},
|
||||||
|
ImagePullPolicy: "PullIfNotPresent",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
Status: api.PodStatus{
|
Status: api.PodStatus{
|
||||||
PodIP: "1.2.3.4",
|
PodIP: "1.2.3.4",
|
||||||
@ -541,7 +548,9 @@ func runServiceTest(client *client.Client) {
|
|||||||
Selector: map[string]string{
|
Selector: map[string]string{
|
||||||
"name": "thisisalonglabel",
|
"name": "thisisalonglabel",
|
||||||
},
|
},
|
||||||
Port: 8080,
|
Port: 8080,
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err = client.Services(api.NamespaceDefault).Create(&svc1)
|
_, err = client.Services(api.NamespaceDefault).Create(&svc1)
|
||||||
@ -558,7 +567,9 @@ func runServiceTest(client *client.Client) {
|
|||||||
Selector: map[string]string{
|
Selector: map[string]string{
|
||||||
"name": "thisisalonglabel",
|
"name": "thisisalonglabel",
|
||||||
},
|
},
|
||||||
Port: 8080,
|
Port: 8080,
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err = client.Services(api.NamespaceDefault).Create(&svc2)
|
_, err = client.Services(api.NamespaceDefault).Create(&svc2)
|
||||||
|
@ -47,14 +47,6 @@ func init() {
|
|||||||
out.Spec.DNSPolicy = in.DNSPolicy
|
out.Spec.DNSPolicy = in.DNSPolicy
|
||||||
out.Name = in.ID
|
out.Name = in.ID
|
||||||
out.UID = in.UUID
|
out.UID = in.UUID
|
||||||
// TODO(dchen1107): Move this conversion to pkg/api/v1beta[123]/conversion.go
|
|
||||||
// along with fixing #1502
|
|
||||||
for i := range out.Spec.Containers {
|
|
||||||
ctr := &out.Spec.Containers[i]
|
|
||||||
if len(ctr.TerminationMessagePath) == 0 {
|
|
||||||
ctr.TerminationMessagePath = TerminationMessagePathDefault
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
func(in *BoundPod, out *ContainerManifest, s conversion.Scope) error {
|
func(in *BoundPod, out *ContainerManifest, s conversion.Scope) error {
|
||||||
@ -65,12 +57,6 @@ func init() {
|
|||||||
out.Version = "v1beta2"
|
out.Version = "v1beta2"
|
||||||
out.ID = in.Name
|
out.ID = in.Name
|
||||||
out.UUID = in.UID
|
out.UUID = in.UID
|
||||||
for i := range out.Containers {
|
|
||||||
ctr := &out.Containers[i]
|
|
||||||
if len(ctr.TerminationMessagePath) == 0 {
|
|
||||||
ctr.TerminationMessagePath = TerminationMessagePathDefault
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -158,6 +158,10 @@ func TestEncode_Ptr(t *testing.T) {
|
|||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Labels: map[string]string{"name": "foo"},
|
Labels: map[string]string{"name": "foo"},
|
||||||
},
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
obj := runtime.Object(pod)
|
obj := runtime.Object(pod)
|
||||||
data, err := latest.Codec.Encode(obj)
|
data, err := latest.Codec.Encode(obj)
|
||||||
@ -169,7 +173,7 @@ func TestEncode_Ptr(t *testing.T) {
|
|||||||
t.Fatalf("Got wrong type")
|
t.Fatalf("Got wrong type")
|
||||||
}
|
}
|
||||||
if !api.Semantic.DeepEqual(obj2, pod) {
|
if !api.Semantic.DeepEqual(obj2, pod) {
|
||||||
t.Errorf("Expected:\n %#v,\n Got:\n %#v", &pod, obj2)
|
t.Errorf("Expected:\n %#v,\n Got:\n %#v", pod, obj2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,14 @@ import (
|
|||||||
"speter.net/go/exp/math/dec/inf"
|
"speter.net/go/exp/math/dec/inf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func fuzzOneOf(c fuzz.Continue, objs ...interface{}) {
|
||||||
|
// Use a new fuzzer which cannot populate nil to ensure one obj will be set.
|
||||||
|
// FIXME: would be nicer to use FuzzOnePtr() and reflect.
|
||||||
|
f := fuzz.New().NilChance(0).NumElements(1, 1)
|
||||||
|
i := c.RandUint64() % uint64(len(objs))
|
||||||
|
f.Fuzz(objs[i])
|
||||||
|
}
|
||||||
|
|
||||||
// FuzzerFor can randomly populate api objects that are destined for version.
|
// FuzzerFor can randomly populate api objects that are destined for version.
|
||||||
func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
|
func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
|
||||||
f := fuzz.New().NilChance(.5).NumElements(1, 1)
|
f := fuzz.New().NilChance(.5).NumElements(1, 1)
|
||||||
@ -84,15 +92,18 @@ func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
|
|||||||
statuses := []api.PodPhase{api.PodPending, api.PodRunning, api.PodFailed, api.PodUnknown}
|
statuses := []api.PodPhase{api.PodPending, api.PodRunning, api.PodFailed, api.PodUnknown}
|
||||||
*j = statuses[c.Rand.Intn(len(statuses))]
|
*j = statuses[c.Rand.Intn(len(statuses))]
|
||||||
},
|
},
|
||||||
|
func(j *api.PodTemplateSpec, c fuzz.Continue) {
|
||||||
|
// TODO: v1beta1/2 can't round trip a nil template correctly, fix by having v1beta1/2
|
||||||
|
// conversion compare converted object to nil via DeepEqual
|
||||||
|
j.ObjectMeta = api.ObjectMeta{}
|
||||||
|
c.Fuzz(&j.ObjectMeta)
|
||||||
|
j.ObjectMeta = api.ObjectMeta{Labels: j.ObjectMeta.Labels}
|
||||||
|
j.Spec = api.PodSpec{}
|
||||||
|
c.Fuzz(&j.Spec)
|
||||||
|
},
|
||||||
func(j *api.ReplicationControllerSpec, c fuzz.Continue) {
|
func(j *api.ReplicationControllerSpec, c fuzz.Continue) {
|
||||||
// TemplateRef must be nil for round trip
|
// TemplateRef is set to nil by omission; this is required for round trip
|
||||||
c.Fuzz(&j.Template)
|
c.Fuzz(&j.Template)
|
||||||
if j.Template == nil {
|
|
||||||
// TODO: v1beta1/2 can't round trip a nil template correctly, fix by having v1beta1/2
|
|
||||||
// conversion compare converted object to nil via DeepEqual
|
|
||||||
j.Template = &api.PodTemplateSpec{}
|
|
||||||
}
|
|
||||||
j.Template.ObjectMeta = api.ObjectMeta{Labels: j.Template.ObjectMeta.Labels}
|
|
||||||
c.Fuzz(&j.Selector)
|
c.Fuzz(&j.Selector)
|
||||||
j.Replicas = int(c.RandUint64())
|
j.Replicas = int(c.RandUint64())
|
||||||
},
|
},
|
||||||
@ -160,6 +171,46 @@ func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
|
|||||||
policies := []api.PullPolicy{api.PullAlways, api.PullNever, api.PullIfNotPresent}
|
policies := []api.PullPolicy{api.PullAlways, api.PullNever, api.PullIfNotPresent}
|
||||||
*p = policies[c.Rand.Intn(len(policies))]
|
*p = policies[c.Rand.Intn(len(policies))]
|
||||||
},
|
},
|
||||||
|
func(rp *api.RestartPolicy, c fuzz.Continue) {
|
||||||
|
// Exactly one of the fields should be set.
|
||||||
|
fuzzOneOf(c, &rp.Always, &rp.OnFailure, &rp.Never)
|
||||||
|
},
|
||||||
|
func(vs *api.VolumeSource, c fuzz.Continue) {
|
||||||
|
// Exactly one of the fields should be set.
|
||||||
|
//FIXME: the fuzz can still end up nil. What if fuzz allowed me to say that?
|
||||||
|
fuzzOneOf(c, &vs.HostPath, &vs.EmptyDir, &vs.GCEPersistentDisk, &vs.GitRepo)
|
||||||
|
},
|
||||||
|
func(d *api.DNSPolicy, c fuzz.Continue) {
|
||||||
|
policies := []api.DNSPolicy{api.DNSClusterFirst, api.DNSDefault}
|
||||||
|
*d = policies[c.Rand.Intn(len(policies))]
|
||||||
|
},
|
||||||
|
func(p *api.Protocol, c fuzz.Continue) {
|
||||||
|
protocols := []api.Protocol{api.ProtocolTCP, api.ProtocolUDP}
|
||||||
|
*p = protocols[c.Rand.Intn(len(protocols))]
|
||||||
|
},
|
||||||
|
func(p *api.AffinityType, c fuzz.Continue) {
|
||||||
|
types := []api.AffinityType{api.AffinityTypeClientIP, api.AffinityTypeNone}
|
||||||
|
*p = types[c.Rand.Intn(len(types))]
|
||||||
|
},
|
||||||
|
func(ct *api.Container, c fuzz.Continue) {
|
||||||
|
// This function exists soley to set TerminationMessagePath to a
|
||||||
|
// non-empty string. TODO: consider making TerminationMessagePath a
|
||||||
|
// new type to simplify fuzzing.
|
||||||
|
ct.TerminationMessagePath = api.TerminationMessagePathDefault
|
||||||
|
// Let fuzzer handle the rest of the fileds.
|
||||||
|
c.Fuzz(&ct.Name)
|
||||||
|
c.Fuzz(&ct.Image)
|
||||||
|
c.Fuzz(&ct.Command)
|
||||||
|
c.Fuzz(&ct.Ports)
|
||||||
|
c.Fuzz(&ct.WorkingDir)
|
||||||
|
c.Fuzz(&ct.Env)
|
||||||
|
c.Fuzz(&ct.VolumeMounts)
|
||||||
|
c.Fuzz(&ct.LivenessProbe)
|
||||||
|
c.Fuzz(&ct.Lifecycle)
|
||||||
|
c.Fuzz(&ct.ImagePullPolicy)
|
||||||
|
c.Fuzz(&ct.Privileged)
|
||||||
|
c.Fuzz(&ct.Capabilities)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,8 @@ limitations under the License.
|
|||||||
package v1beta1
|
package v1beta1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
@ -24,8 +26,8 @@ import (
|
|||||||
func init() {
|
func init() {
|
||||||
api.Scheme.AddDefaultingFuncs(
|
api.Scheme.AddDefaultingFuncs(
|
||||||
func(obj *Volume) {
|
func(obj *Volume) {
|
||||||
if obj.Source == nil || util.AllPtrFieldsNil(obj.Source) {
|
if util.AllPtrFieldsNil(&obj.Source) {
|
||||||
obj.Source = &VolumeSource{
|
obj.Source = VolumeSource{
|
||||||
EmptyDir: &EmptyDir{},
|
EmptyDir: &EmptyDir{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,13 +38,18 @@ func init() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
func(obj *Container) {
|
func(obj *Container) {
|
||||||
// TODO: delete helper functions that touch this
|
|
||||||
if obj.ImagePullPolicy == "" {
|
if obj.ImagePullPolicy == "" {
|
||||||
obj.ImagePullPolicy = PullIfNotPresent
|
// 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 == "" {
|
if obj.TerminationMessagePath == "" {
|
||||||
// TODO: fix other code that sets this
|
obj.TerminationMessagePath = TerminationMessagePathDefault
|
||||||
obj.TerminationMessagePath = api.TerminationMessagePathDefault
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
func(obj *RestartPolicy) {
|
func(obj *RestartPolicy) {
|
||||||
@ -54,8 +61,19 @@ func init() {
|
|||||||
if obj.Protocol == "" {
|
if obj.Protocol == "" {
|
||||||
obj.Protocol = ProtocolTCP
|
obj.Protocol = ProtocolTCP
|
||||||
}
|
}
|
||||||
|
if obj.SessionAffinity == "" {
|
||||||
|
obj.SessionAffinity = AffinityTypeNone
|
||||||
|
}
|
||||||
|
},
|
||||||
|
func(obj *PodSpec) {
|
||||||
|
if obj.DNSPolicy == "" {
|
||||||
|
obj.DNSPolicy = DNSClusterFirst
|
||||||
|
}
|
||||||
|
},
|
||||||
|
func(obj *ContainerManifest) {
|
||||||
|
if obj.DNSPolicy == "" {
|
||||||
|
obj.DNSPolicy = DNSClusterFirst
|
||||||
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove redundant code in validation and conversion
|
|
||||||
|
65
pkg/api/v1beta1/defaults_test.go
Normal file
65
pkg/api/v1beta1/defaults_test.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 Google Inc. 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"
|
||||||
|
|
||||||
|
current "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
|
||||||
|
data, err := current.Codec.Encode(obj)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v\n %#v", err, obj)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
obj2 := reflect.New(reflect.TypeOf(obj).Elem()).Interface().(runtime.Object)
|
||||||
|
err = current.Codec.DecodeInto(data, obj2)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), obj)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return obj2
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetDefaultService(t *testing.T) {
|
||||||
|
svc := ¤t.Service{}
|
||||||
|
obj2 := roundTrip(t, runtime.Object(svc))
|
||||||
|
svc2 := obj2.(*current.Service)
|
||||||
|
if svc2.Protocol != current.ProtocolTCP {
|
||||||
|
t.Errorf("Expected default protocol :%s, got: %s", current.ProtocolTCP, svc2.Protocol)
|
||||||
|
}
|
||||||
|
if svc2.SessionAffinity != current.AffinityTypeNone {
|
||||||
|
t.Errorf("Expected default sesseion affinity type:%s, got: %s", current.AffinityTypeNone, svc2.SessionAffinity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetDefaulPodSpec(t *testing.T) {
|
||||||
|
bp := ¤t.BoundPod{}
|
||||||
|
obj2 := roundTrip(t, runtime.Object(bp))
|
||||||
|
bp2 := obj2.(*current.BoundPod)
|
||||||
|
if bp2.Spec.DNSPolicy != current.DNSClusterFirst {
|
||||||
|
t.Errorf("Expected default dns policy :%s, got: %s", current.DNSClusterFirst, bp2.Spec.DNSPolicy)
|
||||||
|
}
|
||||||
|
policy := bp2.Spec.RestartPolicy
|
||||||
|
if policy.Never != nil || policy.OnFailure != nil || policy.Always == nil {
|
||||||
|
t.Errorf("Expected only policy.Aways is set, got: %s", policy)
|
||||||
|
}
|
||||||
|
}
|
@ -71,6 +71,11 @@ type ContainerManifestList struct {
|
|||||||
Items []ContainerManifest `json:"items" description:"list of pod container manifests"`
|
Items []ContainerManifest `json:"items" description:"list of pod container manifests"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TerminationMessagePathDefault means the default path to capture the application termination message running in a container
|
||||||
|
TerminationMessagePathDefault string = "/dev/termination-log"
|
||||||
|
)
|
||||||
|
|
||||||
// Volume represents a named volume in a pod that may be accessed by any containers in the pod.
|
// Volume represents a named volume in a pod that may be accessed by any containers in the pod.
|
||||||
type Volume struct {
|
type Volume struct {
|
||||||
// Required: This must be a DNS_LABEL. Each volume in a pod must have
|
// Required: This must be a DNS_LABEL. Each volume in a pod must have
|
||||||
|
79
pkg/api/v1beta2/defaults.go
Normal file
79
pkg/api/v1beta2/defaults.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 Google Inc. 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 (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
api.Scheme.AddDefaultingFuncs(
|
||||||
|
func(obj *Volume) {
|
||||||
|
if util.AllPtrFieldsNil(&obj.Source) {
|
||||||
|
obj.Source = VolumeSource{
|
||||||
|
EmptyDir: &EmptyDir{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
func(obj *Port) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
},
|
||||||
|
func(obj *RestartPolicy) {
|
||||||
|
if util.AllPtrFieldsNil(obj) {
|
||||||
|
obj.Always = &RestartPolicyAlways{}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
func(obj *Service) {
|
||||||
|
if obj.Protocol == "" {
|
||||||
|
obj.Protocol = ProtocolTCP
|
||||||
|
}
|
||||||
|
if obj.SessionAffinity == "" {
|
||||||
|
obj.SessionAffinity = AffinityTypeNone
|
||||||
|
}
|
||||||
|
},
|
||||||
|
func(obj *PodSpec) {
|
||||||
|
if obj.DNSPolicy == "" {
|
||||||
|
obj.DNSPolicy = DNSClusterFirst
|
||||||
|
}
|
||||||
|
},
|
||||||
|
func(obj *ContainerManifest) {
|
||||||
|
if obj.DNSPolicy == "" {
|
||||||
|
obj.DNSPolicy = DNSClusterFirst
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
@ -252,6 +252,11 @@ type Container struct {
|
|||||||
Capabilities Capabilities `json:"capabilities,omitempty" description:"capabilities for container"`
|
Capabilities Capabilities `json:"capabilities,omitempty" description:"capabilities for container"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TerminationMessagePathDefault means the default path to capture the application termination message running in a container
|
||||||
|
TerminationMessagePathDefault string = "/dev/termination-log"
|
||||||
|
)
|
||||||
|
|
||||||
// Handler defines a specific action that should be taken
|
// Handler defines a specific action that should be taken
|
||||||
// TODO: pass structured data to these actions, and document that data here.
|
// TODO: pass structured data to these actions, and document that data here.
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
|
74
pkg/api/v1beta3/defaults.go
Normal file
74
pkg/api/v1beta3/defaults.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 Google Inc. 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 v1beta3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
api.Scheme.AddDefaultingFuncs(
|
||||||
|
func(obj *Volume) {
|
||||||
|
if util.AllPtrFieldsNil(&obj.Source) {
|
||||||
|
obj.Source = VolumeSource{
|
||||||
|
EmptyDir: &EmptyDir{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
func(obj *Port) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
},
|
||||||
|
func(obj *RestartPolicy) {
|
||||||
|
if util.AllPtrFieldsNil(obj) {
|
||||||
|
obj.Always = &RestartPolicyAlways{}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
func(obj *Service) {
|
||||||
|
if obj.Spec.Protocol == "" {
|
||||||
|
obj.Spec.Protocol = ProtocolTCP
|
||||||
|
}
|
||||||
|
if obj.Spec.SessionAffinity == "" {
|
||||||
|
obj.Spec.SessionAffinity = AffinityTypeNone
|
||||||
|
}
|
||||||
|
},
|
||||||
|
func(obj *PodSpec) {
|
||||||
|
if obj.DNSPolicy == "" {
|
||||||
|
obj.DNSPolicy = DNSClusterFirst
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
@ -341,6 +341,11 @@ type ResourceRequirementSpec struct {
|
|||||||
Limits ResourceList `json:"limits,omitempty" description:"Maximum amount of compute resources allowed"`
|
Limits ResourceList `json:"limits,omitempty" description:"Maximum amount of compute resources allowed"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TerminationMessagePathDefault means the default path to capture the application termination message running in a container
|
||||||
|
TerminationMessagePathDefault string = "/dev/termination-log"
|
||||||
|
)
|
||||||
|
|
||||||
// Container represents a single container that is expected to be run on the host.
|
// Container represents a single container that is expected to be run on the host.
|
||||||
type Container struct {
|
type Container struct {
|
||||||
// Required: This must be a DNS_LABEL. Each container in a pod must
|
// Required: This must be a DNS_LABEL. Each container in a pod must
|
||||||
|
@ -103,18 +103,17 @@ var invalidPod2 = `{
|
|||||||
"manifest": {
|
"manifest": {
|
||||||
"version": "v1beta1",
|
"version": "v1beta1",
|
||||||
"id": "apache-php",
|
"id": "apache-php",
|
||||||
"containers": [
|
"containers": [{
|
||||||
{
|
"name": "apache-php",
|
||||||
"name": "apache-php",
|
"image": "php:5.6.2-apache",
|
||||||
"image": "php:5.6.2-apache",
|
"ports": [{ "name": "apache", "containerPort": 80, "hostPort":"13380", "protocol":"TCP" }],
|
||||||
"ports": [{ "name": "apache", "containerPort": 80, "hostPort":"13380", "protocol":"TCP" }],
|
"volumeMounts": [{"name": "shared-disk","mountPath": "/var/www/html", "readOnly": false}]
|
||||||
"volumeMounts": [{"name": "shared-disk","mountPath": "/var/www/html", "readOnly": false}]
|
}]
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"labels": { "name": "apache-php" },
|
"labels": { "name": "apache-php" },
|
||||||
"restartPolicy": {"always": {}},
|
"restartPolicy": {"always": {}},
|
||||||
|
"dnsPolicy": "ClusterFirst",
|
||||||
"volumes": [
|
"volumes": [
|
||||||
"name": "shared-disk",
|
"name": "shared-disk",
|
||||||
"source": {
|
"source": {
|
||||||
@ -134,18 +133,17 @@ var invalidPod3 = `{
|
|||||||
"manifest": {
|
"manifest": {
|
||||||
"version": "v1beta1",
|
"version": "v1beta1",
|
||||||
"id": "apache-php",
|
"id": "apache-php",
|
||||||
"containers": [
|
"containers": [{
|
||||||
{
|
"name": "apache-php",
|
||||||
"name": "apache-php",
|
"image": "php:5.6.2-apache",
|
||||||
"image": "php:5.6.2-apache",
|
"ports": [{ "name": "apache", "containerPort": 80, "hostPort":"13380", "protocol":"TCP" }],
|
||||||
"ports": [{ "name": "apache", "containerPort": 80, "hostPort":"13380", "protocol":"TCP" }],
|
"volumeMounts": [{"name": "shared-disk","mountPath": "/var/www/html", "readOnly": false}]
|
||||||
"volumeMounts": [{"name": "shared-disk","mountPath": "/var/www/html", "readOnly": false}]
|
}]
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"labels": { "name": "apache-php" },
|
"labels": { "name": "apache-php" },
|
||||||
"restartPolicy": {"always": {}},
|
"restartPolicy": {"always": {}},
|
||||||
|
"dnsPolicy": "ClusterFirst",
|
||||||
"volumes": [
|
"volumes": [
|
||||||
{
|
{
|
||||||
"name": "shared-disk",
|
"name": "shared-disk",
|
||||||
|
@ -189,8 +189,7 @@ func validateVolumes(volumes []api.Volume) (util.StringSet, errs.ValidationError
|
|||||||
allErrs := errs.ValidationErrorList{}
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
|
||||||
allNames := util.StringSet{}
|
allNames := util.StringSet{}
|
||||||
for i := range volumes {
|
for i, vol := range volumes {
|
||||||
vol := &volumes[i] // so we can set default values
|
|
||||||
el := validateSource(&vol.Source).Prefix("source")
|
el := validateSource(&vol.Source).Prefix("source")
|
||||||
if len(vol.Name) == 0 {
|
if len(vol.Name) == 0 {
|
||||||
el = append(el, errs.NewFieldRequired("name", vol.Name))
|
el = append(el, errs.NewFieldRequired("name", vol.Name))
|
||||||
@ -227,10 +226,7 @@ func validateSource(source *api.VolumeSource) errs.ValidationErrorList {
|
|||||||
numVolumes++
|
numVolumes++
|
||||||
allErrs = append(allErrs, validateGCEPersistentDisk(source.GCEPersistentDisk).Prefix("persistentDisk")...)
|
allErrs = append(allErrs, validateGCEPersistentDisk(source.GCEPersistentDisk).Prefix("persistentDisk")...)
|
||||||
}
|
}
|
||||||
if numVolumes == 0 {
|
if numVolumes != 1 {
|
||||||
// TODO: Enforce that a source is set once we deprecate the implied form.
|
|
||||||
source.EmptyDir = &api.EmptyDir{}
|
|
||||||
} else if numVolumes != 1 {
|
|
||||||
allErrs = append(allErrs, errs.NewFieldInvalid("", source, "exactly 1 volume type is required"))
|
allErrs = append(allErrs, errs.NewFieldInvalid("", source, "exactly 1 volume type is required"))
|
||||||
}
|
}
|
||||||
return allErrs
|
return allErrs
|
||||||
@ -272,9 +268,8 @@ func validatePorts(ports []api.Port) errs.ValidationErrorList {
|
|||||||
allErrs := errs.ValidationErrorList{}
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
|
||||||
allNames := util.StringSet{}
|
allNames := util.StringSet{}
|
||||||
for i := range ports {
|
for i, port := range ports {
|
||||||
pErrs := errs.ValidationErrorList{}
|
pErrs := errs.ValidationErrorList{}
|
||||||
port := &ports[i] // so we can set default values
|
|
||||||
if len(port.Name) > 0 {
|
if len(port.Name) > 0 {
|
||||||
if len(port.Name) > 63 || !util.IsDNSLabel(port.Name) {
|
if len(port.Name) > 63 || !util.IsDNSLabel(port.Name) {
|
||||||
pErrs = append(pErrs, errs.NewFieldInvalid("name", port.Name, ""))
|
pErrs = append(pErrs, errs.NewFieldInvalid("name", port.Name, ""))
|
||||||
@ -293,7 +288,7 @@ func validatePorts(ports []api.Port) errs.ValidationErrorList {
|
|||||||
pErrs = append(pErrs, errs.NewFieldInvalid("hostPort", port.HostPort, ""))
|
pErrs = append(pErrs, errs.NewFieldInvalid("hostPort", port.HostPort, ""))
|
||||||
}
|
}
|
||||||
if len(port.Protocol) == 0 {
|
if len(port.Protocol) == 0 {
|
||||||
port.Protocol = "TCP"
|
pErrs = append(pErrs, errs.NewFieldRequired("protocol", port.Protocol))
|
||||||
} else if !supportedPortProtocols.Has(strings.ToUpper(string(port.Protocol))) {
|
} else if !supportedPortProtocols.Has(strings.ToUpper(string(port.Protocol))) {
|
||||||
pErrs = append(pErrs, errs.NewFieldNotSupported("protocol", port.Protocol))
|
pErrs = append(pErrs, errs.NewFieldNotSupported("protocol", port.Protocol))
|
||||||
}
|
}
|
||||||
@ -305,9 +300,8 @@ func validatePorts(ports []api.Port) errs.ValidationErrorList {
|
|||||||
func validateEnv(vars []api.EnvVar) errs.ValidationErrorList {
|
func validateEnv(vars []api.EnvVar) errs.ValidationErrorList {
|
||||||
allErrs := errs.ValidationErrorList{}
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
|
||||||
for i := range vars {
|
for i, ev := range vars {
|
||||||
vErrs := errs.ValidationErrorList{}
|
vErrs := errs.ValidationErrorList{}
|
||||||
ev := &vars[i] // so we can set default values
|
|
||||||
if len(ev.Name) == 0 {
|
if len(ev.Name) == 0 {
|
||||||
vErrs = append(vErrs, errs.NewFieldRequired("name", ev.Name))
|
vErrs = append(vErrs, errs.NewFieldRequired("name", ev.Name))
|
||||||
}
|
}
|
||||||
@ -322,9 +316,8 @@ func validateEnv(vars []api.EnvVar) errs.ValidationErrorList {
|
|||||||
func validateVolumeMounts(mounts []api.VolumeMount, volumes util.StringSet) errs.ValidationErrorList {
|
func validateVolumeMounts(mounts []api.VolumeMount, volumes util.StringSet) errs.ValidationErrorList {
|
||||||
allErrs := errs.ValidationErrorList{}
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
|
||||||
for i := range mounts {
|
for i, mnt := range mounts {
|
||||||
mErrs := errs.ValidationErrorList{}
|
mErrs := errs.ValidationErrorList{}
|
||||||
mnt := &mounts[i] // so we can set default values
|
|
||||||
if len(mnt.Name) == 0 {
|
if len(mnt.Name) == 0 {
|
||||||
mErrs = append(mErrs, errs.NewFieldRequired("name", mnt.Name))
|
mErrs = append(mErrs, errs.NewFieldRequired("name", mnt.Name))
|
||||||
} else if !volumes.Has(mnt.Name) {
|
} else if !volumes.Has(mnt.Name) {
|
||||||
@ -343,9 +336,8 @@ func validateVolumeMounts(mounts []api.VolumeMount, volumes util.StringSet) errs
|
|||||||
func AccumulateUniquePorts(containers []api.Container, accumulator map[int]bool, extract func(*api.Port) int) errs.ValidationErrorList {
|
func AccumulateUniquePorts(containers []api.Container, accumulator map[int]bool, extract func(*api.Port) int) errs.ValidationErrorList {
|
||||||
allErrs := errs.ValidationErrorList{}
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
|
||||||
for ci := range containers {
|
for ci, ctr := range containers {
|
||||||
cErrs := errs.ValidationErrorList{}
|
cErrs := errs.ValidationErrorList{}
|
||||||
ctr := &containers[ci]
|
|
||||||
for pi := range ctr.Ports {
|
for pi := range ctr.Ports {
|
||||||
port := extract(&ctr.Ports[pi])
|
port := extract(&ctr.Ports[pi])
|
||||||
if port == 0 {
|
if port == 0 {
|
||||||
@ -413,22 +405,14 @@ func validateLifecycle(lifecycle *api.Lifecycle) errs.ValidationErrorList {
|
|||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(dchen1107): Move this along with other defaulting values
|
func validatePullPolicy(ctr *api.Container) errs.ValidationErrorList {
|
||||||
func validatePullPolicyWithDefault(ctr *api.Container) errs.ValidationErrorList {
|
|
||||||
allErrors := errs.ValidationErrorList{}
|
allErrors := errs.ValidationErrorList{}
|
||||||
|
|
||||||
switch ctr.ImagePullPolicy {
|
switch ctr.ImagePullPolicy {
|
||||||
case "":
|
|
||||||
// TODO(dchen1107): Move ParseImageName code to pkg/util
|
|
||||||
parts := strings.Split(ctr.Image, ":")
|
|
||||||
// Check image tag
|
|
||||||
if parts[len(parts)-1] == "latest" {
|
|
||||||
ctr.ImagePullPolicy = api.PullAlways
|
|
||||||
} else {
|
|
||||||
ctr.ImagePullPolicy = api.PullIfNotPresent
|
|
||||||
}
|
|
||||||
case api.PullAlways, api.PullIfNotPresent, api.PullNever:
|
case api.PullAlways, api.PullIfNotPresent, api.PullNever:
|
||||||
break
|
break
|
||||||
|
case "":
|
||||||
|
allErrors = append(allErrors, errs.NewFieldRequired("", ctr.ImagePullPolicy))
|
||||||
default:
|
default:
|
||||||
allErrors = append(allErrors, errs.NewFieldNotSupported("", ctr.ImagePullPolicy))
|
allErrors = append(allErrors, errs.NewFieldNotSupported("", ctr.ImagePullPolicy))
|
||||||
}
|
}
|
||||||
@ -440,9 +424,8 @@ func validateContainers(containers []api.Container, volumes util.StringSet) errs
|
|||||||
allErrs := errs.ValidationErrorList{}
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
|
||||||
allNames := util.StringSet{}
|
allNames := util.StringSet{}
|
||||||
for i := range containers {
|
for i, ctr := range containers {
|
||||||
cErrs := errs.ValidationErrorList{}
|
cErrs := errs.ValidationErrorList{}
|
||||||
ctr := &containers[i] // so we can set default values
|
|
||||||
capabilities := capabilities.Get()
|
capabilities := capabilities.Get()
|
||||||
if len(ctr.Name) == 0 {
|
if len(ctr.Name) == 0 {
|
||||||
cErrs = append(cErrs, errs.NewFieldRequired("name", ctr.Name))
|
cErrs = append(cErrs, errs.NewFieldRequired("name", ctr.Name))
|
||||||
@ -464,8 +447,8 @@ func validateContainers(containers []api.Container, volumes util.StringSet) errs
|
|||||||
cErrs = append(cErrs, validatePorts(ctr.Ports).Prefix("ports")...)
|
cErrs = append(cErrs, validatePorts(ctr.Ports).Prefix("ports")...)
|
||||||
cErrs = append(cErrs, validateEnv(ctr.Env).Prefix("env")...)
|
cErrs = append(cErrs, validateEnv(ctr.Env).Prefix("env")...)
|
||||||
cErrs = append(cErrs, validateVolumeMounts(ctr.VolumeMounts, volumes).Prefix("volumeMounts")...)
|
cErrs = append(cErrs, validateVolumeMounts(ctr.VolumeMounts, volumes).Prefix("volumeMounts")...)
|
||||||
cErrs = append(cErrs, validatePullPolicyWithDefault(ctr).Prefix("pullPolicy")...)
|
cErrs = append(cErrs, validatePullPolicy(&ctr).Prefix("pullPolicy")...)
|
||||||
cErrs = append(cErrs, validateResourceRequirements(ctr).Prefix("resources")...)
|
cErrs = append(cErrs, validateResourceRequirements(&ctr).Prefix("resources")...)
|
||||||
allErrs = append(allErrs, cErrs.PrefixIndex(i)...)
|
allErrs = append(allErrs, cErrs.PrefixIndex(i)...)
|
||||||
}
|
}
|
||||||
// Check for colliding ports across all containers.
|
// Check for colliding ports across all containers.
|
||||||
@ -513,10 +496,7 @@ func validateRestartPolicy(restartPolicy *api.RestartPolicy) errs.ValidationErro
|
|||||||
if restartPolicy.Never != nil {
|
if restartPolicy.Never != nil {
|
||||||
numPolicies++
|
numPolicies++
|
||||||
}
|
}
|
||||||
if numPolicies == 0 {
|
if numPolicies != 1 {
|
||||||
restartPolicy.Always = &api.RestartPolicyAlways{}
|
|
||||||
}
|
|
||||||
if numPolicies > 1 {
|
|
||||||
allErrors = append(allErrors, errs.NewFieldInvalid("", restartPolicy, "only 1 policy is allowed"))
|
allErrors = append(allErrors, errs.NewFieldInvalid("", restartPolicy, "only 1 policy is allowed"))
|
||||||
}
|
}
|
||||||
return allErrors
|
return allErrors
|
||||||
@ -525,11 +505,10 @@ func validateRestartPolicy(restartPolicy *api.RestartPolicy) errs.ValidationErro
|
|||||||
func validateDNSPolicy(dnsPolicy *api.DNSPolicy) errs.ValidationErrorList {
|
func validateDNSPolicy(dnsPolicy *api.DNSPolicy) errs.ValidationErrorList {
|
||||||
allErrors := errs.ValidationErrorList{}
|
allErrors := errs.ValidationErrorList{}
|
||||||
switch *dnsPolicy {
|
switch *dnsPolicy {
|
||||||
case "":
|
|
||||||
// TODO: move this out to standard defaulting logic, when that is ready.
|
|
||||||
*dnsPolicy = api.DNSClusterFirst // Default value.
|
|
||||||
case api.DNSClusterFirst, api.DNSDefault:
|
case api.DNSClusterFirst, api.DNSDefault:
|
||||||
break
|
break
|
||||||
|
case "":
|
||||||
|
allErrors = append(allErrors, errs.NewFieldRequired("", *dnsPolicy))
|
||||||
default:
|
default:
|
||||||
allErrors = append(allErrors, errs.NewFieldNotSupported("", dnsPolicy))
|
allErrors = append(allErrors, errs.NewFieldNotSupported("", dnsPolicy))
|
||||||
}
|
}
|
||||||
@ -598,7 +577,7 @@ func ValidateService(service *api.Service) errs.ValidationErrorList {
|
|||||||
allErrs = append(allErrs, errs.NewFieldInvalid("spec.port", service.Spec.Port, ""))
|
allErrs = append(allErrs, errs.NewFieldInvalid("spec.port", service.Spec.Port, ""))
|
||||||
}
|
}
|
||||||
if len(service.Spec.Protocol) == 0 {
|
if len(service.Spec.Protocol) == 0 {
|
||||||
service.Spec.Protocol = "TCP"
|
allErrs = append(allErrs, errs.NewFieldRequired("spec.protocol", service.Spec.Protocol))
|
||||||
} else if !supportedPortProtocols.Has(strings.ToUpper(string(service.Spec.Protocol))) {
|
} else if !supportedPortProtocols.Has(strings.ToUpper(string(service.Spec.Protocol))) {
|
||||||
allErrs = append(allErrs, errs.NewFieldNotSupported("spec.protocol", service.Spec.Protocol))
|
allErrs = append(allErrs, errs.NewFieldNotSupported("spec.protocol", service.Spec.Protocol))
|
||||||
}
|
}
|
||||||
@ -608,7 +587,7 @@ func ValidateService(service *api.Service) errs.ValidationErrorList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if service.Spec.SessionAffinity == "" {
|
if service.Spec.SessionAffinity == "" {
|
||||||
service.Spec.SessionAffinity = api.AffinityTypeNone
|
allErrs = append(allErrs, errs.NewFieldRequired("spec.sessionAffinity", service.Spec.SessionAffinity))
|
||||||
} else if !supportedSessionAffinityType.Has(string(service.Spec.SessionAffinity)) {
|
} else if !supportedSessionAffinityType.Has(string(service.Spec.SessionAffinity)) {
|
||||||
allErrs = append(allErrs, errs.NewFieldNotSupported("spec.sessionAffinity", service.Spec.SessionAffinity))
|
allErrs = append(allErrs, errs.NewFieldNotSupported("spec.sessionAffinity", service.Spec.SessionAffinity))
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ func TestValidateAnnotations(t *testing.T) {
|
|||||||
|
|
||||||
func TestValidateVolumes(t *testing.T) {
|
func TestValidateVolumes(t *testing.T) {
|
||||||
successCase := []api.Volume{
|
successCase := []api.Volume{
|
||||||
{Name: "abc"},
|
{Name: "abc", Source: api.VolumeSource{HostPath: &api.HostPath{"/mnt/path1"}}},
|
||||||
{Name: "123", Source: api.VolumeSource{HostPath: &api.HostPath{"/mnt/path2"}}},
|
{Name: "123", Source: api.VolumeSource{HostPath: &api.HostPath{"/mnt/path2"}}},
|
||||||
{Name: "abc-123", Source: api.VolumeSource{HostPath: &api.HostPath{"/mnt/path3"}}},
|
{Name: "abc-123", Source: api.VolumeSource{HostPath: &api.HostPath{"/mnt/path3"}}},
|
||||||
{Name: "empty", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}},
|
{Name: "empty", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}},
|
||||||
@ -151,16 +151,16 @@ func TestValidateVolumes(t *testing.T) {
|
|||||||
if len(names) != 6 || !names.HasAll("abc", "123", "abc-123", "empty", "gcepd", "gitrepo") {
|
if len(names) != 6 || !names.HasAll("abc", "123", "abc-123", "empty", "gcepd", "gitrepo") {
|
||||||
t.Errorf("wrong names result: %v", names)
|
t.Errorf("wrong names result: %v", names)
|
||||||
}
|
}
|
||||||
|
emptyVS := api.VolumeSource{EmptyDir: &api.EmptyDir{}}
|
||||||
errorCases := map[string]struct {
|
errorCases := map[string]struct {
|
||||||
V []api.Volume
|
V []api.Volume
|
||||||
T errors.ValidationErrorType
|
T errors.ValidationErrorType
|
||||||
F string
|
F string
|
||||||
}{
|
}{
|
||||||
"zero-length name": {[]api.Volume{{Name: ""}}, errors.ValidationErrorTypeRequired, "[0].name"},
|
"zero-length name": {[]api.Volume{{Name: "", Source: emptyVS}}, errors.ValidationErrorTypeRequired, "[0].name"},
|
||||||
"name > 63 characters": {[]api.Volume{{Name: strings.Repeat("a", 64)}}, errors.ValidationErrorTypeInvalid, "[0].name"},
|
"name > 63 characters": {[]api.Volume{{Name: strings.Repeat("a", 64), Source: emptyVS}}, errors.ValidationErrorTypeInvalid, "[0].name"},
|
||||||
"name not a DNS label": {[]api.Volume{{Name: "a.b.c"}}, errors.ValidationErrorTypeInvalid, "[0].name"},
|
"name not a DNS label": {[]api.Volume{{Name: "a.b.c", Source: emptyVS}}, errors.ValidationErrorTypeInvalid, "[0].name"},
|
||||||
"name not unique": {[]api.Volume{{Name: "abc"}, {Name: "abc"}}, errors.ValidationErrorTypeDuplicate, "[1].name"},
|
"name not unique": {[]api.Volume{{Name: "abc", Source: emptyVS}, {Name: "abc", Source: emptyVS}}, errors.ValidationErrorTypeDuplicate, "[1].name"},
|
||||||
}
|
}
|
||||||
for k, v := range errorCases {
|
for k, v := range errorCases {
|
||||||
_, errs := validateVolumes(v.V)
|
_, errs := validateVolumes(v.V)
|
||||||
@ -182,42 +182,39 @@ func TestValidateVolumes(t *testing.T) {
|
|||||||
func TestValidatePorts(t *testing.T) {
|
func TestValidatePorts(t *testing.T) {
|
||||||
successCase := []api.Port{
|
successCase := []api.Port{
|
||||||
{Name: "abc", ContainerPort: 80, HostPort: 80, Protocol: "TCP"},
|
{Name: "abc", ContainerPort: 80, HostPort: 80, Protocol: "TCP"},
|
||||||
{Name: "123", ContainerPort: 81, HostPort: 81},
|
|
||||||
{Name: "easy", ContainerPort: 82, Protocol: "TCP"},
|
{Name: "easy", ContainerPort: 82, Protocol: "TCP"},
|
||||||
{Name: "as", ContainerPort: 83, Protocol: "UDP"},
|
{Name: "as", ContainerPort: 83, Protocol: "UDP"},
|
||||||
{Name: "do-re-me", ContainerPort: 84},
|
{Name: "do-re-me", ContainerPort: 84, Protocol: "UDP"},
|
||||||
{Name: "baby-you-and-me", ContainerPort: 82, Protocol: "tcp"},
|
{Name: "baby-you-and-me", ContainerPort: 82, Protocol: "tcp"},
|
||||||
{ContainerPort: 85},
|
{ContainerPort: 85, Protocol: "TCP"},
|
||||||
}
|
}
|
||||||
if errs := validatePorts(successCase); len(errs) != 0 {
|
if errs := validatePorts(successCase); len(errs) != 0 {
|
||||||
t.Errorf("expected success: %v", errs)
|
t.Errorf("expected success: %v", errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
nonCanonicalCase := []api.Port{
|
nonCanonicalCase := []api.Port{
|
||||||
{ContainerPort: 80},
|
{ContainerPort: 80, Protocol: "TCP"},
|
||||||
}
|
}
|
||||||
if errs := validatePorts(nonCanonicalCase); len(errs) != 0 {
|
if errs := validatePorts(nonCanonicalCase); len(errs) != 0 {
|
||||||
t.Errorf("expected success: %v", errs)
|
t.Errorf("expected success: %v", errs)
|
||||||
}
|
}
|
||||||
if nonCanonicalCase[0].HostPort != 0 || nonCanonicalCase[0].Protocol != "TCP" {
|
|
||||||
t.Errorf("expected default values: %+v", nonCanonicalCase[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
errorCases := map[string]struct {
|
errorCases := map[string]struct {
|
||||||
P []api.Port
|
P []api.Port
|
||||||
T errors.ValidationErrorType
|
T errors.ValidationErrorType
|
||||||
F string
|
F string
|
||||||
}{
|
}{
|
||||||
"name > 63 characters": {[]api.Port{{Name: strings.Repeat("a", 64), ContainerPort: 80}}, errors.ValidationErrorTypeInvalid, "[0].name"},
|
"name > 63 characters": {[]api.Port{{Name: strings.Repeat("a", 64), ContainerPort: 80, Protocol: "TCP"}}, errors.ValidationErrorTypeInvalid, "[0].name"},
|
||||||
"name not a DNS label": {[]api.Port{{Name: "a.b.c", ContainerPort: 80}}, errors.ValidationErrorTypeInvalid, "[0].name"},
|
"name not a DNS label": {[]api.Port{{Name: "a.b.c", ContainerPort: 80, Protocol: "TCP"}}, errors.ValidationErrorTypeInvalid, "[0].name"},
|
||||||
"name not unique": {[]api.Port{
|
"name not unique": {[]api.Port{
|
||||||
{Name: "abc", ContainerPort: 80},
|
{Name: "abc", ContainerPort: 80, Protocol: "TCP"},
|
||||||
{Name: "abc", ContainerPort: 81},
|
{Name: "abc", ContainerPort: 81, Protocol: "TCP"},
|
||||||
}, errors.ValidationErrorTypeDuplicate, "[1].name"},
|
}, errors.ValidationErrorTypeDuplicate, "[1].name"},
|
||||||
"zero container port": {[]api.Port{{ContainerPort: 0}}, errors.ValidationErrorTypeRequired, "[0].containerPort"},
|
"zero container port": {[]api.Port{{ContainerPort: 0, Protocol: "TCP"}}, errors.ValidationErrorTypeRequired, "[0].containerPort"},
|
||||||
"invalid container port": {[]api.Port{{ContainerPort: 65536}}, errors.ValidationErrorTypeInvalid, "[0].containerPort"},
|
"invalid container port": {[]api.Port{{ContainerPort: 65536, Protocol: "TCP"}}, errors.ValidationErrorTypeInvalid, "[0].containerPort"},
|
||||||
"invalid host port": {[]api.Port{{ContainerPort: 80, HostPort: 65536}}, errors.ValidationErrorTypeInvalid, "[0].hostPort"},
|
"invalid host port": {[]api.Port{{ContainerPort: 80, HostPort: 65536, Protocol: "TCP"}}, errors.ValidationErrorTypeInvalid, "[0].hostPort"},
|
||||||
"invalid protocol": {[]api.Port{{ContainerPort: 80, Protocol: "ICMP"}}, errors.ValidationErrorTypeNotSupported, "[0].protocol"},
|
"invalid protocol": {[]api.Port{{ContainerPort: 80, Protocol: "ICMP"}}, errors.ValidationErrorTypeNotSupported, "[0].protocol"},
|
||||||
|
"protocol required": {[]api.Port{{Name: "abc", ContainerPort: 80}}, errors.ValidationErrorTypeRequired, "[0].protocol"}, //yjhong
|
||||||
}
|
}
|
||||||
for k, v := range errorCases {
|
for k, v := range errorCases {
|
||||||
errs := validatePorts(v.P)
|
errs := validatePorts(v.P)
|
||||||
@ -311,14 +308,10 @@ func TestValidatePullPolicy(t *testing.T) {
|
|||||||
api.Container{Name: "abc-1234", Image: "image", ImagePullPolicy: "Never"},
|
api.Container{Name: "abc-1234", Image: "image", ImagePullPolicy: "Never"},
|
||||||
api.PullNever,
|
api.PullNever,
|
||||||
},
|
},
|
||||||
"DefaultToNotPresent": {api.Container{Name: "notPresent", Image: "image"}, api.PullIfNotPresent},
|
|
||||||
"DefaultToNotPresent2": {api.Container{Name: "notPresent1", Image: "image:sometag"}, api.PullIfNotPresent},
|
|
||||||
"DefaultToAlways1": {api.Container{Name: "always", Image: "image:latest"}, api.PullAlways},
|
|
||||||
"DefaultToAlways2": {api.Container{Name: "always", Image: "foo.bar.com:5000/my/image:latest"}, api.PullAlways},
|
|
||||||
}
|
}
|
||||||
for k, v := range testCases {
|
for k, v := range testCases {
|
||||||
ctr := &v.Container
|
ctr := &v.Container
|
||||||
errs := validatePullPolicyWithDefault(ctr)
|
errs := validatePullPolicy(ctr)
|
||||||
if len(errs) != 0 {
|
if len(errs) != 0 {
|
||||||
t.Errorf("case[%s] expected success, got %#v", k, errs)
|
t.Errorf("case[%s] expected success, got %#v", k, errs)
|
||||||
}
|
}
|
||||||
@ -343,9 +336,9 @@ func TestValidateContainers(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
successCase := []api.Container{
|
successCase := []api.Container{
|
||||||
{Name: "abc", Image: "image"},
|
{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"},
|
||||||
{Name: "123", Image: "image"},
|
{Name: "123", Image: "image", ImagePullPolicy: "IfNotPresent"},
|
||||||
{Name: "abc-123", Image: "image"},
|
{Name: "abc-123", Image: "image", ImagePullPolicy: "IfNotPresent"},
|
||||||
{
|
{
|
||||||
Name: "life-123",
|
Name: "life-123",
|
||||||
Image: "image",
|
Image: "image",
|
||||||
@ -354,6 +347,7 @@ func TestValidateContainers(t *testing.T) {
|
|||||||
Exec: &api.ExecAction{Command: []string{"ls", "-l"}},
|
Exec: &api.ExecAction{Command: []string{"ls", "-l"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ImagePullPolicy: "IfNotPresent",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "resources-test",
|
Name: "resources-test",
|
||||||
@ -365,8 +359,9 @@ func TestValidateContainers(t *testing.T) {
|
|||||||
api.ResourceName("my.org/resource"): resource.MustParse("10m"),
|
api.ResourceName("my.org/resource"): resource.MustParse("10m"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ImagePullPolicy: "IfNotPresent",
|
||||||
},
|
},
|
||||||
{Name: "abc-1234", Image: "image", Privileged: true},
|
{Name: "abc-1234", Image: "image", Privileged: true, ImagePullPolicy: "IfNotPresent"},
|
||||||
}
|
}
|
||||||
if errs := validateContainers(successCase, volumes); len(errs) != 0 {
|
if errs := validateContainers(successCase, volumes); len(errs) != 0 {
|
||||||
t.Errorf("expected success: %v", errs)
|
t.Errorf("expected success: %v", errs)
|
||||||
@ -467,7 +462,6 @@ func TestValidateContainers(t *testing.T) {
|
|||||||
|
|
||||||
func TestValidateRestartPolicy(t *testing.T) {
|
func TestValidateRestartPolicy(t *testing.T) {
|
||||||
successCases := []api.RestartPolicy{
|
successCases := []api.RestartPolicy{
|
||||||
{},
|
|
||||||
{Always: &api.RestartPolicyAlways{}},
|
{Always: &api.RestartPolicyAlways{}},
|
||||||
{OnFailure: &api.RestartPolicyOnFailure{}},
|
{OnFailure: &api.RestartPolicyOnFailure{}},
|
||||||
{Never: &api.RestartPolicyNever{}},
|
{Never: &api.RestartPolicyNever{}},
|
||||||
@ -479,6 +473,7 @@ func TestValidateRestartPolicy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
errorCases := []api.RestartPolicy{
|
errorCases := []api.RestartPolicy{
|
||||||
|
{},
|
||||||
{Always: &api.RestartPolicyAlways{}, Never: &api.RestartPolicyNever{}},
|
{Always: &api.RestartPolicyAlways{}, Never: &api.RestartPolicyNever{}},
|
||||||
{Never: &api.RestartPolicyNever{}, OnFailure: &api.RestartPolicyOnFailure{}},
|
{Never: &api.RestartPolicyNever{}, OnFailure: &api.RestartPolicyOnFailure{}},
|
||||||
}
|
}
|
||||||
@ -487,19 +482,10 @@ func TestValidateRestartPolicy(t *testing.T) {
|
|||||||
t.Errorf("expected failure for %d", k)
|
t.Errorf("expected failure for %d", k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
noPolicySpecified := api.RestartPolicy{}
|
|
||||||
errs := validateRestartPolicy(&noPolicySpecified)
|
|
||||||
if len(errs) != 0 {
|
|
||||||
t.Errorf("expected success: %v", errs)
|
|
||||||
}
|
|
||||||
if noPolicySpecified.Always == nil {
|
|
||||||
t.Errorf("expected Always policy specified")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateDNSPolicy(t *testing.T) {
|
func TestValidateDNSPolicy(t *testing.T) {
|
||||||
successCases := []api.DNSPolicy{api.DNSClusterFirst, api.DNSDefault, api.DNSPolicy("")}
|
successCases := []api.DNSPolicy{api.DNSClusterFirst, api.DNSDefault, api.DNSPolicy(api.DNSClusterFirst)}
|
||||||
for _, policy := range successCases {
|
for _, policy := range successCases {
|
||||||
if errs := validateDNSPolicy(&policy); len(errs) != 0 {
|
if errs := validateDNSPolicy(&policy); len(errs) != 0 {
|
||||||
t.Errorf("expected success: %v", errs)
|
t.Errorf("expected success: %v", errs)
|
||||||
@ -516,9 +502,12 @@ func TestValidateDNSPolicy(t *testing.T) {
|
|||||||
|
|
||||||
func TestValidateManifest(t *testing.T) {
|
func TestValidateManifest(t *testing.T) {
|
||||||
successCases := []api.ContainerManifest{
|
successCases := []api.ContainerManifest{
|
||||||
{Version: "v1beta1", ID: "abc"},
|
{Version: "v1beta1", ID: "abc", RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
{Version: "v1beta2", ID: "123"},
|
DNSPolicy: api.DNSClusterFirst},
|
||||||
{Version: "V1BETA1", ID: "abc.123.do-re-mi"},
|
{Version: "v1beta2", ID: "123", RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst},
|
||||||
|
{Version: "V1BETA1", ID: "abc.123.do-re-mi",
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}}, DNSPolicy: api.DNSClusterFirst},
|
||||||
{
|
{
|
||||||
Version: "v1beta1",
|
Version: "v1beta1",
|
||||||
ID: "abc",
|
ID: "abc",
|
||||||
@ -537,9 +526,9 @@ func TestValidateManifest(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Ports: []api.Port{
|
Ports: []api.Port{
|
||||||
{Name: "p1", ContainerPort: 80, HostPort: 8080},
|
{Name: "p1", ContainerPort: 80, HostPort: 8080, Protocol: "TCP"},
|
||||||
{Name: "p2", ContainerPort: 81},
|
{Name: "p2", ContainerPort: 81, Protocol: "TCP"},
|
||||||
{ContainerPort: 82},
|
{ContainerPort: 82, Protocol: "TCP"},
|
||||||
},
|
},
|
||||||
Env: []api.EnvVar{
|
Env: []api.EnvVar{
|
||||||
{Name: "ev1", Value: "val1"},
|
{Name: "ev1", Value: "val1"},
|
||||||
@ -550,8 +539,11 @@ func TestValidateManifest(t *testing.T) {
|
|||||||
{Name: "vol1", MountPath: "/foo"},
|
{Name: "vol1", MountPath: "/foo"},
|
||||||
{Name: "vol1", MountPath: "/bar"},
|
{Name: "vol1", MountPath: "/bar"},
|
||||||
},
|
},
|
||||||
|
ImagePullPolicy: "IfNotPresent",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, manifest := range successCases {
|
for _, manifest := range successCases {
|
||||||
@ -583,22 +575,23 @@ func TestValidateManifest(t *testing.T) {
|
|||||||
|
|
||||||
func TestValidatePodSpec(t *testing.T) {
|
func TestValidatePodSpec(t *testing.T) {
|
||||||
successCases := []api.PodSpec{
|
successCases := []api.PodSpec{
|
||||||
{}, // empty is valid, if not very useful */
|
|
||||||
{ // Populate basic fields, leave defaults for most.
|
{ // Populate basic fields, leave defaults for most.
|
||||||
Volumes: []api.Volume{{Name: "vol"}},
|
Volumes: []api.Volume{{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}}},
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
{ // Populate all fields.
|
{ // Populate all fields.
|
||||||
Volumes: []api.Volume{
|
Volumes: []api.Volume{
|
||||||
{Name: "vol"},
|
{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}},
|
||||||
},
|
},
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||||
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
|
||||||
NodeSelector: map[string]string{
|
NodeSelector: map[string]string{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
Host: "foobar",
|
Host: "foobar",
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i := range successCases {
|
for i := range successCases {
|
||||||
@ -623,38 +616,26 @@ func TestValidatePodSpec(t *testing.T) {
|
|||||||
t.Errorf("expected failure for %q", k)
|
t.Errorf("expected failure for %q", k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultPod := api.PodSpec{} // all empty fields
|
|
||||||
if errs := ValidatePodSpec(&defaultPod); len(errs) != 0 {
|
|
||||||
t.Errorf("expected success: %v", errs)
|
|
||||||
}
|
|
||||||
if util.AllPtrFieldsNil(defaultPod.RestartPolicy) {
|
|
||||||
t.Errorf("expected a default RestartPolicy")
|
|
||||||
}
|
|
||||||
if defaultPod.DNSPolicy == "" {
|
|
||||||
t.Errorf("expected a default DNSPolicy")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidatePod(t *testing.T) {
|
func TestValidatePod(t *testing.T) {
|
||||||
successCases := []api.Pod{
|
successCases := []api.Pod{
|
||||||
{ // Mostly empty.
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: "ns"},
|
|
||||||
},
|
|
||||||
{ // Basic fields.
|
{ // Basic fields.
|
||||||
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: "ns"},
|
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: "ns"},
|
||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{
|
||||||
Volumes: []api.Volume{{Name: "vol"}},
|
Volumes: []api.Volume{{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}}},
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ // Just about everything.
|
{ // Just about everything.
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc.123.do-re-mi", Namespace: "ns"},
|
ObjectMeta: api.ObjectMeta{Name: "abc.123.do-re-mi", Namespace: "ns"},
|
||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{
|
||||||
Volumes: []api.Volume{
|
Volumes: []api.Volume{
|
||||||
{Name: "vol"},
|
{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}},
|
||||||
},
|
},
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||||
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
NodeSelector: map[string]string{
|
NodeSelector: map[string]string{
|
||||||
@ -896,21 +877,27 @@ func TestValidateBoundPods(t *testing.T) {
|
|||||||
successCases := []api.BoundPod{
|
successCases := []api.BoundPod{
|
||||||
{ // Mostly empty.
|
{ // Mostly empty.
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: "ns"},
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: "ns"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{ // Basic fields.
|
{ // Basic fields.
|
||||||
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: "ns"},
|
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: "ns"},
|
||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{
|
||||||
Volumes: []api.Volume{{Name: "vol"}},
|
Volumes: []api.Volume{{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}}},
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ // Just about everything.
|
{ // Just about everything.
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc.123.do-re-mi", Namespace: "ns"},
|
ObjectMeta: api.ObjectMeta{Name: "abc.123.do-re-mi", Namespace: "ns"},
|
||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{
|
||||||
Volumes: []api.Volume{
|
Volumes: []api.Volume{
|
||||||
{Name: "vol"},
|
{Name: "vol", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}},
|
||||||
},
|
},
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||||
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
NodeSelector: map[string]string{
|
NodeSelector: map[string]string{
|
||||||
@ -955,20 +942,50 @@ func TestValidateService(t *testing.T) {
|
|||||||
svc: api.Service{
|
svc: api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 8675,
|
Port: 8675,
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Should fail because the ID is missing.
|
// Should fail because the ID is missing.
|
||||||
numErrs: 1,
|
numErrs: 1,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "missing protocol",
|
||||||
|
svc: api.Service{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: api.ServiceSpec{
|
||||||
|
Port: 8675,
|
||||||
|
Selector: map[string]string{"foo": "bar"},
|
||||||
|
SessionAffinity: "None",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Should fail because protocol is missing.
|
||||||
|
numErrs: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "missing session affinity",
|
||||||
|
svc: api.Service{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: api.ServiceSpec{
|
||||||
|
Port: 8675,
|
||||||
|
Selector: map[string]string{"foo": "bar"},
|
||||||
|
Protocol: "TCP",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Should fail because protocol is missing.
|
||||||
|
numErrs: 1,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "missing namespace",
|
name: "missing namespace",
|
||||||
svc: api.Service{
|
svc: api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 8675,
|
Port: 8675,
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Should fail because the Namespace is missing.
|
// Should fail because the Namespace is missing.
|
||||||
@ -979,8 +996,10 @@ func TestValidateService(t *testing.T) {
|
|||||||
svc: api.Service{
|
svc: api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "-123abc", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "-123abc", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 8675,
|
Port: 8675,
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Should fail because the ID is invalid.
|
// Should fail because the ID is invalid.
|
||||||
@ -995,8 +1014,10 @@ func TestValidateService(t *testing.T) {
|
|||||||
Namespace: api.NamespaceDefault,
|
Namespace: api.NamespaceDefault,
|
||||||
},
|
},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 8675,
|
Port: 8675,
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Should fail because the Base value for generation is invalid
|
// Should fail because the Base value for generation is invalid
|
||||||
@ -1011,8 +1032,10 @@ func TestValidateService(t *testing.T) {
|
|||||||
Namespace: api.NamespaceDefault,
|
Namespace: api.NamespaceDefault,
|
||||||
},
|
},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 8675,
|
Port: 8675,
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Should fail because the generate name type is invalid.
|
// Should fail because the generate name type is invalid.
|
||||||
@ -1023,7 +1046,9 @@ func TestValidateService(t *testing.T) {
|
|||||||
svc: api.Service{
|
svc: api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Should fail because the port number is missing/invalid.
|
// Should fail because the port number is missing/invalid.
|
||||||
@ -1034,8 +1059,10 @@ func TestValidateService(t *testing.T) {
|
|||||||
svc: api.Service{
|
svc: api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 66536,
|
Port: 66536,
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Should fail because the port number is invalid.
|
// Should fail because the port number is invalid.
|
||||||
@ -1046,9 +1073,10 @@ func TestValidateService(t *testing.T) {
|
|||||||
svc: api.Service{
|
svc: api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 8675,
|
Port: 8675,
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
Protocol: "INVALID",
|
Protocol: "INVALID",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Should fail because the protocol is invalid.
|
// Should fail because the protocol is invalid.
|
||||||
@ -1059,7 +1087,9 @@ func TestValidateService(t *testing.T) {
|
|||||||
svc: api.Service{
|
svc: api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 8675,
|
Port: 8675,
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Should be ok because the selector is missing.
|
// Should be ok because the selector is missing.
|
||||||
@ -1070,9 +1100,10 @@ func TestValidateService(t *testing.T) {
|
|||||||
svc: api.Service{
|
svc: api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 8675,
|
Port: 8675,
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
Protocol: "TCP",
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
numErrs: 0,
|
numErrs: 0,
|
||||||
@ -1082,9 +1113,10 @@ func TestValidateService(t *testing.T) {
|
|||||||
svc: api.Service{
|
svc: api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 8675,
|
Port: 8675,
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
Protocol: "UDP",
|
Protocol: "UDP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
numErrs: 0,
|
numErrs: 0,
|
||||||
@ -1094,8 +1126,10 @@ func TestValidateService(t *testing.T) {
|
|||||||
svc: api.Service{
|
svc: api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 8675,
|
Port: 8675,
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
|
Protocol: "UDP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
numErrs: 0,
|
numErrs: 0,
|
||||||
@ -1108,13 +1142,15 @@ func TestValidateService(t *testing.T) {
|
|||||||
Port: 80,
|
Port: 80,
|
||||||
CreateExternalLoadBalancer: true,
|
CreateExternalLoadBalancer: true,
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
existing: api.ServiceList{
|
existing: api.ServiceList{
|
||||||
Items: []api.Service{
|
Items: []api.Service{
|
||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "def123", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "def123", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{Port: 80, CreateExternalLoadBalancer: true},
|
Spec: api.ServiceSpec{Port: 80, CreateExternalLoadBalancer: true, Protocol: "TCP"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1128,13 +1164,15 @@ func TestValidateService(t *testing.T) {
|
|||||||
Port: 80,
|
Port: 80,
|
||||||
CreateExternalLoadBalancer: true,
|
CreateExternalLoadBalancer: true,
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
existing: api.ServiceList{
|
existing: api.ServiceList{
|
||||||
Items: []api.Service{
|
Items: []api.Service{
|
||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "def123", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "def123", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{Port: 80},
|
Spec: api.ServiceSpec{Port: 80, Protocol: "TCP"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1145,15 +1183,17 @@ func TestValidateService(t *testing.T) {
|
|||||||
svc: api.Service{
|
svc: api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 80,
|
Port: 80,
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
existing: api.ServiceList{
|
existing: api.ServiceList{
|
||||||
Items: []api.Service{
|
Items: []api.Service{
|
||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "def123", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "def123", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{Port: 80, CreateExternalLoadBalancer: true},
|
Spec: api.ServiceSpec{Port: 80, CreateExternalLoadBalancer: true, Protocol: "TCP"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1164,15 +1204,17 @@ func TestValidateService(t *testing.T) {
|
|||||||
svc: api.Service{
|
svc: api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 80,
|
Port: 80,
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
existing: api.ServiceList{
|
existing: api.ServiceList{
|
||||||
Items: []api.Service{
|
Items: []api.Service{
|
||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "def123", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "def123", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{Port: 80},
|
Spec: api.ServiceSpec{Port: 80, Protocol: "TCP"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1189,7 +1231,9 @@ func TestValidateService(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 8675,
|
Port: 8675,
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
numErrs: 1,
|
numErrs: 1,
|
||||||
@ -1205,7 +1249,9 @@ func TestValidateService(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 8675,
|
Port: 8675,
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
numErrs: 1,
|
numErrs: 1,
|
||||||
@ -1218,8 +1264,10 @@ func TestValidateService(t *testing.T) {
|
|||||||
Namespace: api.NamespaceDefault,
|
Namespace: api.NamespaceDefault,
|
||||||
},
|
},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 8675,
|
Port: 8675,
|
||||||
Selector: map[string]string{"foo": "bar", "NoUppercaseOrSpecialCharsLike=Equals": "bar"},
|
Selector: map[string]string{"foo": "bar", "NoUppercaseOrSpecialCharsLike=Equals": "bar"},
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
numErrs: 1,
|
numErrs: 1,
|
||||||
@ -1238,17 +1286,16 @@ func TestValidateService(t *testing.T) {
|
|||||||
svc := api.Service{
|
svc := api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 8675,
|
Port: 8675,
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
errs := ValidateService(&svc)
|
errs := ValidateService(&svc)
|
||||||
if len(errs) != 0 {
|
if len(errs) != 0 {
|
||||||
t.Errorf("Unexpected non-zero error list: %#v", errs)
|
t.Errorf("Unexpected non-zero error list: %#v", errs)
|
||||||
}
|
}
|
||||||
if svc.Spec.Protocol != "TCP" {
|
|
||||||
t.Errorf("Expected default protocol of 'TCP': %#v", errs)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateReplicationController(t *testing.T) {
|
func TestValidateReplicationController(t *testing.T) {
|
||||||
@ -1258,6 +1305,10 @@ func TestValidateReplicationController(t *testing.T) {
|
|||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Labels: validSelector,
|
Labels: validSelector,
|
||||||
},
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
invalidVolumePodTemplate := api.PodTemplate{
|
invalidVolumePodTemplate := api.PodTemplate{
|
||||||
@ -1271,9 +1322,8 @@ func TestValidateReplicationController(t *testing.T) {
|
|||||||
invalidPodTemplate := api.PodTemplate{
|
invalidPodTemplate := api.PodTemplate{
|
||||||
Spec: api.PodTemplateSpec{
|
Spec: api.PodTemplateSpec{
|
||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{
|
||||||
RestartPolicy: api.RestartPolicy{
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
Always: &api.RestartPolicyAlways{},
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Labels: invalidSelector,
|
Labels: invalidSelector,
|
||||||
@ -1400,6 +1450,7 @@ func TestValidateReplicationController(t *testing.T) {
|
|||||||
RestartPolicy: api.RestartPolicy{
|
RestartPolicy: api.RestartPolicy{
|
||||||
OnFailure: &api.RestartPolicyOnFailure{},
|
OnFailure: &api.RestartPolicyOnFailure{},
|
||||||
},
|
},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Labels: validSelector,
|
Labels: validSelector,
|
||||||
@ -1419,6 +1470,7 @@ func TestValidateReplicationController(t *testing.T) {
|
|||||||
RestartPolicy: api.RestartPolicy{
|
RestartPolicy: api.RestartPolicy{
|
||||||
Never: &api.RestartPolicyNever{},
|
Never: &api.RestartPolicyNever{},
|
||||||
},
|
},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Labels: validSelector,
|
Labels: validSelector,
|
||||||
|
@ -96,7 +96,7 @@ func (c *testClient) Setup() *testClient {
|
|||||||
func (c *testClient) Validate(t *testing.T, received runtime.Object, err error) {
|
func (c *testClient) Validate(t *testing.T, received runtime.Object, err error) {
|
||||||
c.ValidateCommon(t, err)
|
c.ValidateCommon(t, err)
|
||||||
|
|
||||||
if c.Response.Body != nil && !api.Semantic.DeepEqual(c.Response.Body, received) {
|
if c.Response.Body != nil && !api.Semantic.DeepDerivative(c.Response.Body, received) {
|
||||||
t.Errorf("bad response for request %#v: expected %#v, got %#v", c.Request, c.Response.Body, received)
|
t.Errorf("bad response for request %#v: expected %#v, got %#v", c.Request, c.Response.Body, received)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
// "reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -62,7 +62,7 @@ func TestRequestWithErrorWontChange(t *testing.T) {
|
|||||||
if changed != &r {
|
if changed != &r {
|
||||||
t.Errorf("returned request should point to the same object")
|
t.Errorf("returned request should point to the same object")
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(&original, changed) {
|
if !api.Semantic.DeepDerivative(changed, &original) {
|
||||||
t.Errorf("expected %#v, got %#v", &original, changed)
|
t.Errorf("expected %#v, got %#v", &original, changed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,7 +148,7 @@ func TestRequestParseSelectorParam(t *testing.T) {
|
|||||||
|
|
||||||
func TestRequestParam(t *testing.T) {
|
func TestRequestParam(t *testing.T) {
|
||||||
r := (&Request{}).Param("foo", "a")
|
r := (&Request{}).Param("foo", "a")
|
||||||
if !reflect.DeepEqual(map[string]string{"foo": "a"}, r.params) {
|
if !api.Semantic.DeepDerivative(r.params, map[string]string{"foo": "a"}) {
|
||||||
t.Errorf("should have set a param: %#v", r)
|
t.Errorf("should have set a param: %#v", r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -218,7 +218,7 @@ func TestTransformResponse(t *testing.T) {
|
|||||||
if hasErr != test.Error {
|
if hasErr != test.Error {
|
||||||
t.Errorf("%d: unexpected error: %t %v", i, test.Error, err)
|
t.Errorf("%d: unexpected error: %t %v", i, test.Error, err)
|
||||||
}
|
}
|
||||||
if !(test.Data == nil && response == nil) && !reflect.DeepEqual(test.Data, response) {
|
if !(test.Data == nil && response == nil) && !api.Semantic.DeepDerivative(test.Data, response) {
|
||||||
t.Errorf("%d: unexpected response: %#v %#v", i, test.Data, response)
|
t.Errorf("%d: unexpected response: %#v %#v", i, test.Data, response)
|
||||||
}
|
}
|
||||||
if test.Created != created {
|
if test.Created != created {
|
||||||
@ -491,7 +491,7 @@ func TestDoRequestNewWay(t *testing.T) {
|
|||||||
}
|
}
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
t.Error("nil obj")
|
t.Error("nil obj")
|
||||||
} else if !reflect.DeepEqual(obj, expectedObj) {
|
} else if !api.Semantic.DeepDerivative(expectedObj, obj) {
|
||||||
t.Errorf("Expected: %#v, got %#v", expectedObj, obj)
|
t.Errorf("Expected: %#v, got %#v", expectedObj, obj)
|
||||||
}
|
}
|
||||||
fakeHandler.ValidateRequest(t, "/api/v1beta2/foo/bar/baz?labels=name%3Dfoo&timeout=1s", "POST", &reqBody)
|
fakeHandler.ValidateRequest(t, "/api/v1beta2/foo/bar/baz?labels=name%3Dfoo&timeout=1s", "POST", &reqBody)
|
||||||
@ -526,7 +526,7 @@ func TestDoRequestNewWayReader(t *testing.T) {
|
|||||||
}
|
}
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
t.Error("nil obj")
|
t.Error("nil obj")
|
||||||
} else if !reflect.DeepEqual(obj, expectedObj) {
|
} else if !api.Semantic.DeepDerivative(expectedObj, obj) {
|
||||||
t.Errorf("Expected: %#v, got %#v", expectedObj, obj)
|
t.Errorf("Expected: %#v, got %#v", expectedObj, obj)
|
||||||
}
|
}
|
||||||
tmpStr := string(reqBodyExpected)
|
tmpStr := string(reqBodyExpected)
|
||||||
@ -562,7 +562,7 @@ func TestDoRequestNewWayObj(t *testing.T) {
|
|||||||
}
|
}
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
t.Error("nil obj")
|
t.Error("nil obj")
|
||||||
} else if !reflect.DeepEqual(obj, expectedObj) {
|
} else if !api.Semantic.DeepDerivative(expectedObj, obj) {
|
||||||
t.Errorf("Expected: %#v, got %#v", expectedObj, obj)
|
t.Errorf("Expected: %#v, got %#v", expectedObj, obj)
|
||||||
}
|
}
|
||||||
tmpStr := string(reqBodyExpected)
|
tmpStr := string(reqBodyExpected)
|
||||||
@ -611,7 +611,7 @@ func TestDoRequestNewWayFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
t.Error("nil obj")
|
t.Error("nil obj")
|
||||||
} else if !reflect.DeepEqual(obj, expectedObj) {
|
} else if !api.Semantic.DeepDerivative(expectedObj, obj) {
|
||||||
t.Errorf("Expected: %#v, got %#v", expectedObj, obj)
|
t.Errorf("Expected: %#v, got %#v", expectedObj, obj)
|
||||||
}
|
}
|
||||||
if wasCreated {
|
if wasCreated {
|
||||||
@ -653,7 +653,7 @@ func TestWasCreated(t *testing.T) {
|
|||||||
}
|
}
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
t.Error("nil obj")
|
t.Error("nil obj")
|
||||||
} else if !reflect.DeepEqual(obj, expectedObj) {
|
} else if !api.Semantic.DeepDerivative(expectedObj, obj) {
|
||||||
t.Errorf("Expected: %#v, got %#v", expectedObj, obj)
|
t.Errorf("Expected: %#v, got %#v", expectedObj, obj)
|
||||||
}
|
}
|
||||||
if !wasCreated {
|
if !wasCreated {
|
||||||
@ -790,7 +790,7 @@ func checkAuth(t *testing.T, expect *Config, r *http.Request) {
|
|||||||
foundAuth, found := authFromReq(r)
|
foundAuth, found := authFromReq(r)
|
||||||
if !found {
|
if !found {
|
||||||
t.Errorf("no auth found")
|
t.Errorf("no auth found")
|
||||||
} else if e, a := expect, foundAuth; !reflect.DeepEqual(e, a) {
|
} else if e, a := expect, foundAuth; !api.Semantic.DeepDerivative(e, a) {
|
||||||
t.Fatalf("Wrong basic auth: wanted %#v, got %#v", e, a)
|
t.Fatalf("Wrong basic auth: wanted %#v, got %#v", e, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -849,7 +849,7 @@ func TestWatch(t *testing.T) {
|
|||||||
if e, a := item.t, got.Type; e != a {
|
if e, a := item.t, got.Type; e != a {
|
||||||
t.Errorf("Expected %v, got %v", e, a)
|
t.Errorf("Expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
if e, a := item.obj, got.Object; !reflect.DeepEqual(e, a) {
|
if e, a := item.obj, got.Object; !api.Semantic.DeepDerivative(e, a) {
|
||||||
t.Errorf("Expected %v, got %v", e, a)
|
t.Errorf("Expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,7 +239,7 @@ func TestCreateReplica(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %#v", err)
|
t.Errorf("Unexpected error: %#v", err)
|
||||||
}
|
}
|
||||||
if !api.Semantic.DeepEqual(&expectedPod, actualPod) {
|
if !api.Semantic.DeepDerivative(&expectedPod, actualPod) {
|
||||||
t.Logf("Body: %s", fakeHandler.RequestBody)
|
t.Logf("Body: %s", fakeHandler.RequestBody)
|
||||||
t.Errorf("Unexpected mismatch. Expected\n %#v,\n Got:\n %#v", &expectedPod, actualPod)
|
t.Errorf("Unexpected mismatch. Expected\n %#v,\n Got:\n %#v", &expectedPod, actualPod)
|
||||||
}
|
}
|
||||||
@ -351,7 +351,7 @@ func TestWatchControllers(t *testing.T) {
|
|||||||
var testControllerSpec api.ReplicationController
|
var testControllerSpec api.ReplicationController
|
||||||
received := make(chan struct{})
|
received := make(chan struct{})
|
||||||
manager.syncHandler = func(controllerSpec api.ReplicationController) error {
|
manager.syncHandler = func(controllerSpec api.ReplicationController) error {
|
||||||
if !api.Semantic.DeepEqual(controllerSpec, testControllerSpec) {
|
if !api.Semantic.DeepDerivative(controllerSpec, testControllerSpec) {
|
||||||
t.Errorf("Expected %#v, but got %#v", testControllerSpec, controllerSpec)
|
t.Errorf("Expected %#v, but got %#v", testControllerSpec, controllerSpec)
|
||||||
}
|
}
|
||||||
close(received)
|
close(received)
|
||||||
|
@ -68,7 +68,6 @@ func NewConverter() *Converter {
|
|||||||
return &Converter{
|
return &Converter{
|
||||||
conversionFuncs: map[typePair]reflect.Value{},
|
conversionFuncs: map[typePair]reflect.Value{},
|
||||||
defaultingFuncs: map[reflect.Type]reflect.Value{},
|
defaultingFuncs: map[reflect.Type]reflect.Value{},
|
||||||
funcs: map[typePair]reflect.Value{},
|
|
||||||
nameFunc: func(t reflect.Type) string { return t.Name() },
|
nameFunc: func(t reflect.Type) string { return t.Name() },
|
||||||
structFieldDests: map[typeNamePair][]typeNamePair{},
|
structFieldDests: map[typeNamePair][]typeNamePair{},
|
||||||
structFieldSources: map[typeNamePair][]typeNamePair{},
|
structFieldSources: map[typeNamePair][]typeNamePair{},
|
||||||
@ -221,7 +220,7 @@ func (s *scope) error(message string, args ...interface{}) error {
|
|||||||
// used if recursive conversion calls are desired). It must return an error.
|
// used if recursive conversion calls are desired). It must return an error.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// c.RegisteConversionFuncr(
|
// c.RegisteConversionFunc(
|
||||||
// func(in *Pod, out *v1beta1.Pod, s Scope) error {
|
// func(in *Pod, out *v1beta1.Pod, s Scope) error {
|
||||||
// // conversion logic...
|
// // conversion logic...
|
||||||
// return nil
|
// return nil
|
||||||
@ -279,7 +278,7 @@ func (c *Converter) SetStructFieldCopy(srcFieldType interface{}, srcFieldName st
|
|||||||
// defaultingFunc must take one parameters: a pointer to the input type.
|
// defaultingFunc must take one parameters: a pointer to the input type.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// c.RegisteDefaultingFuncr(
|
// c.RegisteDefaultingFunc(
|
||||||
// func(in *v1beta1.Pod) {
|
// func(in *v1beta1.Pod) {
|
||||||
// // defaulting logic...
|
// // defaulting logic...
|
||||||
// })
|
// })
|
||||||
@ -415,7 +414,6 @@ func (c *Converter) callCustom(sv, dv, custom reflect.Value, scope *scope) error
|
|||||||
// one is registered.
|
// one is registered.
|
||||||
func (c *Converter) convert(sv, dv reflect.Value, scope *scope) error {
|
func (c *Converter) convert(sv, dv reflect.Value, scope *scope) error {
|
||||||
dt, st := dv.Type(), sv.Type()
|
dt, st := dv.Type(), sv.Type()
|
||||||
|
|
||||||
// Apply default values.
|
// Apply default values.
|
||||||
if fv, ok := c.defaultingFuncs[st]; ok {
|
if fv, ok := c.defaultingFuncs[st]; ok {
|
||||||
if c.Debug != nil {
|
if c.Debug != nil {
|
||||||
|
@ -36,11 +36,11 @@ func TestConverter_DefaultConvert(t *testing.T) {
|
|||||||
}
|
}
|
||||||
c := NewConverter()
|
c := NewConverter()
|
||||||
c.Debug = t
|
c.Debug = t
|
||||||
c.NameFunc = func(t reflect.Type) string { return "MyType" }
|
c.nameFunc = func(t reflect.Type) string { return "MyType" }
|
||||||
|
|
||||||
// Ensure conversion funcs can call DefaultConvert to get default behavior,
|
// Ensure conversion funcs can call DefaultConvert to get default behavior,
|
||||||
// then fixup remaining fields manually
|
// then fixup remaining fields manually
|
||||||
err := c.Register(func(in *A, out *B, s Scope) error {
|
err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error {
|
||||||
if err := s.DefaultConvert(in, out, IgnoreMissingFields); err != nil {
|
if err := s.DefaultConvert(in, out, IgnoreMissingFields); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -224,7 +224,7 @@ func TestConverter_MapElemAddr(t *testing.T) {
|
|||||||
}
|
}
|
||||||
c := NewConverter()
|
c := NewConverter()
|
||||||
c.Debug = t
|
c.Debug = t
|
||||||
err := c.Register(
|
err := c.RegisterConversionFunc(
|
||||||
func(in *int, out *string, s Scope) error {
|
func(in *int, out *string, s Scope) error {
|
||||||
*out = fmt.Sprintf("%v", *in)
|
*out = fmt.Sprintf("%v", *in)
|
||||||
return nil
|
return nil
|
||||||
@ -233,7 +233,7 @@ func TestConverter_MapElemAddr(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
err = c.Register(
|
err = c.RegisterConversionFunc(
|
||||||
func(in *string, out *int, s Scope) error {
|
func(in *string, out *int, s Scope) error {
|
||||||
if str, err := strconv.Atoi(*in); err != nil {
|
if str, err := strconv.Atoi(*in); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -103,27 +103,19 @@ func (s *Scheme) DecodeInto(data []byte, obj interface{}) error {
|
|||||||
dataVersion = objVersion
|
dataVersion = objVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
if objVersion == dataVersion {
|
external, err := s.NewObject(dataVersion, dataKind)
|
||||||
// Easy case!
|
if err != nil {
|
||||||
err = yaml.Unmarshal(data, obj)
|
return err
|
||||||
if err != nil {
|
}
|
||||||
return err
|
// yaml is a superset of json, so we use it to decode here. That way,
|
||||||
}
|
// we understand both.
|
||||||
} else {
|
err = yaml.Unmarshal(data, external)
|
||||||
external, err := s.NewObject(dataVersion, dataKind)
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
}
|
err = s.converter.Convert(external, obj, 0, s.generateConvertMeta(dataVersion, objVersion))
|
||||||
// yaml is a superset of json, so we use it to decode here. That way,
|
if err != nil {
|
||||||
// we understand both.
|
return err
|
||||||
err = yaml.Unmarshal(data, external)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = s.converter.Convert(external, obj, 0, s.generateConvertMeta(dataVersion, objVersion))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version and Kind should be blank in memory.
|
// Version and Kind should be blank in memory.
|
||||||
|
@ -233,3 +233,140 @@ func (e Equalities) DeepEqual(a1, a2 interface{}) bool {
|
|||||||
}
|
}
|
||||||
return e.deepValueEqual(v1, v2, make(map[visit]bool), 0)
|
return e.deepValueEqual(v1, v2, make(map[visit]bool), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e Equalities) deepValueDerive(v1, v2 reflect.Value, visited map[visit]bool, depth int) bool {
|
||||||
|
if !v1.IsValid() || !v2.IsValid() {
|
||||||
|
return v1.IsValid() == v2.IsValid()
|
||||||
|
}
|
||||||
|
if v1.Type() != v2.Type() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if fv, ok := e[v1.Type()]; ok {
|
||||||
|
return fv.Call([]reflect.Value{v1, v2})[0].Bool()
|
||||||
|
}
|
||||||
|
|
||||||
|
hard := func(k reflect.Kind) bool {
|
||||||
|
switch k {
|
||||||
|
case reflect.Array, reflect.Map, reflect.Slice, reflect.Struct:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if v1.CanAddr() && v2.CanAddr() && hard(v1.Kind()) {
|
||||||
|
addr1 := v1.UnsafeAddr()
|
||||||
|
addr2 := v2.UnsafeAddr()
|
||||||
|
if addr1 > addr2 {
|
||||||
|
// Canonicalize order to reduce number of entries in visited.
|
||||||
|
addr1, addr2 = addr2, addr1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Short circuit if references are identical ...
|
||||||
|
if addr1 == addr2 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... or already seen
|
||||||
|
typ := v1.Type()
|
||||||
|
v := visit{addr1, addr2, typ}
|
||||||
|
if visited[v] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember for later.
|
||||||
|
visited[v] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v1.Kind() {
|
||||||
|
case reflect.Array:
|
||||||
|
for i := 0; i < v1.Len(); i++ {
|
||||||
|
if !e.deepValueDerive(v1.Index(i), v2.Index(i), visited, depth+1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
case reflect.Slice:
|
||||||
|
if (v1.IsNil() || v1.Len() == 0) != (v2.IsNil() || v2.Len() == 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if v1.IsNil() || v1.Len() == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if v1.Pointer() == v2.Pointer() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for i := 0; i < v1.Len(); i++ {
|
||||||
|
if !e.deepValueDerive(v1.Index(i), v2.Index(i), visited, depth+1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
case reflect.String:
|
||||||
|
if v1.Len() == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return v1.String() == v2.String()
|
||||||
|
case reflect.Interface:
|
||||||
|
if v1.IsNil() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return e.deepValueDerive(v1.Elem(), v2.Elem(), visited, depth+1)
|
||||||
|
case reflect.Ptr:
|
||||||
|
if v1.IsNil() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return e.deepValueDerive(v1.Elem(), v2.Elem(), visited, depth+1)
|
||||||
|
case reflect.Struct:
|
||||||
|
for i, n := 0, v1.NumField(); i < n; i++ {
|
||||||
|
if !e.deepValueDerive(v1.Field(i), v2.Field(i), visited, depth+1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
case reflect.Map:
|
||||||
|
if (v1.IsNil() || v1.Len() == 0) != (v2.IsNil() || v2.Len() == 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if v1.IsNil() || v1.Len() == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if v1.Pointer() == v2.Pointer() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for _, k := range v1.MapKeys() {
|
||||||
|
if !e.deepValueDerive(v1.MapIndex(k), v2.MapIndex(k), visited, depth+1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
case reflect.Func:
|
||||||
|
if v1.IsNil() && v2.IsNil() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// Can't do better than this:
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
// Normal equality suffices
|
||||||
|
if v1.CanInterface() && v2.CanInterface() {
|
||||||
|
return v1.Interface() == v2.Interface()
|
||||||
|
}
|
||||||
|
return v1.CanInterface() == v2.CanInterface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepDerivative is similar to DeepEqual except that unset fields in a1 are
|
||||||
|
// ignored (not compared). This allows we to focus on the fields that matter to
|
||||||
|
// the semantic comparison.
|
||||||
|
//
|
||||||
|
// The unset fields include a nil pointer and an empty string.
|
||||||
|
func (e Equalities) DeepDerivative(a1, a2 interface{}) bool {
|
||||||
|
if a1 == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
v1 := reflect.ValueOf(a1)
|
||||||
|
v2 := reflect.ValueOf(a2)
|
||||||
|
if v1.Type() != v2.Type() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return e.deepValueDerive(v1, v2, make(map[visit]bool), 0)
|
||||||
|
}
|
||||||
|
@ -73,11 +73,17 @@ func TestParsePod(t *testing.T) {
|
|||||||
ObjectMeta: api.ObjectMeta{Name: "test pod"},
|
ObjectMeta: api.ObjectMeta{Name: "test pod"},
|
||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{
|
||||||
Containers: []api.Container{
|
Containers: []api.Container{
|
||||||
{Name: "my container"},
|
{
|
||||||
|
Name: "my container",
|
||||||
|
ImagePullPolicy: api.PullIfNotPresent,
|
||||||
|
TerminationMessagePath: api.TerminationMessagePathDefault,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Volumes: []api.Volume{
|
Volumes: []api.Volume{
|
||||||
{Name: "volume"},
|
{Name: "volume", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}},
|
||||||
},
|
},
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
}, v1beta1.Codec, testParser)
|
}, v1beta1.Codec, testParser)
|
||||||
}
|
}
|
||||||
@ -96,6 +102,8 @@ func TestParseService(t *testing.T) {
|
|||||||
Selector: map[string]string{
|
Selector: map[string]string{
|
||||||
"area": "staging",
|
"area": "staging",
|
||||||
},
|
},
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
}, v1beta1.Codec, testParser)
|
}, v1beta1.Codec, testParser)
|
||||||
}
|
}
|
||||||
@ -109,11 +117,17 @@ func TestParseController(t *testing.T) {
|
|||||||
Template: &api.PodTemplateSpec{
|
Template: &api.PodTemplateSpec{
|
||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{
|
||||||
Containers: []api.Container{
|
Containers: []api.Container{
|
||||||
{Name: "my container"},
|
{
|
||||||
|
Name: "my container",
|
||||||
|
ImagePullPolicy: api.PullIfNotPresent,
|
||||||
|
TerminationMessagePath: api.TerminationMessagePathDefault,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Volumes: []api.Volume{
|
Volumes: []api.Volume{
|
||||||
{Name: "volume"},
|
{Name: "volume", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}},
|
||||||
},
|
},
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -71,6 +71,10 @@ func TestYAMLPrinterPrint(t *testing.T) {
|
|||||||
|
|
||||||
obj := &api.Pod{
|
obj := &api.Pod{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
printer.PrintObj(obj, buf)
|
printer.PrintObj(obj, buf)
|
||||||
@ -95,6 +99,10 @@ func TestIdentityPrinter(t *testing.T) {
|
|||||||
|
|
||||||
obj := &api.Pod{
|
obj := &api.Pod{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
buff.Reset()
|
buff.Reset()
|
||||||
printer.PrintObj(obj, buff)
|
printer.PrintObj(obj, buff)
|
||||||
|
@ -42,9 +42,17 @@ func testData() (*api.PodList, *api.ServiceList) {
|
|||||||
Items: []api.Pod{
|
Items: []api.Pod{
|
||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "10"},
|
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "10"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "test", ResourceVersion: "11"},
|
ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "test", ResourceVersion: "11"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -55,6 +63,10 @@ func testData() (*api.PodList, *api.ServiceList) {
|
|||||||
Items: []api.Service{
|
Items: []api.Service{
|
||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
|
ObjectMeta: api.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
|
||||||
|
Spec: api.ServiceSpec{
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -296,6 +308,10 @@ func watchTestData() ([]api.Pod, []watch.Event) {
|
|||||||
Namespace: "test",
|
Namespace: "test",
|
||||||
ResourceVersion: "10",
|
ResourceVersion: "10",
|
||||||
},
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
events := []watch.Event{
|
events := []watch.Event{
|
||||||
@ -307,6 +323,10 @@ func watchTestData() ([]api.Pod, []watch.Event) {
|
|||||||
Namespace: "test",
|
Namespace: "test",
|
||||||
ResourceVersion: "11",
|
ResourceVersion: "11",
|
||||||
},
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -317,6 +337,10 @@ func watchTestData() ([]api.Pod, []watch.Event) {
|
|||||||
Namespace: "test",
|
Namespace: "test",
|
||||||
ResourceVersion: "12",
|
ResourceVersion: "12",
|
||||||
},
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,12 @@ func TestMerge(t *testing.T) {
|
|||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
},
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{
|
||||||
|
Always: &api.RestartPolicyAlways{},
|
||||||
|
},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -57,6 +63,10 @@ func TestMerge(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{
|
||||||
Host: "bar",
|
Host: "bar",
|
||||||
|
RestartPolicy: api.RestartPolicy{
|
||||||
|
Always: &api.RestartPolicyAlways{},
|
||||||
|
},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -74,12 +84,18 @@ func TestMerge(t *testing.T) {
|
|||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{
|
||||||
Volumes: []api.Volume{
|
Volumes: []api.Volume{
|
||||||
{
|
{
|
||||||
Name: "v1",
|
Name: "v1",
|
||||||
|
Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "v2",
|
Name: "v2",
|
||||||
|
Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
RestartPolicy: api.RestartPolicy{
|
||||||
|
Always: &api.RestartPolicyAlways{},
|
||||||
|
},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -91,13 +107,13 @@ func TestMerge(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for i, test := range tests {
|
||||||
err := Merge(test.obj, test.fragment, "Pod")
|
err := Merge(test.obj, test.fragment, "Pod")
|
||||||
if !test.expectErr {
|
if !test.expectErr {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
} else if !reflect.DeepEqual(test.obj, test.expected) {
|
} else if !reflect.DeepEqual(test.obj, test.expected) {
|
||||||
t.Errorf("\nexpected:\n%v\nsaw:\n%v", test.expected, test.obj)
|
t.Errorf("\n\ntestcase[%d]\nexpected:\n%v\nsaw:\n%v", i, test.expected, test.obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if test.expectErr && err == nil {
|
if test.expectErr && err == nil {
|
||||||
|
@ -88,9 +88,17 @@ func testData() (*api.PodList, *api.ServiceList) {
|
|||||||
Items: []api.Pod{
|
Items: []api.Pod{
|
||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "10"},
|
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "10"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "test", ResourceVersion: "11"},
|
ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "test", ResourceVersion: "11"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -376,7 +384,7 @@ func TestSelector(t *testing.T) {
|
|||||||
if err != nil || singular || len(test.Infos) != 3 {
|
if err != nil || singular || len(test.Infos) != 3 {
|
||||||
t.Fatalf("unexpected response: %v %f %#v", err, singular, test.Infos)
|
t.Fatalf("unexpected response: %v %f %#v", err, singular, test.Infos)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual([]runtime.Object{&pods.Items[0], &pods.Items[1], &svc.Items[0]}, test.Objects()) {
|
if !api.Semantic.DeepDerivative([]runtime.Object{&pods.Items[0], &pods.Items[1], &svc.Items[0]}, test.Objects()) {
|
||||||
t.Errorf("unexpected visited objects: %#v", test.Objects())
|
t.Errorf("unexpected visited objects: %#v", test.Objects())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,7 +427,7 @@ func TestStream(t *testing.T) {
|
|||||||
if err != nil || singular || len(test.Infos) != 3 {
|
if err != nil || singular || len(test.Infos) != 3 {
|
||||||
t.Fatalf("unexpected response: %v %f %#v", err, singular, test.Infos)
|
t.Fatalf("unexpected response: %v %f %#v", err, singular, test.Infos)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual([]runtime.Object{&pods.Items[0], &pods.Items[1], &rc.Items[0]}, test.Objects()) {
|
if !api.Semantic.DeepDerivative([]runtime.Object{&pods.Items[0], &pods.Items[1], &rc.Items[0]}, test.Objects()) {
|
||||||
t.Errorf("unexpected visited objects: %#v", test.Objects())
|
t.Errorf("unexpected visited objects: %#v", test.Objects())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -436,7 +444,7 @@ func TestYAMLStream(t *testing.T) {
|
|||||||
if err != nil || singular || len(test.Infos) != 3 {
|
if err != nil || singular || len(test.Infos) != 3 {
|
||||||
t.Fatalf("unexpected response: %v %f %#v", err, singular, test.Infos)
|
t.Fatalf("unexpected response: %v %f %#v", err, singular, test.Infos)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual([]runtime.Object{&pods.Items[0], &pods.Items[1], &rc.Items[0]}, test.Objects()) {
|
if !api.Semantic.DeepDerivative([]runtime.Object{&pods.Items[0], &pods.Items[1], &rc.Items[0]}, test.Objects()) {
|
||||||
t.Errorf("unexpected visited objects: %#v", test.Objects())
|
t.Errorf("unexpected visited objects: %#v", test.Objects())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -458,7 +466,7 @@ func TestMultipleObject(t *testing.T) {
|
|||||||
&svc.Items[0],
|
&svc.Items[0],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(expected, obj) {
|
if !api.Semantic.DeepDerivative(expected, obj) {
|
||||||
t.Errorf("unexpected visited objects: %#v", obj)
|
t.Errorf("unexpected visited objects: %#v", obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -612,7 +620,7 @@ func TestLatest(t *testing.T) {
|
|||||||
if err != nil || singular || len(test.Infos) != 3 {
|
if err != nil || singular || len(test.Infos) != 3 {
|
||||||
t.Fatalf("unexpected response: %v %f %#v", err, singular, test.Infos)
|
t.Fatalf("unexpected response: %v %f %#v", err, singular, test.Infos)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual([]runtime.Object{newPod, newPod2, newSvc}, test.Objects()) {
|
if !api.Semantic.DeepDerivative([]runtime.Object{newPod, newPod2, newSvc}, test.Objects()) {
|
||||||
t.Errorf("unexpected visited objects: %#v", test.Objects())
|
t.Errorf("unexpected visited objects: %#v", test.Objects())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -646,7 +654,7 @@ func TestIgnoreStreamErrors(t *testing.T) {
|
|||||||
t.Fatalf("unexpected response: %v %f %#v", err, singular, test.Infos)
|
t.Fatalf("unexpected response: %v %f %#v", err, singular, test.Infos)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual([]runtime.Object{&pods.Items[0], &svc.Items[0]}, test.Objects()) {
|
if !api.Semantic.DeepDerivative([]runtime.Object{&pods.Items[0], &svc.Items[0]}, test.Objects()) {
|
||||||
t.Errorf("unexpected visited objects: %#v", test.Objects())
|
t.Errorf("unexpected visited objects: %#v", test.Objects())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,11 +162,17 @@ func TestHelperCreate(t *testing.T) {
|
|||||||
Req: expectPost,
|
Req: expectPost,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Modify: true,
|
Modify: true,
|
||||||
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}},
|
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}},
|
||||||
ExpectObject: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}},
|
ExpectObject: &api.Pod{
|
||||||
Resp: &http.Response{StatusCode: http.StatusOK, Body: objBody(&api.Status{Status: api.StatusSuccess})},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
Req: expectPost,
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Resp: &http.Response{StatusCode: http.StatusOK, Body: objBody(&api.Status{Status: api.StatusSuccess})},
|
||||||
|
Req: expectPost,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
@ -400,9 +406,14 @@ func TestHelperUpdate(t *testing.T) {
|
|||||||
Req: expectPut,
|
Req: expectPut,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}},
|
Object: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}},
|
||||||
ExpectObject: &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"}},
|
ExpectObject: &api.Pod{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "10"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
|
},
|
||||||
Overwrite: true,
|
Overwrite: true,
|
||||||
RespFunc: func(req *http.Request) (*http.Response, error) {
|
RespFunc: func(req *http.Request) (*http.Response, error) {
|
||||||
if req.Method == "PUT" {
|
if req.Method == "PUT" {
|
||||||
|
@ -177,7 +177,7 @@ func TestNewPodAddedSnapshotAndUpdates(t *testing.T) {
|
|||||||
|
|
||||||
// container updates are separated as UPDATE
|
// container updates are separated as UPDATE
|
||||||
pod := podUpdate.Pods[0]
|
pod := podUpdate.Pods[0]
|
||||||
pod.Spec.Containers = []api.Container{{Name: "bar", Image: "test"}}
|
pod.Spec.Containers = []api.Container{{Name: "bar", Image: "test", ImagePullPolicy: api.PullIfNotPresent}}
|
||||||
channel <- CreatePodUpdate(kubelet.ADD, NoneSource, pod)
|
channel <- CreatePodUpdate(kubelet.ADD, NoneSource, pod)
|
||||||
expectPodUpdate(t, ch, CreatePodUpdate(kubelet.UPDATE, NoneSource, pod))
|
expectPodUpdate(t, ch, CreatePodUpdate(kubelet.UPDATE, NoneSource, pod))
|
||||||
}
|
}
|
||||||
@ -195,7 +195,7 @@ func TestNewPodAddedSnapshot(t *testing.T) {
|
|||||||
|
|
||||||
// container updates are separated as UPDATE
|
// container updates are separated as UPDATE
|
||||||
pod := podUpdate.Pods[0]
|
pod := podUpdate.Pods[0]
|
||||||
pod.Spec.Containers = []api.Container{{Name: "bar", Image: "test"}}
|
pod.Spec.Containers = []api.Container{{Name: "bar", Image: "test", ImagePullPolicy: api.PullIfNotPresent}}
|
||||||
channel <- CreatePodUpdate(kubelet.ADD, NoneSource, pod)
|
channel <- CreatePodUpdate(kubelet.ADD, NoneSource, pod)
|
||||||
expectPodUpdate(t, ch, CreatePodUpdate(kubelet.SET, TestSource, pod))
|
expectPodUpdate(t, ch, CreatePodUpdate(kubelet.SET, TestSource, pod))
|
||||||
}
|
}
|
||||||
@ -213,7 +213,7 @@ func TestNewPodAddedUpdatedRemoved(t *testing.T) {
|
|||||||
|
|
||||||
// an kubelet.ADD should be converted to kubelet.UPDATE
|
// an kubelet.ADD should be converted to kubelet.UPDATE
|
||||||
pod := CreateValidPod("foo", "new", "test")
|
pod := CreateValidPod("foo", "new", "test")
|
||||||
pod.Spec.Containers = []api.Container{{Name: "bar", Image: "test"}}
|
pod.Spec.Containers = []api.Container{{Name: "bar", Image: "test", ImagePullPolicy: api.PullIfNotPresent}}
|
||||||
podUpdate = CreatePodUpdate(kubelet.ADD, NoneSource, pod)
|
podUpdate = CreatePodUpdate(kubelet.ADD, NoneSource, pod)
|
||||||
channel <- podUpdate
|
channel <- podUpdate
|
||||||
expectPodUpdate(t, ch, CreatePodUpdate(kubelet.UPDATE, NoneSource, pod))
|
expectPodUpdate(t, ch, CreatePodUpdate(kubelet.UPDATE, NoneSource, pod))
|
||||||
@ -236,7 +236,7 @@ func TestNewPodAddedUpdatedSet(t *testing.T) {
|
|||||||
|
|
||||||
// should be converted to an kubelet.ADD, kubelet.REMOVE, and kubelet.UPDATE
|
// should be converted to an kubelet.ADD, kubelet.REMOVE, and kubelet.UPDATE
|
||||||
pod := CreateValidPod("foo2", "new", "test")
|
pod := CreateValidPod("foo2", "new", "test")
|
||||||
pod.Spec.Containers = []api.Container{{Name: "bar", Image: "test"}}
|
pod.Spec.Containers = []api.Container{{Name: "bar", Image: "test", ImagePullPolicy: api.PullIfNotPresent}}
|
||||||
podUpdate = CreatePodUpdate(kubelet.SET, NoneSource, pod, CreateValidPod("foo3", "new", ""), CreateValidPod("foo4", "new", "test"))
|
podUpdate = CreatePodUpdate(kubelet.SET, NoneSource, pod, CreateValidPod("foo3", "new", ""), CreateValidPod("foo4", "new", "test"))
|
||||||
channel <- podUpdate
|
channel <- podUpdate
|
||||||
expectPodUpdate(t, ch,
|
expectPodUpdate(t, ch,
|
||||||
|
@ -62,7 +62,6 @@ func ExampleManifestAndPod(id string) (v1beta1.ContainerManifest, api.BoundPod)
|
|||||||
{
|
{
|
||||||
Name: "c" + id,
|
Name: "c" + id,
|
||||||
Image: "foo",
|
Image: "foo",
|
||||||
TerminationMessagePath: "/somepath",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Volumes: []api.Volume{
|
Volumes: []api.Volume{
|
||||||
@ -94,7 +93,7 @@ func TestUpdateOnNonExistentFile(t *testing.T) {
|
|||||||
case got := <-ch:
|
case got := <-ch:
|
||||||
update := got.(kubelet.PodUpdate)
|
update := got.(kubelet.PodUpdate)
|
||||||
expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource)
|
expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource)
|
||||||
if !api.Semantic.DeepEqual(expected, update) {
|
if !api.Semantic.DeepDerivative(expected, update) {
|
||||||
t.Fatalf("Expected %#v, Got %#v", expected, update)
|
t.Fatalf("Expected %#v, Got %#v", expected, update)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,15 +136,7 @@ func TestReadFromFile(t *testing.T) {
|
|||||||
Namespace: "",
|
Namespace: "",
|
||||||
SelfLink: "",
|
SelfLink: "",
|
||||||
},
|
},
|
||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{Containers: []api.Container{{Image: "test/image"}}},
|
||||||
Containers: []api.Container{
|
|
||||||
{
|
|
||||||
Image: "test/image",
|
|
||||||
TerminationMessagePath: "/dev/termination-log",
|
|
||||||
ImagePullPolicy: api.PullAlways,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// There's no way to provide namespace in ContainerManifest, so
|
// There's no way to provide namespace in ContainerManifest, so
|
||||||
@ -161,7 +152,7 @@ func TestReadFromFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
update.Pods[0].ObjectMeta.SelfLink = ""
|
update.Pods[0].ObjectMeta.SelfLink = ""
|
||||||
|
|
||||||
if !api.Semantic.DeepEqual(expected, update) {
|
if !api.Semantic.DeepDerivative(expected, update) {
|
||||||
t.Fatalf("Expected %#v, Got %#v", expected, update)
|
t.Fatalf("Expected %#v, Got %#v", expected, update)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,15 +182,7 @@ func TestReadFromFileWithoutID(t *testing.T) {
|
|||||||
Namespace: "",
|
Namespace: "",
|
||||||
SelfLink: "",
|
SelfLink: "",
|
||||||
},
|
},
|
||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{Containers: []api.Container{{Image: "test/image"}}},
|
||||||
Containers: []api.Container{
|
|
||||||
{
|
|
||||||
Image: "test/image",
|
|
||||||
TerminationMessagePath: "/dev/termination-log",
|
|
||||||
ImagePullPolicy: api.PullAlways,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if len(update.Pods[0].ObjectMeta.Name) == 0 {
|
if len(update.Pods[0].ObjectMeta.Name) == 0 {
|
||||||
@ -209,7 +192,7 @@ func TestReadFromFileWithoutID(t *testing.T) {
|
|||||||
update.Pods[0].ObjectMeta.Namespace = ""
|
update.Pods[0].ObjectMeta.Namespace = ""
|
||||||
update.Pods[0].ObjectMeta.SelfLink = ""
|
update.Pods[0].ObjectMeta.SelfLink = ""
|
||||||
|
|
||||||
if !api.Semantic.DeepEqual(expected, update) {
|
if !api.Semantic.DeepDerivative(expected, update) {
|
||||||
t.Fatalf("Expected %#v, Got %#v", expected, update)
|
t.Fatalf("Expected %#v, Got %#v", expected, update)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,21 +223,13 @@ func TestReadV1Beta2FromFile(t *testing.T) {
|
|||||||
Namespace: "",
|
Namespace: "",
|
||||||
SelfLink: "",
|
SelfLink: "",
|
||||||
},
|
},
|
||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{Containers: []api.Container{{Image: "test/image"}}},
|
||||||
Containers: []api.Container{
|
|
||||||
{
|
|
||||||
Image: "test/image",
|
|
||||||
TerminationMessagePath: "/dev/termination-log",
|
|
||||||
ImagePullPolicy: api.PullAlways,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
update.Pods[0].ObjectMeta.Namespace = ""
|
update.Pods[0].ObjectMeta.Namespace = ""
|
||||||
update.Pods[0].ObjectMeta.SelfLink = ""
|
update.Pods[0].ObjectMeta.SelfLink = ""
|
||||||
|
|
||||||
if !api.Semantic.DeepEqual(expected, update) {
|
if !api.Semantic.DeepDerivative(expected, update) {
|
||||||
t.Fatalf("Expected %#v, Got %#v", expected, update)
|
t.Fatalf("Expected %#v, Got %#v", expected, update)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,7 +290,7 @@ func TestExtractFromEmptyDir(t *testing.T) {
|
|||||||
|
|
||||||
update := (<-ch).(kubelet.PodUpdate)
|
update := (<-ch).(kubelet.PodUpdate)
|
||||||
expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource)
|
expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource)
|
||||||
if !api.Semantic.DeepEqual(expected, update) {
|
if !api.Semantic.DeepDerivative(expected, update) {
|
||||||
t.Errorf("Expected %#v, Got %#v", expected, update)
|
t.Errorf("Expected %#v, Got %#v", expected, update)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -371,7 +346,7 @@ func TestExtractFromDir(t *testing.T) {
|
|||||||
}
|
}
|
||||||
sort.Sort(sortedPods(update.Pods))
|
sort.Sort(sortedPods(update.Pods))
|
||||||
sort.Sort(sortedPods(expected.Pods))
|
sort.Sort(sortedPods(expected.Pods))
|
||||||
if !api.Semantic.DeepEqual(expected, update) {
|
if !api.Semantic.DeepDerivative(expected, update) {
|
||||||
t.Fatalf("Expected %#v, Got %#v", expected, update)
|
t.Fatalf("Expected %#v, Got %#v", expected, update)
|
||||||
}
|
}
|
||||||
for i := range update.Pods {
|
for i := range update.Pods {
|
||||||
|
@ -90,8 +90,10 @@ func (m *Master) createMasterServiceIfNeeded(serviceName string, serviceIP net.I
|
|||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: servicePort,
|
Port: servicePort,
|
||||||
// maintained by this code, not by the pod selector
|
// maintained by this code, not by the pod selector
|
||||||
Selector: nil,
|
Selector: nil,
|
||||||
PortalIP: serviceIP.String(),
|
PortalIP: serviceIP.String(),
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Kids, don't do this at home: this is a hack. There's no good way to call the business
|
// Kids, don't do this at home: this is a hack. There's no good way to call the business
|
||||||
|
@ -126,6 +126,10 @@ func TestControllerDecode(t *testing.T) {
|
|||||||
"name": "nginx",
|
"name": "nginx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -225,10 +229,13 @@ var validPodTemplate = api.PodTemplate{
|
|||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{
|
||||||
Containers: []api.Container{
|
Containers: []api.Container{
|
||||||
{
|
{
|
||||||
Name: "test",
|
Name: "test",
|
||||||
Image: "test_image",
|
Image: "test_image",
|
||||||
|
ImagePullPolicy: api.PullIfNotPresent,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ limitations under the License.
|
|||||||
package etcd
|
package etcd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@ -441,6 +440,10 @@ func TestEtcdUpdatePodNotScheduled(t *testing.T) {
|
|||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
err := registry.UpdatePod(ctx, &podIn)
|
err := registry.UpdatePod(ctx, &podIn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -515,9 +518,13 @@ func TestEtcdUpdatePodScheduled(t *testing.T) {
|
|||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{
|
||||||
Containers: []api.Container{
|
Containers: []api.Container{
|
||||||
{
|
{
|
||||||
Image: "foo:v2",
|
Image: "foo:v2",
|
||||||
|
ImagePullPolicy: api.PullIfNotPresent,
|
||||||
|
TerminationMessagePath: api.TerminationMessagePathDefault,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
Status: api.PodStatus{
|
Status: api.PodStatus{
|
||||||
Host: "machine",
|
Host: "machine",
|
||||||
@ -1338,6 +1345,8 @@ func TestEtcdUpdateService(t *testing.T) {
|
|||||||
Selector: map[string]string{
|
Selector: map[string]string{
|
||||||
"baz": "bar",
|
"baz": "bar",
|
||||||
},
|
},
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := registry.UpdateService(ctx, &testService)
|
err := registry.UpdateService(ctx, &testService)
|
||||||
@ -1352,7 +1361,7 @@ func TestEtcdUpdateService(t *testing.T) {
|
|||||||
// Clear modified indices before the equality test.
|
// Clear modified indices before the equality test.
|
||||||
svc.ResourceVersion = ""
|
svc.ResourceVersion = ""
|
||||||
testService.ResourceVersion = ""
|
testService.ResourceVersion = ""
|
||||||
if !reflect.DeepEqual(*svc, testService) {
|
if !api.Semantic.DeepEqual(*svc, testService) {
|
||||||
t.Errorf("Unexpected service: got\n %#v\n, wanted\n %#v", svc, testService)
|
t.Errorf("Unexpected service: got\n %#v\n, wanted\n %#v", svc, testService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1404,7 +1413,7 @@ func TestEtcdGetEndpoints(t *testing.T) {
|
|||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if e, a := endpoints, got; !reflect.DeepEqual(e, a) {
|
if e, a := endpoints, got; !api.Semantic.DeepEqual(e, a) {
|
||||||
t.Errorf("Unexpected endpoints: %#v, expected %#v", e, a)
|
t.Errorf("Unexpected endpoints: %#v, expected %#v", e, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1433,7 +1442,7 @@ func TestEtcdUpdateEndpoints(t *testing.T) {
|
|||||||
}
|
}
|
||||||
var endpointsOut api.Endpoints
|
var endpointsOut api.Endpoints
|
||||||
err = latest.Codec.DecodeInto([]byte(response.Node.Value), &endpointsOut)
|
err = latest.Codec.DecodeInto([]byte(response.Node.Value), &endpointsOut)
|
||||||
if !reflect.DeepEqual(endpoints, endpointsOut) {
|
if !api.Semantic.DeepEqual(endpoints, endpointsOut) {
|
||||||
t.Errorf("Unexpected endpoints: %#v, expected %#v", endpointsOut, endpoints)
|
t.Errorf("Unexpected endpoints: %#v, expected %#v", endpointsOut, endpoints)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ package etcd
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
"path"
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
@ -146,7 +145,7 @@ func TestEtcdList(t *testing.T) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if e, a := item.out, list; !reflect.DeepEqual(e, a) {
|
if e, a := item.out, list; !api.Semantic.DeepDerivative(e, a) {
|
||||||
t.Errorf("%v: Expected %#v, got %#v", name, e, a)
|
t.Errorf("%v: Expected %#v, got %#v", name, e, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,7 +208,7 @@ func TestEtcdCreate(t *testing.T) {
|
|||||||
t.Errorf("%v: unexpected error: %v", name, err)
|
t.Errorf("%v: unexpected error: %v", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if e, a := item.expect, fakeClient.Data[path]; !reflect.DeepEqual(e, a) {
|
if e, a := item.expect, fakeClient.Data[path]; !api.Semantic.DeepDerivative(e, a) {
|
||||||
t.Errorf("%v:\n%s", name, util.ObjectDiff(e, a))
|
t.Errorf("%v:\n%s", name, util.ObjectDiff(e, a))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -284,7 +283,7 @@ func TestEtcdUpdate(t *testing.T) {
|
|||||||
t.Errorf("%v: unexpected error: %v", name, err)
|
t.Errorf("%v: unexpected error: %v", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if e, a := item.expect, fakeClient.Data[path]; !reflect.DeepEqual(e, a) {
|
if e, a := item.expect, fakeClient.Data[path]; !api.Semantic.DeepDerivative(e, a) {
|
||||||
t.Errorf("%v:\n%s", name, util.ObjectDiff(e, a))
|
t.Errorf("%v:\n%s", name, util.ObjectDiff(e, a))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -340,7 +339,7 @@ func TestEtcdGet(t *testing.T) {
|
|||||||
t.Errorf("%v: unexpected error: %v", name, err)
|
t.Errorf("%v: unexpected error: %v", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if e, a := item.expect, got; !reflect.DeepEqual(e, a) {
|
if e, a := item.expect, got; !api.Semantic.DeepDerivative(e, a) {
|
||||||
t.Errorf("%v:\n%s", name, util.ObjectDiff(e, a))
|
t.Errorf("%v:\n%s", name, util.ObjectDiff(e, a))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -396,7 +395,7 @@ func TestEtcdDelete(t *testing.T) {
|
|||||||
t.Errorf("%v: unexpected error: %v", name, err)
|
t.Errorf("%v: unexpected error: %v", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if e, a := item.expect, fakeClient.Data[path]; !reflect.DeepEqual(e, a) {
|
if e, a := item.expect, fakeClient.Data[path]; !api.Semantic.DeepDerivative(e, a) {
|
||||||
t.Errorf("%v:\n%s", name, util.ObjectDiff(e, a))
|
t.Errorf("%v:\n%s", name, util.ObjectDiff(e, a))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -432,7 +431,7 @@ func TestEtcdWatch(t *testing.T) {
|
|||||||
t.Fatalf("unexpected channel close")
|
t.Fatalf("unexpected channel close")
|
||||||
}
|
}
|
||||||
|
|
||||||
if e, a := podA, got.Object; !reflect.DeepEqual(e, a) {
|
if e, a := podA, got.Object; !api.Semantic.DeepDerivative(e, a) {
|
||||||
t.Errorf("difference: %s", util.ObjectDiff(e, a))
|
t.Errorf("difference: %s", util.ObjectDiff(e, a))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,10 @@ func TestCreatePodRegistryError(t *testing.T) {
|
|||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
},
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
ch, err := storage.Create(ctx, pod)
|
ch, err := storage.Create(ctx, pod)
|
||||||
@ -108,6 +112,10 @@ func TestCreatePodSetsIds(t *testing.T) {
|
|||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
},
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
ch, err := storage.Create(ctx, pod)
|
ch, err := storage.Create(ctx, pod)
|
||||||
@ -135,6 +143,10 @@ func TestCreatePodSetsUID(t *testing.T) {
|
|||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
},
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
ch, err := storage.Create(ctx, pod)
|
ch, err := storage.Create(ctx, pod)
|
||||||
@ -346,6 +358,10 @@ func TestPodDecode(t *testing.T) {
|
|||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
},
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
body, err := latest.Codec.Encode(expected)
|
body, err := latest.Codec.Encode(expected)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -447,7 +463,12 @@ func TestCreatePod(t *testing.T) {
|
|||||||
registry: podRegistry,
|
registry: podRegistry,
|
||||||
podCache: &fakeCache{statusToReturn: &api.PodStatus{}},
|
podCache: &fakeCache{statusToReturn: &api.PodStatus{}},
|
||||||
}
|
}
|
||||||
pod := &api.Pod{}
|
pod := &api.Pod{
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
|
}
|
||||||
pod.Name = "foo"
|
pod.Name = "foo"
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
channel, err := storage.Create(ctx, pod)
|
channel, err := storage.Create(ctx, pod)
|
||||||
@ -470,6 +491,10 @@ func TestCreatePodWithConflictingNamespace(t *testing.T) {
|
|||||||
storage := REST{}
|
storage := REST{}
|
||||||
pod := &api.Pod{
|
pod := &api.Pod{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "test", Namespace: "not-default"},
|
ObjectMeta: api.ObjectMeta{Name: "test", Namespace: "not-default"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
@ -488,6 +513,10 @@ func TestUpdatePodWithConflictingNamespace(t *testing.T) {
|
|||||||
storage := REST{}
|
storage := REST{}
|
||||||
pod := &api.Pod{
|
pod := &api.Pod{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "test", Namespace: "not-default"},
|
ObjectMeta: api.ObjectMeta{Name: "test", Namespace: "not-default"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
@ -647,10 +676,13 @@ func TestCreate(t *testing.T) {
|
|||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{
|
||||||
Containers: []api.Container{
|
Containers: []api.Container{
|
||||||
{
|
{
|
||||||
Name: "test1",
|
Name: "test1",
|
||||||
Image: "foo",
|
Image: "foo",
|
||||||
|
ImagePullPolicy: api.PullIfNotPresent,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// invalid
|
// invalid
|
||||||
|
@ -49,8 +49,10 @@ func TestServiceRegistryCreate(t *testing.T) {
|
|||||||
svc := &api.Service{
|
svc := &api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 6502,
|
Port: 6502,
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
@ -91,14 +93,18 @@ func TestServiceStorageValidatesCreate(t *testing.T) {
|
|||||||
"empty ID": {
|
"empty ID": {
|
||||||
ObjectMeta: api.ObjectMeta{Name: ""},
|
ObjectMeta: api.ObjectMeta{Name: ""},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 6502,
|
Port: 6502,
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"empty selector": {
|
"empty selector": {
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -129,8 +135,10 @@ func TestServiceRegistryUpdate(t *testing.T) {
|
|||||||
c, err := storage.Update(ctx, &api.Service{
|
c, err := storage.Update(ctx, &api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 6502,
|
Port: 6502,
|
||||||
Selector: map[string]string{"bar": "baz2"},
|
Selector: map[string]string{"bar": "baz2"},
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -164,15 +172,19 @@ func TestServiceStorageValidatesUpdate(t *testing.T) {
|
|||||||
"empty ID": {
|
"empty ID": {
|
||||||
ObjectMeta: api.ObjectMeta{Name: ""},
|
ObjectMeta: api.ObjectMeta{Name: ""},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 6502,
|
Port: 6502,
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"invalid selector": {
|
"invalid selector": {
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Port: 6502,
|
Port: 6502,
|
||||||
Selector: map[string]string{"ThisSelectorFailsValidation": "ok"},
|
Selector: map[string]string{"ThisSelectorFailsValidation": "ok"},
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -199,6 +211,8 @@ func TestServiceRegistryExternalService(t *testing.T) {
|
|||||||
Port: 6502,
|
Port: 6502,
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
CreateExternalLoadBalancer: true,
|
CreateExternalLoadBalancer: true,
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
c, _ := storage.Create(ctx, svc)
|
c, _ := storage.Create(ctx, svc)
|
||||||
@ -228,6 +242,8 @@ func TestServiceRegistryExternalServiceError(t *testing.T) {
|
|||||||
Port: 6502,
|
Port: 6502,
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
CreateExternalLoadBalancer: true,
|
CreateExternalLoadBalancer: true,
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
@ -250,7 +266,9 @@ func TestServiceRegistryDelete(t *testing.T) {
|
|||||||
svc := &api.Service{
|
svc := &api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
registry.CreateService(ctx, svc)
|
registry.CreateService(ctx, svc)
|
||||||
@ -275,6 +293,8 @@ func TestServiceRegistryDeleteExternal(t *testing.T) {
|
|||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
CreateExternalLoadBalancer: true,
|
CreateExternalLoadBalancer: true,
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
registry.CreateService(ctx, svc)
|
registry.CreateService(ctx, svc)
|
||||||
@ -389,8 +409,10 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
|
|||||||
svc1 := &api.Service{
|
svc1 := &api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
Port: 6502,
|
Port: 6502,
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
@ -407,8 +429,10 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
|
|||||||
svc2 := &api.Service{
|
svc2 := &api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "bar"},
|
ObjectMeta: api.ObjectMeta{Name: "bar"},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
Port: 6502,
|
Port: 6502,
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
}}
|
}}
|
||||||
ctx = api.NewDefaultContext()
|
ctx = api.NewDefaultContext()
|
||||||
c2, _ := rest.Create(ctx, svc2)
|
c2, _ := rest.Create(ctx, svc2)
|
||||||
@ -424,9 +448,11 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
|
|||||||
svc3 := &api.Service{
|
svc3 := &api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "quux"},
|
ObjectMeta: api.ObjectMeta{Name: "quux"},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
PortalIP: "1.2.3.93",
|
PortalIP: "1.2.3.93",
|
||||||
Port: 6502,
|
Port: 6502,
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ctx = api.NewDefaultContext()
|
ctx = api.NewDefaultContext()
|
||||||
@ -448,8 +474,10 @@ func TestServiceRegistryIPReallocation(t *testing.T) {
|
|||||||
svc1 := &api.Service{
|
svc1 := &api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
Port: 6502,
|
Port: 6502,
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
@ -469,8 +497,10 @@ func TestServiceRegistryIPReallocation(t *testing.T) {
|
|||||||
svc2 := &api.Service{
|
svc2 := &api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "bar"},
|
ObjectMeta: api.ObjectMeta{Name: "bar"},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
Port: 6502,
|
Port: 6502,
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ctx = api.NewDefaultContext()
|
ctx = api.NewDefaultContext()
|
||||||
@ -495,8 +525,10 @@ func TestServiceRegistryIPUpdate(t *testing.T) {
|
|||||||
svc := &api.Service{
|
svc := &api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
Port: 6502,
|
Port: 6502,
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
@ -551,6 +583,8 @@ func TestServiceRegistryIPExternalLoadBalancer(t *testing.T) {
|
|||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
Port: 6502,
|
Port: 6502,
|
||||||
CreateExternalLoadBalancer: true,
|
CreateExternalLoadBalancer: true,
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
@ -586,8 +620,10 @@ func TestServiceRegistryIPReloadFromStorage(t *testing.T) {
|
|||||||
svc := &api.Service{
|
svc := &api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
Port: 6502,
|
Port: 6502,
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
@ -596,8 +632,10 @@ func TestServiceRegistryIPReloadFromStorage(t *testing.T) {
|
|||||||
svc = &api.Service{
|
svc = &api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
Port: 6502,
|
Port: 6502,
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
c, _ = rest1.Create(ctx, svc)
|
c, _ = rest1.Create(ctx, svc)
|
||||||
@ -610,8 +648,10 @@ func TestServiceRegistryIPReloadFromStorage(t *testing.T) {
|
|||||||
svc = &api.Service{
|
svc = &api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
Port: 6502,
|
Port: 6502,
|
||||||
|
Protocol: api.ProtocolTCP,
|
||||||
|
SessionAffinity: api.AffinityTypeNone,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
c, _ = rest2.Create(ctx, svc)
|
c, _ = rest2.Create(ctx, svc)
|
||||||
@ -671,8 +711,10 @@ func TestCreate(t *testing.T) {
|
|||||||
// valid
|
// valid
|
||||||
&api.Service{
|
&api.Service{
|
||||||
Spec: api.ServiceSpec{
|
Spec: api.ServiceSpec{
|
||||||
Selector: map[string]string{"bar": "baz"},
|
Selector: map[string]string{"bar": "baz"},
|
||||||
Port: 6502,
|
Port: 6502,
|
||||||
|
Protocol: "TCP",
|
||||||
|
SessionAffinity: "None",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// invalid
|
// invalid
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
"github.com/coreos/go-etcd/etcd"
|
"github.com/coreos/go-etcd/etcd"
|
||||||
)
|
)
|
||||||
@ -47,6 +48,12 @@ func init() {
|
|||||||
scheme.AddKnownTypes("", &TestResource{})
|
scheme.AddKnownTypes("", &TestResource{})
|
||||||
scheme.AddKnownTypes("v1beta1", &TestResource{})
|
scheme.AddKnownTypes("v1beta1", &TestResource{})
|
||||||
codec = runtime.CodecFor(scheme, "v1beta1")
|
codec = runtime.CodecFor(scheme, "v1beta1")
|
||||||
|
scheme.AddConversionFuncs(
|
||||||
|
func(in *TestResource, out *TestResource, s conversion.Scope) error {
|
||||||
|
*out = *in
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsEtcdNotFound(t *testing.T) {
|
func TestIsEtcdNotFound(t *testing.T) {
|
||||||
@ -94,10 +101,27 @@ func TestExtractToList(t *testing.T) {
|
|||||||
expect := api.PodList{
|
expect := api.PodList{
|
||||||
ListMeta: api.ListMeta{ResourceVersion: "10"},
|
ListMeta: api.ListMeta{ResourceVersion: "10"},
|
||||||
Items: []api.Pod{
|
Items: []api.Pod{
|
||||||
// We expect items to be sorted by its name.
|
{
|
||||||
{ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"}},
|
ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"},
|
||||||
{ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "3"}},
|
Spec: api.PodSpec{
|
||||||
{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "3"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,9 +184,27 @@ func TestExtractToListAcrossDirectories(t *testing.T) {
|
|||||||
ListMeta: api.ListMeta{ResourceVersion: "10"},
|
ListMeta: api.ListMeta{ResourceVersion: "10"},
|
||||||
Items: []api.Pod{
|
Items: []api.Pod{
|
||||||
// We expect list to be sorted by directory (e.g. namespace) first, then by name.
|
// We expect list to be sorted by directory (e.g. namespace) first, then by name.
|
||||||
{ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "1"}},
|
{
|
||||||
{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
|
ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "1"},
|
||||||
{ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"}},
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,9 +254,27 @@ func TestExtractToListExcludesDirectories(t *testing.T) {
|
|||||||
expect := api.PodList{
|
expect := api.PodList{
|
||||||
ListMeta: api.ListMeta{ResourceVersion: "10"},
|
ListMeta: api.ListMeta{ResourceVersion: "10"},
|
||||||
Items: []api.Pod{
|
Items: []api.Pod{
|
||||||
{ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"}},
|
{
|
||||||
{ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "3"}},
|
ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "2"},
|
||||||
{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}},
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "3"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +291,13 @@ func TestExtractToListExcludesDirectories(t *testing.T) {
|
|||||||
|
|
||||||
func TestExtractObj(t *testing.T) {
|
func TestExtractObj(t *testing.T) {
|
||||||
fakeClient := NewFakeEtcdClient(t)
|
fakeClient := NewFakeEtcdClient(t)
|
||||||
expect := api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}
|
expect := api.Pod{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
|
}
|
||||||
fakeClient.Set("/some/key", runtime.EncodeOrDie(testapi.Codec(), &expect), 0)
|
fakeClient.Set("/some/key", runtime.EncodeOrDie(testapi.Codec(), &expect), 0)
|
||||||
helper := EtcdHelper{fakeClient, testapi.Codec(), versioner}
|
helper := EtcdHelper{fakeClient, testapi.Codec(), versioner}
|
||||||
var got api.Pod
|
var got api.Pod
|
||||||
|
@ -18,7 +18,6 @@ package tools
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -123,7 +122,7 @@ func TestWatchInterpretations(t *testing.T) {
|
|||||||
if e, a := item.expectType, event.Type; e != a {
|
if e, a := item.expectType, event.Type; e != a {
|
||||||
t.Errorf("'%v - %v': expected %v, got %v", name, action, e, a)
|
t.Errorf("'%v - %v': expected %v, got %v", name, action, e, a)
|
||||||
}
|
}
|
||||||
if e, a := item.expectObject, event.Object; !reflect.DeepEqual(e, a) {
|
if e, a := item.expectObject, event.Object; !api.Semantic.DeepDerivative(e, a) {
|
||||||
t.Errorf("'%v - %v': expected %v, got %v", name, action, e, a)
|
t.Errorf("'%v - %v': expected %v, got %v", name, action, e, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -250,7 +249,7 @@ func TestWatch(t *testing.T) {
|
|||||||
if e, a := watch.Added, event.Type; e != a {
|
if e, a := watch.Added, event.Type; e != a {
|
||||||
t.Errorf("Expected %v, got %v", e, a)
|
t.Errorf("Expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
if e, a := pod, event.Object; !reflect.DeepEqual(e, a) {
|
if e, a := pod, event.Object; !api.Semantic.DeepDerivative(e, a) {
|
||||||
t.Errorf("Expected %v, got %v", e, a)
|
t.Errorf("Expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,7 +380,7 @@ func TestWatchEtcdState(t *testing.T) {
|
|||||||
t.Errorf("%s: expected type %v, got %v", k, e, a)
|
t.Errorf("%s: expected type %v, got %v", k, e, a)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if e, a := testCase.Expected[i].Endpoints, event.Object.(*api.Endpoints).Endpoints; !reflect.DeepEqual(e, a) {
|
if e, a := testCase.Expected[i].Endpoints, event.Object.(*api.Endpoints).Endpoints; !api.Semantic.DeepDerivative(e, a) {
|
||||||
t.Errorf("%s: expected type %v, got %v", k, e, a)
|
t.Errorf("%s: expected type %v, got %v", k, e, a)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -456,7 +455,7 @@ func TestWatchFromZeroIndex(t *testing.T) {
|
|||||||
t.Errorf("%s: expected pod with resource version %v, Got %#v", k, testCase.ExpectedVersion, actualPod)
|
t.Errorf("%s: expected pod with resource version %v, Got %#v", k, testCase.ExpectedVersion, actualPod)
|
||||||
}
|
}
|
||||||
pod.ResourceVersion = testCase.ExpectedVersion
|
pod.ResourceVersion = testCase.ExpectedVersion
|
||||||
if e, a := pod, event.Object; !reflect.DeepEqual(e, a) {
|
if e, a := pod, event.Object; !api.Semantic.DeepDerivative(e, a) {
|
||||||
t.Errorf("%s: expected %v, got %v", k, e, a)
|
t.Errorf("%s: expected %v, got %v", k, e, a)
|
||||||
}
|
}
|
||||||
watching.Stop()
|
watching.Stop()
|
||||||
@ -515,7 +514,7 @@ func TestWatchListFromZeroIndex(t *testing.T) {
|
|||||||
t.Errorf("Expected pod with resource version %d, Got %#v", 1, actualPod)
|
t.Errorf("Expected pod with resource version %d, Got %#v", 1, actualPod)
|
||||||
}
|
}
|
||||||
pod.ResourceVersion = "1"
|
pod.ResourceVersion = "1"
|
||||||
if e, a := pod, event.Object; !reflect.DeepEqual(e, a) {
|
if e, a := pod, event.Object; !api.Semantic.DeepDerivative(e, a) {
|
||||||
t.Errorf("Expected %v, got %v", e, a)
|
t.Errorf("Expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ package json
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -58,7 +57,7 @@ func TestDecoder(t *testing.T) {
|
|||||||
if e, a := eventType, action; e != a {
|
if e, a := eventType, action; e != a {
|
||||||
t.Errorf("Expected %v, got %v", e, a)
|
t.Errorf("Expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
if e, a := expect, got; !reflect.DeepEqual(e, a) {
|
if e, a := expect, got; !api.Semantic.DeepDerivative(e, a) {
|
||||||
t.Errorf("Expected %v, got %v", e, a)
|
t.Errorf("Expected %v, got %v", e, a)
|
||||||
}
|
}
|
||||||
t.Logf("Exited read")
|
t.Logf("Exited read")
|
||||||
|
@ -19,7 +19,6 @@ package json
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
@ -66,7 +65,7 @@ func TestEncodeDecodeRoundTrip(t *testing.T) {
|
|||||||
t.Errorf("%d: unexpected error: %v", i, err)
|
t.Errorf("%d: unexpected error: %v", i, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(testCase.Object, obj) {
|
if !api.Semantic.DeepDerivative(testCase.Object, obj) {
|
||||||
t.Errorf("%d: expected %#v, got %#v", i, testCase.Object, obj)
|
t.Errorf("%d: expected %#v, got %#v", i, testCase.Object, obj)
|
||||||
}
|
}
|
||||||
if event != testCase.Type {
|
if event != testCase.Type {
|
||||||
|
@ -195,7 +195,13 @@ func makeURL(suffix string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDefaultErrorFunc(t *testing.T) {
|
func TestDefaultErrorFunc(t *testing.T) {
|
||||||
testPod := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"}}
|
testPod := &api.Pod{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
|
}
|
||||||
handler := util.FakeHandler{
|
handler := util.FakeHandler{
|
||||||
StatusCode: 200,
|
StatusCode: 200,
|
||||||
ResponseBody: runtime.EncodeOrDie(latest.Codec, testPod),
|
ResponseBody: runtime.EncodeOrDie(latest.Codec, testPod),
|
||||||
|
Loading…
Reference in New Issue
Block a user