Change rest storage Update interface to retrieve updated object

Add OldObject to admission attributes

Update resthandler Patch/Update admission plumbing
pull/6/head
Jordan Liggitt 2016-04-28 21:21:35 -04:00
parent 4215fe57a5
commit 29252acd1a
71 changed files with 772 additions and 325 deletions

View File

@ -53,6 +53,7 @@ import (
"k8s.io/kubernetes/pkg/kubelet/dockertools"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/master"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/util/flag"
"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.")
}

View File

@ -20,6 +20,7 @@ import (
"k8s.io/kubernetes/federation/apis/federation"
"k8s.io/kubernetes/federation/registry/cluster"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/registry/generic/registry"
"k8s.io/kubernetes/pkg/runtime"
@ -38,8 +39,8 @@ func (r *StatusREST) New() runtime.Object {
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}
// NewREST returns a RESTStorage object that will work against clusters.

View File

@ -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 {
_, _, err := s.Update(ctx, cluster)
_, _, err := s.Update(ctx, cluster.Name, rest.DefaultUpdatedObjectInfo(cluster, api.Scheme))
return err
}

View File

@ -30,10 +30,11 @@ type attributesRecord struct {
subresource string
operation Operation
object runtime.Object
oldObject runtime.Object
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{
kind: kind,
namespace: namespace,
@ -42,6 +43,7 @@ func NewAttributesRecord(object runtime.Object, kind unversioned.GroupVersionKin
subresource: subresource,
operation: operation,
object: object,
oldObject: oldObject,
userInfo: userInfo,
}
}
@ -74,6 +76,10 @@ func (record *attributesRecord) GetObject() runtime.Object {
return record.object
}
func (record *attributesRecord) GetOldObject() runtime.Object {
return record.oldObject
}
func (record *attributesRecord) GetUserInfo() user.Info {
return record.userInfo
}

View File

@ -100,7 +100,7 @@ func TestAdmit(t *testing.T) {
},
}
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)
if accepted != test.accept {
t.Errorf("%s: unexpected result of admit call: %v\n", test.name, accepted)

View File

@ -41,6 +41,8 @@ type Attributes interface {
GetOperation() Operation
// GetObject is the object from the incoming request prior to default values being applied
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() unversioned.GroupVersionKind
// GetUserInfo is information about the requesting user

View File

@ -174,6 +174,19 @@ type NamedCreater interface {
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.
type Updater interface {
// 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
// may allow updates creates the object - they should set the created boolean
// 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.
// Go prevents embedded interfaces that implement the same method.
type CreaterUpdater interface {
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.

View File

@ -170,6 +170,8 @@ func (t *Tester) TestUpdate(valid runtime.Object, createFn CreateFunc, getFn Get
}
t.testUpdateInvokesValidation(copyOrDie(valid), createFn, invalidUpdateFn...)
t.testUpdateWithWrongUID(copyOrDie(valid), createFn, getFn)
t.testUpdateRetrievesOldObject(copyOrDie(valid), createFn, getFn)
t.testUpdatePropagatesUpdatedObjectError(copyOrDie(valid), createFn, getFn)
}
// Test deleting an object.
@ -442,7 +444,8 @@ func (t *Tester) testUpdateEquals(obj runtime.Object, createFn CreateFunc, getFn
t.Errorf("unexpected error: %v", err)
}
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 {
t.Errorf("unexpected error: %v", err)
}
@ -482,7 +485,7 @@ func (t *Tester) testUpdateFailsOnVersionTooOld(obj runtime.Object, createFn Cre
olderMeta := t.getObjectMetaOrFail(older)
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 {
t.Errorf("Expected an error, but we didn't get one")
} else if !errors.IsConflict(err) {
@ -501,7 +504,8 @@ func (t *Tester) testUpdateInvokesValidation(obj runtime.Object, createFn Create
for _, update := range invalidUpdateFn {
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 {
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")
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 {
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) {
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 err != nil {
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.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 {
t.Errorf("expected nil object and not updated")
}

View File

@ -21,6 +21,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/validation/field"
@ -103,3 +104,72 @@ func BeforeUpdate(strategy RESTUpdateStrategy, ctx api.Context, obj, old runtime
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
}

View File

@ -462,6 +462,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
ParameterCodec: a.group.ParameterCodec,
Creater: a.group.Creater,
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.
Resource: a.group.GroupVersion.WithResource(resource),

View File

@ -91,6 +91,7 @@ type APIGroupVersion struct {
Typer runtime.ObjectTyper
Creater runtime.ObjectCreater
Convertor runtime.ObjectConvertor
Copier runtime.ObjectCopier
Linker runtime.SelfLinker
Admit admission.Interface

View File

@ -271,6 +271,7 @@ func handleInternal(storage map[string]rest.Storage, admissionControl admission.
Creater: api.Scheme,
Convertor: api.Scheme,
Copier: api.Scheme,
Typer: api.Scheme,
Linker: selfLinker,
Mapper: namespaceMapper,
@ -502,13 +503,16 @@ func (storage *SimpleRESTStorage) Create(ctx api.Context, obj runtime.Object) (r
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)
obj, err := objInfo.UpdatedObject(ctx, &storage.item)
if err != nil {
return nil, false, err
}
storage.updated = obj.(*apiservertesting.Simple)
if err := storage.errors["update"]; err != nil {
return nil, false, err
}
var err error
if storage.injectedFunction != nil {
obj, err = storage.injectedFunction(obj)
}
@ -2022,6 +2026,7 @@ func TestPatch(t *testing.T) {
ObjectMeta: api.ObjectMeta{
Name: ID,
Namespace: "", // update should allow the client to send an empty namespace
UID: "uid",
},
Other: "bar",
}
@ -2060,6 +2065,7 @@ func TestPatchRequiresMatchingName(t *testing.T) {
ObjectMeta: api.ObjectMeta{
Name: ID,
Namespace: "", // update should allow the client to send an empty namespace
UID: "uid",
},
Other: "bar",
}
@ -2399,6 +2405,7 @@ func TestUpdateREST(t *testing.T) {
RequestInfoResolver: newTestRequestInfoResolver(),
Creater: api.Scheme,
Convertor: api.Scheme,
Copier: api.Scheme,
Typer: api.Scheme,
Linker: selfLinker,
@ -2483,6 +2490,7 @@ func TestParentResourceIsRequired(t *testing.T) {
RequestInfoResolver: newTestRequestInfoResolver(),
Creater: api.Scheme,
Convertor: api.Scheme,
Copier: api.Scheme,
Typer: api.Scheme,
Linker: selfLinker,
@ -2514,6 +2522,7 @@ func TestParentResourceIsRequired(t *testing.T) {
RequestInfoResolver: newTestRequestInfoResolver(),
Creater: api.Scheme,
Convertor: api.Scheme,
Copier: api.Scheme,
Typer: api.Scheme,
Linker: selfLinker,
@ -3211,6 +3220,7 @@ func TestXGSubresource(t *testing.T) {
Creater: api.Scheme,
Convertor: api.Scheme,
Copier: api.Scheme,
Typer: api.Scheme,
Linker: selfLinker,
Mapper: namespaceMapper,

View File

@ -77,6 +77,7 @@ type RequestScope struct {
Creater runtime.ObjectCreater
Convertor runtime.ObjectConvertor
Copier runtime.ObjectCopier
Resource unversioned.GroupVersionResource
Kind unversioned.GroupVersionKind
@ -200,7 +201,7 @@ func ConnectResource(connecter rest.Connecter, scope RequestScope, admit admissi
}
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 {
scope.err(err, res.ResponseWriter, req.Request)
return
@ -391,7 +392,7 @@ func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.Object
if admit != nil && admit.Handles(admission.Create) {
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 {
scope.err(err, res.ResponseWriter, req.Request)
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}),
)
updateAdmit := func(updatedObject runtime.Object) error {
updateAdmit := func(updatedObject runtime.Object, currentObject runtime.Object) error {
if admit != nil && admit.Handles(admission.Update) {
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
}
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 {
scope.err(err, res.ResponseWriter, req.Request)
return
@ -516,24 +517,57 @@ 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
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)
original, err := patcher.Get(ctx, name)
if err != nil {
var (
originalObjJS []byte
originalPatchedObjJS []byte
lastConflictErr error
)
// applyPatch is called every time GuaranteedUpdate asks for the updated object,
// and is given the currently persisted object as input.
applyPatch := func(_ api.Context, _, currentObject runtime.Object) (runtime.Object, error) {
// Make sure we actually have a persisted currentObject
if hasUID, err := hasUID(currentObject); err != nil {
return nil, err
} else if !hasUID {
return nil, errors.NewNotFound(resource.GroupResource(), name)
}
originalObjJS, err := runtime.Encode(codec, original)
if err != nil {
switch {
case len(originalObjJS) == 0 || len(originalPatchedObjJS) == 0:
// 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
}
originalPatchedObjJS, err := getPatchedJS(patchType, originalObjJS, patchJS, versionedObj)
if err != nil {
if js, err := getPatchedJS(patchType, originalObjJS, patchJS, versionedObj); err != nil {
return nil, err
} else {
originalPatchedObjJS = js
}
objToUpdate := patcher.New()
@ -543,16 +577,9 @@ func patchResource(ctx api.Context, admit updateAdmissionFunc, timeout time.Dura
if err := checkName(objToUpdate, name, namespace, namer); err != nil {
return nil, err
}
return objToUpdate, nil
return finishRequest(timeout, func() (runtime.Object, error) {
if err := admit(objToUpdate); err != nil {
return nil, err
}
// update should never create as previous get would fail
updateObject, _, updateErr := patcher.Update(ctx, objToUpdate)
for i := 0; i < MaxPatchConflicts && (errors.IsConflict(updateErr)); i++ {
default:
// on a conflict,
// 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
@ -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
// 3. ensure no conflicts between the two patches
// 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)
if err != nil {
return nil, err
}
currentPatch, err := strategicpatch.CreateStrategicMergePatch(originalObjJS, currentObjectJS, versionedObj)
if err != nil {
return nil, err
@ -592,25 +613,41 @@ func patchResource(ctx api.Context, admit updateAdmissionFunc, timeout time.Dura
return nil, err
}
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)
return updateObject, updateErr
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 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)
if err != nil {
return nil, err
}
objToUpdate := patcher.New()
if err := runtime.DecodeInto(codec, newlyPatchedObjJS, objToUpdate); err != nil {
return nil, err
}
if err := admit(objToUpdate); err != nil {
return nil, err
return objToUpdate, nil
}
}
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
})
}
@ -667,20 +704,18 @@ func UpdateResource(r rest.Updater, scope RequestScope, typer runtime.ObjectType
return
}
var transformers []rest.TransformFunc
if admit != nil && admit.Handles(admission.Update) {
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))
if err != nil {
scope.err(err, res.ResponseWriter, req.Request)
return
}
return newObj, admit.Admit(admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo))
})
}
trace.Step("About to store object in database")
wasCreated := false
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
return obj, err
})
@ -753,7 +788,7 @@ func DeleteResource(r rest.GracefulDeleter, checkBody bool, scope RequestScope,
if admit != nil && admit.Handles(admission.Delete) {
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 {
scope.err(err, res.ResponseWriter, req.Request)
return
@ -814,7 +849,7 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestSco
if admit != nil && admit.Handles(admission.Delete) {
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 {
scope.err(err, res.ResponseWriter, req.Request)
return
@ -969,6 +1004,20 @@ func setSelfLink(obj runtime.Object, req *restful.Request, namer ScopeNamer) err
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
func checkName(obj runtime.Object, name, namespace string, namer ScopeNamer) error {
if objNamespace, objName, err := namer.ObjectName(obj); err == nil {

View File

@ -28,9 +28,11 @@ import (
"k8s.io/kubernetes/pkg/api"
apierrors "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/util/diff"
"k8s.io/kubernetes/pkg/util/strategicpatch"
)
@ -64,20 +66,32 @@ func TestPatchAnonymousField(t *testing.T) {
}
type testPatcher struct {
// startingPod is used for the first Get
t *testing.T
// startingPod is used for the first Update
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
numGets int
numUpdates int
}
func (p *testPatcher) New() runtime.Object {
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)
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))
@ -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) {
if p.numGets > 0 {
return p.updatePod, nil
}
p.numGets++
return p.startingPod, nil
p.t.Fatal("Unexpected call to testPatcher.Get")
return nil, errors.New("Unexpected call to testPatcher.Get")
}
type testNamer struct {
@ -138,12 +148,12 @@ type patchTestCase struct {
// admission chain to use, nil is fine
admit updateAdmissionFunc
// startingPod is used for the first Get
// startingPod is used as the starting point for the first Update
startingPod *api.Pod
// 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
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
// 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()
admit := tc.admit
if admit == nil {
admit = func(updatedObject runtime.Object) error {
admit = func(updatedObject runtime.Object, currentObject runtime.Object) error {
return nil
}
}
testPatcher := &testPatcher{}
testPatcher.t = t
testPatcher.startingPod = tc.startingPod
testPatcher.updatePod = tc.updatePod
@ -173,6 +184,8 @@ func (tc *patchTestCase) Run(t *testing.T) {
ctx = api.WithNamespace(ctx, namespace)
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"})
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 err == nil || err.Error() != tc.expectedError {
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) {
namespace := "bar"
name := "foo"
uid := types.UID("uid")
fifteen := int64(15)
thirty := int64(30)
@ -280,18 +294,21 @@ func TestPatchResourceWithVersionConflict(t *testing.T) {
tc.startingPod.Name = name
tc.startingPod.Namespace = namespace
tc.startingPod.UID = uid
tc.startingPod.ResourceVersion = "1"
tc.startingPod.APIVersion = "v1"
tc.startingPod.Spec.ActiveDeadlineSeconds = &fifteen
tc.changedPod.Name = name
tc.changedPod.Namespace = namespace
tc.changedPod.UID = uid
tc.changedPod.ResourceVersion = "1"
tc.changedPod.APIVersion = "v1"
tc.changedPod.Spec.ActiveDeadlineSeconds = &thirty
tc.updatePod.Name = name
tc.updatePod.Namespace = namespace
tc.updatePod.UID = uid
tc.updatePod.ResourceVersion = "2"
tc.updatePod.APIVersion = "v1"
tc.updatePod.Spec.ActiveDeadlineSeconds = &fifteen
@ -299,6 +316,7 @@ func TestPatchResourceWithVersionConflict(t *testing.T) {
tc.expectedPod.Name = name
tc.expectedPod.Namespace = namespace
tc.expectedPod.UID = uid
tc.expectedPod.ResourceVersion = "2"
tc.expectedPod.Spec.ActiveDeadlineSeconds = &thirty
tc.expectedPod.Spec.NodeName = "anywhere"
@ -309,6 +327,7 @@ func TestPatchResourceWithVersionConflict(t *testing.T) {
func TestPatchResourceWithConflict(t *testing.T) {
namespace := "bar"
name := "foo"
uid := types.UID("uid")
tc := &patchTestCase{
name: "TestPatchResourceWithConflict",
@ -322,18 +341,21 @@ func TestPatchResourceWithConflict(t *testing.T) {
tc.startingPod.Name = name
tc.startingPod.Namespace = namespace
tc.startingPod.UID = uid
tc.startingPod.ResourceVersion = "1"
tc.startingPod.APIVersion = "v1"
tc.startingPod.Spec.NodeName = "here"
tc.changedPod.Name = name
tc.changedPod.Namespace = namespace
tc.changedPod.UID = uid
tc.changedPod.ResourceVersion = "1"
tc.changedPod.APIVersion = "v1"
tc.changedPod.Spec.NodeName = "there"
tc.updatePod.Name = name
tc.updatePod.Namespace = namespace
tc.updatePod.UID = uid
tc.updatePod.ResourceVersion = "2"
tc.updatePod.APIVersion = "v1"
tc.updatePod.Spec.NodeName = "anywhere"
@ -344,13 +366,14 @@ func TestPatchResourceWithConflict(t *testing.T) {
func TestPatchWithAdmissionRejection(t *testing.T) {
namespace := "bar"
name := "foo"
uid := types.UID("uid")
fifteen := int64(15)
thirty := int64(30)
tc := &patchTestCase{
name: "TestPatchWithAdmissionRejection",
admit: func(updatedObject runtime.Object) error {
admit: func(updatedObject runtime.Object, currentObject runtime.Object) error {
return errors.New("admission failure")
},
@ -363,12 +386,14 @@ func TestPatchWithAdmissionRejection(t *testing.T) {
tc.startingPod.Name = name
tc.startingPod.Namespace = namespace
tc.startingPod.UID = uid
tc.startingPod.ResourceVersion = "1"
tc.startingPod.APIVersion = "v1"
tc.startingPod.Spec.ActiveDeadlineSeconds = &fifteen
tc.changedPod.Name = name
tc.changedPod.Namespace = namespace
tc.changedPod.UID = uid
tc.changedPod.ResourceVersion = "1"
tc.changedPod.APIVersion = "v1"
tc.changedPod.Spec.ActiveDeadlineSeconds = &thirty
@ -379,6 +404,7 @@ func TestPatchWithAdmissionRejection(t *testing.T) {
func TestPatchWithVersionConflictThenAdmissionFailure(t *testing.T) {
namespace := "bar"
name := "foo"
uid := types.UID("uid")
fifteen := int64(15)
thirty := int64(30)
seen := false
@ -386,7 +412,7 @@ func TestPatchWithVersionConflictThenAdmissionFailure(t *testing.T) {
tc := &patchTestCase{
name: "TestPatchWithVersionConflictThenAdmissionFailure",
admit: func(updatedObject runtime.Object) error {
admit: func(updatedObject runtime.Object, currentObject runtime.Object) error {
if seen {
return errors.New("admission failure")
}
@ -404,18 +430,21 @@ func TestPatchWithVersionConflictThenAdmissionFailure(t *testing.T) {
tc.startingPod.Name = name
tc.startingPod.Namespace = namespace
tc.startingPod.UID = uid
tc.startingPod.ResourceVersion = "1"
tc.startingPod.APIVersion = "v1"
tc.startingPod.Spec.ActiveDeadlineSeconds = &fifteen
tc.changedPod.Name = name
tc.changedPod.Namespace = namespace
tc.changedPod.UID = uid
tc.changedPod.ResourceVersion = "1"
tc.changedPod.APIVersion = "v1"
tc.changedPod.Spec.ActiveDeadlineSeconds = &thirty
tc.updatePod.Name = name
tc.updatePod.Namespace = namespace
tc.updatePod.UID = uid
tc.updatePod.ResourceVersion = "2"
tc.updatePod.APIVersion = "v1"
tc.updatePod.Spec.ActiveDeadlineSeconds = &fifteen
@ -423,3 +452,26 @@ func TestPatchWithVersionConflictThenAdmissionFailure(t *testing.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)
}
}
}

View File

@ -862,6 +862,7 @@ func (s *GenericAPIServer) getAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupV
version.Serializer = apiGroupInfo.NegotiatedSerializer
version.Creater = apiGroupInfo.Scheme
version.Convertor = apiGroupInfo.Scheme
version.Copier = apiGroupInfo.Scheme
version.Typer = apiGroupInfo.Scheme
version.SubresourceGroupVersionKind = apiGroupInfo.SubresourceGroupVersionKind
return version, err

View File

@ -749,6 +749,7 @@ func (m *Master) thirdpartyapi(group, kind, version string) *apiserver.APIGroupV
Creater: thirdpartyresourcedata.NewObjectCreator(group, version, api.Scheme),
Convertor: api.Scheme,
Copier: api.Scheme,
Typer: api.Scheme,
Mapper: thirdpartyresourcedata.NewMapper(registered.GroupOrDie(extensions.GroupName).RESTMapper, kind, version, group),

View File

@ -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) {
obj, _, err := s.Update(ctx, cfg)
obj, _, err := s.Update(ctx, cfg.Name, rest.DefaultUpdatedObjectInfo(cfg, api.Scheme))
if err != nil {
return nil, err
}

View File

@ -117,8 +117,8 @@ func (r *StatusREST) New() runtime.Object {
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}
type ScaleREST struct {
@ -141,7 +141,18 @@ func (r *ScaleREST) Get(ctx api.Context, name string) (runtime.Object, error) {
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 {
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)
}
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.ResourceVersion = scale.ResourceVersion
rc, err = r.registry.UpdateController(ctx, rc)

View File

@ -21,6 +21,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/apis/autoscaling"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
@ -159,7 +160,7 @@ func TestGenerationNumber(t *testing.T) {
// Updates to spec should increment the generation number
controller.Spec.Replicas += 1
storage.Controller.Update(ctx, controller)
storage.Controller.Update(ctx, controller.Name, rest.DefaultUpdatedObjectInfo(controller, api.Scheme))
if err != nil {
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
controller.Status.Replicas += 1
storage.Controller.Update(ctx, controller)
storage.Controller.Update(ctx, controller.Name, rest.DefaultUpdatedObjectInfo(controller, api.Scheme))
if err != nil {
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)
}
obj, err := storage.Scale.Get(ctx, name)
@ -304,7 +305,7 @@ func TestScaleUpdate(t *testing.T) {
update.ResourceVersion = rc.ResourceVersion
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)
}
}

View File

@ -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) {
obj, _, err := s.Update(ctx, controller)
obj, _, err := s.Update(ctx, controller.Name, rest.DefaultUpdatedObjectInfo(controller, api.Scheme))
if err != nil {
return nil, err
}

View File

@ -18,6 +18,7 @@ package etcd
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
@ -92,6 +93,6 @@ func (r *StatusREST) New() runtime.Object {
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}

View File

@ -116,8 +116,8 @@ func (r *StatusREST) New() runtime.Object {
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}
// 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
}
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 {
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 {
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.ResourceVersion = scale.ResourceVersion
deployment, err = r.registry.UpdateDeployment(ctx, deployment)

View File

@ -23,6 +23,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
storeerr "k8s.io/kubernetes/pkg/api/errors/storage"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions"
"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)
}
obj, err := storage.Scale.Get(ctx, name)
@ -248,7 +249,7 @@ func TestScaleUpdate(t *testing.T) {
update.ResourceVersion = deployment.ResourceVersion
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)
}
}
@ -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)
}
obj, err := storage.Deployment.Get(ctx, name)

View File

@ -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) {
obj, _, err := s.Update(ctx, deployment)
obj, _, err := s.Update(ctx, deployment.Name, rest.DefaultUpdatedObjectInfo(deployment, api.Scheme))
if err != nil {
return nil, err
}

View File

@ -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 {
_, _, err := s.Update(ctx, endpoints)
_, _, err := s.Update(ctx, endpoints.Name, rest.DefaultUpdatedObjectInfo(endpoints, api.Scheme))
return err
}

View File

@ -70,7 +70,15 @@ func (r *ScaleREST) Get(ctx api.Context, name string) (runtime.Object, error) {
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 {
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)
}
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.ResourceVersion = scale.ResourceVersion
rc, err = (*r.registry).UpdateController(ctx, rc)

View File

@ -20,6 +20,7 @@ import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions"
"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)
}
obj, err := storage.Get(ctx, "foo")

View File

@ -238,45 +238,39 @@ 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
// 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.
func (e *Store) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
name, err := e.ObjectNameFunc(obj)
if err != nil {
return nil, false, err
}
func (e *Store) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
key, err := e.KeyFunc(ctx, name)
if err != nil {
return nil, false, err
}
var (
creatingObj runtime.Object
creating = false
)
storagePreconditions := &storage.Preconditions{}
if preconditions := objInfo.Preconditions(); preconditions != nil {
storagePreconditions.UID = preconditions.UID
}
out := e.NewFunc()
err = e.Storage.GuaranteedUpdate(ctx, key, out, true, storagePreconditions, func(existing runtime.Object, res storage.ResponseMeta) (runtime.Object, *uint64, error) {
// Given the existing object, get the new object
obj, err := objInfo.UpdatedObject(ctx, existing)
if err != nil {
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, false, err
}
doUnconditionalUpdate := resourceVersion == 0 && e.UpdateStrategy.AllowUnconditionalUpdate()
// TODO: expose TTL
creating := false
out := e.NewFunc()
meta, err := api.ObjectMetaFor(obj)
if err != nil {
return nil, false, kubeerr.NewInternalError(err)
}
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 {
return nil, nil, err
}
doUnconditionalUpdate := resourceVersion == 0 && e.UpdateStrategy.AllowUnconditionalUpdate()
version, err := e.Storage.Versioner().ObjectResourceVersion(existing)
if err != nil {
@ -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)
}
creating = true
creatingObj = obj
if err := rest.BeforeCreate(e.CreateStrategy, ctx, obj); err != nil {
return nil, nil, err
}
@ -298,6 +293,7 @@ func (e *Store) Update(ctx api.Context, obj runtime.Object) (runtime.Object, boo
}
creating = false
creatingObj = nil
if doUnconditionalUpdate {
// Update the object's resource version to match the latest storage object's resource version.
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 creating {
err = storeerr.InterpretCreateError(err, e.QualifiedResource, name)
err = rest.CheckGeneratedNameError(e.CreateStrategy, err, obj)
err = rest.CheckGeneratedNameError(e.CreateStrategy, err, creatingObj)
} else {
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 err := e.Decorator(obj); err != nil {
if err := e.Decorator(out); err != nil {
return nil, false, err
}
}

View File

@ -28,6 +28,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/unversioned"
"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 {
obj, _, err := registry.Update(ctx, pod)
obj, _, err := registry.Update(ctx, pod.Name, rest.DefaultUpdatedObjectInfo(pod, api.Scheme))
if err != nil {
t.Errorf("Unexpected error: %v", err)
return false
@ -309,7 +310,7 @@ func TestStoreUpdate(t *testing.T) {
defer server.Terminate(t)
// 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) {
t.Errorf("Unexpected error: %v", err)
}
@ -322,7 +323,7 @@ func TestStoreUpdate(t *testing.T) {
registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = false
// Test3 outofDate
_, _, err = registry.Update(testContext, podAWithResourceVersion)
_, _, err = registry.Update(testContext, podAWithResourceVersion.Name, rest.DefaultUpdatedObjectInfo(podAWithResourceVersion, api.Scheme))
if !errors.IsConflict(err) {
t.Errorf("Unexpected error updating podAWithResourceVersion: %v", err)
}
@ -369,7 +370,8 @@ func TestNoOpUpdates(t *testing.T) {
}
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)
}
@ -446,8 +448,12 @@ func TestStoreCustomExport(t *testing.T) {
if exportedPod.Labels["exact"] != "false" {
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, "exact")
delete(exportedPod.Labels, "prepare_create")
exportObjectMeta(&podA.ObjectMeta, false)
podA.Spec = exportedPod.Spec
if !reflect.DeepEqual(&podA, exportedPod) {
@ -483,6 +489,7 @@ func TestStoreBasicExport(t *testing.T) {
if exportedPod.Labels["prepare_create"] != "true" {
t.Errorf("expected: prepare_create->true, found: %s", exportedPod.Labels["prepare_create"])
}
delete(exportedPod.Labels, "prepare_create")
exportObjectMeta(&podA.ObjectMeta, false)
podA.Spec = exportedPod.Spec
if !reflect.DeepEqual(&podA, exportedPod) {

View File

@ -18,6 +18,7 @@ package etcd
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/apis/autoscaling"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
@ -89,6 +90,6 @@ func (r *StatusREST) New() runtime.Object {
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}

View File

@ -18,6 +18,7 @@ package etcd
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
@ -91,6 +92,6 @@ func (r *StatusREST) New() runtime.Object {
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}

View File

@ -18,6 +18,7 @@ package etcd
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
@ -93,6 +94,6 @@ func (r *StatusREST) New() runtime.Object {
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}

View File

@ -22,6 +22,7 @@ import (
"k8s.io/kubernetes/pkg/api"
apierrors "k8s.io/kubernetes/pkg/api/errors"
storageerr "k8s.io/kubernetes/pkg/api/errors/storage"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
@ -176,8 +177,8 @@ func (r *StatusREST) New() runtime.Object {
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}
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.
func (r *FinalizeREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *FinalizeREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}

View File

@ -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 {
_, _, err := s.Update(ctx, namespace)
_, _, err := s.Update(ctx, namespace.Name, rest.DefaultUpdatedObjectInfo(namespace, api.Scheme))
return err
}

View File

@ -55,8 +55,8 @@ func (r *StatusREST) New() runtime.Object {
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}
// NewREST returns a RESTStorage object that will work against nodes.

View File

@ -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 {
_, _, err := s.Update(ctx, node)
_, _, err := s.Update(ctx, node.Name, rest.DefaultUpdatedObjectInfo(node, api.Scheme))
return err
}

View File

@ -18,6 +18,7 @@ package etcd
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/cachesize"
@ -81,6 +82,6 @@ func (r *StatusREST) New() runtime.Object {
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}

View File

@ -21,6 +21,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"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 {
t.Fatalf("Unexpected error: %v", err)
}

View File

@ -18,6 +18,7 @@ package etcd
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/cachesize"
@ -81,6 +82,6 @@ func (r *StatusREST) New() runtime.Object {
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}

View File

@ -21,6 +21,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"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 {
t.Fatalf("Unexpected error: %v", err)
}

View File

@ -18,6 +18,7 @@ package etcd
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/rest"
appsapi "k8s.io/kubernetes/pkg/apis/apps"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
@ -91,6 +92,6 @@ func (r *StatusREST) New() runtime.Object {
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}

View File

@ -20,6 +20,7 @@ import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/apps"
"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)
}
obj, err := storage.Get(ctx, "foo")

View File

@ -199,6 +199,6 @@ func (r *StatusREST) New() runtime.Object {
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}

View File

@ -608,7 +608,7 @@ func TestEtcdUpdateNotScheduled(t *testing.T) {
}
podIn := validChangedPod()
_, _, err := storage.Update(ctx, podIn)
_, _, err := storage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(podIn, api.Scheme))
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
@ -675,7 +675,7 @@ func TestEtcdUpdateScheduled(t *testing.T) {
SecurityContext: &api.PodSecurityContext{},
},
}
_, _, err = storage.Update(ctx, &podIn)
_, _, err = storage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(&podIn, api.Scheme))
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
@ -756,7 +756,7 @@ func TestEtcdUpdateStatus(t *testing.T) {
expected.Labels = podIn.Labels
expected.Status = podIn.Status
_, _, err = statusStorage.Update(ctx, &podIn)
_, _, err = statusStorage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(&podIn, api.Scheme))
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
@ -765,10 +765,10 @@ func TestEtcdUpdateStatus(t *testing.T) {
t.Errorf("unexpected error: %v", err)
}
podOut := obj.(*api.Pod)
// Check to verify the Spec, Label, and Status updates match from change above. Those are the fields changed.
if !api.Semantic.DeepEqual(podOut.Spec, podIn.Spec) ||
!api.Semantic.DeepEqual(podOut.Labels, podIn.Labels) ||
!api.Semantic.DeepEqual(podOut.Status, podIn.Status) {
t.Errorf("objects differ: %v", diff.ObjectDiff(podOut, podIn))
// Check to verify the Label, and Status updates match from change above. Those are the fields changed.
if !api.Semantic.DeepEqual(podOut.Spec, expected.Spec) ||
!api.Semantic.DeepEqual(podOut.Labels, expected.Labels) ||
!api.Semantic.DeepEqual(podOut.Status, expected.Status) {
t.Errorf("objects differ: %v", diff.ObjectDiff(podOut, expected))
}
}

View File

@ -18,6 +18,7 @@ package etcd
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/rest"
policyapi "k8s.io/kubernetes/pkg/apis/policy"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
@ -91,6 +92,6 @@ func (r *StatusREST) New() runtime.Object {
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}

View File

@ -20,6 +20,7 @@ import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/policy"
"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)
}
obj, err := storage.Get(ctx, "foo")

View File

@ -116,8 +116,8 @@ func (r *StatusREST) New() runtime.Object {
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}
type ScaleREST struct {
@ -144,7 +144,21 @@ func (r *ScaleREST) Get(ctx api.Context, name string) (runtime.Object, error) {
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 {
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)
}
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.ResourceVersion = scale.ResourceVersion
rs, err = r.registry.UpdateReplicaSet(ctx, rs)

View File

@ -21,6 +21,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/fields"
@ -162,7 +163,7 @@ func TestGenerationNumber(t *testing.T) {
// Updates to spec should increment the generation number
storedRS.Spec.Replicas += 1
storage.ReplicaSet.Update(ctx, storedRS)
storage.ReplicaSet.Update(ctx, storedRS.Name, rest.DefaultUpdatedObjectInfo(storedRS, api.Scheme))
if err != nil {
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
storedRS.Status.Replicas += 1
storage.ReplicaSet.Update(ctx, storedRS)
storage.ReplicaSet.Update(ctx, storedRS.Name, rest.DefaultUpdatedObjectInfo(storedRS, api.Scheme))
if err != nil {
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)
}
@ -315,7 +316,7 @@ func TestScaleUpdate(t *testing.T) {
update.ResourceVersion = rs.ResourceVersion
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)
}
}
@ -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)
}
obj, err := storage.ReplicaSet.Get(ctx, "foo")

View File

@ -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) {
obj, _, err := s.Update(ctx, replicaSet)
obj, _, err := s.Update(ctx, replicaSet.Name, rest.DefaultUpdatedObjectInfo(replicaSet, api.Scheme))
if err != nil {
return nil, err
}

View File

@ -18,6 +18,7 @@ package etcd
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/cachesize"
@ -81,6 +82,6 @@ func (r *StatusREST) New() runtime.Object {
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}

View File

@ -21,6 +21,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"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 {
t.Fatalf("Unexpected error: %v", err)
}

View File

@ -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) {
obj, _, err := s.Update(ctx, secret)
obj, _, err := s.Update(ctx, secret.Name, rest.DefaultUpdatedObjectInfo(secret, api.Scheme))
return obj.(*api.Secret), err
}

View File

@ -18,6 +18,7 @@ package etcd
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/cachesize"
@ -79,6 +80,6 @@ func (r *StatusREST) New() runtime.Object {
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
return r.store.Update(ctx, obj)
func (r *StatusREST) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
return r.store.Update(ctx, name, objInfo)
}

View File

@ -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) {
obj, _, err := s.Update(ctx, svc)
obj, _, err := s.Update(ctx, svc.Name, rest.DefaultUpdatedObjectInfo(svc, api.Scheme))
if err != nil {
return nil, err
}

View File

@ -212,17 +212,22 @@ func (*REST) NewList() runtime.Object {
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)
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"))
}
oldService, err := rs.registry.GetService(ctx, service.Name)
if err != nil {
return nil, false, err
}
// Copy over non-user fields
// TODO: make this a merge function
if errs := validation.ValidateServiceUpdate(service, oldService); len(errs) > 0 {

View File

@ -180,7 +180,7 @@ func TestServiceRegistryUpdate(t *testing.T) {
if err != nil {
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{
Name: "foo",
ResourceVersion: svc.ResourceVersion},
@ -194,7 +194,7 @@ func TestServiceRegistryUpdate(t *testing.T) {
TargetPort: intstr.FromInt(6502),
}},
},
})
}, api.Scheme))
if err != nil {
t.Fatalf("Expected no error: %v", err)
}
@ -255,7 +255,7 @@ func TestServiceStorageValidatesUpdate(t *testing.T) {
},
}
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 {
t.Errorf("Expected nil object or created false")
}
@ -363,14 +363,14 @@ func TestServiceRegistryUpdateExternalService(t *testing.T) {
// Modify load balancer to be external.
svc2 := deepCloneService(svc1)
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)
}
// Change port.
svc3 := deepCloneService(svc2)
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)
}
}
@ -406,7 +406,7 @@ func TestServiceRegistryUpdateMultiPortExternalService(t *testing.T) {
// Modify ports
svc2 := deepCloneService(svc1)
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)
}
}
@ -580,7 +580,7 @@ func TestServiceRegistryList(t *testing.T) {
}
func TestServiceRegistryIPAllocation(t *testing.T) {
rest, _ := NewTestREST(t, nil)
storage, _ := NewTestREST(t, nil)
svc1 := &api.Service{
ObjectMeta: api.ObjectMeta{Name: "foo"},
@ -596,7 +596,7 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
},
}
ctx := api.NewDefaultContext()
created_svc1, _ := rest.Create(ctx, svc1)
created_svc1, _ := storage.Create(ctx, svc1)
created_service_1 := created_svc1.(*api.Service)
if created_service_1.Name != "foo" {
t.Errorf("Expected foo, but got %v", created_service_1.Name)
@ -618,7 +618,7 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
}},
}}
ctx = api.NewDefaultContext()
created_svc2, _ := rest.Create(ctx, svc2)
created_svc2, _ := storage.Create(ctx, svc2)
created_service_2 := created_svc2.(*api.Service)
if created_service_2.Name != "bar" {
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"}
testIP := ""
for _, ip := range testIPs {
if !rest.serviceIPs.(*ipallocator.Range).Has(net.ParseIP(ip)) {
if !storage.serviceIPs.(*ipallocator.Range).Has(net.ParseIP(ip)) {
testIP = ip
break
}
@ -651,7 +651,7 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
},
}
ctx = api.NewDefaultContext()
created_svc3, err := rest.Create(ctx, svc3)
created_svc3, err := storage.Create(ctx, svc3)
if err != nil {
t.Fatal(err)
}
@ -662,7 +662,7 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
}
func TestServiceRegistryIPReallocation(t *testing.T) {
rest, _ := NewTestREST(t, nil)
storage, _ := NewTestREST(t, nil)
svc1 := &api.Service{
ObjectMeta: api.ObjectMeta{Name: "foo"},
@ -678,7 +678,7 @@ func TestServiceRegistryIPReallocation(t *testing.T) {
},
}
ctx := api.NewDefaultContext()
created_svc1, _ := rest.Create(ctx, svc1)
created_svc1, _ := storage.Create(ctx, svc1)
created_service_1 := created_svc1.(*api.Service)
if created_service_1.Name != "foo" {
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)
}
_, err := rest.Delete(ctx, created_service_1.Name)
_, err := storage.Delete(ctx, created_service_1.Name)
if err != nil {
t.Errorf("Unexpected error deleting service: %v", err)
}
@ -706,7 +706,7 @@ func TestServiceRegistryIPReallocation(t *testing.T) {
},
}
ctx = api.NewDefaultContext()
created_svc2, _ := rest.Create(ctx, svc2)
created_svc2, _ := storage.Create(ctx, svc2)
created_service_2 := created_svc2.(*api.Service)
if created_service_2.Name != "bar" {
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) {
rest, _ := NewTestREST(t, nil)
storage, _ := NewTestREST(t, nil)
svc := &api.Service{
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
@ -733,7 +733,7 @@ func TestServiceRegistryIPUpdate(t *testing.T) {
},
}
ctx := api.NewDefaultContext()
created_svc, _ := rest.Create(ctx, svc)
created_svc, _ := storage.Create(ctx, svc)
created_service := created_svc.(*api.Service)
if created_service.Spec.Ports[0].Port != 6502 {
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.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)
if updated_service.Spec.Ports[0].Port != 6503 {
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"}
testIP := ""
for _, ip := range testIPs {
if !rest.serviceIPs.(*ipallocator.Range).Has(net.ParseIP(ip)) {
if !storage.serviceIPs.(*ipallocator.Range).Has(net.ParseIP(ip)) {
testIP = ip
break
}
@ -764,14 +764,14 @@ func TestServiceRegistryIPUpdate(t *testing.T) {
update.Spec.Ports[0].Port = 6503
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) {
t.Errorf("Unexpected error type: %v", err)
}
}
func TestServiceRegistryIPLoadBalancer(t *testing.T) {
rest, _ := NewTestREST(t, nil)
storage, _ := NewTestREST(t, nil)
svc := &api.Service{
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
@ -787,7 +787,7 @@ func TestServiceRegistryIPLoadBalancer(t *testing.T) {
},
}
ctx := api.NewDefaultContext()
created_svc, _ := rest.Create(ctx, svc)
created_svc, _ := storage.Create(ctx, svc)
created_service := created_svc.(*api.Service)
if created_service.Spec.Ports[0].Port != 6502 {
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)
_, _, err := rest.Update(ctx, update)
_, _, err := storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(update, api.Scheme))
if err != nil {
t.Errorf("Unexpected error %v", err)
}
}
func TestUpdateServiceWithConflictingNamespace(t *testing.T) {
storage := REST{}
storage, _ := NewTestREST(t, nil)
service := &api.Service{
ObjectMeta: api.ObjectMeta{Name: "test", Namespace: "not-default"},
}
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 {
t.Error("Expected a nil object, but we got a value or created was true")
}

View File

@ -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 {
_, _, err := s.Update(ctx, serviceAccount)
_, _, err := s.Update(ctx, serviceAccount.Name, rest.DefaultUpdatedObjectInfo(serviceAccount, api.Scheme))
return err
}

View File

@ -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) {
obj, _, err := s.Update(ctx, ThirdPartyResourceData)
obj, _, err := s.Update(ctx, ThirdPartyResourceData.Name, rest.DefaultUpdatedObjectInfo(ThirdPartyResourceData, api.Scheme))
return obj.(*extensions.ThirdPartyResourceData), err
}

View File

@ -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 {
t.Errorf("Unexpected error returned from admission handler")
}
@ -108,7 +108,7 @@ func TestOtherResources(t *testing.T) {
for _, tc := range tests {
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 err == nil {

View File

@ -17,10 +17,11 @@ limitations under the License.
package antiaffinity
import (
"testing"
"k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"testing"
)
// 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 {
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 {
t.Errorf("Expected error for Anti Affinity %+v but did not get an error", test.affinity)

View File

@ -25,7 +25,7 @@ import (
func TestAdmission(t *testing.T) {
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 {
t.Errorf("Expected error returned from admission handler")
}

View File

@ -125,7 +125,7 @@ func testAdmission(t *testing.T, pod *api.Pod, handler *denyExec, shouldAccept b
// 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 {
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
{
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 {
t.Errorf("Unexpected error returned from admission handler: %v", err)
}

View File

@ -107,7 +107,7 @@ func expectNoAnnotation(t *testing.T, pod *api.Pod) {
func admit(t *testing.T, ir admission.Interface, pods []*api.Pod) {
for i := range pods {
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)
}
}

View File

@ -527,12 +527,12 @@ func TestLimitRangerIgnoresSubresource(t *testing.T) {
testPod := validPod("testPod", 1, api.ResourceRequirements{})
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 {
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 {
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
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 {
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 {
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{})
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 {
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 {
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
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 {
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 {
t.Errorf("Should have ignored calls to any subresource of pod %v", err)
}

View File

@ -43,7 +43,7 @@ func TestAdmission(t *testing.T) {
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 {
t.Errorf("Unexpected error returned from admission handler")
}
@ -75,7 +75,7 @@ func TestAdmissionNamespaceExists(t *testing.T) {
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 {
t.Errorf("Unexpected error returned from admission handler")
}
@ -96,7 +96,7 @@ func TestIgnoreAdmission(t *testing.T) {
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 {
t.Errorf("Unexpected error returned from admission handler")
}
@ -125,7 +125,7 @@ func TestAdmissionNamespaceExistsUnknownToHandler(t *testing.T) {
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 {
t.Errorf("Unexpected error returned from admission handler")
}

View File

@ -78,7 +78,7 @@ func TestAdmission(t *testing.T) {
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 {
t.Errorf("Unexpected error returned from admission handler: %v", err)
}
@ -90,47 +90,47 @@ func TestAdmission(t *testing.T) {
store.Add(namespaceObj)
// 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 {
t.Errorf("Expected error rejecting creates in a namespace when it is terminating")
}
// 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 {
t.Errorf("Unexpected error returned from admission handler: %v", err)
}
// 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 {
t.Errorf("Unexpected error returned from admission handler: %v", err)
}
// 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 {
t.Errorf("Expected an error that this namespace can never be deleted")
}
// 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 {
t.Errorf("Did not expect an error %v", err)
}
// 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 {
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 {
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 {
t.Errorf("Expected, but didn't get, an error (%v) that objects cannot be deleted in non-existant namespaces", err)
}

View File

@ -87,20 +87,20 @@ func TestAdmission(t *testing.T) {
}
// 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 {
t.Errorf("Unexpected error returned from admission handler (on ignored pv): %v", err)
}
// 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 {
t.Errorf("Unexpected error returned from admission handler (when deleting aws pv): %v", err)
}
// Errors from the cloudprovider block creation of the 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 {
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
labels := make(map[string]string)
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 {
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
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 {
t.Errorf("Expected no error when cloud provider returns empty labels")
}
@ -128,7 +128,7 @@ func TestAdmission(t *testing.T) {
labels["a"] = "1"
labels["b"] = "2"
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 {
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["a"] = "not1"
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 {
t.Errorf("Expected no error when creating aws pv")
}

View File

@ -123,7 +123,7 @@ func TestAdmissionIgnoresDelete(t *testing.T) {
t.Errorf("Unexpected error %v", err)
}
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 {
t.Errorf("ResourceQuota should admit all deletes: %v", err)
}
@ -156,11 +156,11 @@ func TestAdmissionIgnoresSubresources(t *testing.T) {
}
indexer.Add(resourceQuota)
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 {
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 {
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)
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 {
t.Errorf("Unexpected error: %v", err)
}
@ -274,7 +274,7 @@ func TestAdmitExceedQuotaLimit(t *testing.T) {
}
indexer.Add(resourceQuota)
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 {
t.Errorf("Expected an error exceeding quota")
}
@ -316,13 +316,13 @@ func TestAdmitEnforceQuotaConstraints(t *testing.T) {
indexer.Add(resourceQuota)
// verify all values are specified as required on the quota
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 {
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)
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 {
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", "")))
// 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{}})
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 {
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("", "")))
activeDeadlineSeconds := int64(30)
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 {
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
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 {
t.Errorf("Unexpected error: %v", err)
}
@ -620,7 +620,7 @@ func TestAdmitBestEffortQuotaLimitIgnoresBurstable(t *testing.T) {
}
indexer.Add(resourceQuota)
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 {
t.Errorf("Unexpected error: %v", err)
}
@ -740,7 +740,7 @@ func TestAdmissionSetsMissingNamespace(t *testing.T) {
// unset the 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 {
t.Errorf("Got unexpected error: %v", err)
}

View File

@ -953,7 +953,7 @@ func testPSPAdmit(testCaseName string, psps []*extensions.PodSecurityPolicy, pod
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)
if shouldPass && err != nil {

View File

@ -82,7 +82,7 @@ func TestAdmission(t *testing.T) {
p.Spec.SecurityContext = tc.podSc
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 {
t.Errorf("%v: unexpected error: %v", tc.name, err)
} else if err == nil && tc.expectError {
@ -96,7 +96,7 @@ func TestAdmission(t *testing.T) {
p.Spec.InitContainers = p.Spec.Containers
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 {
t.Errorf("%v: unexpected error: %v", tc.name, err)
} else if err == nil && tc.expectError {
@ -140,7 +140,7 @@ func TestPodSecurityContextAdmission(t *testing.T) {
}
for _, test := range tests {
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 {
t.Errorf("Expected error for security context %+v but did not get an error", test.securityContext)

View File

@ -32,7 +32,7 @@ import (
func TestIgnoresNonCreate(t *testing.T) {
pod := &api.Pod{}
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))
err := handler.Admit(attrs)
if err != nil {
@ -43,7 +43,7 @@ func TestIgnoresNonCreate(t *testing.T) {
func TestIgnoresNonPodResource(t *testing.T) {
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)
if err != nil {
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) {
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)
if err != nil {
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) {
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)
if err != nil {
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)
if err != nil {
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",
},
}
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)
if err == nil {
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)
if err == nil {
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{}
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)
if err != nil {
t.Errorf("Unexpected error: %v", err)
@ -167,7 +167,7 @@ func TestAssignsDefaultServiceAccountAndRejectsMissingAPIToken(t *testing.T) {
})
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)
if err == nil || !errors.IsServerTimeout(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
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)
if err != nil {
t.Errorf("Unexpected error: %v", err)
@ -208,7 +208,7 @@ func TestDeniesInvalidServiceAccount(t *testing.T) {
admit := NewServiceAccount(client)
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)
if err == nil {
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)
if err != nil {
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 {
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)
if err != nil {
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 {
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 {
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 {
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 {
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 {
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") {
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") {
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)
if err == nil {
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"}},
},
}
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)
if err != nil {
t.Errorf("Unexpected error: %v", err)
@ -660,7 +660,7 @@ func TestRejectsUnreferencedImagePullSecrets(t *testing.T) {
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)
if err == nil {
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"}},
},
}
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)
if err != nil {
t.Errorf("Unexpected error: %v", err)
@ -723,7 +723,7 @@ func TestAddImagePullSecrets(t *testing.T) {
admit.serviceAccounts.Add(sa)
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)
if err != nil {
t.Errorf("Unexpected error: %v", err)