2015-02-11 23:37:12 +00:00
|
|
|
/*
|
2015-05-01 16:19:44 +00:00
|
|
|
Copyright 2014 The Kubernetes Authors All rights reserved.
|
2015-02-11 23:37:12 +00:00
|
|
|
|
|
|
|
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 etcd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api"
|
|
|
|
"k8s.io/kubernetes/pkg/api/errors"
|
|
|
|
etcderrors "k8s.io/kubernetes/pkg/api/errors/etcd"
|
|
|
|
"k8s.io/kubernetes/pkg/api/rest"
|
2015-08-20 09:17:04 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api/testapi"
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/fields"
|
|
|
|
"k8s.io/kubernetes/pkg/labels"
|
2015-11-05 15:04:42 +00:00
|
|
|
"k8s.io/kubernetes/pkg/registry/generic"
|
2015-08-18 15:03:54 +00:00
|
|
|
"k8s.io/kubernetes/pkg/registry/registrytest"
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/runtime"
|
|
|
|
"k8s.io/kubernetes/pkg/securitycontext"
|
2015-11-10 11:23:51 +00:00
|
|
|
"k8s.io/kubernetes/pkg/storage/etcd/etcdtest"
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/tools"
|
|
|
|
"k8s.io/kubernetes/pkg/util"
|
2015-02-11 23:37:12 +00:00
|
|
|
)
|
|
|
|
|
2015-10-23 04:25:38 +00:00
|
|
|
func newStorage(t *testing.T) (*REST, *BindingREST, *StatusREST, *tools.FakeEtcdClient) {
|
2015-09-04 07:06:01 +00:00
|
|
|
etcdStorage, fakeClient := registrytest.NewEtcdStorage(t, "")
|
2015-11-05 15:04:42 +00:00
|
|
|
storage := NewStorage(etcdStorage, generic.UndecoratedStorage, nil, nil)
|
2015-10-23 04:25:38 +00:00
|
|
|
return storage.Pod, storage.Binding, storage.Status, fakeClient
|
2015-02-11 23:37:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func validNewPod() *api.Pod {
|
2015-08-19 23:59:43 +00:00
|
|
|
grace := int64(30)
|
2015-02-11 23:37:12 +00:00
|
|
|
return &api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: api.NamespaceDefault,
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2015-03-14 01:38:07 +00:00
|
|
|
RestartPolicy: api.RestartPolicyAlways,
|
2015-02-11 23:37:12 +00:00
|
|
|
DNSPolicy: api.DNSClusterFirst,
|
2015-08-19 23:59:43 +00:00
|
|
|
|
|
|
|
TerminationGracePeriodSeconds: &grace,
|
2015-02-11 23:37:12 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{
|
|
|
|
Name: "foo",
|
|
|
|
Image: "test",
|
|
|
|
ImagePullPolicy: api.PullAlways,
|
|
|
|
|
|
|
|
TerminationMessagePath: api.TerminationMessagePathDefault,
|
2015-05-05 23:02:13 +00:00
|
|
|
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
|
2015-02-11 23:37:12 +00:00
|
|
|
},
|
|
|
|
},
|
2015-09-14 21:56:51 +00:00
|
|
|
SecurityContext: &api.PodSecurityContext{},
|
2015-02-11 23:37:12 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func validChangedPod() *api.Pod {
|
|
|
|
pod := validNewPod()
|
|
|
|
pod.ResourceVersion = "1"
|
|
|
|
pod.Labels = map[string]string{
|
|
|
|
"foo": "bar",
|
|
|
|
}
|
|
|
|
return pod
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCreate(t *testing.T) {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, _, _, fakeClient := newStorage(t)
|
2015-08-31 12:11:11 +00:00
|
|
|
test := registrytest.New(t, fakeClient, storage.Etcd)
|
2015-02-11 23:37:12 +00:00
|
|
|
pod := validNewPod()
|
|
|
|
pod.ObjectMeta = api.ObjectMeta{}
|
2015-08-20 08:23:09 +00:00
|
|
|
// Make an invalid pod with an an incorrect label.
|
|
|
|
invalidPod := validNewPod()
|
|
|
|
invalidPod.Namespace = test.TestNamespace()
|
|
|
|
invalidPod.Labels = map[string]string{
|
|
|
|
"invalid/label/to/cause/validation/failure": "bar",
|
|
|
|
}
|
2015-02-11 23:37:12 +00:00
|
|
|
test.TestCreate(
|
|
|
|
// valid
|
|
|
|
pod,
|
2015-08-20 08:23:09 +00:00
|
|
|
// invalid (empty contains list)
|
2015-02-11 23:37:12 +00:00
|
|
|
&api.Pod{
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{},
|
|
|
|
},
|
|
|
|
},
|
2015-08-20 08:23:09 +00:00
|
|
|
// invalid (invalid labels)
|
|
|
|
invalidPod,
|
2015-02-11 23:37:12 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2015-08-28 13:45:38 +00:00
|
|
|
func TestUpdate(t *testing.T) {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, _, _, fakeClient := newStorage(t)
|
2015-08-31 12:11:11 +00:00
|
|
|
test := registrytest.New(t, fakeClient, storage.Etcd)
|
2015-08-28 13:45:38 +00:00
|
|
|
test.TestUpdate(
|
|
|
|
// valid
|
|
|
|
validNewPod(),
|
|
|
|
// updateFunc
|
|
|
|
func(obj runtime.Object) runtime.Object {
|
|
|
|
object := obj.(*api.Pod)
|
|
|
|
object.Labels = map[string]string{"a": "b"}
|
|
|
|
return object
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2015-03-05 03:34:31 +00:00
|
|
|
func TestDelete(t *testing.T) {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, _, _, fakeClient := newStorage(t)
|
2015-09-01 13:27:13 +00:00
|
|
|
test := registrytest.New(t, fakeClient, storage.Etcd).ReturnDeletedObject()
|
|
|
|
test.TestDelete(validNewPod())
|
2015-03-05 03:34:31 +00:00
|
|
|
|
2015-09-01 13:27:13 +00:00
|
|
|
scheduledPod := validNewPod()
|
|
|
|
scheduledPod.Spec.NodeName = "some-node"
|
|
|
|
test.TestDeleteGraceful(scheduledPod, 30)
|
2015-02-11 23:37:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestCreateRegistryError(t *testing.T) {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, _, _, fakeClient := newStorage(t)
|
2015-08-20 09:17:04 +00:00
|
|
|
fakeClient.Err = fmt.Errorf("test error")
|
2015-02-11 23:37:12 +00:00
|
|
|
|
|
|
|
pod := validNewPod()
|
|
|
|
_, err := storage.Create(api.NewDefaultContext(), pod)
|
2015-08-20 09:17:04 +00:00
|
|
|
if err != fakeClient.Err {
|
2015-02-11 23:37:12 +00:00
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCreateSetsFields(t *testing.T) {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, _, _, fakeClient := newStorage(t)
|
2015-02-11 23:37:12 +00:00
|
|
|
pod := validNewPod()
|
|
|
|
_, err := storage.Create(api.NewDefaultContext(), pod)
|
2015-08-20 09:17:04 +00:00
|
|
|
if err != fakeClient.Err {
|
2015-02-11 23:37:12 +00:00
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
2015-03-11 17:10:09 +00:00
|
|
|
ctx := api.NewDefaultContext()
|
2015-08-20 09:17:04 +00:00
|
|
|
object, err := storage.Get(ctx, "foo")
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
2015-02-11 23:37:12 +00:00
|
|
|
}
|
2015-08-20 09:17:04 +00:00
|
|
|
actual := object.(*api.Pod)
|
2015-02-11 23:37:12 +00:00
|
|
|
if actual.Name != pod.Name {
|
|
|
|
t.Errorf("unexpected pod: %#v", actual)
|
|
|
|
}
|
|
|
|
if len(actual.UID) == 0 {
|
|
|
|
t.Errorf("expected pod UID to be set: %#v", actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestResourceLocation(t *testing.T) {
|
|
|
|
expectedIP := "1.2.3.4"
|
|
|
|
testCases := []struct {
|
|
|
|
pod api.Pod
|
|
|
|
query string
|
|
|
|
location string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
pod: api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
2015-03-24 12:35:38 +00:00
|
|
|
Status: api.PodStatus{PodIP: expectedIP},
|
2015-02-11 23:37:12 +00:00
|
|
|
},
|
|
|
|
query: "foo",
|
|
|
|
location: expectedIP,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
pod: api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
2015-03-24 12:35:38 +00:00
|
|
|
Status: api.PodStatus{PodIP: expectedIP},
|
2015-02-11 23:37:12 +00:00
|
|
|
},
|
|
|
|
query: "foo:12345",
|
|
|
|
location: expectedIP + ":12345",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
pod: api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "ctr"},
|
|
|
|
},
|
|
|
|
},
|
2015-03-24 12:35:38 +00:00
|
|
|
Status: api.PodStatus{PodIP: expectedIP},
|
2015-02-11 23:37:12 +00:00
|
|
|
},
|
|
|
|
query: "foo",
|
|
|
|
location: expectedIP,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
pod: api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
2015-02-23 22:25:56 +00:00
|
|
|
{Name: "ctr", Ports: []api.ContainerPort{{ContainerPort: 9376}}},
|
2015-02-11 23:37:12 +00:00
|
|
|
},
|
|
|
|
},
|
2015-03-24 12:35:38 +00:00
|
|
|
Status: api.PodStatus{PodIP: expectedIP},
|
2015-02-11 23:37:12 +00:00
|
|
|
},
|
|
|
|
query: "foo",
|
|
|
|
location: expectedIP + ":9376",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
pod: api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
2015-02-23 22:25:56 +00:00
|
|
|
{Name: "ctr", Ports: []api.ContainerPort{{ContainerPort: 9376}}},
|
2015-02-11 23:37:12 +00:00
|
|
|
},
|
|
|
|
},
|
2015-03-24 12:35:38 +00:00
|
|
|
Status: api.PodStatus{PodIP: expectedIP},
|
2015-02-11 23:37:12 +00:00
|
|
|
},
|
|
|
|
query: "foo:12345",
|
|
|
|
location: expectedIP + ":12345",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
pod: api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "ctr1"},
|
2015-02-23 22:25:56 +00:00
|
|
|
{Name: "ctr2", Ports: []api.ContainerPort{{ContainerPort: 9376}}},
|
2015-02-11 23:37:12 +00:00
|
|
|
},
|
|
|
|
},
|
2015-03-24 12:35:38 +00:00
|
|
|
Status: api.PodStatus{PodIP: expectedIP},
|
2015-02-11 23:37:12 +00:00
|
|
|
},
|
|
|
|
query: "foo",
|
|
|
|
location: expectedIP + ":9376",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
pod: api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
2015-02-23 22:25:56 +00:00
|
|
|
{Name: "ctr1", Ports: []api.ContainerPort{{ContainerPort: 9376}}},
|
|
|
|
{Name: "ctr2", Ports: []api.ContainerPort{{ContainerPort: 1234}}},
|
2015-02-11 23:37:12 +00:00
|
|
|
},
|
|
|
|
},
|
2015-03-24 12:35:38 +00:00
|
|
|
Status: api.PodStatus{PodIP: expectedIP},
|
2015-02-11 23:37:12 +00:00
|
|
|
},
|
|
|
|
query: "foo",
|
|
|
|
location: expectedIP + ":9376",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-03-11 17:10:09 +00:00
|
|
|
ctx := api.NewDefaultContext()
|
2015-02-11 23:37:12 +00:00
|
|
|
for _, tc := range testCases {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, _, _, fakeClient := newStorage(t)
|
2015-09-03 13:27:01 +00:00
|
|
|
key, _ := storage.KeyFunc(ctx, tc.pod.Name)
|
2015-03-11 17:10:09 +00:00
|
|
|
key = etcdtest.AddPrefix(key)
|
2015-09-04 07:06:01 +00:00
|
|
|
if _, err := fakeClient.Set(key, runtime.EncodeOrDie(testapi.Default.Codec(), &tc.pod), 0); err != nil {
|
2015-09-03 13:27:01 +00:00
|
|
|
t.Fatalf("unexpected error: %v", err)
|
2015-02-11 23:37:12 +00:00
|
|
|
}
|
|
|
|
|
2015-03-21 16:24:16 +00:00
|
|
|
redirector := rest.Redirector(storage)
|
2015-03-23 18:42:39 +00:00
|
|
|
location, _, err := redirector.ResourceLocation(api.NewDefaultContext(), tc.query)
|
2015-02-11 23:37:12 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Unexpected error: %v", err)
|
|
|
|
}
|
2015-03-23 18:42:39 +00:00
|
|
|
if location == nil {
|
|
|
|
t.Errorf("Unexpected nil: %v", location)
|
|
|
|
}
|
2015-02-11 23:37:12 +00:00
|
|
|
|
2015-03-23 18:42:39 +00:00
|
|
|
if location.Scheme != "" {
|
|
|
|
t.Errorf("Expected '%v', but got '%v'", "", location.Scheme)
|
|
|
|
}
|
|
|
|
if location.Host != tc.location {
|
|
|
|
t.Errorf("Expected %v, but got %v", tc.location, location.Host)
|
2015-02-11 23:37:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-31 12:11:11 +00:00
|
|
|
func TestGet(t *testing.T) {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, _, _, fakeClient := newStorage(t)
|
2015-08-31 12:11:11 +00:00
|
|
|
test := registrytest.New(t, fakeClient, storage.Etcd)
|
2015-08-28 09:24:34 +00:00
|
|
|
test.TestGet(validNewPod())
|
2015-02-11 23:37:12 +00:00
|
|
|
}
|
|
|
|
|
2015-08-31 12:11:11 +00:00
|
|
|
func TestList(t *testing.T) {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, _, _, fakeClient := newStorage(t)
|
2015-08-31 12:11:11 +00:00
|
|
|
test := registrytest.New(t, fakeClient, storage.Etcd)
|
|
|
|
test.TestList(validNewPod())
|
2015-08-18 15:03:54 +00:00
|
|
|
}
|
|
|
|
|
2015-08-31 12:11:11 +00:00
|
|
|
func TestWatch(t *testing.T) {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, _, _, fakeClient := newStorage(t)
|
2015-08-31 12:11:11 +00:00
|
|
|
test := registrytest.New(t, fakeClient, storage.Etcd)
|
2015-08-28 09:24:34 +00:00
|
|
|
test.TestWatch(
|
|
|
|
validNewPod(),
|
|
|
|
// matching labels
|
|
|
|
[]labels.Set{},
|
|
|
|
// not matching labels
|
|
|
|
[]labels.Set{
|
|
|
|
{"foo": "bar"},
|
|
|
|
},
|
|
|
|
// matching fields
|
|
|
|
[]fields.Set{
|
|
|
|
{"metadata.name": "foo"},
|
|
|
|
},
|
|
|
|
// not matchin fields
|
|
|
|
[]fields.Set{
|
|
|
|
{"metadata.name": "bar"},
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2015-02-11 23:37:12 +00:00
|
|
|
func TestEtcdCreate(t *testing.T) {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, bindingStorage, _, fakeClient := newStorage(t)
|
2015-02-11 23:37:12 +00:00
|
|
|
ctx := api.NewDefaultContext()
|
|
|
|
fakeClient.TestIndex = true
|
2015-08-20 09:17:04 +00:00
|
|
|
key, _ := storage.KeyFunc(ctx, "foo")
|
2015-03-11 17:10:09 +00:00
|
|
|
key = etcdtest.AddPrefix(key)
|
2015-09-03 13:27:01 +00:00
|
|
|
fakeClient.ExpectNotFoundGet(key)
|
2015-08-20 09:17:04 +00:00
|
|
|
_, err := storage.Create(ctx, validNewPod())
|
2015-02-11 23:37:12 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Suddenly, a wild scheduler appears:
|
2015-08-20 09:17:04 +00:00
|
|
|
_, err = bindingStorage.Create(ctx, &api.Binding{
|
2015-03-04 20:55:41 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"},
|
|
|
|
Target: api.ObjectReference{Name: "machine"},
|
|
|
|
})
|
2015-02-11 23:37:12 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := fakeClient.Get(key, false, false)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected error %v", err)
|
|
|
|
}
|
|
|
|
var pod api.Pod
|
2015-09-04 07:06:01 +00:00
|
|
|
err = testapi.Default.Codec().DecodeInto([]byte(resp.Node.Value), &pod)
|
2015-02-11 23:37:12 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if pod.Name != "foo" {
|
|
|
|
t.Errorf("Unexpected pod: %#v %s", pod, resp.Node.Value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-02 16:53:23 +00:00
|
|
|
// Ensure that when scheduler creates a binding for a pod that has already been deleted
|
|
|
|
// by the API server, API server returns not-found error.
|
2015-02-24 18:21:09 +00:00
|
|
|
func TestEtcdCreateBindingNoPod(t *testing.T) {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, bindingStorage, _, fakeClient := newStorage(t)
|
2015-02-24 18:21:09 +00:00
|
|
|
ctx := api.NewDefaultContext()
|
|
|
|
fakeClient.TestIndex = true
|
|
|
|
|
2015-08-20 09:17:04 +00:00
|
|
|
key, _ := storage.KeyFunc(ctx, "foo")
|
2015-03-11 17:10:09 +00:00
|
|
|
key = etcdtest.AddPrefix(key)
|
2015-09-03 13:27:01 +00:00
|
|
|
fakeClient.ExpectNotFoundGet(key)
|
2015-02-24 18:21:09 +00:00
|
|
|
// Assume that a pod has undergone the following:
|
|
|
|
// - Create (apiserver)
|
|
|
|
// - Schedule (scheduler)
|
|
|
|
// - Delete (apiserver)
|
2015-08-20 09:17:04 +00:00
|
|
|
_, err := bindingStorage.Create(ctx, &api.Binding{
|
2015-03-04 20:55:41 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"},
|
|
|
|
Target: api.ObjectReference{Name: "machine"},
|
|
|
|
})
|
2015-03-06 07:02:04 +00:00
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("Expected not-found-error but got nothing")
|
|
|
|
}
|
2015-02-24 18:21:09 +00:00
|
|
|
if !errors.IsNotFound(etcderrors.InterpretGetError(err, "Pod", "foo")) {
|
|
|
|
t.Fatalf("Unexpected error returned: %#v", err)
|
|
|
|
}
|
|
|
|
|
2015-08-20 09:17:04 +00:00
|
|
|
_, err = storage.Get(ctx, "foo")
|
2015-03-06 07:02:04 +00:00
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("Expected not-found-error but got nothing")
|
|
|
|
}
|
2015-02-24 18:21:09 +00:00
|
|
|
if !errors.IsNotFound(etcderrors.InterpretGetError(err, "Pod", "foo")) {
|
|
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-11 23:37:12 +00:00
|
|
|
func TestEtcdCreateFailsWithoutNamespace(t *testing.T) {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, _, _, fakeClient := newStorage(t)
|
2015-02-11 23:37:12 +00:00
|
|
|
fakeClient.TestIndex = true
|
|
|
|
pod := validNewPod()
|
|
|
|
pod.Namespace = ""
|
2015-08-20 09:17:04 +00:00
|
|
|
_, err := storage.Create(api.NewContext(), pod)
|
2015-02-11 23:37:12 +00:00
|
|
|
// Accept "namespace" or "Namespace".
|
|
|
|
if err == nil || !strings.Contains(err.Error(), "amespace") {
|
|
|
|
t.Fatalf("expected error that namespace was missing from context, got: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestEtcdCreateWithContainersNotFound(t *testing.T) {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, bindingStorage, _, fakeClient := newStorage(t)
|
2015-02-11 23:37:12 +00:00
|
|
|
ctx := api.NewDefaultContext()
|
|
|
|
fakeClient.TestIndex = true
|
2015-08-20 09:17:04 +00:00
|
|
|
key, _ := storage.KeyFunc(ctx, "foo")
|
2015-03-11 17:10:09 +00:00
|
|
|
key = etcdtest.AddPrefix(key)
|
2015-09-03 13:27:01 +00:00
|
|
|
fakeClient.ExpectNotFoundGet(key)
|
2015-08-20 09:17:04 +00:00
|
|
|
_, err := storage.Create(ctx, validNewPod())
|
2015-02-11 23:37:12 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Suddenly, a wild scheduler appears:
|
2015-08-20 09:17:04 +00:00
|
|
|
_, err = bindingStorage.Create(ctx, &api.Binding{
|
2015-03-03 23:19:17 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
Namespace: api.NamespaceDefault,
|
|
|
|
Name: "foo",
|
|
|
|
Annotations: map[string]string{"label1": "value1"},
|
|
|
|
},
|
|
|
|
Target: api.ObjectReference{Name: "machine"},
|
2015-03-04 20:55:41 +00:00
|
|
|
})
|
2015-02-11 23:37:12 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := fakeClient.Get(key, false, false)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected error %v", err)
|
|
|
|
}
|
|
|
|
var pod api.Pod
|
2015-09-04 07:06:01 +00:00
|
|
|
err = testapi.Default.Codec().DecodeInto([]byte(resp.Node.Value), &pod)
|
2015-02-11 23:37:12 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if pod.Name != "foo" {
|
|
|
|
t.Errorf("Unexpected pod: %#v %s", pod, resp.Node.Value)
|
|
|
|
}
|
2015-03-03 23:19:17 +00:00
|
|
|
if !(pod.Annotations != nil && pod.Annotations["label1"] == "value1") {
|
|
|
|
t.Fatalf("Pod annotations don't match the expected: %v", pod.Annotations)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestEtcdCreateWithConflict(t *testing.T) {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, bindingStorage, _, fakeClient := newStorage(t)
|
2015-03-03 23:19:17 +00:00
|
|
|
ctx := api.NewDefaultContext()
|
|
|
|
fakeClient.TestIndex = true
|
2015-08-20 09:17:04 +00:00
|
|
|
key, _ := storage.KeyFunc(ctx, "foo")
|
2015-09-03 13:27:01 +00:00
|
|
|
fakeClient.ExpectNotFoundGet(key)
|
2015-03-03 23:19:17 +00:00
|
|
|
|
2015-08-20 09:17:04 +00:00
|
|
|
_, err := storage.Create(ctx, validNewPod())
|
2015-03-03 23:19:17 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Suddenly, a wild scheduler appears:
|
|
|
|
binding := api.Binding{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
Namespace: api.NamespaceDefault,
|
|
|
|
Name: "foo",
|
|
|
|
Annotations: map[string]string{"label1": "value1"},
|
|
|
|
},
|
|
|
|
Target: api.ObjectReference{Name: "machine"},
|
|
|
|
}
|
2015-08-20 09:17:04 +00:00
|
|
|
_, err = bindingStorage.Create(ctx, &binding)
|
2015-03-03 23:19:17 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-08-20 09:17:04 +00:00
|
|
|
_, err = bindingStorage.Create(ctx, &binding)
|
2015-03-03 23:19:17 +00:00
|
|
|
if err == nil || !errors.IsConflict(err) {
|
|
|
|
t.Fatalf("expected resource conflict error, not: %v", err)
|
|
|
|
}
|
2015-02-11 23:37:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestEtcdCreateWithExistingContainers(t *testing.T) {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, bindingStorage, _, fakeClient := newStorage(t)
|
2015-02-11 23:37:12 +00:00
|
|
|
ctx := api.NewDefaultContext()
|
|
|
|
fakeClient.TestIndex = true
|
2015-08-20 09:17:04 +00:00
|
|
|
key, _ := storage.KeyFunc(ctx, "foo")
|
2015-03-11 17:10:09 +00:00
|
|
|
key = etcdtest.AddPrefix(key)
|
2015-09-03 13:27:01 +00:00
|
|
|
fakeClient.ExpectNotFoundGet(key)
|
2015-08-20 09:17:04 +00:00
|
|
|
_, err := storage.Create(ctx, validNewPod())
|
2015-02-11 23:37:12 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Suddenly, a wild scheduler appears:
|
2015-08-20 09:17:04 +00:00
|
|
|
_, err = bindingStorage.Create(ctx, &api.Binding{
|
2015-03-04 20:55:41 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"},
|
|
|
|
Target: api.ObjectReference{Name: "machine"},
|
|
|
|
})
|
2015-02-11 23:37:12 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := fakeClient.Get(key, false, false)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected error %v", err)
|
|
|
|
}
|
|
|
|
var pod api.Pod
|
2015-09-04 07:06:01 +00:00
|
|
|
err = testapi.Default.Codec().DecodeInto([]byte(resp.Node.Value), &pod)
|
2015-02-11 23:37:12 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if pod.Name != "foo" {
|
|
|
|
t.Errorf("Unexpected pod: %#v %s", pod, resp.Node.Value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-04 20:55:41 +00:00
|
|
|
func TestEtcdCreateBinding(t *testing.T) {
|
|
|
|
ctx := api.NewDefaultContext()
|
|
|
|
|
|
|
|
testCases := map[string]struct {
|
|
|
|
binding api.Binding
|
|
|
|
errOK func(error) bool
|
|
|
|
}{
|
|
|
|
"noName": {
|
|
|
|
binding: api.Binding{
|
|
|
|
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"},
|
|
|
|
Target: api.ObjectReference{},
|
|
|
|
},
|
|
|
|
errOK: func(err error) bool { return errors.IsInvalid(err) },
|
|
|
|
},
|
|
|
|
"badKind": {
|
|
|
|
binding: api.Binding{
|
|
|
|
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"},
|
2015-03-10 18:17:04 +00:00
|
|
|
Target: api.ObjectReference{Name: "machine1", Kind: "unknown"},
|
2015-03-04 20:55:41 +00:00
|
|
|
},
|
|
|
|
errOK: func(err error) bool { return errors.IsInvalid(err) },
|
|
|
|
},
|
|
|
|
"emptyKind": {
|
|
|
|
binding: api.Binding{
|
|
|
|
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"},
|
2015-03-10 18:17:04 +00:00
|
|
|
Target: api.ObjectReference{Name: "machine2"},
|
2015-03-04 20:55:41 +00:00
|
|
|
},
|
|
|
|
errOK: func(err error) bool { return err == nil },
|
|
|
|
},
|
|
|
|
"kindNode": {
|
|
|
|
binding: api.Binding{
|
|
|
|
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"},
|
2015-03-10 18:17:04 +00:00
|
|
|
Target: api.ObjectReference{Name: "machine3", Kind: "Node"},
|
2015-03-04 20:55:41 +00:00
|
|
|
},
|
|
|
|
errOK: func(err error) bool { return err == nil },
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for k, test := range testCases {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, bindingStorage, _, fakeClient := newStorage(t)
|
2015-08-20 09:17:04 +00:00
|
|
|
key, _ := storage.KeyFunc(ctx, "foo")
|
2015-03-11 17:10:09 +00:00
|
|
|
key = etcdtest.AddPrefix(key)
|
2015-09-03 13:27:01 +00:00
|
|
|
fakeClient.ExpectNotFoundGet(key)
|
|
|
|
|
2015-08-20 09:17:04 +00:00
|
|
|
if _, err := storage.Create(ctx, validNewPod()); err != nil {
|
2015-03-04 20:55:41 +00:00
|
|
|
t.Fatalf("%s: unexpected error: %v", k, err)
|
|
|
|
}
|
2015-08-20 09:17:04 +00:00
|
|
|
if _, err := bindingStorage.Create(ctx, &test.binding); !test.errOK(err) {
|
2015-03-04 20:55:41 +00:00
|
|
|
t.Errorf("%s: unexpected error: %v", k, err)
|
2015-03-10 18:17:04 +00:00
|
|
|
} else if err == nil {
|
|
|
|
// If bind succeeded, verify Host field in pod's Spec.
|
2015-08-20 09:17:04 +00:00
|
|
|
pod, err := storage.Get(ctx, validNewPod().ObjectMeta.Name)
|
2015-03-10 18:17:04 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("%s: unexpected error: %v", k, err)
|
2015-05-22 23:40:57 +00:00
|
|
|
} else if pod.(*api.Pod).Spec.NodeName != test.binding.Target.Name {
|
|
|
|
t.Errorf("%s: expected: %v, got: %v", k, pod.(*api.Pod).Spec.NodeName, test.binding.Target.Name)
|
2015-03-10 18:17:04 +00:00
|
|
|
}
|
2015-03-04 20:55:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-11 23:37:12 +00:00
|
|
|
func TestEtcdUpdateNotScheduled(t *testing.T) {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, _, _, fakeClient := newStorage(t)
|
2015-02-11 23:37:12 +00:00
|
|
|
ctx := api.NewDefaultContext()
|
|
|
|
fakeClient.TestIndex = true
|
|
|
|
|
2015-08-20 09:17:04 +00:00
|
|
|
key, _ := storage.KeyFunc(ctx, "foo")
|
2015-03-11 17:10:09 +00:00
|
|
|
key = etcdtest.AddPrefix(key)
|
2015-09-04 07:06:01 +00:00
|
|
|
fakeClient.Set(key, runtime.EncodeOrDie(testapi.Default.Codec(), validNewPod()), 1)
|
2015-02-11 23:37:12 +00:00
|
|
|
|
|
|
|
podIn := validChangedPod()
|
2015-08-20 09:17:04 +00:00
|
|
|
_, _, err := storage.Update(ctx, podIn)
|
2015-02-11 23:37:12 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
response, err := fakeClient.Get(key, false, false)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
podOut := &api.Pod{}
|
2015-09-04 07:06:01 +00:00
|
|
|
testapi.Default.Codec().DecodeInto([]byte(response.Node.Value), podOut)
|
2015-02-11 23:37:12 +00:00
|
|
|
if !api.Semantic.DeepEqual(podOut, podIn) {
|
|
|
|
t.Errorf("objects differ: %v", util.ObjectDiff(podOut, podIn))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestEtcdUpdateScheduled(t *testing.T) {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, _, _, fakeClient := newStorage(t)
|
2015-02-11 23:37:12 +00:00
|
|
|
ctx := api.NewDefaultContext()
|
|
|
|
fakeClient.TestIndex = true
|
|
|
|
|
2015-08-20 09:17:04 +00:00
|
|
|
key, _ := storage.KeyFunc(ctx, "foo")
|
2015-03-11 17:10:09 +00:00
|
|
|
key = etcdtest.AddPrefix(key)
|
2015-09-04 07:06:01 +00:00
|
|
|
fakeClient.Set(key, runtime.EncodeOrDie(testapi.Default.Codec(), &api.Pod{
|
2015-02-11 23:37:12 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: api.NamespaceDefault,
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2015-05-22 23:40:57 +00:00
|
|
|
NodeName: "machine",
|
2015-02-11 23:37:12 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{
|
2015-05-05 23:02:13 +00:00
|
|
|
Name: "foobar",
|
|
|
|
Image: "foo:v1",
|
|
|
|
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
|
2015-02-11 23:37:12 +00:00
|
|
|
},
|
|
|
|
},
|
2015-09-14 21:56:51 +00:00
|
|
|
SecurityContext: &api.PodSecurityContext{},
|
2015-02-11 23:37:12 +00:00
|
|
|
},
|
|
|
|
}), 1)
|
|
|
|
|
2015-08-19 23:59:43 +00:00
|
|
|
grace := int64(30)
|
2015-02-11 23:37:12 +00:00
|
|
|
podIn := api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
Name: "foo",
|
|
|
|
ResourceVersion: "1",
|
|
|
|
Labels: map[string]string{
|
|
|
|
"foo": "bar",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2015-05-22 23:40:57 +00:00
|
|
|
NodeName: "machine",
|
2015-09-14 21:56:51 +00:00
|
|
|
Containers: []api.Container{{
|
|
|
|
Name: "foobar",
|
|
|
|
Image: "foo:v2",
|
|
|
|
ImagePullPolicy: api.PullIfNotPresent,
|
|
|
|
TerminationMessagePath: api.TerminationMessagePathDefault,
|
|
|
|
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
|
|
|
|
}},
|
2015-03-14 01:38:07 +00:00
|
|
|
RestartPolicy: api.RestartPolicyAlways,
|
2015-02-11 23:37:12 +00:00
|
|
|
DNSPolicy: api.DNSClusterFirst,
|
2015-08-19 23:59:43 +00:00
|
|
|
|
|
|
|
TerminationGracePeriodSeconds: &grace,
|
2015-09-14 21:56:51 +00:00
|
|
|
SecurityContext: &api.PodSecurityContext{},
|
2015-02-11 23:37:12 +00:00
|
|
|
},
|
|
|
|
}
|
2015-08-20 09:17:04 +00:00
|
|
|
_, _, err := storage.Update(ctx, &podIn)
|
2015-02-11 23:37:12 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
response, err := fakeClient.Get(key, false, false)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
var podOut api.Pod
|
2015-09-04 07:06:01 +00:00
|
|
|
testapi.Default.Codec().DecodeInto([]byte(response.Node.Value), &podOut)
|
2015-02-11 23:37:12 +00:00
|
|
|
if !api.Semantic.DeepEqual(podOut, podIn) {
|
|
|
|
t.Errorf("expected: %#v, got: %#v", podOut, podIn)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-02-24 05:42:27 +00:00
|
|
|
func TestEtcdUpdateStatus(t *testing.T) {
|
2015-10-23 04:25:38 +00:00
|
|
|
storage, _, statusStorage, fakeClient := newStorage(t)
|
2015-02-24 05:42:27 +00:00
|
|
|
ctx := api.NewDefaultContext()
|
|
|
|
fakeClient.TestIndex = true
|
|
|
|
|
2015-08-20 09:17:04 +00:00
|
|
|
key, _ := storage.KeyFunc(ctx, "foo")
|
2015-03-11 17:10:09 +00:00
|
|
|
key = etcdtest.AddPrefix(key)
|
2015-02-24 05:42:27 +00:00
|
|
|
podStart := api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: api.NamespaceDefault,
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2015-05-22 23:40:57 +00:00
|
|
|
NodeName: "machine",
|
2015-02-24 05:42:27 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{
|
2015-05-05 23:02:13 +00:00
|
|
|
Image: "foo:v1",
|
|
|
|
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
|
2015-02-24 05:42:27 +00:00
|
|
|
},
|
|
|
|
},
|
2015-09-14 21:56:51 +00:00
|
|
|
SecurityContext: &api.PodSecurityContext{},
|
2015-02-24 05:42:27 +00:00
|
|
|
},
|
|
|
|
}
|
2015-09-04 07:06:01 +00:00
|
|
|
fakeClient.Set(key, runtime.EncodeOrDie(testapi.Default.Codec(), &podStart), 0)
|
2015-02-24 05:42:27 +00:00
|
|
|
|
|
|
|
podIn := api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
Name: "foo",
|
|
|
|
ResourceVersion: "1",
|
|
|
|
Labels: map[string]string{
|
|
|
|
"foo": "bar",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2015-05-22 23:40:57 +00:00
|
|
|
NodeName: "machine",
|
2015-02-24 05:42:27 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{
|
|
|
|
Image: "foo:v2",
|
|
|
|
ImagePullPolicy: api.PullIfNotPresent,
|
|
|
|
TerminationMessagePath: api.TerminationMessagePathDefault,
|
|
|
|
},
|
|
|
|
},
|
2015-09-14 21:56:51 +00:00
|
|
|
SecurityContext: &api.PodSecurityContext{},
|
2015-02-24 05:42:27 +00:00
|
|
|
},
|
|
|
|
Status: api.PodStatus{
|
|
|
|
Phase: api.PodRunning,
|
|
|
|
PodIP: "127.0.0.1",
|
|
|
|
Message: "is now scheduled",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
expected := podStart
|
|
|
|
expected.ResourceVersion = "2"
|
2015-08-19 23:59:43 +00:00
|
|
|
grace := int64(30)
|
|
|
|
expected.Spec.TerminationGracePeriodSeconds = &grace
|
2015-03-14 01:38:07 +00:00
|
|
|
expected.Spec.RestartPolicy = api.RestartPolicyAlways
|
2015-02-24 05:42:27 +00:00
|
|
|
expected.Spec.DNSPolicy = api.DNSClusterFirst
|
|
|
|
expected.Spec.Containers[0].ImagePullPolicy = api.PullIfNotPresent
|
|
|
|
expected.Spec.Containers[0].TerminationMessagePath = api.TerminationMessagePathDefault
|
|
|
|
expected.Labels = podIn.Labels
|
|
|
|
expected.Status = podIn.Status
|
|
|
|
|
2015-08-20 09:17:04 +00:00
|
|
|
_, _, err := statusStorage.Update(ctx, &podIn)
|
2015-02-24 05:42:27 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
|
|
}
|
2015-08-20 09:17:04 +00:00
|
|
|
podOut, err := storage.Get(ctx, "foo")
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
2015-02-24 05:42:27 +00:00
|
|
|
}
|
2015-08-20 09:17:04 +00:00
|
|
|
if !api.Semantic.DeepEqual(&expected, podOut) {
|
|
|
|
t.Errorf("unexpected object: %s", util.ObjectDiff(&expected, podOut))
|
2015-02-24 05:42:27 +00:00
|
|
|
}
|
|
|
|
}
|