mirror of
https://github.com/optim-enterprises-bv/kubernetes.git
synced 2025-11-02 19:28:16 +00:00
Merge pull request #25787 from liggitt/update-admission
Automatic merge from submit-queue plumb Update resthandler to allow old/new comparisons in admission Rework how updated objects are passed to rest storage Update methods (first pass at https://github.com/kubernetes/kubernetes/pull/23928#discussion_r61444342) * allows centralizing precondition checks (uid and resourceVersion) * allows admission to have the old and new objects on patch/update operations (sets us up for field level authorization, differential quota updates, etc) * allows patch operations to avoid double-GETting the object to apply the patch Overview of important changes: * pkg/api/rest/rest.go * changes `rest.Update` interface to give rest storage an `UpdatedObjectInfo` interface instead of the object directly. To get the updated object, the storage must call `UpdatedObject()`, passing in the current object * pkg/api/rest/update.go * provides a default `UpdatedObjectInfo` impl * passes a copy of the updated object through any provided transforming functions and returns it when asked * builds UID preconditions from the updated object if they can be extracted * pkg/apiserver/resthandler.go * Reworks update and patch operations to give old objects to admission * pkg/registry/generic/registry/store.go * Calls `UpdatedObject()` inside `GuaranteedUpdate` so it can provide the old object Todo: - [x] Update rest.Update interface: * Given the name of the object being updated * To get the updated object data, the rest storage must pass the current object (fetched using the name) to an `UpdatedObject(ctx, oldObject) (newObject, error)` func. This is typically done inside a `GuaranteedUpdate` call. - [x] Add old object to admission attributes interface - [x] Update resthandler Update to move admission into the UpdatedObject() call - [x] Update resthandler Patch to move the patch application and admission into the UpdatedObject() call - [x] Add resttest tests to make sure oldObj is correctly passed to UpdatedObject(), and errors propagate back up Follow-up: * populate oldObject in admission for delete operations? * update quota plugin to use `GetOldObject()` in admission attributes * admission plugin to gate ownerReference modification on delete permission * Decide how to handle preconditions (does that belong in the storage layer or in the resthander layer?)
This commit is contained in:
@@ -53,6 +53,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/master"
|
"k8s.io/kubernetes/pkg/master"
|
||||||
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
"k8s.io/kubernetes/pkg/util"
|
"k8s.io/kubernetes/pkg/util"
|
||||||
"k8s.io/kubernetes/pkg/util/flag"
|
"k8s.io/kubernetes/pkg/util/flag"
|
||||||
"k8s.io/kubernetes/pkg/util/flowcontrol"
|
"k8s.io/kubernetes/pkg/util/flowcontrol"
|
||||||
@@ -647,6 +648,105 @@ func runPatchTest(c *client.Client) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test patch with a resource that allows create on update
|
||||||
|
endpointTemplate := &api.Endpoints{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "patchendpoint"},
|
||||||
|
Subsets: []api.EndpointSubset{
|
||||||
|
{
|
||||||
|
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
|
||||||
|
Ports: []api.EndpointPort{{Port: 80, Protocol: api.ProtocolTCP}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
patchEndpoint := func(json []byte) (runtime.Object, error) {
|
||||||
|
return c.Patch(api.MergePatchType).Resource("endpoints").Namespace(api.NamespaceDefault).Name("patchendpoint").Body(json).Do().Get()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure patch doesn't get to CreateOnUpdate
|
||||||
|
{
|
||||||
|
endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("Failed creating endpoint JSON: %v", err)
|
||||||
|
}
|
||||||
|
if obj, err := patchEndpoint(endpointJSON); !apierrors.IsNotFound(err) {
|
||||||
|
glog.Fatalf("Expected notfound creating from patch, got error=%v and object: %#v", err, obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the endpoint (endpoints set AllowCreateOnUpdate=true) to get a UID and resource version
|
||||||
|
createdEndpoint, err := c.Endpoints(api.NamespaceDefault).Update(endpointTemplate)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("Failed creating endpoint: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure identity patch is accepted
|
||||||
|
{
|
||||||
|
endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), createdEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("Failed creating endpoint JSON: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := patchEndpoint(endpointJSON); err != nil {
|
||||||
|
glog.Fatalf("Failed patching endpoint: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure patch complains about a mismatched resourceVersion
|
||||||
|
{
|
||||||
|
endpointTemplate.Name = ""
|
||||||
|
endpointTemplate.UID = ""
|
||||||
|
endpointTemplate.ResourceVersion = "1"
|
||||||
|
endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("Failed creating endpoint JSON: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := patchEndpoint(endpointJSON); !apierrors.IsConflict(err) {
|
||||||
|
glog.Fatalf("Expected error, got %#v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure patch complains about mutating the UID
|
||||||
|
{
|
||||||
|
endpointTemplate.Name = ""
|
||||||
|
endpointTemplate.UID = "abc"
|
||||||
|
endpointTemplate.ResourceVersion = ""
|
||||||
|
endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("Failed creating endpoint JSON: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := patchEndpoint(endpointJSON); !apierrors.IsInvalid(err) {
|
||||||
|
glog.Fatalf("Expected error, got %#v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure patch complains about a mismatched name
|
||||||
|
{
|
||||||
|
endpointTemplate.Name = "changedname"
|
||||||
|
endpointTemplate.UID = ""
|
||||||
|
endpointTemplate.ResourceVersion = ""
|
||||||
|
endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("Failed creating endpoint JSON: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := patchEndpoint(endpointJSON); !apierrors.IsBadRequest(err) {
|
||||||
|
glog.Fatalf("Expected error, got %#v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure patch containing originally submitted JSON is accepted
|
||||||
|
{
|
||||||
|
endpointTemplate.Name = ""
|
||||||
|
endpointTemplate.UID = ""
|
||||||
|
endpointTemplate.ResourceVersion = ""
|
||||||
|
endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("Failed creating endpoint JSON: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := patchEndpoint(endpointJSON); err != nil {
|
||||||
|
glog.Fatalf("Failed patching endpoint: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
glog.Info("PATCHs work.")
|
glog.Info("PATCHs work.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import (
|
|||||||
"k8s.io/kubernetes/federation/apis/federation"
|
"k8s.io/kubernetes/federation/apis/federation"
|
||||||
"k8s.io/kubernetes/federation/registry/cluster"
|
"k8s.io/kubernetes/federation/registry/cluster"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/registry/generic"
|
"k8s.io/kubernetes/pkg/registry/generic"
|
||||||
"k8s.io/kubernetes/pkg/registry/generic/registry"
|
"k8s.io/kubernetes/pkg/registry/generic/registry"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
@@ -38,8 +39,8 @@ func (r *StatusREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status subset of an object.
|
// Update alters the status subset of an object.
|
||||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewREST returns a RESTStorage object that will work against clusters.
|
// NewREST returns a RESTStorage object that will work against clusters.
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ func (s *storage) CreateCluster(ctx api.Context, cluster *federation.Cluster) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) UpdateCluster(ctx api.Context, cluster *federation.Cluster) error {
|
func (s *storage) UpdateCluster(ctx api.Context, cluster *federation.Cluster) error {
|
||||||
_, _, err := s.Update(ctx, cluster)
|
_, _, err := s.Update(ctx, cluster.Name, rest.DefaultUpdatedObjectInfo(cluster, api.Scheme))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,10 +30,11 @@ type attributesRecord struct {
|
|||||||
subresource string
|
subresource string
|
||||||
operation Operation
|
operation Operation
|
||||||
object runtime.Object
|
object runtime.Object
|
||||||
|
oldObject runtime.Object
|
||||||
userInfo user.Info
|
userInfo user.Info
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAttributesRecord(object runtime.Object, kind unversioned.GroupVersionKind, namespace, name string, resource unversioned.GroupVersionResource, subresource string, operation Operation, userInfo user.Info) Attributes {
|
func NewAttributesRecord(object runtime.Object, oldObject runtime.Object, kind unversioned.GroupVersionKind, namespace, name string, resource unversioned.GroupVersionResource, subresource string, operation Operation, userInfo user.Info) Attributes {
|
||||||
return &attributesRecord{
|
return &attributesRecord{
|
||||||
kind: kind,
|
kind: kind,
|
||||||
namespace: namespace,
|
namespace: namespace,
|
||||||
@@ -42,6 +43,7 @@ func NewAttributesRecord(object runtime.Object, kind unversioned.GroupVersionKin
|
|||||||
subresource: subresource,
|
subresource: subresource,
|
||||||
operation: operation,
|
operation: operation,
|
||||||
object: object,
|
object: object,
|
||||||
|
oldObject: oldObject,
|
||||||
userInfo: userInfo,
|
userInfo: userInfo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,6 +76,10 @@ func (record *attributesRecord) GetObject() runtime.Object {
|
|||||||
return record.object
|
return record.object
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (record *attributesRecord) GetOldObject() runtime.Object {
|
||||||
|
return record.oldObject
|
||||||
|
}
|
||||||
|
|
||||||
func (record *attributesRecord) GetUserInfo() user.Info {
|
func (record *attributesRecord) GetUserInfo() user.Info {
|
||||||
return record.userInfo
|
return record.userInfo
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ func TestAdmit(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
err := test.chain.Admit(NewAttributesRecord(nil, unversioned.GroupVersionKind{}, "", "", unversioned.GroupVersionResource{}, "", test.operation, nil))
|
err := test.chain.Admit(NewAttributesRecord(nil, nil, unversioned.GroupVersionKind{}, "", "", unversioned.GroupVersionResource{}, "", test.operation, nil))
|
||||||
accepted := (err == nil)
|
accepted := (err == nil)
|
||||||
if accepted != test.accept {
|
if accepted != test.accept {
|
||||||
t.Errorf("%s: unexpected result of admit call: %v\n", test.name, accepted)
|
t.Errorf("%s: unexpected result of admit call: %v\n", test.name, accepted)
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ type Attributes interface {
|
|||||||
GetOperation() Operation
|
GetOperation() Operation
|
||||||
// GetObject is the object from the incoming request prior to default values being applied
|
// GetObject is the object from the incoming request prior to default values being applied
|
||||||
GetObject() runtime.Object
|
GetObject() runtime.Object
|
||||||
|
// GetOldObject is the existing object. Only populated for UPDATE requests.
|
||||||
|
GetOldObject() runtime.Object
|
||||||
// GetKind is the type of object being manipulated. For example: Pod
|
// GetKind is the type of object being manipulated. For example: Pod
|
||||||
GetKind() unversioned.GroupVersionKind
|
GetKind() unversioned.GroupVersionKind
|
||||||
// GetUserInfo is information about the requesting user
|
// GetUserInfo is information about the requesting user
|
||||||
|
|||||||
@@ -174,6 +174,19 @@ type NamedCreater interface {
|
|||||||
Create(ctx api.Context, name string, obj runtime.Object) (runtime.Object, error)
|
Create(ctx api.Context, name string, obj runtime.Object) (runtime.Object, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdatedObjectInfo provides information about an updated object to an Updater.
|
||||||
|
// It requires access to the old object in order to return the newly updated object.
|
||||||
|
type UpdatedObjectInfo interface {
|
||||||
|
// Returns preconditions built from the updated object, if applicable.
|
||||||
|
// May return nil, or a preconditions object containing nil fields,
|
||||||
|
// if no preconditions can be determined from the updated object.
|
||||||
|
Preconditions() *api.Preconditions
|
||||||
|
|
||||||
|
// UpdatedObject returns the updated object, given a context and old object.
|
||||||
|
// The only time an empty oldObj should be passed in is if a "create on update" is occurring (there is no oldObj).
|
||||||
|
UpdatedObject(ctx api.Context, oldObj runtime.Object) (newObj runtime.Object, err error)
|
||||||
|
}
|
||||||
|
|
||||||
// Updater is an object that can update an instance of a RESTful object.
|
// Updater is an object that can update an instance of a RESTful object.
|
||||||
type Updater interface {
|
type Updater interface {
|
||||||
// New returns an empty object that can be used with Update after request data has been put into it.
|
// New returns an empty object that can be used with Update after request data has been put into it.
|
||||||
@@ -183,14 +196,14 @@ type Updater interface {
|
|||||||
// Update finds a resource in the storage and updates it. Some implementations
|
// Update finds a resource in the storage and updates it. Some implementations
|
||||||
// may allow updates creates the object - they should set the created boolean
|
// may allow updates creates the object - they should set the created boolean
|
||||||
// to true.
|
// to true.
|
||||||
Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error)
|
Update(ctx api.Context, name string, objInfo UpdatedObjectInfo) (runtime.Object, bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreaterUpdater is a storage object that must support both create and update.
|
// CreaterUpdater is a storage object that must support both create and update.
|
||||||
// Go prevents embedded interfaces that implement the same method.
|
// Go prevents embedded interfaces that implement the same method.
|
||||||
type CreaterUpdater interface {
|
type CreaterUpdater interface {
|
||||||
Creater
|
Creater
|
||||||
Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error)
|
Update(ctx api.Context, name string, objInfo UpdatedObjectInfo) (runtime.Object, bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreaterUpdater must satisfy the Updater interface.
|
// CreaterUpdater must satisfy the Updater interface.
|
||||||
|
|||||||
@@ -170,6 +170,8 @@ func (t *Tester) TestUpdate(valid runtime.Object, createFn CreateFunc, getFn Get
|
|||||||
}
|
}
|
||||||
t.testUpdateInvokesValidation(copyOrDie(valid), createFn, invalidUpdateFn...)
|
t.testUpdateInvokesValidation(copyOrDie(valid), createFn, invalidUpdateFn...)
|
||||||
t.testUpdateWithWrongUID(copyOrDie(valid), createFn, getFn)
|
t.testUpdateWithWrongUID(copyOrDie(valid), createFn, getFn)
|
||||||
|
t.testUpdateRetrievesOldObject(copyOrDie(valid), createFn, getFn)
|
||||||
|
t.testUpdatePropagatesUpdatedObjectError(copyOrDie(valid), createFn, getFn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test deleting an object.
|
// Test deleting an object.
|
||||||
@@ -442,7 +444,8 @@ func (t *Tester) testUpdateEquals(obj runtime.Object, createFn CreateFunc, getFn
|
|||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
toUpdate = updateFn(toUpdate)
|
toUpdate = updateFn(toUpdate)
|
||||||
updated, created, err := t.storage.(rest.Updater).Update(ctx, toUpdate)
|
toUpdateMeta := t.getObjectMetaOrFail(toUpdate)
|
||||||
|
updated, created, err := t.storage.(rest.Updater).Update(ctx, toUpdateMeta.Name, rest.DefaultUpdatedObjectInfo(toUpdate, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -482,7 +485,7 @@ func (t *Tester) testUpdateFailsOnVersionTooOld(obj runtime.Object, createFn Cre
|
|||||||
olderMeta := t.getObjectMetaOrFail(older)
|
olderMeta := t.getObjectMetaOrFail(older)
|
||||||
olderMeta.ResourceVersion = "1"
|
olderMeta.ResourceVersion = "1"
|
||||||
|
|
||||||
_, _, err = t.storage.(rest.Updater).Update(t.TestContext(), older)
|
_, _, err = t.storage.(rest.Updater).Update(t.TestContext(), olderMeta.Name, rest.DefaultUpdatedObjectInfo(older, api.Scheme))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected an error, but we didn't get one")
|
t.Errorf("Expected an error, but we didn't get one")
|
||||||
} else if !errors.IsConflict(err) {
|
} else if !errors.IsConflict(err) {
|
||||||
@@ -501,7 +504,8 @@ func (t *Tester) testUpdateInvokesValidation(obj runtime.Object, createFn Create
|
|||||||
|
|
||||||
for _, update := range invalidUpdateFn {
|
for _, update := range invalidUpdateFn {
|
||||||
toUpdate := update(copyOrDie(foo))
|
toUpdate := update(copyOrDie(foo))
|
||||||
got, created, err := t.storage.(rest.Updater).Update(t.TestContext(), toUpdate)
|
toUpdateMeta := t.getObjectMetaOrFail(toUpdate)
|
||||||
|
got, created, err := t.storage.(rest.Updater).Update(t.TestContext(), toUpdateMeta.Name, rest.DefaultUpdatedObjectInfo(toUpdate, api.Scheme))
|
||||||
if got != nil || created {
|
if got != nil || created {
|
||||||
t.Errorf("expected nil object and no creation for object: %v", toUpdate)
|
t.Errorf("expected nil object and no creation for object: %v", toUpdate)
|
||||||
}
|
}
|
||||||
@@ -522,7 +526,7 @@ func (t *Tester) testUpdateWithWrongUID(obj runtime.Object, createFn CreateFunc,
|
|||||||
}
|
}
|
||||||
objectMeta.UID = types.UID("UID1111")
|
objectMeta.UID = types.UID("UID1111")
|
||||||
|
|
||||||
obj, created, err := t.storage.(rest.Updater).Update(ctx, foo)
|
obj, created, err := t.storage.(rest.Updater).Update(ctx, objectMeta.Name, rest.DefaultUpdatedObjectInfo(foo, api.Scheme))
|
||||||
if created || obj != nil {
|
if created || obj != nil {
|
||||||
t.Errorf("expected nil object and no creation for object: %v", foo)
|
t.Errorf("expected nil object and no creation for object: %v", foo)
|
||||||
}
|
}
|
||||||
@@ -531,9 +535,85 @@ func (t *Tester) testUpdateWithWrongUID(obj runtime.Object, createFn CreateFunc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Tester) testUpdateRetrievesOldObject(obj runtime.Object, createFn CreateFunc, getFn GetFunc) {
|
||||||
|
ctx := t.TestContext()
|
||||||
|
foo := copyOrDie(obj)
|
||||||
|
t.setObjectMeta(foo, t.namer(6))
|
||||||
|
objectMeta := t.getObjectMetaOrFail(foo)
|
||||||
|
objectMeta.Annotations = map[string]string{"A": "1"}
|
||||||
|
if err := createFn(ctx, foo); err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
storedFoo, err := getFn(ctx, foo)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
storedFooWithUpdates := copyOrDie(storedFoo)
|
||||||
|
objectMeta = t.getObjectMetaOrFail(storedFooWithUpdates)
|
||||||
|
objectMeta.Annotations = map[string]string{"A": "2"}
|
||||||
|
|
||||||
|
// Make sure a custom transform is called, and sees the expected updatedObject and oldObject
|
||||||
|
// This tests the mechanism used to pass the old and new object to admission
|
||||||
|
calledUpdatedObject := 0
|
||||||
|
noopTransform := func(_ api.Context, updatedObject runtime.Object, oldObject runtime.Object) (runtime.Object, error) {
|
||||||
|
if !reflect.DeepEqual(storedFoo, oldObject) {
|
||||||
|
t.Errorf("Expected\n\t%#v\ngot\n\t%#v", storedFoo, oldObject)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(storedFooWithUpdates, updatedObject) {
|
||||||
|
t.Errorf("Expected\n\t%#v\ngot\n\t%#v", storedFooWithUpdates, updatedObject)
|
||||||
|
}
|
||||||
|
calledUpdatedObject++
|
||||||
|
return updatedObject, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedObj, created, err := t.storage.(rest.Updater).Update(ctx, objectMeta.Name, rest.DefaultUpdatedObjectInfo(storedFooWithUpdates, api.Scheme, noopTransform))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if created {
|
||||||
|
t.Errorf("expected no creation for object")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if updatedObj == nil {
|
||||||
|
t.Errorf("expected non-nil object from update")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if calledUpdatedObject != 1 {
|
||||||
|
t.Errorf("expected UpdatedObject() to be called 1 time, was called %d", calledUpdatedObject)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tester) testUpdatePropagatesUpdatedObjectError(obj runtime.Object, createFn CreateFunc, getFn GetFunc) {
|
||||||
|
ctx := t.TestContext()
|
||||||
|
foo := copyOrDie(obj)
|
||||||
|
name := t.namer(7)
|
||||||
|
t.setObjectMeta(foo, name)
|
||||||
|
if err := createFn(ctx, foo); err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure our transform is called, and sees the expected updatedObject and oldObject
|
||||||
|
propagateErr := fmt.Errorf("custom updated object error for %v", foo)
|
||||||
|
noopTransform := func(_ api.Context, updatedObject runtime.Object, oldObject runtime.Object) (runtime.Object, error) {
|
||||||
|
return nil, propagateErr
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err := t.storage.(rest.Updater).Update(ctx, name, rest.DefaultUpdatedObjectInfo(foo, api.Scheme, noopTransform))
|
||||||
|
if err != propagateErr {
|
||||||
|
t.Errorf("expected propagated error, got %#v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Tester) testUpdateOnNotFound(obj runtime.Object) {
|
func (t *Tester) testUpdateOnNotFound(obj runtime.Object) {
|
||||||
t.setObjectMeta(obj, t.namer(0))
|
t.setObjectMeta(obj, t.namer(0))
|
||||||
_, created, err := t.storage.(rest.Updater).Update(t.TestContext(), obj)
|
_, created, err := t.storage.(rest.Updater).Update(t.TestContext(), t.namer(0), rest.DefaultUpdatedObjectInfo(obj, api.Scheme))
|
||||||
if t.createOnUpdate {
|
if t.createOnUpdate {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("creation allowed on updated, but got an error: %v", err)
|
t.Errorf("creation allowed on updated, but got an error: %v", err)
|
||||||
@@ -563,7 +643,7 @@ func (t *Tester) testUpdateRejectsMismatchedNamespace(obj runtime.Object, create
|
|||||||
objectMeta.Name = t.namer(1)
|
objectMeta.Name = t.namer(1)
|
||||||
objectMeta.Namespace = "not-default"
|
objectMeta.Namespace = "not-default"
|
||||||
|
|
||||||
obj, updated, err := t.storage.(rest.Updater).Update(t.TestContext(), obj)
|
obj, updated, err := t.storage.(rest.Updater).Update(t.TestContext(), "foo1", rest.DefaultUpdatedObjectInfo(obj, api.Scheme))
|
||||||
if obj != nil || updated {
|
if obj != nil || updated {
|
||||||
t.Errorf("expected nil object and not updated")
|
t.Errorf("expected nil object and not updated")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/errors"
|
"k8s.io/kubernetes/pkg/api/errors"
|
||||||
|
"k8s.io/kubernetes/pkg/api/meta"
|
||||||
"k8s.io/kubernetes/pkg/api/validation"
|
"k8s.io/kubernetes/pkg/api/validation"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
"k8s.io/kubernetes/pkg/util/validation/field"
|
"k8s.io/kubernetes/pkg/util/validation/field"
|
||||||
@@ -103,3 +104,72 @@ func BeforeUpdate(strategy RESTUpdateStrategy, ctx api.Context, obj, old runtime
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TransformFunc is a function to transform and return newObj
|
||||||
|
type TransformFunc func(ctx api.Context, newObj runtime.Object, oldObj runtime.Object) (transformedNewObj runtime.Object, err error)
|
||||||
|
|
||||||
|
// defaultUpdatedObjectInfo implements UpdatedObjectInfo
|
||||||
|
type defaultUpdatedObjectInfo struct {
|
||||||
|
// obj is the updated object
|
||||||
|
obj runtime.Object
|
||||||
|
|
||||||
|
// copier makes a copy of the object before returning it.
|
||||||
|
// this allows repeated calls to UpdatedObject() to return
|
||||||
|
// pristine data, even if the returned value is mutated.
|
||||||
|
copier runtime.ObjectCopier
|
||||||
|
|
||||||
|
// transformers is an optional list of transforming functions that modify or
|
||||||
|
// replace obj using information from the context, old object, or other sources.
|
||||||
|
transformers []TransformFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultUpdatedObjectInfo returns an UpdatedObjectInfo impl based on the specified object.
|
||||||
|
func DefaultUpdatedObjectInfo(obj runtime.Object, copier runtime.ObjectCopier, transformers ...TransformFunc) UpdatedObjectInfo {
|
||||||
|
return &defaultUpdatedObjectInfo{obj, copier, transformers}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preconditions satisfies the UpdatedObjectInfo interface.
|
||||||
|
func (i *defaultUpdatedObjectInfo) Preconditions() *api.Preconditions {
|
||||||
|
// Attempt to get the UID out of the object
|
||||||
|
accessor, err := meta.Accessor(i.obj)
|
||||||
|
if err != nil {
|
||||||
|
// If no UID can be read, no preconditions are possible
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If empty, no preconditions needed
|
||||||
|
uid := accessor.GetUID()
|
||||||
|
if len(uid) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &api.Preconditions{UID: &uid}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdatedObject satisfies the UpdatedObjectInfo interface.
|
||||||
|
// It returns a copy of the held obj, passed through any configured transformers.
|
||||||
|
func (i *defaultUpdatedObjectInfo) UpdatedObject(ctx api.Context, oldObj runtime.Object) (runtime.Object, error) {
|
||||||
|
var err error
|
||||||
|
// Start with the configured object
|
||||||
|
newObj := i.obj
|
||||||
|
|
||||||
|
// If the original is non-nil (might be nil if the first transformer builds the object from the oldObj), make a copy,
|
||||||
|
// so we don't return the original. BeforeUpdate can mutate the returned object, doing things like clearing ResourceVersion.
|
||||||
|
// If we're re-called, we need to be able to return the pristine version.
|
||||||
|
if newObj != nil {
|
||||||
|
newObj, err = i.copier.Copy(newObj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow any configured transformers to update the new object
|
||||||
|
for _, transformer := range i.transformers {
|
||||||
|
newObj, err = transformer(ctx, newObj, oldObj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newObj, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -462,6 +462,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
ParameterCodec: a.group.ParameterCodec,
|
ParameterCodec: a.group.ParameterCodec,
|
||||||
Creater: a.group.Creater,
|
Creater: a.group.Creater,
|
||||||
Convertor: a.group.Convertor,
|
Convertor: a.group.Convertor,
|
||||||
|
Copier: a.group.Copier,
|
||||||
|
|
||||||
// TODO: This seems wrong for cross-group subresources. It makes an assumption that a subresource and its parent are in the same group version. Revisit this.
|
// TODO: This seems wrong for cross-group subresources. It makes an assumption that a subresource and its parent are in the same group version. Revisit this.
|
||||||
Resource: a.group.GroupVersion.WithResource(resource),
|
Resource: a.group.GroupVersion.WithResource(resource),
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ type APIGroupVersion struct {
|
|||||||
Typer runtime.ObjectTyper
|
Typer runtime.ObjectTyper
|
||||||
Creater runtime.ObjectCreater
|
Creater runtime.ObjectCreater
|
||||||
Convertor runtime.ObjectConvertor
|
Convertor runtime.ObjectConvertor
|
||||||
|
Copier runtime.ObjectCopier
|
||||||
Linker runtime.SelfLinker
|
Linker runtime.SelfLinker
|
||||||
|
|
||||||
Admit admission.Interface
|
Admit admission.Interface
|
||||||
|
|||||||
@@ -271,6 +271,7 @@ func handleInternal(storage map[string]rest.Storage, admissionControl admission.
|
|||||||
|
|
||||||
Creater: api.Scheme,
|
Creater: api.Scheme,
|
||||||
Convertor: api.Scheme,
|
Convertor: api.Scheme,
|
||||||
|
Copier: api.Scheme,
|
||||||
Typer: api.Scheme,
|
Typer: api.Scheme,
|
||||||
Linker: selfLinker,
|
Linker: selfLinker,
|
||||||
Mapper: namespaceMapper,
|
Mapper: namespaceMapper,
|
||||||
@@ -502,13 +503,16 @@ func (storage *SimpleRESTStorage) Create(ctx api.Context, obj runtime.Object) (r
|
|||||||
return obj, err
|
return obj, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *SimpleRESTStorage) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (storage *SimpleRESTStorage) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
storage.checkContext(ctx)
|
storage.checkContext(ctx)
|
||||||
|
obj, err := objInfo.UpdatedObject(ctx, &storage.item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
storage.updated = obj.(*apiservertesting.Simple)
|
storage.updated = obj.(*apiservertesting.Simple)
|
||||||
if err := storage.errors["update"]; err != nil {
|
if err := storage.errors["update"]; err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
var err error
|
|
||||||
if storage.injectedFunction != nil {
|
if storage.injectedFunction != nil {
|
||||||
obj, err = storage.injectedFunction(obj)
|
obj, err = storage.injectedFunction(obj)
|
||||||
}
|
}
|
||||||
@@ -2022,6 +2026,7 @@ func TestPatch(t *testing.T) {
|
|||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: ID,
|
Name: ID,
|
||||||
Namespace: "", // update should allow the client to send an empty namespace
|
Namespace: "", // update should allow the client to send an empty namespace
|
||||||
|
UID: "uid",
|
||||||
},
|
},
|
||||||
Other: "bar",
|
Other: "bar",
|
||||||
}
|
}
|
||||||
@@ -2060,6 +2065,7 @@ func TestPatchRequiresMatchingName(t *testing.T) {
|
|||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: ID,
|
Name: ID,
|
||||||
Namespace: "", // update should allow the client to send an empty namespace
|
Namespace: "", // update should allow the client to send an empty namespace
|
||||||
|
UID: "uid",
|
||||||
},
|
},
|
||||||
Other: "bar",
|
Other: "bar",
|
||||||
}
|
}
|
||||||
@@ -2399,6 +2405,7 @@ func TestUpdateREST(t *testing.T) {
|
|||||||
RequestInfoResolver: newTestRequestInfoResolver(),
|
RequestInfoResolver: newTestRequestInfoResolver(),
|
||||||
Creater: api.Scheme,
|
Creater: api.Scheme,
|
||||||
Convertor: api.Scheme,
|
Convertor: api.Scheme,
|
||||||
|
Copier: api.Scheme,
|
||||||
Typer: api.Scheme,
|
Typer: api.Scheme,
|
||||||
Linker: selfLinker,
|
Linker: selfLinker,
|
||||||
|
|
||||||
@@ -2483,6 +2490,7 @@ func TestParentResourceIsRequired(t *testing.T) {
|
|||||||
RequestInfoResolver: newTestRequestInfoResolver(),
|
RequestInfoResolver: newTestRequestInfoResolver(),
|
||||||
Creater: api.Scheme,
|
Creater: api.Scheme,
|
||||||
Convertor: api.Scheme,
|
Convertor: api.Scheme,
|
||||||
|
Copier: api.Scheme,
|
||||||
Typer: api.Scheme,
|
Typer: api.Scheme,
|
||||||
Linker: selfLinker,
|
Linker: selfLinker,
|
||||||
|
|
||||||
@@ -2514,6 +2522,7 @@ func TestParentResourceIsRequired(t *testing.T) {
|
|||||||
RequestInfoResolver: newTestRequestInfoResolver(),
|
RequestInfoResolver: newTestRequestInfoResolver(),
|
||||||
Creater: api.Scheme,
|
Creater: api.Scheme,
|
||||||
Convertor: api.Scheme,
|
Convertor: api.Scheme,
|
||||||
|
Copier: api.Scheme,
|
||||||
Typer: api.Scheme,
|
Typer: api.Scheme,
|
||||||
Linker: selfLinker,
|
Linker: selfLinker,
|
||||||
|
|
||||||
@@ -3211,6 +3220,7 @@ func TestXGSubresource(t *testing.T) {
|
|||||||
|
|
||||||
Creater: api.Scheme,
|
Creater: api.Scheme,
|
||||||
Convertor: api.Scheme,
|
Convertor: api.Scheme,
|
||||||
|
Copier: api.Scheme,
|
||||||
Typer: api.Scheme,
|
Typer: api.Scheme,
|
||||||
Linker: selfLinker,
|
Linker: selfLinker,
|
||||||
Mapper: namespaceMapper,
|
Mapper: namespaceMapper,
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ type RequestScope struct {
|
|||||||
|
|
||||||
Creater runtime.ObjectCreater
|
Creater runtime.ObjectCreater
|
||||||
Convertor runtime.ObjectConvertor
|
Convertor runtime.ObjectConvertor
|
||||||
|
Copier runtime.ObjectCopier
|
||||||
|
|
||||||
Resource unversioned.GroupVersionResource
|
Resource unversioned.GroupVersionResource
|
||||||
Kind unversioned.GroupVersionKind
|
Kind unversioned.GroupVersionKind
|
||||||
@@ -200,7 +201,7 @@ func ConnectResource(connecter rest.Connecter, scope RequestScope, admit admissi
|
|||||||
}
|
}
|
||||||
userInfo, _ := api.UserFrom(ctx)
|
userInfo, _ := api.UserFrom(ctx)
|
||||||
|
|
||||||
err = admit.Admit(admission.NewAttributesRecord(connectRequest, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, userInfo))
|
err = admit.Admit(admission.NewAttributesRecord(connectRequest, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, userInfo))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scope.err(err, res.ResponseWriter, req.Request)
|
scope.err(err, res.ResponseWriter, req.Request)
|
||||||
return
|
return
|
||||||
@@ -391,7 +392,7 @@ func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.Object
|
|||||||
if admit != nil && admit.Handles(admission.Create) {
|
if admit != nil && admit.Handles(admission.Create) {
|
||||||
userInfo, _ := api.UserFrom(ctx)
|
userInfo, _ := api.UserFrom(ctx)
|
||||||
|
|
||||||
err = admit.Admit(admission.NewAttributesRecord(obj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, userInfo))
|
err = admit.Admit(admission.NewAttributesRecord(obj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, userInfo))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scope.err(err, res.ResponseWriter, req.Request)
|
scope.err(err, res.ResponseWriter, req.Request)
|
||||||
return
|
return
|
||||||
@@ -491,16 +492,16 @@ func PatchResource(r rest.Patcher, scope RequestScope, typer runtime.ObjectTyper
|
|||||||
scope.Serializer.DecoderToVersion(s, unversioned.GroupVersion{Group: gv.Group, Version: runtime.APIVersionInternal}),
|
scope.Serializer.DecoderToVersion(s, unversioned.GroupVersion{Group: gv.Group, Version: runtime.APIVersionInternal}),
|
||||||
)
|
)
|
||||||
|
|
||||||
updateAdmit := func(updatedObject runtime.Object) error {
|
updateAdmit := func(updatedObject runtime.Object, currentObject runtime.Object) error {
|
||||||
if admit != nil && admit.Handles(admission.Update) {
|
if admit != nil && admit.Handles(admission.Update) {
|
||||||
userInfo, _ := api.UserFrom(ctx)
|
userInfo, _ := api.UserFrom(ctx)
|
||||||
return admit.Admit(admission.NewAttributesRecord(updatedObject, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo))
|
return admit.Admit(admission.NewAttributesRecord(updatedObject, currentObject, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := patchResource(ctx, updateAdmit, timeout, versionedObj, r, name, patchType, patchJS, scope.Namer, codec)
|
result, err := patchResource(ctx, updateAdmit, timeout, versionedObj, r, name, patchType, patchJS, scope.Namer, scope.Copier, scope.Resource, codec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scope.err(err, res.ResponseWriter, req.Request)
|
scope.err(err, res.ResponseWriter, req.Request)
|
||||||
return
|
return
|
||||||
@@ -516,43 +517,69 @@ func PatchResource(r rest.Patcher, scope RequestScope, typer runtime.ObjectTyper
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type updateAdmissionFunc func(updatedObject runtime.Object) error
|
type updateAdmissionFunc func(updatedObject runtime.Object, currentObject runtime.Object) error
|
||||||
|
|
||||||
// patchResource divides PatchResource for easier unit testing
|
// patchResource divides PatchResource for easier unit testing
|
||||||
func patchResource(ctx api.Context, admit updateAdmissionFunc, timeout time.Duration, versionedObj runtime.Object, patcher rest.Patcher, name string, patchType api.PatchType, patchJS []byte, namer ScopeNamer, codec runtime.Codec) (runtime.Object, error) {
|
func patchResource(
|
||||||
|
ctx api.Context,
|
||||||
|
admit updateAdmissionFunc,
|
||||||
|
timeout time.Duration,
|
||||||
|
versionedObj runtime.Object,
|
||||||
|
patcher rest.Patcher,
|
||||||
|
name string,
|
||||||
|
patchType api.PatchType,
|
||||||
|
patchJS []byte,
|
||||||
|
namer ScopeNamer,
|
||||||
|
copier runtime.ObjectCopier,
|
||||||
|
resource unversioned.GroupVersionResource,
|
||||||
|
codec runtime.Codec,
|
||||||
|
) (runtime.Object, error) {
|
||||||
|
|
||||||
namespace := api.NamespaceValue(ctx)
|
namespace := api.NamespaceValue(ctx)
|
||||||
|
|
||||||
original, err := patcher.Get(ctx, name)
|
var (
|
||||||
if err != nil {
|
originalObjJS []byte
|
||||||
return nil, err
|
originalPatchedObjJS []byte
|
||||||
}
|
lastConflictErr error
|
||||||
|
)
|
||||||
|
|
||||||
originalObjJS, err := runtime.Encode(codec, original)
|
// applyPatch is called every time GuaranteedUpdate asks for the updated object,
|
||||||
if err != nil {
|
// and is given the currently persisted object as input.
|
||||||
return nil, err
|
applyPatch := func(_ api.Context, _, currentObject runtime.Object) (runtime.Object, error) {
|
||||||
}
|
// Make sure we actually have a persisted currentObject
|
||||||
originalPatchedObjJS, err := getPatchedJS(patchType, originalObjJS, patchJS, versionedObj)
|
if hasUID, err := hasUID(currentObject); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
objToUpdate := patcher.New()
|
|
||||||
if err := runtime.DecodeInto(codec, originalPatchedObjJS, objToUpdate); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := checkName(objToUpdate, name, namespace, namer); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return finishRequest(timeout, func() (runtime.Object, error) {
|
|
||||||
if err := admit(objToUpdate); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
|
} else if !hasUID {
|
||||||
|
return nil, errors.NewNotFound(resource.GroupResource(), name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// update should never create as previous get would fail
|
switch {
|
||||||
updateObject, _, updateErr := patcher.Update(ctx, objToUpdate)
|
case len(originalObjJS) == 0 || len(originalPatchedObjJS) == 0:
|
||||||
for i := 0; i < MaxPatchConflicts && (errors.IsConflict(updateErr)); i++ {
|
// first time through,
|
||||||
|
// 1. apply the patch
|
||||||
|
// 2. save the originalJS and patchedJS to detect whether there were conflicting changes on retries
|
||||||
|
if js, err := runtime.Encode(codec, currentObject); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
originalObjJS = js
|
||||||
|
}
|
||||||
|
|
||||||
|
if js, err := getPatchedJS(patchType, originalObjJS, patchJS, versionedObj); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
originalPatchedObjJS = js
|
||||||
|
}
|
||||||
|
|
||||||
|
objToUpdate := patcher.New()
|
||||||
|
if err := runtime.DecodeInto(codec, originalPatchedObjJS, objToUpdate); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := checkName(objToUpdate, name, namespace, namer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return objToUpdate, nil
|
||||||
|
|
||||||
|
default:
|
||||||
// on a conflict,
|
// on a conflict,
|
||||||
// 1. build a strategic merge patch from originalJS and the patchedJS. Different patch types can
|
// 1. build a strategic merge patch from originalJS and the patchedJS. Different patch types can
|
||||||
// be specified, but a strategic merge patch should be expressive enough handle them. Build the
|
// be specified, but a strategic merge patch should be expressive enough handle them. Build the
|
||||||
@@ -560,16 +587,10 @@ func patchResource(ctx api.Context, admit updateAdmissionFunc, timeout time.Dura
|
|||||||
// 2. build a strategic merge patch from originalJS and the currentJS
|
// 2. build a strategic merge patch from originalJS and the currentJS
|
||||||
// 3. ensure no conflicts between the two patches
|
// 3. ensure no conflicts between the two patches
|
||||||
// 4. apply the #1 patch to the currentJS object
|
// 4. apply the #1 patch to the currentJS object
|
||||||
// 5. retry the update
|
|
||||||
currentObject, err := patcher.Get(ctx, name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
currentObjectJS, err := runtime.Encode(codec, currentObject)
|
currentObjectJS, err := runtime.Encode(codec, currentObject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
currentPatch, err := strategicpatch.CreateStrategicMergePatch(originalObjJS, currentObjectJS, versionedObj)
|
currentPatch, err := strategicpatch.CreateStrategicMergePatch(originalObjJS, currentObjectJS, versionedObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -592,25 +613,41 @@ func patchResource(ctx api.Context, admit updateAdmissionFunc, timeout time.Dura
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if hasConflicts {
|
if hasConflicts {
|
||||||
glog.V(4).Infof("patchResource failed for resource %s, becauase there is a meaningful conflict.\n diff1=%v\n, diff2=%v\n", name, diff1, diff2)
|
glog.V(4).Infof("patchResource failed for resource %s, because there is a meaningful conflict.\n diff1=%v\n, diff2=%v\n", name, diff1, diff2)
|
||||||
return updateObject, updateErr
|
// Return the last conflict error we got if we have one
|
||||||
|
if lastConflictErr != nil {
|
||||||
|
return nil, lastConflictErr
|
||||||
|
}
|
||||||
|
// Otherwise manufacture one of our own
|
||||||
|
return nil, errors.NewConflict(resource.GroupResource(), name, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
newlyPatchedObjJS, err := getPatchedJS(api.StrategicMergePatchType, currentObjectJS, originalPatch, versionedObj)
|
newlyPatchedObjJS, err := getPatchedJS(api.StrategicMergePatchType, currentObjectJS, originalPatch, versionedObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
objToUpdate := patcher.New()
|
||||||
if err := runtime.DecodeInto(codec, newlyPatchedObjJS, objToUpdate); err != nil {
|
if err := runtime.DecodeInto(codec, newlyPatchedObjJS, objToUpdate); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return objToUpdate, nil
|
||||||
if err := admit(objToUpdate); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
updateObject, _, updateErr = patcher.Update(ctx, objToUpdate)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyAdmission is called every time GuaranteedUpdate asks for the updated object,
|
||||||
|
// and is given the currently persisted object and the patched object as input.
|
||||||
|
applyAdmission := func(ctx api.Context, patchedObject runtime.Object, currentObject runtime.Object) (runtime.Object, error) {
|
||||||
|
return patchedObject, admit(patchedObject, currentObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedObjectInfo := rest.DefaultUpdatedObjectInfo(nil, copier, applyPatch, applyAdmission)
|
||||||
|
|
||||||
|
return finishRequest(timeout, func() (runtime.Object, error) {
|
||||||
|
updateObject, _, updateErr := patcher.Update(ctx, name, updatedObjectInfo)
|
||||||
|
for i := 0; i < MaxPatchConflicts && (errors.IsConflict(updateErr)); i++ {
|
||||||
|
lastConflictErr = updateErr
|
||||||
|
updateObject, _, updateErr = patcher.Update(ctx, name, updatedObjectInfo)
|
||||||
|
}
|
||||||
return updateObject, updateErr
|
return updateObject, updateErr
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -667,20 +704,18 @@ func UpdateResource(r rest.Updater, scope RequestScope, typer runtime.ObjectType
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var transformers []rest.TransformFunc
|
||||||
if admit != nil && admit.Handles(admission.Update) {
|
if admit != nil && admit.Handles(admission.Update) {
|
||||||
userInfo, _ := api.UserFrom(ctx)
|
transformers = append(transformers, func(ctx api.Context, newObj, oldObj runtime.Object) (runtime.Object, error) {
|
||||||
|
userInfo, _ := api.UserFrom(ctx)
|
||||||
err = admit.Admit(admission.NewAttributesRecord(obj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo))
|
return newObj, admit.Admit(admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo))
|
||||||
if err != nil {
|
})
|
||||||
scope.err(err, res.ResponseWriter, req.Request)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trace.Step("About to store object in database")
|
trace.Step("About to store object in database")
|
||||||
wasCreated := false
|
wasCreated := false
|
||||||
result, err := finishRequest(timeout, func() (runtime.Object, error) {
|
result, err := finishRequest(timeout, func() (runtime.Object, error) {
|
||||||
obj, created, err := r.Update(ctx, obj)
|
obj, created, err := r.Update(ctx, name, rest.DefaultUpdatedObjectInfo(obj, scope.Copier, transformers...))
|
||||||
wasCreated = created
|
wasCreated = created
|
||||||
return obj, err
|
return obj, err
|
||||||
})
|
})
|
||||||
@@ -753,7 +788,7 @@ func DeleteResource(r rest.GracefulDeleter, checkBody bool, scope RequestScope,
|
|||||||
if admit != nil && admit.Handles(admission.Delete) {
|
if admit != nil && admit.Handles(admission.Delete) {
|
||||||
userInfo, _ := api.UserFrom(ctx)
|
userInfo, _ := api.UserFrom(ctx)
|
||||||
|
|
||||||
err = admit.Admit(admission.NewAttributesRecord(nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, userInfo))
|
err = admit.Admit(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, userInfo))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scope.err(err, res.ResponseWriter, req.Request)
|
scope.err(err, res.ResponseWriter, req.Request)
|
||||||
return
|
return
|
||||||
@@ -814,7 +849,7 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestSco
|
|||||||
if admit != nil && admit.Handles(admission.Delete) {
|
if admit != nil && admit.Handles(admission.Delete) {
|
||||||
userInfo, _ := api.UserFrom(ctx)
|
userInfo, _ := api.UserFrom(ctx)
|
||||||
|
|
||||||
err = admit.Admit(admission.NewAttributesRecord(nil, scope.Kind, namespace, "", scope.Resource, scope.Subresource, admission.Delete, userInfo))
|
err = admit.Admit(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, "", scope.Resource, scope.Subresource, admission.Delete, userInfo))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scope.err(err, res.ResponseWriter, req.Request)
|
scope.err(err, res.ResponseWriter, req.Request)
|
||||||
return
|
return
|
||||||
@@ -969,6 +1004,20 @@ func setSelfLink(obj runtime.Object, req *restful.Request, namer ScopeNamer) err
|
|||||||
return namer.SetSelfLink(obj, newURL.String())
|
return namer.SetSelfLink(obj, newURL.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hasUID(obj runtime.Object) (bool, error) {
|
||||||
|
if obj == nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
accessor, err := meta.Accessor(obj)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.NewInternalError(err)
|
||||||
|
}
|
||||||
|
if len(accessor.GetUID()) == 0 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
// checkName checks the provided name against the request
|
// checkName checks the provided name against the request
|
||||||
func checkName(obj runtime.Object, name, namespace string, namer ScopeNamer) error {
|
func checkName(obj runtime.Object, name, namespace string, namer ScopeNamer) error {
|
||||||
if objNamespace, objName, err := namer.ObjectName(obj); err == nil {
|
if objNamespace, objName, err := namer.ObjectName(obj); err == nil {
|
||||||
|
|||||||
@@ -28,9 +28,11 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
apierrors "k8s.io/kubernetes/pkg/api/errors"
|
apierrors "k8s.io/kubernetes/pkg/api/errors"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/api/testapi"
|
"k8s.io/kubernetes/pkg/api/testapi"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
|
"k8s.io/kubernetes/pkg/types"
|
||||||
"k8s.io/kubernetes/pkg/util/diff"
|
"k8s.io/kubernetes/pkg/util/diff"
|
||||||
"k8s.io/kubernetes/pkg/util/strategicpatch"
|
"k8s.io/kubernetes/pkg/util/strategicpatch"
|
||||||
)
|
)
|
||||||
@@ -64,20 +66,32 @@ func TestPatchAnonymousField(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type testPatcher struct {
|
type testPatcher struct {
|
||||||
// startingPod is used for the first Get
|
t *testing.T
|
||||||
|
|
||||||
|
// startingPod is used for the first Update
|
||||||
startingPod *api.Pod
|
startingPod *api.Pod
|
||||||
|
|
||||||
// updatePod is the pod that is used for conflict comparison and returned for the SECOND Get
|
// updatePod is the pod that is used for conflict comparison and used for subsequent Update calls
|
||||||
updatePod *api.Pod
|
updatePod *api.Pod
|
||||||
|
|
||||||
numGets int
|
numUpdates int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *testPatcher) New() runtime.Object {
|
func (p *testPatcher) New() runtime.Object {
|
||||||
return &api.Pod{}
|
return &api.Pod{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *testPatcher) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (p *testPatcher) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
|
currentPod := p.startingPod
|
||||||
|
if p.numUpdates > 0 {
|
||||||
|
currentPod = p.updatePod
|
||||||
|
}
|
||||||
|
p.numUpdates++
|
||||||
|
|
||||||
|
obj, err := objInfo.UpdatedObject(ctx, currentPod)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
inPod := obj.(*api.Pod)
|
inPod := obj.(*api.Pod)
|
||||||
if inPod.ResourceVersion != p.updatePod.ResourceVersion {
|
if inPod.ResourceVersion != p.updatePod.ResourceVersion {
|
||||||
return nil, false, apierrors.NewConflict(api.Resource("pods"), inPod.Name, fmt.Errorf("existing %v, new %v", p.updatePod.ResourceVersion, inPod.ResourceVersion))
|
return nil, false, apierrors.NewConflict(api.Resource("pods"), inPod.Name, fmt.Errorf("existing %v, new %v", p.updatePod.ResourceVersion, inPod.ResourceVersion))
|
||||||
@@ -87,12 +101,8 @@ func (p *testPatcher) Update(ctx api.Context, obj runtime.Object) (runtime.Objec
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *testPatcher) Get(ctx api.Context, name string) (runtime.Object, error) {
|
func (p *testPatcher) Get(ctx api.Context, name string) (runtime.Object, error) {
|
||||||
if p.numGets > 0 {
|
p.t.Fatal("Unexpected call to testPatcher.Get")
|
||||||
return p.updatePod, nil
|
return nil, errors.New("Unexpected call to testPatcher.Get")
|
||||||
}
|
|
||||||
p.numGets++
|
|
||||||
|
|
||||||
return p.startingPod, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type testNamer struct {
|
type testNamer struct {
|
||||||
@@ -138,12 +148,12 @@ type patchTestCase struct {
|
|||||||
// admission chain to use, nil is fine
|
// admission chain to use, nil is fine
|
||||||
admit updateAdmissionFunc
|
admit updateAdmissionFunc
|
||||||
|
|
||||||
// startingPod is used for the first Get
|
// startingPod is used as the starting point for the first Update
|
||||||
startingPod *api.Pod
|
startingPod *api.Pod
|
||||||
// changedPod is the "destination" pod for the patch. The test will create a patch from the startingPod to the changedPod
|
// changedPod is the "destination" pod for the patch. The test will create a patch from the startingPod to the changedPod
|
||||||
// to use when calling the patch operation
|
// to use when calling the patch operation
|
||||||
changedPod *api.Pod
|
changedPod *api.Pod
|
||||||
// updatePod is the pod that is used for conflict comparison and returned for the SECOND Get
|
// updatePod is the pod that is used for conflict comparison and as the starting point for the second Update
|
||||||
updatePod *api.Pod
|
updatePod *api.Pod
|
||||||
|
|
||||||
// expectedPod is the pod that you expect to get back after the patch is complete
|
// expectedPod is the pod that you expect to get back after the patch is complete
|
||||||
@@ -160,12 +170,13 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
|||||||
codec := testapi.Default.Codec()
|
codec := testapi.Default.Codec()
|
||||||
admit := tc.admit
|
admit := tc.admit
|
||||||
if admit == nil {
|
if admit == nil {
|
||||||
admit = func(updatedObject runtime.Object) error {
|
admit = func(updatedObject runtime.Object, currentObject runtime.Object) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
testPatcher := &testPatcher{}
|
testPatcher := &testPatcher{}
|
||||||
|
testPatcher.t = t
|
||||||
testPatcher.startingPod = tc.startingPod
|
testPatcher.startingPod = tc.startingPod
|
||||||
testPatcher.updatePod = tc.updatePod
|
testPatcher.updatePod = tc.updatePod
|
||||||
|
|
||||||
@@ -173,6 +184,8 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
|||||||
ctx = api.WithNamespace(ctx, namespace)
|
ctx = api.WithNamespace(ctx, namespace)
|
||||||
|
|
||||||
namer := &testNamer{namespace, name}
|
namer := &testNamer{namespace, name}
|
||||||
|
copier := runtime.ObjectCopier(api.Scheme)
|
||||||
|
resource := unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
|
||||||
|
|
||||||
versionedObj, err := api.Scheme.ConvertToVersion(&api.Pod{}, unversioned.GroupVersion{Version: "v1"})
|
versionedObj, err := api.Scheme.ConvertToVersion(&api.Pod{}, unversioned.GroupVersion{Version: "v1"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -219,7 +232,7 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resultObj, err := patchResource(ctx, admit, 1*time.Second, versionedObj, testPatcher, name, patchType, patch, namer, codec)
|
resultObj, err := patchResource(ctx, admit, 1*time.Second, versionedObj, testPatcher, name, patchType, patch, namer, copier, resource, codec)
|
||||||
if len(tc.expectedError) != 0 {
|
if len(tc.expectedError) != 0 {
|
||||||
if err == nil || err.Error() != tc.expectedError {
|
if err == nil || err.Error() != tc.expectedError {
|
||||||
t.Errorf("%s: expected error %v, but got %v", tc.name, tc.expectedError, err)
|
t.Errorf("%s: expected error %v, but got %v", tc.name, tc.expectedError, err)
|
||||||
@@ -265,6 +278,7 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
|||||||
func TestPatchResourceWithVersionConflict(t *testing.T) {
|
func TestPatchResourceWithVersionConflict(t *testing.T) {
|
||||||
namespace := "bar"
|
namespace := "bar"
|
||||||
name := "foo"
|
name := "foo"
|
||||||
|
uid := types.UID("uid")
|
||||||
fifteen := int64(15)
|
fifteen := int64(15)
|
||||||
thirty := int64(30)
|
thirty := int64(30)
|
||||||
|
|
||||||
@@ -280,18 +294,21 @@ func TestPatchResourceWithVersionConflict(t *testing.T) {
|
|||||||
|
|
||||||
tc.startingPod.Name = name
|
tc.startingPod.Name = name
|
||||||
tc.startingPod.Namespace = namespace
|
tc.startingPod.Namespace = namespace
|
||||||
|
tc.startingPod.UID = uid
|
||||||
tc.startingPod.ResourceVersion = "1"
|
tc.startingPod.ResourceVersion = "1"
|
||||||
tc.startingPod.APIVersion = "v1"
|
tc.startingPod.APIVersion = "v1"
|
||||||
tc.startingPod.Spec.ActiveDeadlineSeconds = &fifteen
|
tc.startingPod.Spec.ActiveDeadlineSeconds = &fifteen
|
||||||
|
|
||||||
tc.changedPod.Name = name
|
tc.changedPod.Name = name
|
||||||
tc.changedPod.Namespace = namespace
|
tc.changedPod.Namespace = namespace
|
||||||
|
tc.changedPod.UID = uid
|
||||||
tc.changedPod.ResourceVersion = "1"
|
tc.changedPod.ResourceVersion = "1"
|
||||||
tc.changedPod.APIVersion = "v1"
|
tc.changedPod.APIVersion = "v1"
|
||||||
tc.changedPod.Spec.ActiveDeadlineSeconds = &thirty
|
tc.changedPod.Spec.ActiveDeadlineSeconds = &thirty
|
||||||
|
|
||||||
tc.updatePod.Name = name
|
tc.updatePod.Name = name
|
||||||
tc.updatePod.Namespace = namespace
|
tc.updatePod.Namespace = namespace
|
||||||
|
tc.updatePod.UID = uid
|
||||||
tc.updatePod.ResourceVersion = "2"
|
tc.updatePod.ResourceVersion = "2"
|
||||||
tc.updatePod.APIVersion = "v1"
|
tc.updatePod.APIVersion = "v1"
|
||||||
tc.updatePod.Spec.ActiveDeadlineSeconds = &fifteen
|
tc.updatePod.Spec.ActiveDeadlineSeconds = &fifteen
|
||||||
@@ -299,6 +316,7 @@ func TestPatchResourceWithVersionConflict(t *testing.T) {
|
|||||||
|
|
||||||
tc.expectedPod.Name = name
|
tc.expectedPod.Name = name
|
||||||
tc.expectedPod.Namespace = namespace
|
tc.expectedPod.Namespace = namespace
|
||||||
|
tc.expectedPod.UID = uid
|
||||||
tc.expectedPod.ResourceVersion = "2"
|
tc.expectedPod.ResourceVersion = "2"
|
||||||
tc.expectedPod.Spec.ActiveDeadlineSeconds = &thirty
|
tc.expectedPod.Spec.ActiveDeadlineSeconds = &thirty
|
||||||
tc.expectedPod.Spec.NodeName = "anywhere"
|
tc.expectedPod.Spec.NodeName = "anywhere"
|
||||||
@@ -309,6 +327,7 @@ func TestPatchResourceWithVersionConflict(t *testing.T) {
|
|||||||
func TestPatchResourceWithConflict(t *testing.T) {
|
func TestPatchResourceWithConflict(t *testing.T) {
|
||||||
namespace := "bar"
|
namespace := "bar"
|
||||||
name := "foo"
|
name := "foo"
|
||||||
|
uid := types.UID("uid")
|
||||||
|
|
||||||
tc := &patchTestCase{
|
tc := &patchTestCase{
|
||||||
name: "TestPatchResourceWithConflict",
|
name: "TestPatchResourceWithConflict",
|
||||||
@@ -322,18 +341,21 @@ func TestPatchResourceWithConflict(t *testing.T) {
|
|||||||
|
|
||||||
tc.startingPod.Name = name
|
tc.startingPod.Name = name
|
||||||
tc.startingPod.Namespace = namespace
|
tc.startingPod.Namespace = namespace
|
||||||
|
tc.startingPod.UID = uid
|
||||||
tc.startingPod.ResourceVersion = "1"
|
tc.startingPod.ResourceVersion = "1"
|
||||||
tc.startingPod.APIVersion = "v1"
|
tc.startingPod.APIVersion = "v1"
|
||||||
tc.startingPod.Spec.NodeName = "here"
|
tc.startingPod.Spec.NodeName = "here"
|
||||||
|
|
||||||
tc.changedPod.Name = name
|
tc.changedPod.Name = name
|
||||||
tc.changedPod.Namespace = namespace
|
tc.changedPod.Namespace = namespace
|
||||||
|
tc.changedPod.UID = uid
|
||||||
tc.changedPod.ResourceVersion = "1"
|
tc.changedPod.ResourceVersion = "1"
|
||||||
tc.changedPod.APIVersion = "v1"
|
tc.changedPod.APIVersion = "v1"
|
||||||
tc.changedPod.Spec.NodeName = "there"
|
tc.changedPod.Spec.NodeName = "there"
|
||||||
|
|
||||||
tc.updatePod.Name = name
|
tc.updatePod.Name = name
|
||||||
tc.updatePod.Namespace = namespace
|
tc.updatePod.Namespace = namespace
|
||||||
|
tc.updatePod.UID = uid
|
||||||
tc.updatePod.ResourceVersion = "2"
|
tc.updatePod.ResourceVersion = "2"
|
||||||
tc.updatePod.APIVersion = "v1"
|
tc.updatePod.APIVersion = "v1"
|
||||||
tc.updatePod.Spec.NodeName = "anywhere"
|
tc.updatePod.Spec.NodeName = "anywhere"
|
||||||
@@ -344,13 +366,14 @@ func TestPatchResourceWithConflict(t *testing.T) {
|
|||||||
func TestPatchWithAdmissionRejection(t *testing.T) {
|
func TestPatchWithAdmissionRejection(t *testing.T) {
|
||||||
namespace := "bar"
|
namespace := "bar"
|
||||||
name := "foo"
|
name := "foo"
|
||||||
|
uid := types.UID("uid")
|
||||||
fifteen := int64(15)
|
fifteen := int64(15)
|
||||||
thirty := int64(30)
|
thirty := int64(30)
|
||||||
|
|
||||||
tc := &patchTestCase{
|
tc := &patchTestCase{
|
||||||
name: "TestPatchWithAdmissionRejection",
|
name: "TestPatchWithAdmissionRejection",
|
||||||
|
|
||||||
admit: func(updatedObject runtime.Object) error {
|
admit: func(updatedObject runtime.Object, currentObject runtime.Object) error {
|
||||||
return errors.New("admission failure")
|
return errors.New("admission failure")
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -363,12 +386,14 @@ func TestPatchWithAdmissionRejection(t *testing.T) {
|
|||||||
|
|
||||||
tc.startingPod.Name = name
|
tc.startingPod.Name = name
|
||||||
tc.startingPod.Namespace = namespace
|
tc.startingPod.Namespace = namespace
|
||||||
|
tc.startingPod.UID = uid
|
||||||
tc.startingPod.ResourceVersion = "1"
|
tc.startingPod.ResourceVersion = "1"
|
||||||
tc.startingPod.APIVersion = "v1"
|
tc.startingPod.APIVersion = "v1"
|
||||||
tc.startingPod.Spec.ActiveDeadlineSeconds = &fifteen
|
tc.startingPod.Spec.ActiveDeadlineSeconds = &fifteen
|
||||||
|
|
||||||
tc.changedPod.Name = name
|
tc.changedPod.Name = name
|
||||||
tc.changedPod.Namespace = namespace
|
tc.changedPod.Namespace = namespace
|
||||||
|
tc.changedPod.UID = uid
|
||||||
tc.changedPod.ResourceVersion = "1"
|
tc.changedPod.ResourceVersion = "1"
|
||||||
tc.changedPod.APIVersion = "v1"
|
tc.changedPod.APIVersion = "v1"
|
||||||
tc.changedPod.Spec.ActiveDeadlineSeconds = &thirty
|
tc.changedPod.Spec.ActiveDeadlineSeconds = &thirty
|
||||||
@@ -379,6 +404,7 @@ func TestPatchWithAdmissionRejection(t *testing.T) {
|
|||||||
func TestPatchWithVersionConflictThenAdmissionFailure(t *testing.T) {
|
func TestPatchWithVersionConflictThenAdmissionFailure(t *testing.T) {
|
||||||
namespace := "bar"
|
namespace := "bar"
|
||||||
name := "foo"
|
name := "foo"
|
||||||
|
uid := types.UID("uid")
|
||||||
fifteen := int64(15)
|
fifteen := int64(15)
|
||||||
thirty := int64(30)
|
thirty := int64(30)
|
||||||
seen := false
|
seen := false
|
||||||
@@ -386,7 +412,7 @@ func TestPatchWithVersionConflictThenAdmissionFailure(t *testing.T) {
|
|||||||
tc := &patchTestCase{
|
tc := &patchTestCase{
|
||||||
name: "TestPatchWithVersionConflictThenAdmissionFailure",
|
name: "TestPatchWithVersionConflictThenAdmissionFailure",
|
||||||
|
|
||||||
admit: func(updatedObject runtime.Object) error {
|
admit: func(updatedObject runtime.Object, currentObject runtime.Object) error {
|
||||||
if seen {
|
if seen {
|
||||||
return errors.New("admission failure")
|
return errors.New("admission failure")
|
||||||
}
|
}
|
||||||
@@ -404,18 +430,21 @@ func TestPatchWithVersionConflictThenAdmissionFailure(t *testing.T) {
|
|||||||
|
|
||||||
tc.startingPod.Name = name
|
tc.startingPod.Name = name
|
||||||
tc.startingPod.Namespace = namespace
|
tc.startingPod.Namespace = namespace
|
||||||
|
tc.startingPod.UID = uid
|
||||||
tc.startingPod.ResourceVersion = "1"
|
tc.startingPod.ResourceVersion = "1"
|
||||||
tc.startingPod.APIVersion = "v1"
|
tc.startingPod.APIVersion = "v1"
|
||||||
tc.startingPod.Spec.ActiveDeadlineSeconds = &fifteen
|
tc.startingPod.Spec.ActiveDeadlineSeconds = &fifteen
|
||||||
|
|
||||||
tc.changedPod.Name = name
|
tc.changedPod.Name = name
|
||||||
tc.changedPod.Namespace = namespace
|
tc.changedPod.Namespace = namespace
|
||||||
|
tc.changedPod.UID = uid
|
||||||
tc.changedPod.ResourceVersion = "1"
|
tc.changedPod.ResourceVersion = "1"
|
||||||
tc.changedPod.APIVersion = "v1"
|
tc.changedPod.APIVersion = "v1"
|
||||||
tc.changedPod.Spec.ActiveDeadlineSeconds = &thirty
|
tc.changedPod.Spec.ActiveDeadlineSeconds = &thirty
|
||||||
|
|
||||||
tc.updatePod.Name = name
|
tc.updatePod.Name = name
|
||||||
tc.updatePod.Namespace = namespace
|
tc.updatePod.Namespace = namespace
|
||||||
|
tc.updatePod.UID = uid
|
||||||
tc.updatePod.ResourceVersion = "2"
|
tc.updatePod.ResourceVersion = "2"
|
||||||
tc.updatePod.APIVersion = "v1"
|
tc.updatePod.APIVersion = "v1"
|
||||||
tc.updatePod.Spec.ActiveDeadlineSeconds = &fifteen
|
tc.updatePod.Spec.ActiveDeadlineSeconds = &fifteen
|
||||||
@@ -423,3 +452,26 @@ func TestPatchWithVersionConflictThenAdmissionFailure(t *testing.T) {
|
|||||||
|
|
||||||
tc.Run(t)
|
tc.Run(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHasUID(t *testing.T) {
|
||||||
|
testcases := []struct {
|
||||||
|
obj runtime.Object
|
||||||
|
hasUID bool
|
||||||
|
}{
|
||||||
|
{obj: nil, hasUID: false},
|
||||||
|
{obj: &api.Pod{}, hasUID: false},
|
||||||
|
{obj: nil, hasUID: false},
|
||||||
|
{obj: runtime.Object(nil), hasUID: false},
|
||||||
|
{obj: &api.Pod{ObjectMeta: api.ObjectMeta{UID: types.UID("A")}}, hasUID: true},
|
||||||
|
}
|
||||||
|
for i, tc := range testcases {
|
||||||
|
actual, err := hasUID(tc.obj)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%d: unexpected error %v", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if tc.hasUID != actual {
|
||||||
|
t.Errorf("%d: expected %v, got %v", i, tc.hasUID, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -862,6 +862,7 @@ func (s *GenericAPIServer) getAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupV
|
|||||||
version.Serializer = apiGroupInfo.NegotiatedSerializer
|
version.Serializer = apiGroupInfo.NegotiatedSerializer
|
||||||
version.Creater = apiGroupInfo.Scheme
|
version.Creater = apiGroupInfo.Scheme
|
||||||
version.Convertor = apiGroupInfo.Scheme
|
version.Convertor = apiGroupInfo.Scheme
|
||||||
|
version.Copier = apiGroupInfo.Scheme
|
||||||
version.Typer = apiGroupInfo.Scheme
|
version.Typer = apiGroupInfo.Scheme
|
||||||
version.SubresourceGroupVersionKind = apiGroupInfo.SubresourceGroupVersionKind
|
version.SubresourceGroupVersionKind = apiGroupInfo.SubresourceGroupVersionKind
|
||||||
return version, err
|
return version, err
|
||||||
|
|||||||
@@ -749,6 +749,7 @@ func (m *Master) thirdpartyapi(group, kind, version string) *apiserver.APIGroupV
|
|||||||
|
|
||||||
Creater: thirdpartyresourcedata.NewObjectCreator(group, version, api.Scheme),
|
Creater: thirdpartyresourcedata.NewObjectCreator(group, version, api.Scheme),
|
||||||
Convertor: api.Scheme,
|
Convertor: api.Scheme,
|
||||||
|
Copier: api.Scheme,
|
||||||
Typer: api.Scheme,
|
Typer: api.Scheme,
|
||||||
|
|
||||||
Mapper: thirdpartyresourcedata.NewMapper(registered.GroupOrDie(extensions.GroupName).RESTMapper, kind, version, group),
|
Mapper: thirdpartyresourcedata.NewMapper(registered.GroupOrDie(extensions.GroupName).RESTMapper, kind, version, group),
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ func (s *storage) CreateConfigMap(ctx api.Context, cfg *api.ConfigMap) (*api.Con
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) UpdateConfigMap(ctx api.Context, cfg *api.ConfigMap) (*api.ConfigMap, error) {
|
func (s *storage) UpdateConfigMap(ctx api.Context, cfg *api.ConfigMap) (*api.ConfigMap, error) {
|
||||||
obj, _, err := s.Update(ctx, cfg)
|
obj, _, err := s.Update(ctx, cfg.Name, rest.DefaultUpdatedObjectInfo(cfg, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,8 +117,8 @@ func (r *StatusREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status subset of an object.
|
// Update alters the status subset of an object.
|
||||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScaleREST struct {
|
type ScaleREST struct {
|
||||||
@@ -141,7 +141,18 @@ func (r *ScaleREST) Get(ctx api.Context, name string) (runtime.Object, error) {
|
|||||||
return scaleFromRC(rc), nil
|
return scaleFromRC(rc), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *ScaleREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
|
rc, err := r.registry.GetController(ctx, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, errors.NewNotFound(autoscaling.Resource("replicationcontrollers/scale"), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldScale := scaleFromRC(rc)
|
||||||
|
obj, err := objInfo.UpdatedObject(ctx, oldScale)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return nil, false, errors.NewBadRequest("nil update passed to Scale")
|
return nil, false, errors.NewBadRequest("nil update passed to Scale")
|
||||||
}
|
}
|
||||||
@@ -154,10 +165,6 @@ func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object,
|
|||||||
return nil, false, errors.NewInvalid(autoscaling.Kind("Scale"), scale.Name, errs)
|
return nil, false, errors.NewInvalid(autoscaling.Kind("Scale"), scale.Name, errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
rc, err := r.registry.GetController(ctx, scale.Name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, false, errors.NewNotFound(autoscaling.Resource("replicationcontrollers/scale"), scale.Name)
|
|
||||||
}
|
|
||||||
rc.Spec.Replicas = scale.Spec.Replicas
|
rc.Spec.Replicas = scale.Spec.Replicas
|
||||||
rc.ResourceVersion = scale.ResourceVersion
|
rc.ResourceVersion = scale.ResourceVersion
|
||||||
rc, err = r.registry.UpdateController(ctx, rc)
|
rc, err = r.registry.UpdateController(ctx, rc)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/errors"
|
"k8s.io/kubernetes/pkg/api/errors"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
@@ -159,7 +160,7 @@ func TestGenerationNumber(t *testing.T) {
|
|||||||
|
|
||||||
// Updates to spec should increment the generation number
|
// Updates to spec should increment the generation number
|
||||||
controller.Spec.Replicas += 1
|
controller.Spec.Replicas += 1
|
||||||
storage.Controller.Update(ctx, controller)
|
storage.Controller.Update(ctx, controller.Name, rest.DefaultUpdatedObjectInfo(controller, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -174,7 +175,7 @@ func TestGenerationNumber(t *testing.T) {
|
|||||||
|
|
||||||
// Updates to status should not increment either spec or status generation numbers
|
// Updates to status should not increment either spec or status generation numbers
|
||||||
controller.Status.Replicas += 1
|
controller.Status.Replicas += 1
|
||||||
storage.Controller.Update(ctx, controller)
|
storage.Controller.Update(ctx, controller.Name, rest.DefaultUpdatedObjectInfo(controller, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -289,7 +290,7 @@ func TestScaleUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, _, err := storage.Scale.Update(ctx, &update); err != nil {
|
if _, _, err := storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil {
|
||||||
t.Fatalf("error updating scale %v: %v", update, err)
|
t.Fatalf("error updating scale %v: %v", update, err)
|
||||||
}
|
}
|
||||||
obj, err := storage.Scale.Get(ctx, name)
|
obj, err := storage.Scale.Get(ctx, name)
|
||||||
@@ -304,7 +305,7 @@ func TestScaleUpdate(t *testing.T) {
|
|||||||
update.ResourceVersion = rc.ResourceVersion
|
update.ResourceVersion = rc.ResourceVersion
|
||||||
update.Spec.Replicas = 15
|
update.Spec.Replicas = 15
|
||||||
|
|
||||||
if _, _, err = storage.Scale.Update(ctx, &update); err != nil && !errors.IsConflict(err) {
|
if _, _, err = storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil && !errors.IsConflict(err) {
|
||||||
t.Fatalf("unexpected error, expecting an update conflict but got %v", err)
|
t.Fatalf("unexpected error, expecting an update conflict but got %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ func (s *storage) CreateController(ctx api.Context, controller *api.ReplicationC
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) UpdateController(ctx api.Context, controller *api.ReplicationController) (*api.ReplicationController, error) {
|
func (s *storage) UpdateController(ctx api.Context, controller *api.ReplicationController) (*api.ReplicationController, error) {
|
||||||
obj, _, err := s.Update(ctx, controller)
|
obj, _, err := s.Update(ctx, controller.Name, rest.DefaultUpdatedObjectInfo(controller, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package etcd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
@@ -92,6 +93,6 @@ func (r *StatusREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status subset of an object.
|
// Update alters the status subset of an object.
|
||||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,8 +116,8 @@ func (r *StatusREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status subset of an object.
|
// Update alters the status subset of an object.
|
||||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RollbackREST implements the REST endpoint for initiating the rollback of a deployment
|
// RollbackREST implements the REST endpoint for initiating the rollback of a deployment
|
||||||
@@ -205,7 +205,21 @@ func (r *ScaleREST) Get(ctx api.Context, name string) (runtime.Object, error) {
|
|||||||
return scale, nil
|
return scale, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *ScaleREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
|
deployment, err := r.registry.GetDeployment(ctx, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, errors.NewNotFound(extensions.Resource("deployments/scale"), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldScale, err := scaleFromDeployment(deployment)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
obj, err := objInfo.UpdatedObject(ctx, oldScale)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale"))
|
return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale"))
|
||||||
}
|
}
|
||||||
@@ -215,13 +229,9 @@ func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if errs := extvalidation.ValidateScale(scale); len(errs) > 0 {
|
if errs := extvalidation.ValidateScale(scale); len(errs) > 0 {
|
||||||
return nil, false, errors.NewInvalid(extensions.Kind("Scale"), scale.Name, errs)
|
return nil, false, errors.NewInvalid(extensions.Kind("Scale"), name, errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
deployment, err := r.registry.GetDeployment(ctx, scale.Name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, false, errors.NewNotFound(extensions.Resource("deployments/scale"), scale.Name)
|
|
||||||
}
|
|
||||||
deployment.Spec.Replicas = scale.Spec.Replicas
|
deployment.Spec.Replicas = scale.Spec.Replicas
|
||||||
deployment.ResourceVersion = scale.ResourceVersion
|
deployment.ResourceVersion = scale.ResourceVersion
|
||||||
deployment, err = r.registry.UpdateDeployment(ctx, deployment)
|
deployment, err = r.registry.UpdateDeployment(ctx, deployment)
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/errors"
|
"k8s.io/kubernetes/pkg/api/errors"
|
||||||
storeerr "k8s.io/kubernetes/pkg/api/errors/storage"
|
storeerr "k8s.io/kubernetes/pkg/api/errors/storage"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
@@ -233,7 +234,7 @@ func TestScaleUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, _, err := storage.Scale.Update(ctx, &update); err != nil {
|
if _, _, err := storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil {
|
||||||
t.Fatalf("error updating scale %v: %v", update, err)
|
t.Fatalf("error updating scale %v: %v", update, err)
|
||||||
}
|
}
|
||||||
obj, err := storage.Scale.Get(ctx, name)
|
obj, err := storage.Scale.Get(ctx, name)
|
||||||
@@ -248,7 +249,7 @@ func TestScaleUpdate(t *testing.T) {
|
|||||||
update.ResourceVersion = deployment.ResourceVersion
|
update.ResourceVersion = deployment.ResourceVersion
|
||||||
update.Spec.Replicas = 15
|
update.Spec.Replicas = 15
|
||||||
|
|
||||||
if _, _, err = storage.Scale.Update(ctx, &update); err != nil && !errors.IsConflict(err) {
|
if _, _, err = storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil && !errors.IsConflict(err) {
|
||||||
t.Fatalf("unexpected error, expecting an update conflict but got %v", err)
|
t.Fatalf("unexpected error, expecting an update conflict but got %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -272,7 +273,7 @@ func TestStatusUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, _, err := storage.Status.Update(ctx, &update); err != nil {
|
if _, _, err := storage.Status.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
obj, err := storage.Deployment.Get(ctx, name)
|
obj, err := storage.Deployment.Get(ctx, name)
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ func (s *storage) CreateDeployment(ctx api.Context, deployment *extensions.Deplo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) UpdateDeployment(ctx api.Context, deployment *extensions.Deployment) (*extensions.Deployment, error) {
|
func (s *storage) UpdateDeployment(ctx api.Context, deployment *extensions.Deployment) (*extensions.Deployment, error) {
|
||||||
obj, _, err := s.Update(ctx, deployment)
|
obj, _, err := s.Update(ctx, deployment.Name, rest.DefaultUpdatedObjectInfo(deployment, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ func (s *storage) GetEndpoints(ctx api.Context, name string) (*api.Endpoints, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) UpdateEndpoints(ctx api.Context, endpoints *api.Endpoints) error {
|
func (s *storage) UpdateEndpoints(ctx api.Context, endpoints *api.Endpoints) error {
|
||||||
_, _, err := s.Update(ctx, endpoints)
|
_, _, err := s.Update(ctx, endpoints.Name, rest.DefaultUpdatedObjectInfo(endpoints, api.Scheme))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,15 @@ func (r *ScaleREST) Get(ctx api.Context, name string) (runtime.Object, error) {
|
|||||||
return scaleFromRC(rc), nil
|
return scaleFromRC(rc), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *ScaleREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
|
rc, err := (*r.registry).GetController(ctx, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, errors.NewNotFound(extensions.Resource("replicationcontrollers/scale"), name)
|
||||||
|
}
|
||||||
|
oldScale := scaleFromRC(rc)
|
||||||
|
|
||||||
|
obj, err := objInfo.UpdatedObject(ctx, oldScale)
|
||||||
|
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale"))
|
return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale"))
|
||||||
}
|
}
|
||||||
@@ -83,10 +91,6 @@ func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object,
|
|||||||
return nil, false, errors.NewInvalid(extensions.Kind("Scale"), scale.Name, errs)
|
return nil, false, errors.NewInvalid(extensions.Kind("Scale"), scale.Name, errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
rc, err := (*r.registry).GetController(ctx, scale.Name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, false, errors.NewNotFound(extensions.Resource("replicationcontrollers/scale"), scale.Name)
|
|
||||||
}
|
|
||||||
rc.Spec.Replicas = scale.Spec.Replicas
|
rc.Spec.Replicas = scale.Spec.Replicas
|
||||||
rc.ResourceVersion = scale.ResourceVersion
|
rc.ResourceVersion = scale.ResourceVersion
|
||||||
rc, err = (*r.registry).UpdateController(ctx, rc)
|
rc, err = (*r.registry).UpdateController(ctx, rc)
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
"k8s.io/kubernetes/pkg/registry/generic"
|
"k8s.io/kubernetes/pkg/registry/generic"
|
||||||
@@ -116,7 +117,7 @@ func TestUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, _, err := storage.Update(ctx, &update); err != nil {
|
if _, _, err := storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
obj, err := storage.Get(ctx, "foo")
|
obj, err := storage.Get(ctx, "foo")
|
||||||
|
|||||||
@@ -238,46 +238,40 @@ func (e *Store) Create(ctx api.Context, obj runtime.Object) (runtime.Object, err
|
|||||||
// Update performs an atomic update and set of the object. Returns the result of the update
|
// Update performs an atomic update and set of the object. Returns the result of the update
|
||||||
// or an error. If the registry allows create-on-update, the create flow will be executed.
|
// or an error. If the registry allows create-on-update, the create flow will be executed.
|
||||||
// A bool is returned along with the object and any errors, to indicate object creation.
|
// A bool is returned along with the object and any errors, to indicate object creation.
|
||||||
func (e *Store) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (e *Store) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
name, err := e.ObjectNameFunc(obj)
|
|
||||||
if err != nil {
|
|
||||||
return nil, false, err
|
|
||||||
}
|
|
||||||
key, err := e.KeyFunc(ctx, name)
|
key, err := e.KeyFunc(ctx, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
// If AllowUnconditionalUpdate() is true and the object specified by the user does not have a resource version,
|
|
||||||
// then we populate it with the latest version.
|
var (
|
||||||
// Else, we check that the version specified by the user matches the version of latest storage object.
|
creatingObj runtime.Object
|
||||||
resourceVersion, err := e.Storage.Versioner().ObjectResourceVersion(obj)
|
creating = false
|
||||||
if err != nil {
|
)
|
||||||
return nil, false, err
|
|
||||||
|
storagePreconditions := &storage.Preconditions{}
|
||||||
|
if preconditions := objInfo.Preconditions(); preconditions != nil {
|
||||||
|
storagePreconditions.UID = preconditions.UID
|
||||||
}
|
}
|
||||||
doUnconditionalUpdate := resourceVersion == 0 && e.UpdateStrategy.AllowUnconditionalUpdate()
|
|
||||||
// TODO: expose TTL
|
|
||||||
creating := false
|
|
||||||
out := e.NewFunc()
|
out := e.NewFunc()
|
||||||
meta, err := api.ObjectMetaFor(obj)
|
|
||||||
if err != nil {
|
err = e.Storage.GuaranteedUpdate(ctx, key, out, true, storagePreconditions, func(existing runtime.Object, res storage.ResponseMeta) (runtime.Object, *uint64, error) {
|
||||||
return nil, false, kubeerr.NewInternalError(err)
|
// Given the existing object, get the new object
|
||||||
}
|
obj, err := objInfo.UpdatedObject(ctx, existing)
|
||||||
var preconditions *storage.Preconditions
|
|
||||||
// If the UID of the new object is specified, we use it as an Update precondition.
|
|
||||||
if len(meta.UID) != 0 {
|
|
||||||
UIDCopy := meta.UID
|
|
||||||
preconditions = &storage.Preconditions{UID: &UIDCopy}
|
|
||||||
}
|
|
||||||
err = e.Storage.GuaranteedUpdate(ctx, key, out, true, preconditions, func(existing runtime.Object, res storage.ResponseMeta) (runtime.Object, *uint64, error) {
|
|
||||||
// Since we return 'obj' from this function and it can be modified outside this
|
|
||||||
// function, we are resetting resourceVersion to the initial value here.
|
|
||||||
//
|
|
||||||
// TODO: In fact, we should probably return a DeepCopy of obj in all places.
|
|
||||||
err := e.Storage.Versioner().UpdateObject(obj, resourceVersion)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If AllowUnconditionalUpdate() is true and the object specified by the user does not have a resource version,
|
||||||
|
// then we populate it with the latest version.
|
||||||
|
// Else, we check that the version specified by the user matches the version of latest storage object.
|
||||||
|
resourceVersion, err := e.Storage.Versioner().ObjectResourceVersion(obj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
doUnconditionalUpdate := resourceVersion == 0 && e.UpdateStrategy.AllowUnconditionalUpdate()
|
||||||
|
|
||||||
version, err := e.Storage.Versioner().ObjectResourceVersion(existing)
|
version, err := e.Storage.Versioner().ObjectResourceVersion(existing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -287,6 +281,7 @@ func (e *Store) Update(ctx api.Context, obj runtime.Object) (runtime.Object, boo
|
|||||||
return nil, nil, kubeerr.NewNotFound(e.QualifiedResource, name)
|
return nil, nil, kubeerr.NewNotFound(e.QualifiedResource, name)
|
||||||
}
|
}
|
||||||
creating = true
|
creating = true
|
||||||
|
creatingObj = obj
|
||||||
if err := rest.BeforeCreate(e.CreateStrategy, ctx, obj); err != nil {
|
if err := rest.BeforeCreate(e.CreateStrategy, ctx, obj); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -298,6 +293,7 @@ func (e *Store) Update(ctx api.Context, obj runtime.Object) (runtime.Object, boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
creating = false
|
creating = false
|
||||||
|
creatingObj = nil
|
||||||
if doUnconditionalUpdate {
|
if doUnconditionalUpdate {
|
||||||
// Update the object's resource version to match the latest storage object's resource version.
|
// Update the object's resource version to match the latest storage object's resource version.
|
||||||
err = e.Storage.Versioner().UpdateObject(obj, res.ResourceVersion)
|
err = e.Storage.Versioner().UpdateObject(obj, res.ResourceVersion)
|
||||||
@@ -338,7 +334,7 @@ func (e *Store) Update(ctx api.Context, obj runtime.Object) (runtime.Object, boo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if creating {
|
if creating {
|
||||||
err = storeerr.InterpretCreateError(err, e.QualifiedResource, name)
|
err = storeerr.InterpretCreateError(err, e.QualifiedResource, name)
|
||||||
err = rest.CheckGeneratedNameError(e.CreateStrategy, err, obj)
|
err = rest.CheckGeneratedNameError(e.CreateStrategy, err, creatingObj)
|
||||||
} else {
|
} else {
|
||||||
err = storeerr.InterpretUpdateError(err, e.QualifiedResource, name)
|
err = storeerr.InterpretUpdateError(err, e.QualifiedResource, name)
|
||||||
}
|
}
|
||||||
@@ -358,7 +354,7 @@ func (e *Store) Update(ctx api.Context, obj runtime.Object) (runtime.Object, boo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if e.Decorator != nil {
|
if e.Decorator != nil {
|
||||||
if err := e.Decorator(obj); err != nil {
|
if err := e.Decorator(out); err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/errors"
|
"k8s.io/kubernetes/pkg/api/errors"
|
||||||
"k8s.io/kubernetes/pkg/api/meta"
|
"k8s.io/kubernetes/pkg/api/meta"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/api/testapi"
|
"k8s.io/kubernetes/pkg/api/testapi"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
@@ -273,7 +274,7 @@ func TestStoreCreate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateAndVerify(t *testing.T, ctx api.Context, registry *Store, pod *api.Pod) bool {
|
func updateAndVerify(t *testing.T, ctx api.Context, registry *Store, pod *api.Pod) bool {
|
||||||
obj, _, err := registry.Update(ctx, pod)
|
obj, _, err := registry.Update(ctx, pod.Name, rest.DefaultUpdatedObjectInfo(pod, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
return false
|
return false
|
||||||
@@ -309,7 +310,7 @@ func TestStoreUpdate(t *testing.T) {
|
|||||||
defer server.Terminate(t)
|
defer server.Terminate(t)
|
||||||
|
|
||||||
// Test1 try to update a non-existing node
|
// Test1 try to update a non-existing node
|
||||||
_, _, err := registry.Update(testContext, podA)
|
_, _, err := registry.Update(testContext, podA.Name, rest.DefaultUpdatedObjectInfo(podA, api.Scheme))
|
||||||
if !errors.IsNotFound(err) {
|
if !errors.IsNotFound(err) {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -322,7 +323,7 @@ func TestStoreUpdate(t *testing.T) {
|
|||||||
registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = false
|
registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = false
|
||||||
|
|
||||||
// Test3 outofDate
|
// Test3 outofDate
|
||||||
_, _, err = registry.Update(testContext, podAWithResourceVersion)
|
_, _, err = registry.Update(testContext, podAWithResourceVersion.Name, rest.DefaultUpdatedObjectInfo(podAWithResourceVersion, api.Scheme))
|
||||||
if !errors.IsConflict(err) {
|
if !errors.IsConflict(err) {
|
||||||
t.Errorf("Unexpected error updating podAWithResourceVersion: %v", err)
|
t.Errorf("Unexpected error updating podAWithResourceVersion: %v", err)
|
||||||
}
|
}
|
||||||
@@ -369,7 +370,8 @@ func TestNoOpUpdates(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var updateResult runtime.Object
|
var updateResult runtime.Object
|
||||||
if updateResult, _, err = registry.Update(api.NewDefaultContext(), newPod()); err != nil {
|
p := newPod()
|
||||||
|
if updateResult, _, err = registry.Update(api.NewDefaultContext(), p.Name, rest.DefaultUpdatedObjectInfo(p, api.Scheme)); err != nil {
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,8 +448,12 @@ func TestStoreCustomExport(t *testing.T) {
|
|||||||
if exportedPod.Labels["exact"] != "false" {
|
if exportedPod.Labels["exact"] != "false" {
|
||||||
t.Errorf("expected: exact->false, found: %s", exportedPod.Labels["exact"])
|
t.Errorf("expected: exact->false, found: %s", exportedPod.Labels["exact"])
|
||||||
}
|
}
|
||||||
|
if exportedPod.Labels["prepare_create"] != "true" {
|
||||||
|
t.Errorf("expected: prepare_create->true, found: %s", exportedPod.Labels["prepare_create"])
|
||||||
|
}
|
||||||
delete(exportedPod.Labels, "exported")
|
delete(exportedPod.Labels, "exported")
|
||||||
delete(exportedPod.Labels, "exact")
|
delete(exportedPod.Labels, "exact")
|
||||||
|
delete(exportedPod.Labels, "prepare_create")
|
||||||
exportObjectMeta(&podA.ObjectMeta, false)
|
exportObjectMeta(&podA.ObjectMeta, false)
|
||||||
podA.Spec = exportedPod.Spec
|
podA.Spec = exportedPod.Spec
|
||||||
if !reflect.DeepEqual(&podA, exportedPod) {
|
if !reflect.DeepEqual(&podA, exportedPod) {
|
||||||
@@ -483,6 +489,7 @@ func TestStoreBasicExport(t *testing.T) {
|
|||||||
if exportedPod.Labels["prepare_create"] != "true" {
|
if exportedPod.Labels["prepare_create"] != "true" {
|
||||||
t.Errorf("expected: prepare_create->true, found: %s", exportedPod.Labels["prepare_create"])
|
t.Errorf("expected: prepare_create->true, found: %s", exportedPod.Labels["prepare_create"])
|
||||||
}
|
}
|
||||||
|
delete(exportedPod.Labels, "prepare_create")
|
||||||
exportObjectMeta(&podA.ObjectMeta, false)
|
exportObjectMeta(&podA.ObjectMeta, false)
|
||||||
podA.Spec = exportedPod.Spec
|
podA.Spec = exportedPod.Spec
|
||||||
if !reflect.DeepEqual(&podA, exportedPod) {
|
if !reflect.DeepEqual(&podA, exportedPod) {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package etcd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
@@ -89,6 +90,6 @@ func (r *StatusREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status subset of an object.
|
// Update alters the status subset of an object.
|
||||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package etcd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
@@ -91,6 +92,6 @@ func (r *StatusREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status subset of an object.
|
// Update alters the status subset of an object.
|
||||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package etcd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/apis/batch"
|
"k8s.io/kubernetes/pkg/apis/batch"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
@@ -93,6 +94,6 @@ func (r *StatusREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status subset of an object.
|
// Update alters the status subset of an object.
|
||||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
apierrors "k8s.io/kubernetes/pkg/api/errors"
|
apierrors "k8s.io/kubernetes/pkg/api/errors"
|
||||||
storageerr "k8s.io/kubernetes/pkg/api/errors/storage"
|
storageerr "k8s.io/kubernetes/pkg/api/errors/storage"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
@@ -176,8 +177,8 @@ func (r *StatusREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status subset of an object.
|
// Update alters the status subset of an object.
|
||||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FinalizeREST) New() runtime.Object {
|
func (r *FinalizeREST) New() runtime.Object {
|
||||||
@@ -185,6 +186,6 @@ func (r *FinalizeREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status finalizers subset of an object.
|
// Update alters the status finalizers subset of an object.
|
||||||
func (r *FinalizeREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *FinalizeREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func (s *storage) CreateNamespace(ctx api.Context, namespace *api.Namespace) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) UpdateNamespace(ctx api.Context, namespace *api.Namespace) error {
|
func (s *storage) UpdateNamespace(ctx api.Context, namespace *api.Namespace) error {
|
||||||
_, _, err := s.Update(ctx, namespace)
|
_, _, err := s.Update(ctx, namespace.Name, rest.DefaultUpdatedObjectInfo(namespace, api.Scheme))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ func (r *StatusREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status subset of an object.
|
// Update alters the status subset of an object.
|
||||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewREST returns a RESTStorage object that will work against nodes.
|
// NewREST returns a RESTStorage object that will work against nodes.
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func (s *storage) CreateNode(ctx api.Context, node *api.Node) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) UpdateNode(ctx api.Context, node *api.Node) error {
|
func (s *storage) UpdateNode(ctx api.Context, node *api.Node) error {
|
||||||
_, _, err := s.Update(ctx, node)
|
_, _, err := s.Update(ctx, node.Name, rest.DefaultUpdatedObjectInfo(node, api.Scheme))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package etcd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/registry/cachesize"
|
"k8s.io/kubernetes/pkg/registry/cachesize"
|
||||||
@@ -81,6 +82,6 @@ func (r *StatusREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status subset of an object.
|
// Update alters the status subset of an object.
|
||||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/resource"
|
"k8s.io/kubernetes/pkg/api/resource"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/registry/generic"
|
"k8s.io/kubernetes/pkg/registry/generic"
|
||||||
@@ -167,7 +168,7 @@ func TestUpdateStatus(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = statusStorage.Update(ctx, pvIn)
|
_, _, err = statusStorage.Update(ctx, pvIn.Name, rest.DefaultUpdatedObjectInfo(pvIn, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package etcd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/registry/cachesize"
|
"k8s.io/kubernetes/pkg/registry/cachesize"
|
||||||
@@ -81,6 +82,6 @@ func (r *StatusREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status subset of an object.
|
// Update alters the status subset of an object.
|
||||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/resource"
|
"k8s.io/kubernetes/pkg/api/resource"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/registry/generic"
|
"k8s.io/kubernetes/pkg/registry/generic"
|
||||||
@@ -168,7 +169,7 @@ func TestUpdateStatus(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = statusStorage.Update(ctx, pvc)
|
_, _, err = statusStorage.Update(ctx, pvc.Name, rest.DefaultUpdatedObjectInfo(pvc, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package etcd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
appsapi "k8s.io/kubernetes/pkg/apis/apps"
|
appsapi "k8s.io/kubernetes/pkg/apis/apps"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
@@ -91,6 +92,6 @@ func (r *StatusREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status subset of an object.
|
// Update alters the status subset of an object.
|
||||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/apis/apps"
|
"k8s.io/kubernetes/pkg/apis/apps"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
@@ -114,7 +115,7 @@ func TestStatusUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, _, err := statusStorage.Update(ctx, &update); err != nil {
|
if _, _, err := statusStorage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
obj, err := storage.Get(ctx, "foo")
|
obj, err := storage.Get(ctx, "foo")
|
||||||
|
|||||||
@@ -199,6 +199,6 @@ func (r *StatusREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status subset of an object.
|
// Update alters the status subset of an object.
|
||||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -608,7 +608,7 @@ func TestEtcdUpdateNotScheduled(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
podIn := validChangedPod()
|
podIn := validChangedPod()
|
||||||
_, _, err := storage.Update(ctx, podIn)
|
_, _, err := storage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(podIn, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -675,7 +675,7 @@ func TestEtcdUpdateScheduled(t *testing.T) {
|
|||||||
SecurityContext: &api.PodSecurityContext{},
|
SecurityContext: &api.PodSecurityContext{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, _, err = storage.Update(ctx, &podIn)
|
_, _, err = storage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(&podIn, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -756,7 +756,7 @@ func TestEtcdUpdateStatus(t *testing.T) {
|
|||||||
expected.Labels = podIn.Labels
|
expected.Labels = podIn.Labels
|
||||||
expected.Status = podIn.Status
|
expected.Status = podIn.Status
|
||||||
|
|
||||||
_, _, err = statusStorage.Update(ctx, &podIn)
|
_, _, err = statusStorage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(&podIn, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -765,10 +765,10 @@ func TestEtcdUpdateStatus(t *testing.T) {
|
|||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
podOut := obj.(*api.Pod)
|
podOut := obj.(*api.Pod)
|
||||||
// Check to verify the Spec, Label, and Status updates match from change above. Those are the fields changed.
|
// Check to verify the Label, and Status updates match from change above. Those are the fields changed.
|
||||||
if !api.Semantic.DeepEqual(podOut.Spec, podIn.Spec) ||
|
if !api.Semantic.DeepEqual(podOut.Spec, expected.Spec) ||
|
||||||
!api.Semantic.DeepEqual(podOut.Labels, podIn.Labels) ||
|
!api.Semantic.DeepEqual(podOut.Labels, expected.Labels) ||
|
||||||
!api.Semantic.DeepEqual(podOut.Status, podIn.Status) {
|
!api.Semantic.DeepEqual(podOut.Status, expected.Status) {
|
||||||
t.Errorf("objects differ: %v", diff.ObjectDiff(podOut, podIn))
|
t.Errorf("objects differ: %v", diff.ObjectDiff(podOut, expected))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package etcd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
policyapi "k8s.io/kubernetes/pkg/apis/policy"
|
policyapi "k8s.io/kubernetes/pkg/apis/policy"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
@@ -91,6 +92,6 @@ func (r *StatusREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status subset of an object.
|
// Update alters the status subset of an object.
|
||||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/apis/policy"
|
"k8s.io/kubernetes/pkg/apis/policy"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
@@ -99,7 +100,7 @@ func TestStatusUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, _, err := statusStorage.Update(ctx, &update); err != nil {
|
if _, _, err := statusStorage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
obj, err := storage.Get(ctx, "foo")
|
obj, err := storage.Get(ctx, "foo")
|
||||||
|
|||||||
@@ -116,8 +116,8 @@ func (r *StatusREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status subset of an object.
|
// Update alters the status subset of an object.
|
||||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScaleREST struct {
|
type ScaleREST struct {
|
||||||
@@ -144,7 +144,21 @@ func (r *ScaleREST) Get(ctx api.Context, name string) (runtime.Object, error) {
|
|||||||
return scale, err
|
return scale, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *ScaleREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
|
rs, err := r.registry.GetReplicaSet(ctx, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, errors.NewNotFound(extensions.Resource("replicasets/scale"), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldScale, err := scaleFromReplicaSet(rs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
obj, err := objInfo.UpdatedObject(ctx, oldScale)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale"))
|
return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale"))
|
||||||
}
|
}
|
||||||
@@ -157,10 +171,6 @@ func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object,
|
|||||||
return nil, false, errors.NewInvalid(extensions.Kind("Scale"), scale.Name, errs)
|
return nil, false, errors.NewInvalid(extensions.Kind("Scale"), scale.Name, errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
rs, err := r.registry.GetReplicaSet(ctx, scale.Name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, false, errors.NewNotFound(extensions.Resource("replicasets/scale"), scale.Name)
|
|
||||||
}
|
|
||||||
rs.Spec.Replicas = scale.Spec.Replicas
|
rs.Spec.Replicas = scale.Spec.Replicas
|
||||||
rs.ResourceVersion = scale.ResourceVersion
|
rs.ResourceVersion = scale.ResourceVersion
|
||||||
rs, err = r.registry.UpdateReplicaSet(ctx, rs)
|
rs, err = r.registry.UpdateReplicaSet(ctx, rs)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/errors"
|
"k8s.io/kubernetes/pkg/api/errors"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
@@ -162,7 +163,7 @@ func TestGenerationNumber(t *testing.T) {
|
|||||||
|
|
||||||
// Updates to spec should increment the generation number
|
// Updates to spec should increment the generation number
|
||||||
storedRS.Spec.Replicas += 1
|
storedRS.Spec.Replicas += 1
|
||||||
storage.ReplicaSet.Update(ctx, storedRS)
|
storage.ReplicaSet.Update(ctx, storedRS.Name, rest.DefaultUpdatedObjectInfo(storedRS, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -177,7 +178,7 @@ func TestGenerationNumber(t *testing.T) {
|
|||||||
|
|
||||||
// Updates to status should not increment either spec or status generation numbers
|
// Updates to status should not increment either spec or status generation numbers
|
||||||
storedRS.Status.Replicas += 1
|
storedRS.Status.Replicas += 1
|
||||||
storage.ReplicaSet.Update(ctx, storedRS)
|
storage.ReplicaSet.Update(ctx, storedRS.Name, rest.DefaultUpdatedObjectInfo(storedRS, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -299,7 +300,7 @@ func TestScaleUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, _, err := storage.Scale.Update(ctx, &update); err != nil {
|
if _, _, err := storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil {
|
||||||
t.Fatalf("error updating scale %v: %v", update, err)
|
t.Fatalf("error updating scale %v: %v", update, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,7 +316,7 @@ func TestScaleUpdate(t *testing.T) {
|
|||||||
update.ResourceVersion = rs.ResourceVersion
|
update.ResourceVersion = rs.ResourceVersion
|
||||||
update.Spec.Replicas = 15
|
update.Spec.Replicas = 15
|
||||||
|
|
||||||
if _, _, err = storage.Scale.Update(ctx, &update); err != nil && !errors.IsConflict(err) {
|
if _, _, err = storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil && !errors.IsConflict(err) {
|
||||||
t.Fatalf("unexpected error, expecting an update conflict but got %v", err)
|
t.Fatalf("unexpected error, expecting an update conflict but got %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -339,7 +340,7 @@ func TestStatusUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, _, err := storage.Status.Update(ctx, &update); err != nil {
|
if _, _, err := storage.Status.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
obj, err := storage.ReplicaSet.Get(ctx, "foo")
|
obj, err := storage.ReplicaSet.Get(ctx, "foo")
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ func (s *storage) CreateReplicaSet(ctx api.Context, replicaSet *extensions.Repli
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) UpdateReplicaSet(ctx api.Context, replicaSet *extensions.ReplicaSet) (*extensions.ReplicaSet, error) {
|
func (s *storage) UpdateReplicaSet(ctx api.Context, replicaSet *extensions.ReplicaSet) (*extensions.ReplicaSet, error) {
|
||||||
obj, _, err := s.Update(ctx, replicaSet)
|
obj, _, err := s.Update(ctx, replicaSet.Name, rest.DefaultUpdatedObjectInfo(replicaSet, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package etcd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/registry/cachesize"
|
"k8s.io/kubernetes/pkg/registry/cachesize"
|
||||||
@@ -81,6 +82,6 @@ func (r *StatusREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status subset of an object.
|
// Update alters the status subset of an object.
|
||||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/resource"
|
"k8s.io/kubernetes/pkg/api/resource"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/registry/generic"
|
"k8s.io/kubernetes/pkg/registry/generic"
|
||||||
@@ -177,7 +178,7 @@ func TestUpdateStatus(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = status.Update(ctx, resourcequotaIn)
|
_, _, err = status.Update(ctx, resourcequotaIn.Name, rest.DefaultUpdatedObjectInfo(resourcequotaIn, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func (s *storage) CreateSecret(ctx api.Context, secret *api.Secret) (*api.Secret
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) UpdateSecret(ctx api.Context, secret *api.Secret) (*api.Secret, error) {
|
func (s *storage) UpdateSecret(ctx api.Context, secret *api.Secret) (*api.Secret, error) {
|
||||||
obj, _, err := s.Update(ctx, secret)
|
obj, _, err := s.Update(ctx, secret.Name, rest.DefaultUpdatedObjectInfo(secret, api.Scheme))
|
||||||
return obj.(*api.Secret), err
|
return obj.(*api.Secret), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package etcd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/registry/cachesize"
|
"k8s.io/kubernetes/pkg/registry/cachesize"
|
||||||
@@ -79,6 +80,6 @@ func (r *StatusREST) New() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update alters the status subset of an object.
|
// Update alters the status subset of an object.
|
||||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
return r.store.Update(ctx, obj)
|
return r.store.Update(ctx, name, objInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ func (s *storage) DeleteService(ctx api.Context, name string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) UpdateService(ctx api.Context, svc *api.Service) (*api.Service, error) {
|
func (s *storage) UpdateService(ctx api.Context, svc *api.Service) (*api.Service, error) {
|
||||||
obj, _, err := s.Update(ctx, svc)
|
obj, _, err := s.Update(ctx, svc.Name, rest.DefaultUpdatedObjectInfo(svc, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -212,17 +212,22 @@ func (*REST) NewList() runtime.Object {
|
|||||||
return &api.ServiceList{}
|
return &api.ServiceList{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
func (rs *REST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
||||||
|
oldService, err := rs.registry.GetService(ctx, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
obj, err := objInfo.UpdatedObject(ctx, oldService)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
service := obj.(*api.Service)
|
service := obj.(*api.Service)
|
||||||
if !api.ValidNamespace(ctx, &service.ObjectMeta) {
|
if !api.ValidNamespace(ctx, &service.ObjectMeta) {
|
||||||
return nil, false, errors.NewConflict(api.Resource("services"), service.Namespace, fmt.Errorf("Service.Namespace does not match the provided context"))
|
return nil, false, errors.NewConflict(api.Resource("services"), service.Namespace, fmt.Errorf("Service.Namespace does not match the provided context"))
|
||||||
}
|
}
|
||||||
|
|
||||||
oldService, err := rs.registry.GetService(ctx, service.Name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy over non-user fields
|
// Copy over non-user fields
|
||||||
// TODO: make this a merge function
|
// TODO: make this a merge function
|
||||||
if errs := validation.ValidateServiceUpdate(service, oldService); len(errs) > 0 {
|
if errs := validation.ValidateServiceUpdate(service, oldService); len(errs) > 0 {
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ func TestServiceRegistryUpdate(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Expected no error: %v", err)
|
t.Fatalf("Expected no error: %v", err)
|
||||||
}
|
}
|
||||||
updated_svc, created, err := storage.Update(ctx, &api.Service{
|
updated_svc, created, err := storage.Update(ctx, "foo", rest.DefaultUpdatedObjectInfo(&api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
ResourceVersion: svc.ResourceVersion},
|
ResourceVersion: svc.ResourceVersion},
|
||||||
@@ -194,7 +194,7 @@ func TestServiceRegistryUpdate(t *testing.T) {
|
|||||||
TargetPort: intstr.FromInt(6502),
|
TargetPort: intstr.FromInt(6502),
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
})
|
}, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Expected no error: %v", err)
|
t.Fatalf("Expected no error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -255,7 +255,7 @@ func TestServiceStorageValidatesUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, failureCase := range failureCases {
|
for _, failureCase := range failureCases {
|
||||||
c, created, err := storage.Update(ctx, &failureCase)
|
c, created, err := storage.Update(ctx, failureCase.Name, rest.DefaultUpdatedObjectInfo(&failureCase, api.Scheme))
|
||||||
if c != nil || created {
|
if c != nil || created {
|
||||||
t.Errorf("Expected nil object or created false")
|
t.Errorf("Expected nil object or created false")
|
||||||
}
|
}
|
||||||
@@ -363,14 +363,14 @@ func TestServiceRegistryUpdateExternalService(t *testing.T) {
|
|||||||
// Modify load balancer to be external.
|
// Modify load balancer to be external.
|
||||||
svc2 := deepCloneService(svc1)
|
svc2 := deepCloneService(svc1)
|
||||||
svc2.Spec.Type = api.ServiceTypeLoadBalancer
|
svc2.Spec.Type = api.ServiceTypeLoadBalancer
|
||||||
if _, _, err := storage.Update(ctx, svc2); err != nil {
|
if _, _, err := storage.Update(ctx, svc2.Name, rest.DefaultUpdatedObjectInfo(svc2, api.Scheme)); err != nil {
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change port.
|
// Change port.
|
||||||
svc3 := deepCloneService(svc2)
|
svc3 := deepCloneService(svc2)
|
||||||
svc3.Spec.Ports[0].Port = 6504
|
svc3.Spec.Ports[0].Port = 6504
|
||||||
if _, _, err := storage.Update(ctx, svc3); err != nil {
|
if _, _, err := storage.Update(ctx, svc3.Name, rest.DefaultUpdatedObjectInfo(svc3, api.Scheme)); err != nil {
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -406,7 +406,7 @@ func TestServiceRegistryUpdateMultiPortExternalService(t *testing.T) {
|
|||||||
// Modify ports
|
// Modify ports
|
||||||
svc2 := deepCloneService(svc1)
|
svc2 := deepCloneService(svc1)
|
||||||
svc2.Spec.Ports[1].Port = 8088
|
svc2.Spec.Ports[1].Port = 8088
|
||||||
if _, _, err := storage.Update(ctx, svc2); err != nil {
|
if _, _, err := storage.Update(ctx, svc2.Name, rest.DefaultUpdatedObjectInfo(svc2, api.Scheme)); err != nil {
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -580,7 +580,7 @@ func TestServiceRegistryList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestServiceRegistryIPAllocation(t *testing.T) {
|
func TestServiceRegistryIPAllocation(t *testing.T) {
|
||||||
rest, _ := NewTestREST(t, nil)
|
storage, _ := NewTestREST(t, nil)
|
||||||
|
|
||||||
svc1 := &api.Service{
|
svc1 := &api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
@@ -596,7 +596,7 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
created_svc1, _ := rest.Create(ctx, svc1)
|
created_svc1, _ := storage.Create(ctx, svc1)
|
||||||
created_service_1 := created_svc1.(*api.Service)
|
created_service_1 := created_svc1.(*api.Service)
|
||||||
if created_service_1.Name != "foo" {
|
if created_service_1.Name != "foo" {
|
||||||
t.Errorf("Expected foo, but got %v", created_service_1.Name)
|
t.Errorf("Expected foo, but got %v", created_service_1.Name)
|
||||||
@@ -618,7 +618,7 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
}}
|
}}
|
||||||
ctx = api.NewDefaultContext()
|
ctx = api.NewDefaultContext()
|
||||||
created_svc2, _ := rest.Create(ctx, svc2)
|
created_svc2, _ := storage.Create(ctx, svc2)
|
||||||
created_service_2 := created_svc2.(*api.Service)
|
created_service_2 := created_svc2.(*api.Service)
|
||||||
if created_service_2.Name != "bar" {
|
if created_service_2.Name != "bar" {
|
||||||
t.Errorf("Expected bar, but got %v", created_service_2.Name)
|
t.Errorf("Expected bar, but got %v", created_service_2.Name)
|
||||||
@@ -630,7 +630,7 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
|
|||||||
testIPs := []string{"1.2.3.93", "1.2.3.94", "1.2.3.95", "1.2.3.96"}
|
testIPs := []string{"1.2.3.93", "1.2.3.94", "1.2.3.95", "1.2.3.96"}
|
||||||
testIP := ""
|
testIP := ""
|
||||||
for _, ip := range testIPs {
|
for _, ip := range testIPs {
|
||||||
if !rest.serviceIPs.(*ipallocator.Range).Has(net.ParseIP(ip)) {
|
if !storage.serviceIPs.(*ipallocator.Range).Has(net.ParseIP(ip)) {
|
||||||
testIP = ip
|
testIP = ip
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -651,7 +651,7 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
ctx = api.NewDefaultContext()
|
ctx = api.NewDefaultContext()
|
||||||
created_svc3, err := rest.Create(ctx, svc3)
|
created_svc3, err := storage.Create(ctx, svc3)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -662,7 +662,7 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestServiceRegistryIPReallocation(t *testing.T) {
|
func TestServiceRegistryIPReallocation(t *testing.T) {
|
||||||
rest, _ := NewTestREST(t, nil)
|
storage, _ := NewTestREST(t, nil)
|
||||||
|
|
||||||
svc1 := &api.Service{
|
svc1 := &api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
@@ -678,7 +678,7 @@ func TestServiceRegistryIPReallocation(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
created_svc1, _ := rest.Create(ctx, svc1)
|
created_svc1, _ := storage.Create(ctx, svc1)
|
||||||
created_service_1 := created_svc1.(*api.Service)
|
created_service_1 := created_svc1.(*api.Service)
|
||||||
if created_service_1.Name != "foo" {
|
if created_service_1.Name != "foo" {
|
||||||
t.Errorf("Expected foo, but got %v", created_service_1.Name)
|
t.Errorf("Expected foo, but got %v", created_service_1.Name)
|
||||||
@@ -687,7 +687,7 @@ func TestServiceRegistryIPReallocation(t *testing.T) {
|
|||||||
t.Errorf("Unexpected ClusterIP: %s", created_service_1.Spec.ClusterIP)
|
t.Errorf("Unexpected ClusterIP: %s", created_service_1.Spec.ClusterIP)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := rest.Delete(ctx, created_service_1.Name)
|
_, err := storage.Delete(ctx, created_service_1.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error deleting service: %v", err)
|
t.Errorf("Unexpected error deleting service: %v", err)
|
||||||
}
|
}
|
||||||
@@ -706,7 +706,7 @@ func TestServiceRegistryIPReallocation(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
ctx = api.NewDefaultContext()
|
ctx = api.NewDefaultContext()
|
||||||
created_svc2, _ := rest.Create(ctx, svc2)
|
created_svc2, _ := storage.Create(ctx, svc2)
|
||||||
created_service_2 := created_svc2.(*api.Service)
|
created_service_2 := created_svc2.(*api.Service)
|
||||||
if created_service_2.Name != "bar" {
|
if created_service_2.Name != "bar" {
|
||||||
t.Errorf("Expected bar, but got %v", created_service_2.Name)
|
t.Errorf("Expected bar, but got %v", created_service_2.Name)
|
||||||
@@ -717,7 +717,7 @@ func TestServiceRegistryIPReallocation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestServiceRegistryIPUpdate(t *testing.T) {
|
func TestServiceRegistryIPUpdate(t *testing.T) {
|
||||||
rest, _ := NewTestREST(t, nil)
|
storage, _ := NewTestREST(t, nil)
|
||||||
|
|
||||||
svc := &api.Service{
|
svc := &api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
|
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
|
||||||
@@ -733,7 +733,7 @@ func TestServiceRegistryIPUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
created_svc, _ := rest.Create(ctx, svc)
|
created_svc, _ := storage.Create(ctx, svc)
|
||||||
created_service := created_svc.(*api.Service)
|
created_service := created_svc.(*api.Service)
|
||||||
if created_service.Spec.Ports[0].Port != 6502 {
|
if created_service.Spec.Ports[0].Port != 6502 {
|
||||||
t.Errorf("Expected port 6502, but got %v", created_service.Spec.Ports[0].Port)
|
t.Errorf("Expected port 6502, but got %v", created_service.Spec.Ports[0].Port)
|
||||||
@@ -745,7 +745,7 @@ func TestServiceRegistryIPUpdate(t *testing.T) {
|
|||||||
update := deepCloneService(created_service)
|
update := deepCloneService(created_service)
|
||||||
update.Spec.Ports[0].Port = 6503
|
update.Spec.Ports[0].Port = 6503
|
||||||
|
|
||||||
updated_svc, _, _ := rest.Update(ctx, update)
|
updated_svc, _, _ := storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(update, api.Scheme))
|
||||||
updated_service := updated_svc.(*api.Service)
|
updated_service := updated_svc.(*api.Service)
|
||||||
if updated_service.Spec.Ports[0].Port != 6503 {
|
if updated_service.Spec.Ports[0].Port != 6503 {
|
||||||
t.Errorf("Expected port 6503, but got %v", updated_service.Spec.Ports[0].Port)
|
t.Errorf("Expected port 6503, but got %v", updated_service.Spec.Ports[0].Port)
|
||||||
@@ -754,7 +754,7 @@ func TestServiceRegistryIPUpdate(t *testing.T) {
|
|||||||
testIPs := []string{"1.2.3.93", "1.2.3.94", "1.2.3.95", "1.2.3.96"}
|
testIPs := []string{"1.2.3.93", "1.2.3.94", "1.2.3.95", "1.2.3.96"}
|
||||||
testIP := ""
|
testIP := ""
|
||||||
for _, ip := range testIPs {
|
for _, ip := range testIPs {
|
||||||
if !rest.serviceIPs.(*ipallocator.Range).Has(net.ParseIP(ip)) {
|
if !storage.serviceIPs.(*ipallocator.Range).Has(net.ParseIP(ip)) {
|
||||||
testIP = ip
|
testIP = ip
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -764,14 +764,14 @@ func TestServiceRegistryIPUpdate(t *testing.T) {
|
|||||||
update.Spec.Ports[0].Port = 6503
|
update.Spec.Ports[0].Port = 6503
|
||||||
update.Spec.ClusterIP = testIP // Error: Cluster IP is immutable
|
update.Spec.ClusterIP = testIP // Error: Cluster IP is immutable
|
||||||
|
|
||||||
_, _, err := rest.Update(ctx, update)
|
_, _, err := storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(update, api.Scheme))
|
||||||
if err == nil || !errors.IsInvalid(err) {
|
if err == nil || !errors.IsInvalid(err) {
|
||||||
t.Errorf("Unexpected error type: %v", err)
|
t.Errorf("Unexpected error type: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServiceRegistryIPLoadBalancer(t *testing.T) {
|
func TestServiceRegistryIPLoadBalancer(t *testing.T) {
|
||||||
rest, _ := NewTestREST(t, nil)
|
storage, _ := NewTestREST(t, nil)
|
||||||
|
|
||||||
svc := &api.Service{
|
svc := &api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
|
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
|
||||||
@@ -787,7 +787,7 @@ func TestServiceRegistryIPLoadBalancer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
created_svc, _ := rest.Create(ctx, svc)
|
created_svc, _ := storage.Create(ctx, svc)
|
||||||
created_service := created_svc.(*api.Service)
|
created_service := created_svc.(*api.Service)
|
||||||
if created_service.Spec.Ports[0].Port != 6502 {
|
if created_service.Spec.Ports[0].Port != 6502 {
|
||||||
t.Errorf("Expected port 6502, but got %v", created_service.Spec.Ports[0].Port)
|
t.Errorf("Expected port 6502, but got %v", created_service.Spec.Ports[0].Port)
|
||||||
@@ -798,20 +798,20 @@ func TestServiceRegistryIPLoadBalancer(t *testing.T) {
|
|||||||
|
|
||||||
update := deepCloneService(created_service)
|
update := deepCloneService(created_service)
|
||||||
|
|
||||||
_, _, err := rest.Update(ctx, update)
|
_, _, err := storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(update, api.Scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error %v", err)
|
t.Errorf("Unexpected error %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateServiceWithConflictingNamespace(t *testing.T) {
|
func TestUpdateServiceWithConflictingNamespace(t *testing.T) {
|
||||||
storage := REST{}
|
storage, _ := NewTestREST(t, nil)
|
||||||
service := &api.Service{
|
service := &api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "test", Namespace: "not-default"},
|
ObjectMeta: api.ObjectMeta{Name: "test", Namespace: "not-default"},
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := api.NewDefaultContext()
|
ctx := api.NewDefaultContext()
|
||||||
obj, created, err := storage.Update(ctx, service)
|
obj, created, err := storage.Update(ctx, service.Name, rest.DefaultUpdatedObjectInfo(service, api.Scheme))
|
||||||
if obj != nil || created {
|
if obj != nil || created {
|
||||||
t.Error("Expected a nil object, but we got a value or created was true")
|
t.Error("Expected a nil object, but we got a value or created was true")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func (s *storage) CreateServiceAccount(ctx api.Context, serviceAccount *api.Serv
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) UpdateServiceAccount(ctx api.Context, serviceAccount *api.ServiceAccount) error {
|
func (s *storage) UpdateServiceAccount(ctx api.Context, serviceAccount *api.ServiceAccount) error {
|
||||||
_, _, err := s.Update(ctx, serviceAccount)
|
_, _, err := s.Update(ctx, serviceAccount.Name, rest.DefaultUpdatedObjectInfo(serviceAccount, api.Scheme))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ func (s *storage) CreateThirdPartyResourceData(ctx api.Context, ThirdPartyResour
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) UpdateThirdPartyResourceData(ctx api.Context, ThirdPartyResourceData *extensions.ThirdPartyResourceData) (*extensions.ThirdPartyResourceData, error) {
|
func (s *storage) UpdateThirdPartyResourceData(ctx api.Context, ThirdPartyResourceData *extensions.ThirdPartyResourceData) (*extensions.ThirdPartyResourceData, error) {
|
||||||
obj, _, err := s.Update(ctx, ThirdPartyResourceData)
|
obj, _, err := s.Update(ctx, ThirdPartyResourceData.Name, rest.DefaultUpdatedObjectInfo(ThirdPartyResourceData, api.Scheme))
|
||||||
return obj.(*extensions.ThirdPartyResourceData), err
|
return obj.(*extensions.ThirdPartyResourceData), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ func TestAdmission(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := handler.Admit(admission.NewAttributesRecord(&pod, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err := handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler")
|
t.Errorf("Unexpected error returned from admission handler")
|
||||||
}
|
}
|
||||||
@@ -108,7 +108,7 @@ func TestOtherResources(t *testing.T) {
|
|||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
handler := &alwaysPullImages{}
|
handler := &alwaysPullImages{}
|
||||||
|
|
||||||
err := handler.Admit(admission.NewAttributesRecord(tc.object, api.Kind(tc.kind).WithVersion("version"), namespace, name, api.Resource(tc.resource).WithVersion("version"), tc.subresource, admission.Create, nil))
|
err := handler.Admit(admission.NewAttributesRecord(tc.object, nil, api.Kind(tc.kind).WithVersion("version"), namespace, name, api.Resource(tc.resource).WithVersion("version"), tc.subresource, admission.Create, nil))
|
||||||
|
|
||||||
if tc.expectError {
|
if tc.expectError {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|||||||
@@ -17,10 +17,11 @@ limitations under the License.
|
|||||||
package antiaffinity
|
package antiaffinity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/admission"
|
"k8s.io/kubernetes/pkg/admission"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ensures the hard PodAntiAffinity is denied if it defines TopologyKey other than kubernetes.io/hostname.
|
// ensures the hard PodAntiAffinity is denied if it defines TopologyKey other than kubernetes.io/hostname.
|
||||||
@@ -202,7 +203,7 @@ func TestInterPodAffinityAdmission(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
pod.ObjectMeta.Annotations = test.affinity
|
pod.ObjectMeta.Annotations = test.affinity
|
||||||
err := handler.Admit(admission.NewAttributesRecord(&pod, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil))
|
err := handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil))
|
||||||
|
|
||||||
if test.errorExpected && err == nil {
|
if test.errorExpected && err == nil {
|
||||||
t.Errorf("Expected error for Anti Affinity %+v but did not get an error", test.affinity)
|
t.Errorf("Expected error for Anti Affinity %+v but did not get an error", test.affinity)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import (
|
|||||||
|
|
||||||
func TestAdmission(t *testing.T) {
|
func TestAdmission(t *testing.T) {
|
||||||
handler := NewAlwaysDeny()
|
handler := NewAlwaysDeny()
|
||||||
err := handler.Admit(admission.NewAttributesRecord(nil, api.Kind("kind").WithVersion("version"), "namespace", "name", api.Resource("resource").WithVersion("version"), "subresource", admission.Create, nil))
|
err := handler.Admit(admission.NewAttributesRecord(nil, nil, api.Kind("kind").WithVersion("version"), "namespace", "name", api.Resource("resource").WithVersion("version"), "subresource", admission.Create, nil))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected error returned from admission handler")
|
t.Errorf("Expected error returned from admission handler")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ func testAdmission(t *testing.T, pod *api.Pod, handler *denyExec, shouldAccept b
|
|||||||
// pods/exec
|
// pods/exec
|
||||||
{
|
{
|
||||||
req := &rest.ConnectRequest{Name: pod.Name, ResourcePath: "pods/exec"}
|
req := &rest.ConnectRequest{Name: pod.Name, ResourcePath: "pods/exec"}
|
||||||
err := handler.Admit(admission.NewAttributesRecord(req, api.Kind("Pod").WithVersion("version"), "test", "name", api.Resource("pods").WithVersion("version"), "exec", admission.Connect, nil))
|
err := handler.Admit(admission.NewAttributesRecord(req, nil, api.Kind("Pod").WithVersion("version"), "test", "name", api.Resource("pods").WithVersion("version"), "exec", admission.Connect, nil))
|
||||||
if shouldAccept && err != nil {
|
if shouldAccept && err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
||||||
}
|
}
|
||||||
@@ -137,7 +137,7 @@ func testAdmission(t *testing.T, pod *api.Pod, handler *denyExec, shouldAccept b
|
|||||||
// pods/attach
|
// pods/attach
|
||||||
{
|
{
|
||||||
req := &rest.ConnectRequest{Name: pod.Name, ResourcePath: "pods/attach"}
|
req := &rest.ConnectRequest{Name: pod.Name, ResourcePath: "pods/attach"}
|
||||||
err := handler.Admit(admission.NewAttributesRecord(req, api.Kind("Pod").WithVersion("version"), "test", "name", api.Resource("pods").WithVersion("version"), "attach", admission.Connect, nil))
|
err := handler.Admit(admission.NewAttributesRecord(req, nil, api.Kind("Pod").WithVersion("version"), "test", "name", api.Resource("pods").WithVersion("version"), "attach", admission.Connect, nil))
|
||||||
if shouldAccept && err != nil {
|
if shouldAccept && err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ func expectNoAnnotation(t *testing.T, pod *api.Pod) {
|
|||||||
func admit(t *testing.T, ir admission.Interface, pods []*api.Pod) {
|
func admit(t *testing.T, ir admission.Interface, pods []*api.Pod) {
|
||||||
for i := range pods {
|
for i := range pods {
|
||||||
p := pods[i]
|
p := pods[i]
|
||||||
if err := ir.Admit(admission.NewAttributesRecord(p, api.Kind("Pod").WithVersion("version"), "test", p.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)); err != nil {
|
if err := ir.Admit(admission.NewAttributesRecord(p, nil, api.Kind("Pod").WithVersion("version"), "test", p.ObjectMeta.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil)); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -527,12 +527,12 @@ func TestLimitRangerIgnoresSubresource(t *testing.T) {
|
|||||||
testPod := validPod("testPod", 1, api.ResourceRequirements{})
|
testPod := validPod("testPod", 1, api.ResourceRequirements{})
|
||||||
|
|
||||||
indexer.Add(&limitRange)
|
indexer.Add(&limitRange)
|
||||||
err := handler.Admit(admission.NewAttributesRecord(&testPod, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, nil))
|
err := handler.Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, nil))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected an error since the pod did not specify resource limits in its update call")
|
t.Errorf("Expected an error since the pod did not specify resource limits in its update call")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&testPod, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Should have ignored calls to any subresource of pod %v", err)
|
t.Errorf("Should have ignored calls to any subresource of pod %v", err)
|
||||||
}
|
}
|
||||||
@@ -561,12 +561,12 @@ func TestLimitRangerCacheMisses(t *testing.T) {
|
|||||||
// add to the lru cache
|
// add to the lru cache
|
||||||
liveLookupCache.Add(limitRange.Namespace, liveLookupEntry{expiry: time.Now().Add(time.Duration(30 * time.Second)), items: []*api.LimitRange{&limitRange}})
|
liveLookupCache.Add(limitRange.Namespace, liveLookupEntry{expiry: time.Now().Add(time.Duration(30 * time.Second)), items: []*api.LimitRange{&limitRange}})
|
||||||
|
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&testPod, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, nil))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected an error since the pod did not specify resource limits in its update call")
|
t.Errorf("Expected an error since the pod did not specify resource limits in its update call")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&testPod, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Should have ignored calls to any subresource of pod %v", err)
|
t.Errorf("Should have ignored calls to any subresource of pod %v", err)
|
||||||
}
|
}
|
||||||
@@ -591,12 +591,12 @@ func TestLimitRangerCacheAndLRUMisses(t *testing.T) {
|
|||||||
|
|
||||||
testPod := validPod("testPod", 1, api.ResourceRequirements{})
|
testPod := validPod("testPod", 1, api.ResourceRequirements{})
|
||||||
|
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&testPod, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, nil))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected an error since the pod did not specify resource limits in its update call")
|
t.Errorf("Expected an error since the pod did not specify resource limits in its update call")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&testPod, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Should have ignored calls to any subresource of pod %v", err)
|
t.Errorf("Should have ignored calls to any subresource of pod %v", err)
|
||||||
}
|
}
|
||||||
@@ -624,12 +624,12 @@ func TestLimitRangerCacheAndLRUExpiredMisses(t *testing.T) {
|
|||||||
// add to the lru cache
|
// add to the lru cache
|
||||||
liveLookupCache.Add(limitRange.Namespace, liveLookupEntry{expiry: time.Now().Add(time.Duration(-30 * time.Second)), items: []*api.LimitRange{}})
|
liveLookupCache.Add(limitRange.Namespace, liveLookupEntry{expiry: time.Now().Add(time.Duration(-30 * time.Second)), items: []*api.LimitRange{}})
|
||||||
|
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&testPod, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, nil))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected an error since the pod did not specify resource limits in its update call")
|
t.Errorf("Expected an error since the pod did not specify resource limits in its update call")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&testPod, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Should have ignored calls to any subresource of pod %v", err)
|
t.Errorf("Should have ignored calls to any subresource of pod %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func TestAdmission(t *testing.T) {
|
|||||||
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := handler.Admit(admission.NewAttributesRecord(&pod, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err := handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler")
|
t.Errorf("Unexpected error returned from admission handler")
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@ func TestAdmissionNamespaceExists(t *testing.T) {
|
|||||||
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := handler.Admit(admission.NewAttributesRecord(&pod, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err := handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler")
|
t.Errorf("Unexpected error returned from admission handler")
|
||||||
}
|
}
|
||||||
@@ -96,7 +96,7 @@ func TestIgnoreAdmission(t *testing.T) {
|
|||||||
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := handler.Admit(admission.NewAttributesRecord(&pod, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, nil))
|
err := handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler")
|
t.Errorf("Unexpected error returned from admission handler")
|
||||||
}
|
}
|
||||||
@@ -125,7 +125,7 @@ func TestAdmissionNamespaceExistsUnknownToHandler(t *testing.T) {
|
|||||||
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := handler.Admit(admission.NewAttributesRecord(&pod, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err := handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler")
|
t.Errorf("Unexpected error returned from admission handler")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ func TestAdmission(t *testing.T) {
|
|||||||
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
Containers: []api.Container{{Name: "ctr", Image: "image"}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := handler.Admit(admission.NewAttributesRecord(&pod, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err := handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
||||||
}
|
}
|
||||||
@@ -90,47 +90,47 @@ func TestAdmission(t *testing.T) {
|
|||||||
store.Add(namespaceObj)
|
store.Add(namespaceObj)
|
||||||
|
|
||||||
// verify create operations in the namespace cause an error
|
// verify create operations in the namespace cause an error
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&pod, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected error rejecting creates in a namespace when it is terminating")
|
t.Errorf("Expected error rejecting creates in a namespace when it is terminating")
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify update operations in the namespace can proceed
|
// verify update operations in the namespace can proceed
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&pod, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify delete operations in the namespace can proceed
|
// verify delete operations in the namespace can proceed
|
||||||
err = handler.Admit(admission.NewAttributesRecord(nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Delete, nil))
|
err = handler.Admit(admission.NewAttributesRecord(nil, nil, api.Kind("Pod").WithVersion("version"), pod.Namespace, pod.Name, api.Resource("pods").WithVersion("version"), "", admission.Delete, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify delete of namespace default can never proceed
|
// verify delete of namespace default can never proceed
|
||||||
err = handler.Admit(admission.NewAttributesRecord(nil, api.Kind("Namespace").WithVersion("version"), "", api.NamespaceDefault, api.Resource("namespaces").WithVersion("version"), "", admission.Delete, nil))
|
err = handler.Admit(admission.NewAttributesRecord(nil, nil, api.Kind("Namespace").WithVersion("version"), "", api.NamespaceDefault, api.Resource("namespaces").WithVersion("version"), "", admission.Delete, nil))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected an error that this namespace can never be deleted")
|
t.Errorf("Expected an error that this namespace can never be deleted")
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify delete of namespace other than default can proceed
|
// verify delete of namespace other than default can proceed
|
||||||
err = handler.Admit(admission.NewAttributesRecord(nil, api.Kind("Namespace").WithVersion("version"), "", "other", api.Resource("namespaces").WithVersion("version"), "", admission.Delete, nil))
|
err = handler.Admit(admission.NewAttributesRecord(nil, nil, api.Kind("Namespace").WithVersion("version"), "", "other", api.Resource("namespaces").WithVersion("version"), "", admission.Delete, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Did not expect an error %v", err)
|
t.Errorf("Did not expect an error %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify create/update/delete of object in non-existent namespace throws error
|
// verify create/update/delete of object in non-existent namespace throws error
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&badPod, api.Kind("Pod").WithVersion("version"), badPod.Namespace, badPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&badPod, nil, api.Kind("Pod").WithVersion("version"), badPod.Namespace, badPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected, but didn't get, an error (%v) that objects cannot be created in non-existant namespaces", err)
|
t.Errorf("Expected, but didn't get, an error (%v) that objects cannot be created in non-existant namespaces", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&badPod, api.Kind("Pod").WithVersion("version"), badPod.Namespace, badPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&badPod, nil, api.Kind("Pod").WithVersion("version"), badPod.Namespace, badPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Update, nil))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected, but didn't get, an error (%v) that objects cannot be updated in non-existant namespaces", err)
|
t.Errorf("Expected, but didn't get, an error (%v) that objects cannot be updated in non-existant namespaces", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&badPod, api.Kind("Pod").WithVersion("version"), badPod.Namespace, badPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Delete, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&badPod, nil, api.Kind("Pod").WithVersion("version"), badPod.Namespace, badPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Delete, nil))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected, but didn't get, an error (%v) that objects cannot be deleted in non-existant namespaces", err)
|
t.Errorf("Expected, but didn't get, an error (%v) that objects cannot be deleted in non-existant namespaces", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,20 +87,20 @@ func TestAdmission(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Non-cloud PVs are ignored
|
// Non-cloud PVs are ignored
|
||||||
err := handler.Admit(admission.NewAttributesRecord(&ignoredPV, api.Kind("PersistentVolume").WithVersion("version"), ignoredPV.Namespace, ignoredPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil))
|
err := handler.Admit(admission.NewAttributesRecord(&ignoredPV, nil, api.Kind("PersistentVolume").WithVersion("version"), ignoredPV.Namespace, ignoredPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler (on ignored pv): %v", err)
|
t.Errorf("Unexpected error returned from admission handler (on ignored pv): %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only add labels on creation
|
// We only add labels on creation
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&awsPV, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Delete, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Delete, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error returned from admission handler (when deleting aws pv): %v", err)
|
t.Errorf("Unexpected error returned from admission handler (when deleting aws pv): %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errors from the cloudprovider block creation of the volume
|
// Errors from the cloudprovider block creation of the volume
|
||||||
pvHandler.ebsVolumes = mockVolumeFailure(fmt.Errorf("invalid volume"))
|
pvHandler.ebsVolumes = mockVolumeFailure(fmt.Errorf("invalid volume"))
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&awsPV, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected error when aws pv info fails")
|
t.Errorf("Expected error when aws pv info fails")
|
||||||
}
|
}
|
||||||
@@ -108,7 +108,7 @@ func TestAdmission(t *testing.T) {
|
|||||||
// Don't add labels if the cloudprovider doesn't return any
|
// Don't add labels if the cloudprovider doesn't return any
|
||||||
labels := make(map[string]string)
|
labels := make(map[string]string)
|
||||||
pvHandler.ebsVolumes = mockVolumeLabels(labels)
|
pvHandler.ebsVolumes = mockVolumeLabels(labels)
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&awsPV, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected no error when creating aws pv")
|
t.Errorf("Expected no error when creating aws pv")
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@ func TestAdmission(t *testing.T) {
|
|||||||
|
|
||||||
// Don't panic if the cloudprovider returns nil, nil
|
// Don't panic if the cloudprovider returns nil, nil
|
||||||
pvHandler.ebsVolumes = mockVolumeFailure(nil)
|
pvHandler.ebsVolumes = mockVolumeFailure(nil)
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&awsPV, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected no error when cloud provider returns empty labels")
|
t.Errorf("Expected no error when cloud provider returns empty labels")
|
||||||
}
|
}
|
||||||
@@ -128,7 +128,7 @@ func TestAdmission(t *testing.T) {
|
|||||||
labels["a"] = "1"
|
labels["a"] = "1"
|
||||||
labels["b"] = "2"
|
labels["b"] = "2"
|
||||||
pvHandler.ebsVolumes = mockVolumeLabels(labels)
|
pvHandler.ebsVolumes = mockVolumeLabels(labels)
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&awsPV, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected no error when creating aws pv")
|
t.Errorf("Expected no error when creating aws pv")
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@ func TestAdmission(t *testing.T) {
|
|||||||
awsPV.ObjectMeta.Labels = make(map[string]string)
|
awsPV.ObjectMeta.Labels = make(map[string]string)
|
||||||
awsPV.ObjectMeta.Labels["a"] = "not1"
|
awsPV.ObjectMeta.Labels["a"] = "not1"
|
||||||
awsPV.ObjectMeta.Labels["c"] = "3"
|
awsPV.ObjectMeta.Labels["c"] = "3"
|
||||||
err = handler.Admit(admission.NewAttributesRecord(&awsPV, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil))
|
err = handler.Admit(admission.NewAttributesRecord(&awsPV, nil, api.Kind("PersistentVolume").WithVersion("version"), awsPV.Namespace, awsPV.Name, api.Resource("persistentvolumes").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected no error when creating aws pv")
|
t.Errorf("Expected no error when creating aws pv")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ func TestAdmissionIgnoresDelete(t *testing.T) {
|
|||||||
t.Errorf("Unexpected error %v", err)
|
t.Errorf("Unexpected error %v", err)
|
||||||
}
|
}
|
||||||
namespace := "default"
|
namespace := "default"
|
||||||
err = handler.Admit(admission.NewAttributesRecord(nil, api.Kind("Pod").WithVersion("version"), namespace, "name", api.Resource("pods").WithVersion("version"), "", admission.Delete, nil))
|
err = handler.Admit(admission.NewAttributesRecord(nil, nil, api.Kind("Pod").WithVersion("version"), namespace, "name", api.Resource("pods").WithVersion("version"), "", admission.Delete, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("ResourceQuota should admit all deletes: %v", err)
|
t.Errorf("ResourceQuota should admit all deletes: %v", err)
|
||||||
}
|
}
|
||||||
@@ -156,11 +156,11 @@ func TestAdmissionIgnoresSubresources(t *testing.T) {
|
|||||||
}
|
}
|
||||||
indexer.Add(resourceQuota)
|
indexer.Add(resourceQuota)
|
||||||
newPod := validPod("123", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("", "")))
|
newPod := validPod("123", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("", "")))
|
||||||
err := handler.Admit(admission.NewAttributesRecord(newPod, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err := handler.Admit(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected an error because the pod exceeded allowed quota")
|
t.Errorf("Expected an error because the pod exceeded allowed quota")
|
||||||
}
|
}
|
||||||
err = handler.Admit(admission.NewAttributesRecord(newPod, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "subresource", admission.Create, nil))
|
err = handler.Admit(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "subresource", admission.Create, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Did not expect an error because the action went to a subresource: %v", err)
|
t.Errorf("Did not expect an error because the action went to a subresource: %v", err)
|
||||||
}
|
}
|
||||||
@@ -197,7 +197,7 @@ func TestAdmitBelowQuotaLimit(t *testing.T) {
|
|||||||
}
|
}
|
||||||
indexer.Add(resourceQuota)
|
indexer.Add(resourceQuota)
|
||||||
newPod := validPod("allowed-pod", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("", "")))
|
newPod := validPod("allowed-pod", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("", "")))
|
||||||
err := handler.Admit(admission.NewAttributesRecord(newPod, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err := handler.Admit(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -274,7 +274,7 @@ func TestAdmitExceedQuotaLimit(t *testing.T) {
|
|||||||
}
|
}
|
||||||
indexer.Add(resourceQuota)
|
indexer.Add(resourceQuota)
|
||||||
newPod := validPod("not-allowed-pod", 1, getResourceRequirements(getResourceList("3", "2Gi"), getResourceList("", "")))
|
newPod := validPod("not-allowed-pod", 1, getResourceRequirements(getResourceList("3", "2Gi"), getResourceList("", "")))
|
||||||
err := handler.Admit(admission.NewAttributesRecord(newPod, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err := handler.Admit(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected an error exceeding quota")
|
t.Errorf("Expected an error exceeding quota")
|
||||||
}
|
}
|
||||||
@@ -316,13 +316,13 @@ func TestAdmitEnforceQuotaConstraints(t *testing.T) {
|
|||||||
indexer.Add(resourceQuota)
|
indexer.Add(resourceQuota)
|
||||||
// verify all values are specified as required on the quota
|
// verify all values are specified as required on the quota
|
||||||
newPod := validPod("not-allowed-pod", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("200m", "")))
|
newPod := validPod("not-allowed-pod", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("200m", "")))
|
||||||
err := handler.Admit(admission.NewAttributesRecord(newPod, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err := handler.Admit(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected an error because the pod does not specify a memory limit")
|
t.Errorf("Expected an error because the pod does not specify a memory limit")
|
||||||
}
|
}
|
||||||
// verify the requests and limits are actually valid (in this case, we fail because the limits < requests)
|
// verify the requests and limits are actually valid (in this case, we fail because the limits < requests)
|
||||||
newPod = validPod("not-allowed-pod", 1, getResourceRequirements(getResourceList("200m", "2Gi"), getResourceList("100m", "1Gi")))
|
newPod = validPod("not-allowed-pod", 1, getResourceRequirements(getResourceList("200m", "2Gi"), getResourceList("100m", "1Gi")))
|
||||||
err = handler.Admit(admission.NewAttributesRecord(newPod, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err = handler.Admit(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected an error because the pod does not specify a memory limit")
|
t.Errorf("Expected an error because the pod does not specify a memory limit")
|
||||||
}
|
}
|
||||||
@@ -369,7 +369,7 @@ func TestAdmitPodInNamespaceWithoutQuota(t *testing.T) {
|
|||||||
newPod := validPod("not-allowed-pod", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("200m", "")))
|
newPod := validPod("not-allowed-pod", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("200m", "")))
|
||||||
// Add to the lru cache so we do not do a live client lookup
|
// Add to the lru cache so we do not do a live client lookup
|
||||||
liveLookupCache.Add(newPod.Namespace, liveLookupEntry{expiry: time.Now().Add(time.Duration(30 * time.Second)), items: []*api.ResourceQuota{}})
|
liveLookupCache.Add(newPod.Namespace, liveLookupEntry{expiry: time.Now().Add(time.Duration(30 * time.Second)), items: []*api.ResourceQuota{}})
|
||||||
err = handler.Admit(admission.NewAttributesRecord(newPod, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err = handler.Admit(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Did not expect an error because the pod is in a different namespace than the quota")
|
t.Errorf("Did not expect an error because the pod is in a different namespace than the quota")
|
||||||
}
|
}
|
||||||
@@ -434,7 +434,7 @@ func TestAdmitBelowTerminatingQuotaLimit(t *testing.T) {
|
|||||||
newPod := validPod("allowed-pod", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("", "")))
|
newPod := validPod("allowed-pod", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("", "")))
|
||||||
activeDeadlineSeconds := int64(30)
|
activeDeadlineSeconds := int64(30)
|
||||||
newPod.Spec.ActiveDeadlineSeconds = &activeDeadlineSeconds
|
newPod.Spec.ActiveDeadlineSeconds = &activeDeadlineSeconds
|
||||||
err := handler.Admit(admission.NewAttributesRecord(newPod, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err := handler.Admit(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -534,7 +534,7 @@ func TestAdmitBelowBestEffortQuotaLimit(t *testing.T) {
|
|||||||
|
|
||||||
// create a pod that is best effort because it does not make a request for anything
|
// create a pod that is best effort because it does not make a request for anything
|
||||||
newPod := validPod("allowed-pod", 1, getResourceRequirements(getResourceList("", ""), getResourceList("", "")))
|
newPod := validPod("allowed-pod", 1, getResourceRequirements(getResourceList("", ""), getResourceList("", "")))
|
||||||
err := handler.Admit(admission.NewAttributesRecord(newPod, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err := handler.Admit(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -620,7 +620,7 @@ func TestAdmitBestEffortQuotaLimitIgnoresBurstable(t *testing.T) {
|
|||||||
}
|
}
|
||||||
indexer.Add(resourceQuota)
|
indexer.Add(resourceQuota)
|
||||||
newPod := validPod("allowed-pod", 1, getResourceRequirements(getResourceList("100m", "1Gi"), getResourceList("", "")))
|
newPod := validPod("allowed-pod", 1, getResourceRequirements(getResourceList("100m", "1Gi"), getResourceList("", "")))
|
||||||
err := handler.Admit(admission.NewAttributesRecord(newPod, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err := handler.Admit(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -740,7 +740,7 @@ func TestAdmissionSetsMissingNamespace(t *testing.T) {
|
|||||||
// unset the namespace
|
// unset the namespace
|
||||||
newPod.ObjectMeta.Namespace = ""
|
newPod.ObjectMeta.Namespace = ""
|
||||||
|
|
||||||
err := handler.Admit(admission.NewAttributesRecord(newPod, api.Kind("Pod").WithVersion("version"), namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err := handler.Admit(admission.NewAttributesRecord(newPod, nil, api.Kind("Pod").WithVersion("version"), namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Got unexpected error: %v", err)
|
t.Errorf("Got unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -953,7 +953,7 @@ func testPSPAdmit(testCaseName string, psps []*extensions.PodSecurityPolicy, pod
|
|||||||
|
|
||||||
plugin := NewTestAdmission(store, tc)
|
plugin := NewTestAdmission(store, tc)
|
||||||
|
|
||||||
attrs := kadmission.NewAttributesRecord(pod, kapi.Kind("Pod").WithVersion("version"), "namespace", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{})
|
attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), "namespace", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{})
|
||||||
err := plugin.Admit(attrs)
|
err := plugin.Admit(attrs)
|
||||||
|
|
||||||
if shouldPass && err != nil {
|
if shouldPass && err != nil {
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ func TestAdmission(t *testing.T) {
|
|||||||
p.Spec.SecurityContext = tc.podSc
|
p.Spec.SecurityContext = tc.podSc
|
||||||
p.Spec.Containers[0].SecurityContext = tc.sc
|
p.Spec.Containers[0].SecurityContext = tc.sc
|
||||||
|
|
||||||
err := handler.Admit(admission.NewAttributesRecord(p, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil))
|
err := handler.Admit(admission.NewAttributesRecord(p, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil))
|
||||||
if err != nil && !tc.expectError {
|
if err != nil && !tc.expectError {
|
||||||
t.Errorf("%v: unexpected error: %v", tc.name, err)
|
t.Errorf("%v: unexpected error: %v", tc.name, err)
|
||||||
} else if err == nil && tc.expectError {
|
} else if err == nil && tc.expectError {
|
||||||
@@ -96,7 +96,7 @@ func TestAdmission(t *testing.T) {
|
|||||||
p.Spec.InitContainers = p.Spec.Containers
|
p.Spec.InitContainers = p.Spec.Containers
|
||||||
p.Spec.Containers = nil
|
p.Spec.Containers = nil
|
||||||
|
|
||||||
err = handler.Admit(admission.NewAttributesRecord(p, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil))
|
err = handler.Admit(admission.NewAttributesRecord(p, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil))
|
||||||
if err != nil && !tc.expectError {
|
if err != nil && !tc.expectError {
|
||||||
t.Errorf("%v: unexpected error: %v", tc.name, err)
|
t.Errorf("%v: unexpected error: %v", tc.name, err)
|
||||||
} else if err == nil && tc.expectError {
|
} else if err == nil && tc.expectError {
|
||||||
@@ -140,7 +140,7 @@ func TestPodSecurityContextAdmission(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
pod.Spec.SecurityContext = &test.securityContext
|
pod.Spec.SecurityContext = &test.securityContext
|
||||||
err := handler.Admit(admission.NewAttributesRecord(&pod, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil))
|
err := handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil))
|
||||||
|
|
||||||
if test.errorExpected && err == nil {
|
if test.errorExpected && err == nil {
|
||||||
t.Errorf("Expected error for security context %+v but did not get an error", test.securityContext)
|
t.Errorf("Expected error for security context %+v but did not get an error", test.securityContext)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import (
|
|||||||
func TestIgnoresNonCreate(t *testing.T) {
|
func TestIgnoresNonCreate(t *testing.T) {
|
||||||
pod := &api.Pod{}
|
pod := &api.Pod{}
|
||||||
for _, op := range []admission.Operation{admission.Update, admission.Delete, admission.Connect} {
|
for _, op := range []admission.Operation{admission.Update, admission.Delete, admission.Connect} {
|
||||||
attrs := admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", op, nil)
|
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", op, nil)
|
||||||
handler := admission.NewChainHandler(NewServiceAccount(nil))
|
handler := admission.NewChainHandler(NewServiceAccount(nil))
|
||||||
err := handler.Admit(attrs)
|
err := handler.Admit(attrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -43,7 +43,7 @@ func TestIgnoresNonCreate(t *testing.T) {
|
|||||||
|
|
||||||
func TestIgnoresNonPodResource(t *testing.T) {
|
func TestIgnoresNonPodResource(t *testing.T) {
|
||||||
pod := &api.Pod{}
|
pod := &api.Pod{}
|
||||||
attrs := admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("CustomResource").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("CustomResource").WithVersion("version"), "", admission.Create, nil)
|
||||||
err := NewServiceAccount(nil).Admit(attrs)
|
err := NewServiceAccount(nil).Admit(attrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected non-pod resource allowed, got err: %v", err)
|
t.Errorf("Expected non-pod resource allowed, got err: %v", err)
|
||||||
@@ -51,7 +51,7 @@ func TestIgnoresNonPodResource(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIgnoresNilObject(t *testing.T) {
|
func TestIgnoresNilObject(t *testing.T) {
|
||||||
attrs := admission.NewAttributesRecord(nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(nil, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
err := NewServiceAccount(nil).Admit(attrs)
|
err := NewServiceAccount(nil).Admit(attrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected nil object allowed allowed, got err: %v", err)
|
t.Errorf("Expected nil object allowed allowed, got err: %v", err)
|
||||||
@@ -60,7 +60,7 @@ func TestIgnoresNilObject(t *testing.T) {
|
|||||||
|
|
||||||
func TestIgnoresNonPodObject(t *testing.T) {
|
func TestIgnoresNonPodObject(t *testing.T) {
|
||||||
obj := &api.Namespace{}
|
obj := &api.Namespace{}
|
||||||
attrs := admission.NewAttributesRecord(obj, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(obj, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
err := NewServiceAccount(nil).Admit(attrs)
|
err := NewServiceAccount(nil).Admit(attrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected non pod object allowed, got err: %v", err)
|
t.Errorf("Expected non pod object allowed, got err: %v", err)
|
||||||
@@ -80,7 +80,7 @@ func TestIgnoresMirrorPod(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
attrs := admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
err := NewServiceAccount(nil).Admit(attrs)
|
err := NewServiceAccount(nil).Admit(attrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected mirror pod without service account or secrets allowed, got err: %v", err)
|
t.Errorf("Expected mirror pod without service account or secrets allowed, got err: %v", err)
|
||||||
@@ -98,7 +98,7 @@ func TestRejectsMirrorPodWithServiceAccount(t *testing.T) {
|
|||||||
ServiceAccountName: "default",
|
ServiceAccountName: "default",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
attrs := admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
err := NewServiceAccount(nil).Admit(attrs)
|
err := NewServiceAccount(nil).Admit(attrs)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected a mirror pod to be prevented from referencing a service account")
|
t.Errorf("Expected a mirror pod to be prevented from referencing a service account")
|
||||||
@@ -118,7 +118,7 @@ func TestRejectsMirrorPodWithSecretVolumes(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
attrs := admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
err := NewServiceAccount(nil).Admit(attrs)
|
err := NewServiceAccount(nil).Admit(attrs)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected a mirror pod to be prevented from referencing a secret volume")
|
t.Errorf("Expected a mirror pod to be prevented from referencing a secret volume")
|
||||||
@@ -141,7 +141,7 @@ func TestAssignsDefaultServiceAccountAndToleratesMissingAPIToken(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
pod := &api.Pod{}
|
pod := &api.Pod{}
|
||||||
attrs := admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
err := admit.Admit(attrs)
|
err := admit.Admit(attrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
@@ -167,7 +167,7 @@ func TestAssignsDefaultServiceAccountAndRejectsMissingAPIToken(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
pod := &api.Pod{}
|
pod := &api.Pod{}
|
||||||
attrs := admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
err := admit.Admit(attrs)
|
err := admit.Admit(attrs)
|
||||||
if err == nil || !errors.IsServerTimeout(err) {
|
if err == nil || !errors.IsServerTimeout(err) {
|
||||||
t.Errorf("Expected server timeout error for missing API token: %v", err)
|
t.Errorf("Expected server timeout error for missing API token: %v", err)
|
||||||
@@ -189,7 +189,7 @@ func TestFetchesUncachedServiceAccount(t *testing.T) {
|
|||||||
admit.RequireAPIToken = false
|
admit.RequireAPIToken = false
|
||||||
|
|
||||||
pod := &api.Pod{}
|
pod := &api.Pod{}
|
||||||
attrs := admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
err := admit.Admit(attrs)
|
err := admit.Admit(attrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
@@ -208,7 +208,7 @@ func TestDeniesInvalidServiceAccount(t *testing.T) {
|
|||||||
admit := NewServiceAccount(client)
|
admit := NewServiceAccount(client)
|
||||||
|
|
||||||
pod := &api.Pod{}
|
pod := &api.Pod{}
|
||||||
attrs := admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
err := admit.Admit(attrs)
|
err := admit.Admit(attrs)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected error for missing service account, got none")
|
t.Errorf("Expected error for missing service account, got none")
|
||||||
@@ -271,7 +271,7 @@ func TestAutomountsAPIToken(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
attrs := admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
err := admit.Admit(attrs)
|
err := admit.Admit(attrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
@@ -299,7 +299,7 @@ func TestAutomountsAPIToken(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
attrs = admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs = admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
if err := admit.Admit(attrs); err != nil {
|
if err := admit.Admit(attrs); err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -377,7 +377,7 @@ func TestRespectsExistingMount(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
attrs := admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
err := admit.Admit(attrs)
|
err := admit.Admit(attrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
@@ -407,7 +407,7 @@ func TestRespectsExistingMount(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
attrs = admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs = admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
if err := admit.Admit(attrs); err != nil {
|
if err := admit.Admit(attrs); err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -450,7 +450,7 @@ func TestAllowsReferencedSecret(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
attrs := admission.NewAttributesRecord(pod1, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(pod1, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
if err := admit.Admit(attrs); err != nil {
|
if err := admit.Admit(attrs); err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -474,7 +474,7 @@ func TestAllowsReferencedSecret(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
attrs = admission.NewAttributesRecord(pod2, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
if err := admit.Admit(attrs); err != nil {
|
if err := admit.Admit(attrs); err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -498,7 +498,7 @@ func TestAllowsReferencedSecret(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
attrs = admission.NewAttributesRecord(pod2, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
if err := admit.Admit(attrs); err != nil {
|
if err := admit.Admit(attrs); err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -526,7 +526,7 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
attrs := admission.NewAttributesRecord(pod1, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(pod1, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
if err := admit.Admit(attrs); err == nil {
|
if err := admit.Admit(attrs); err == nil {
|
||||||
t.Errorf("Expected rejection for using a secret the service account does not reference")
|
t.Errorf("Expected rejection for using a secret the service account does not reference")
|
||||||
}
|
}
|
||||||
@@ -550,7 +550,7 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
attrs = admission.NewAttributesRecord(pod2, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
if err := admit.Admit(attrs); err == nil || !strings.Contains(err.Error(), "with envVar") {
|
if err := admit.Admit(attrs); err == nil || !strings.Contains(err.Error(), "with envVar") {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -574,7 +574,7 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
attrs = admission.NewAttributesRecord(pod2, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
if err := admit.Admit(attrs); err == nil || !strings.Contains(err.Error(), "with envVar") {
|
if err := admit.Admit(attrs); err == nil || !strings.Contains(err.Error(), "with envVar") {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -603,7 +603,7 @@ func TestAllowUnreferencedSecretVolumesForPermissiveSAs(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
attrs := admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
err := admit.Admit(attrs)
|
err := admit.Admit(attrs)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected rejection for using a secret the service account does not reference")
|
t.Errorf("Expected rejection for using a secret the service account does not reference")
|
||||||
@@ -633,7 +633,7 @@ func TestAllowsReferencedImagePullSecrets(t *testing.T) {
|
|||||||
ImagePullSecrets: []api.LocalObjectReference{{Name: "foo"}},
|
ImagePullSecrets: []api.LocalObjectReference{{Name: "foo"}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
attrs := admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
err := admit.Admit(attrs)
|
err := admit.Admit(attrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
@@ -660,7 +660,7 @@ func TestRejectsUnreferencedImagePullSecrets(t *testing.T) {
|
|||||||
ImagePullSecrets: []api.LocalObjectReference{{Name: "foo"}},
|
ImagePullSecrets: []api.LocalObjectReference{{Name: "foo"}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
attrs := admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
err := admit.Admit(attrs)
|
err := admit.Admit(attrs)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected rejection for using a secret the service account does not reference")
|
t.Errorf("Expected rejection for using a secret the service account does not reference")
|
||||||
@@ -691,7 +691,7 @@ func TestDoNotAddImagePullSecrets(t *testing.T) {
|
|||||||
ImagePullSecrets: []api.LocalObjectReference{{Name: "foo"}},
|
ImagePullSecrets: []api.LocalObjectReference{{Name: "foo"}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
attrs := admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
err := admit.Admit(attrs)
|
err := admit.Admit(attrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
@@ -723,7 +723,7 @@ func TestAddImagePullSecrets(t *testing.T) {
|
|||||||
admit.serviceAccounts.Add(sa)
|
admit.serviceAccounts.Add(sa)
|
||||||
|
|
||||||
pod := &api.Pod{}
|
pod := &api.Pod{}
|
||||||
attrs := admission.NewAttributesRecord(pod, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, nil)
|
||||||
err := admit.Admit(attrs)
|
err := admit.Admit(attrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
|||||||
Reference in New Issue
Block a user