mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 15:25:57 +00:00
Add a subbindings resource as /pods/{name}/binding
Allows POST to create a binding as a child. Also refactors internal and v1beta3 Binding to be more generic (so that other resources can support Bindings).
This commit is contained in:
parent
227a1d306d
commit
dfc19185f5
@ -101,6 +101,10 @@ func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
|
||||
j.Spec = api.PodSpec{}
|
||||
c.Fuzz(&j.Spec)
|
||||
},
|
||||
func(j *api.Binding, c fuzz.Continue) {
|
||||
c.Fuzz(&j.ObjectMeta)
|
||||
j.Target.Name = c.RandString()
|
||||
},
|
||||
func(j *api.ReplicationControllerSpec, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(j) // fuzz self without calling this function again
|
||||
j.TemplateRef = nil // this is required for round trip
|
||||
|
@ -918,13 +918,14 @@ type NamespaceList struct {
|
||||
Items []Namespace `json:"items"`
|
||||
}
|
||||
|
||||
// Binding is written by a scheduler to cause a pod to be bound to a host.
|
||||
// Binding ties one object to another - for example, a pod is bound to a node by a scheduler.
|
||||
type Binding struct {
|
||||
TypeMeta `json:",inline"`
|
||||
TypeMeta `json:",inline"`
|
||||
// ObjectMeta describes the object that is being bound.
|
||||
ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
PodID string `json:"podID"`
|
||||
Host string `json:"host"`
|
||||
// Target is the object to bind to.
|
||||
Target ObjectReference `json:"target"`
|
||||
}
|
||||
|
||||
// Status is a return value for calls that don't return other objects.
|
||||
|
@ -1324,6 +1324,24 @@ func init() {
|
||||
|
||||
return nil
|
||||
},
|
||||
func(in *Binding, out *newer.Binding, s conversion.Scope) error {
|
||||
if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Target = newer.ObjectReference{
|
||||
Name: in.Host,
|
||||
}
|
||||
out.Name = in.PodID
|
||||
return nil
|
||||
},
|
||||
func(in *newer.Binding, out *Binding, s conversion.Scope) error {
|
||||
if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Host = in.Target.Name
|
||||
out.PodID = in.Name
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
// If one of the conversion functions is malformed, detect it immediately.
|
||||
|
@ -1240,6 +1240,24 @@ func init() {
|
||||
|
||||
return nil
|
||||
},
|
||||
func(in *Binding, out *newer.Binding, s conversion.Scope) error {
|
||||
if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Target = newer.ObjectReference{
|
||||
Name: in.Host,
|
||||
}
|
||||
out.Name = in.PodID
|
||||
return nil
|
||||
},
|
||||
func(in *newer.Binding, out *Binding, s conversion.Scope) error {
|
||||
if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Host = in.Target.Name
|
||||
out.PodID = in.Name
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
// If one of the conversion functions is malformed, detect it immediately.
|
||||
|
@ -940,16 +940,14 @@ type NamespaceList struct {
|
||||
Items []Namespace `json:"items" description:"items is the list of Namespace objects in the list"`
|
||||
}
|
||||
|
||||
// Binding is written by a scheduler to cause a pod to be bound to a node. Name is not
|
||||
// required for Bindings.
|
||||
// Binding ties one object to another - for example, a pod is bound to a node by a scheduler.
|
||||
type Binding struct {
|
||||
TypeMeta `json:",inline"`
|
||||
TypeMeta `json:",inline"`
|
||||
// ObjectMeta describes the object that is being bound.
|
||||
ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/api-conventions.md#metadata"`
|
||||
|
||||
// PodID is a Pod name to be bound to a node.
|
||||
PodID string `json:"podID" description:"name of the pod to be bound to a node"`
|
||||
// Host is the name of a node to bind to.
|
||||
Host string `json:"host" description:"name of the node to bind to"`
|
||||
// Target is the object to bind to.
|
||||
Target ObjectReference `json:"target" description:"an object to bind to"`
|
||||
}
|
||||
|
||||
// Status is a return value for calls that don't return other objects.
|
||||
|
@ -52,3 +52,8 @@ func (c *FakePods) Update(pod *api.Pod) (*api.Pod, error) {
|
||||
c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "update-pod", Value: pod.Name})
|
||||
return &api.Pod{}, nil
|
||||
}
|
||||
|
||||
func (c *FakePods) Bind(bind *api.Binding) error {
|
||||
c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "bind-pod", Value: bind.Name})
|
||||
return nil
|
||||
}
|
||||
|
@ -36,6 +36,8 @@ type PodInterface interface {
|
||||
Delete(name string) error
|
||||
Create(pod *api.Pod) (*api.Pod, error)
|
||||
Update(pod *api.Pod) (*api.Pod, error)
|
||||
|
||||
Bind(binding *api.Binding) error
|
||||
}
|
||||
|
||||
// pods implements PodsNamespacer interface
|
||||
@ -92,3 +94,8 @@ func (c *pods) Update(pod *api.Pod) (result *api.Pod, err error) {
|
||||
err = c.r.Put().Namespace(c.ns).Resource("pods").Name(pod.Name).Body(pod).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Bind applies the provided binding to the named pod in the current namespace (binding.Namespace is ignored).
|
||||
func (c *pods) Bind(binding *api.Binding) error {
|
||||
return c.r.Post().Namespace(c.ns).Resource("pods").Name(binding.Name).SubResource("binding").Body(binding).Do().Error()
|
||||
}
|
||||
|
@ -404,9 +404,10 @@ func (m *Master) init(c *Config) {
|
||||
|
||||
// TODO: Factor out the core API registration
|
||||
m.storage = map[string]apiserver.RESTStorage{
|
||||
"pods": podStorage,
|
||||
"pods/status": podStatusStorage,
|
||||
"bindings": bindingStorage,
|
||||
"pods": podStorage,
|
||||
"pods/status": podStatusStorage,
|
||||
"pods/binding": bindingStorage,
|
||||
"bindings": bindingStorage,
|
||||
|
||||
"replicationControllers": controller.NewREST(registry, podRegistry),
|
||||
"services": service.NewREST(m.serviceRegistry, c.Cloud, m.nodeRegistry, m.portalNet, c.ClusterName),
|
||||
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
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 binding contains the middle layer logic for bindings.
|
||||
// Bindings are objects containing instructions for how a pod ought to
|
||||
// be bound to a host. This allows a registry object which supports this
|
||||
// action (ApplyBinding) to be served through an apiserver.
|
||||
package binding
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
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 binding
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
// MockRegistry can be used for testing.
|
||||
type MockRegistry struct {
|
||||
OnApplyBinding func(binding *api.Binding) error
|
||||
}
|
||||
|
||||
func (mr MockRegistry) ApplyBinding(ctx api.Context, binding *api.Binding) error {
|
||||
return mr.OnApplyBinding(binding)
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
/*
|
||||
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 binding
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
// Registry contains the functions needed to support a BindingStorage.
|
||||
type Registry interface {
|
||||
// ApplyBinding should apply the binding. That is, it should actually
|
||||
// assign or place pod binding.PodID on machine binding.Host.
|
||||
ApplyBinding(ctx api.Context, binding *api.Binding) error
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
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 binding
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
// REST implements the RESTStorage interface for bindings. When bindings are written, it
|
||||
// changes the location of the affected pods. This information is eventually reflected
|
||||
// in the pod's CurrentState.Host field.
|
||||
type REST struct {
|
||||
registry Registry
|
||||
}
|
||||
|
||||
// NewREST creates a new REST backed by the given bindingRegistry.
|
||||
func NewREST(bindingRegistry Registry) *REST {
|
||||
return &REST{
|
||||
registry: bindingRegistry,
|
||||
}
|
||||
}
|
||||
|
||||
// New returns a new binding object fit for having data unmarshalled into it.
|
||||
func (*REST) New() runtime.Object {
|
||||
return &api.Binding{}
|
||||
}
|
||||
|
||||
// Create attempts to make the assignment indicated by the binding it recieves.
|
||||
func (b *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
|
||||
binding, ok := obj.(*api.Binding)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("incorrect type: %#v", obj)
|
||||
}
|
||||
if err := b.registry.ApplyBinding(ctx, binding); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &api.Status{Status: api.StatusSuccess, Code: http.StatusCreated}, nil
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
/*
|
||||
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 binding
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
)
|
||||
|
||||
func TestNewREST(t *testing.T) {
|
||||
mockRegistry := MockRegistry{
|
||||
OnApplyBinding: func(b *api.Binding) error { return nil },
|
||||
}
|
||||
b := NewREST(mockRegistry)
|
||||
|
||||
binding := &api.Binding{
|
||||
PodID: "foo",
|
||||
Host: "bar",
|
||||
}
|
||||
body, err := latest.Codec.Encode(binding)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected encode error %v", err)
|
||||
}
|
||||
obj := b.New()
|
||||
err = latest.Codec.DecodeInto(body, obj)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
if e, a := binding, obj; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Expected %#v, but got %#v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTPost(t *testing.T) {
|
||||
table := []struct {
|
||||
b *api.Binding
|
||||
err error
|
||||
}{
|
||||
{b: &api.Binding{PodID: "foo", Host: "bar"}, err: errors.New("no host bar")},
|
||||
{b: &api.Binding{PodID: "baz", Host: "qux"}, err: nil},
|
||||
{b: &api.Binding{PodID: "dvorak", Host: "qwerty"}, err: nil},
|
||||
}
|
||||
|
||||
for i, item := range table {
|
||||
mockRegistry := MockRegistry{
|
||||
OnApplyBinding: func(b *api.Binding) error {
|
||||
if !reflect.DeepEqual(item.b, b) {
|
||||
t.Errorf("%v: expected %#v, but got %#v", i, item, b)
|
||||
}
|
||||
return item.err
|
||||
},
|
||||
}
|
||||
ctx := api.NewContext()
|
||||
b := NewREST(mockRegistry)
|
||||
result, err := b.Create(ctx, item.b)
|
||||
if err != nil && item.err == nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
continue
|
||||
}
|
||||
if err == nil && item.err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
continue
|
||||
}
|
||||
var expect interface{}
|
||||
if item.err == nil {
|
||||
expect = &api.Status{Status: api.StatusSuccess, Code: http.StatusCreated}
|
||||
}
|
||||
if e, a := expect, result; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%v: expected %#v, got %#v", i, e, a)
|
||||
}
|
||||
}
|
||||
}
|
@ -20,6 +20,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
etcderr "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors/etcd"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/constraint"
|
||||
@ -146,7 +147,14 @@ func (r *BindingREST) New() runtime.Object {
|
||||
// Create ensures a pod is bound to a specific host.
|
||||
func (r *BindingREST) Create(ctx api.Context, obj runtime.Object) (out runtime.Object, err error) {
|
||||
binding := obj.(*api.Binding)
|
||||
err = r.assignPod(ctx, binding.PodID, binding.Host)
|
||||
// TODO: move me to a binding strategy
|
||||
if len(binding.Target.Kind) != 0 && (binding.Target.Kind != "Node" && binding.Target.Kind != "Minion") {
|
||||
return nil, errors.NewInvalid("binding", binding.Name, errors.ValidationErrorList{errors.NewFieldInvalid("to.kind", binding.Target.Kind, "must be empty, 'Node', or 'Minion'")})
|
||||
}
|
||||
if len(binding.Target.Name) == 0 {
|
||||
return nil, errors.NewInvalid("binding", binding.Name, errors.ValidationErrorList{errors.NewFieldRequired("to.name", binding.Target.Name)})
|
||||
}
|
||||
err = r.assignPod(ctx, binding.Name, binding.Target.Name)
|
||||
err = etcderr.InterpretCreateError(err, "binding", "")
|
||||
out = &api.Status{Status: api.StatusSuccess}
|
||||
return
|
||||
|
@ -817,7 +817,10 @@ func TestEtcdCreate(t *testing.T) {
|
||||
}
|
||||
|
||||
// Suddenly, a wild scheduler appears:
|
||||
_, err = bindingRegistry.Create(ctx, &api.Binding{PodID: "foo", Host: "machine", ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault}})
|
||||
_, err = bindingRegistry.Create(ctx, &api.Binding{
|
||||
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"},
|
||||
Target: api.ObjectReference{Name: "machine"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@ -865,7 +868,10 @@ func TestEtcdCreateBindingNoPod(t *testing.T) {
|
||||
// - Create (apiserver)
|
||||
// - Schedule (scheduler)
|
||||
// - Delete (apiserver)
|
||||
_, err := bindingRegistry.Create(ctx, &api.Binding{PodID: "foo", Host: "machine", ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault}})
|
||||
_, err := bindingRegistry.Create(ctx, &api.Binding{
|
||||
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"},
|
||||
Target: api.ObjectReference{Name: "machine"},
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatalf("Expected not-found-error but got nothing")
|
||||
}
|
||||
@ -935,7 +941,10 @@ func TestEtcdCreateWithContainersError(t *testing.T) {
|
||||
}
|
||||
|
||||
// Suddenly, a wild scheduler appears:
|
||||
_, err = bindingRegistry.Create(ctx, &api.Binding{PodID: "foo", Host: "machine"})
|
||||
_, err = bindingRegistry.Create(ctx, &api.Binding{
|
||||
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"},
|
||||
Target: api.ObjectReference{Name: "machine"},
|
||||
})
|
||||
if !errors.IsAlreadyExists(err) {
|
||||
t.Fatalf("Unexpected error returned: %#v", err)
|
||||
}
|
||||
@ -973,7 +982,10 @@ func TestEtcdCreateWithContainersNotFound(t *testing.T) {
|
||||
}
|
||||
|
||||
// Suddenly, a wild scheduler appears:
|
||||
_, err = bindingRegistry.Create(ctx, &api.Binding{PodID: "foo", Host: "machine"})
|
||||
_, err = bindingRegistry.Create(ctx, &api.Binding{
|
||||
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"},
|
||||
Target: api.ObjectReference{Name: "machine"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@ -1025,7 +1037,10 @@ func TestEtcdCreateWithExistingContainers(t *testing.T) {
|
||||
}
|
||||
|
||||
// Suddenly, a wild scheduler appears:
|
||||
_, err = bindingRegistry.Create(ctx, &api.Binding{PodID: "foo", Host: "machine"})
|
||||
_, err = bindingRegistry.Create(ctx, &api.Binding{
|
||||
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"},
|
||||
Target: api.ObjectReference{Name: "machine"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@ -1055,6 +1070,70 @@ func TestEtcdCreateWithExistingContainers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEtcdCreateBinding(t *testing.T) {
|
||||
registry, bindingRegistry, _, fakeClient, _ := newStorage(t)
|
||||
ctx := api.NewDefaultContext()
|
||||
fakeClient.TestIndex = true
|
||||
|
||||
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"},
|
||||
Target: api.ObjectReference{Name: "machine", Kind: "unknown"},
|
||||
},
|
||||
errOK: func(err error) bool { return errors.IsInvalid(err) },
|
||||
},
|
||||
"emptyKind": {
|
||||
binding: api.Binding{
|
||||
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"},
|
||||
Target: api.ObjectReference{Name: "machine"},
|
||||
},
|
||||
errOK: func(err error) bool { return err == nil },
|
||||
},
|
||||
"kindNode": {
|
||||
binding: api.Binding{
|
||||
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"},
|
||||
Target: api.ObjectReference{Name: "machine", Kind: "Node"},
|
||||
},
|
||||
errOK: func(err error) bool { return err == nil },
|
||||
},
|
||||
"kindMinion": {
|
||||
binding: api.Binding{
|
||||
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"},
|
||||
Target: api.ObjectReference{Name: "machine", Kind: "Minion"},
|
||||
},
|
||||
errOK: func(err error) bool { return err == nil },
|
||||
},
|
||||
}
|
||||
for k, test := range testCases {
|
||||
key, _ := registry.store.KeyFunc(ctx, "foo")
|
||||
fakeClient.Data[key] = tools.EtcdResponseWithError{
|
||||
R: &etcd.Response{
|
||||
Node: nil,
|
||||
},
|
||||
E: tools.EtcdErrorNotFound,
|
||||
}
|
||||
fakeClient.Set("/registry/nodes/machine/boundpods", runtime.EncodeOrDie(latest.Codec, &api.BoundPods{}), 0)
|
||||
if _, err := registry.Create(ctx, validNewPod()); err != nil {
|
||||
t.Fatalf("%s: unexpected error: %v", k, err)
|
||||
}
|
||||
fakeClient.Set("/registry/nodes/machine/boundpods", runtime.EncodeOrDie(latest.Codec, &api.BoundPods{}), 0)
|
||||
if _, err := bindingRegistry.Create(ctx, &test.binding); !test.errOK(err) {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEtcdUpdateNotFound(t *testing.T) {
|
||||
registry, _, _, fakeClient, _ := newStorage(t)
|
||||
ctx := api.NewDefaultContext()
|
||||
|
@ -287,9 +287,11 @@ type binder struct {
|
||||
|
||||
// Bind just does a POST binding RPC.
|
||||
func (b *binder) Bind(binding *api.Binding) error {
|
||||
glog.V(2).Infof("Attempting to bind %v to %v", binding.PodID, binding.Host)
|
||||
glog.V(2).Infof("Attempting to bind %v to %v", binding.Name, binding.Target.Name)
|
||||
ctx := api.WithNamespace(api.NewContext(), binding.Namespace)
|
||||
return b.Post().Namespace(api.NamespaceValue(ctx)).Resource("bindings").Body(binding).Do().Error()
|
||||
// TODO: use Pods interface for binding once clusters are upgraded
|
||||
// return b.Pods(binding.Namespace).Bind(binding)
|
||||
}
|
||||
|
||||
type clock interface {
|
||||
|
@ -366,9 +366,11 @@ func TestBind(t *testing.T) {
|
||||
{binding: &api.Binding{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Namespace: api.NamespaceDefault,
|
||||
Name: "foo",
|
||||
},
|
||||
Target: api.ObjectReference{
|
||||
Name: "foohost.kubernetes.mydomain.com",
|
||||
},
|
||||
PodID: "foo",
|
||||
Host: "foohost.kubernetes.mydomain.com",
|
||||
}},
|
||||
}
|
||||
|
||||
|
@ -80,9 +80,11 @@ func (s *Scheduler) scheduleOne() {
|
||||
return
|
||||
}
|
||||
b := &api.Binding{
|
||||
ObjectMeta: api.ObjectMeta{Namespace: pod.Namespace},
|
||||
PodID: pod.Name,
|
||||
Host: dest,
|
||||
ObjectMeta: api.ObjectMeta{Namespace: pod.Namespace, Name: pod.Name},
|
||||
Target: api.ObjectReference{
|
||||
Kind: "Node",
|
||||
Name: dest,
|
||||
},
|
||||
}
|
||||
if err := s.config.Binder.Bind(b); err != nil {
|
||||
glog.V(1).Infof("Failed to bind pod: %v", err)
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
type fakeBinder struct {
|
||||
@ -63,7 +64,7 @@ func TestScheduler(t *testing.T) {
|
||||
{
|
||||
sendPod: podWithID("foo"),
|
||||
algo: mockScheduler{"machine1", nil},
|
||||
expectBind: &api.Binding{PodID: "foo", Host: "machine1"},
|
||||
expectBind: &api.Binding{ObjectMeta: api.ObjectMeta{Name: "foo"}, Target: api.ObjectReference{Kind: "Node", Name: "machine1"}},
|
||||
eventReason: "scheduled",
|
||||
}, {
|
||||
sendPod: podWithID("foo"),
|
||||
@ -74,7 +75,7 @@ func TestScheduler(t *testing.T) {
|
||||
}, {
|
||||
sendPod: podWithID("foo"),
|
||||
algo: mockScheduler{"machine1", nil},
|
||||
expectBind: &api.Binding{PodID: "foo", Host: "machine1"},
|
||||
expectBind: &api.Binding{ObjectMeta: api.ObjectMeta{Name: "foo"}, Target: api.ObjectReference{Kind: "Node", Name: "machine1"}},
|
||||
injectBindError: errB,
|
||||
expectError: errB,
|
||||
expectErrorPod: podWithID("foo"),
|
||||
@ -120,7 +121,7 @@ func TestScheduler(t *testing.T) {
|
||||
t.Errorf("%v: error: wanted %v, got %v", i, e, a)
|
||||
}
|
||||
if e, a := item.expectBind, gotBinding; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%v: error: wanted %v, got %v", i, e, a)
|
||||
t.Errorf("%v: error: %s", i, util.ObjectDiff(e, a))
|
||||
}
|
||||
<-called
|
||||
events.Stop()
|
||||
|
Loading…
Reference in New Issue
Block a user