mirror of https://github.com/k3s-io/k3s
Change rest storage Update interface to retrieve updated object
Add OldObject to admission attributes Update resthandler Patch/Update admission plumbingpull/6/head
parent
4215fe57a5
commit
29252acd1a
|
@ -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.")
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,43 +517,69 @@ func PatchResource(r rest.Patcher, scope RequestScope, typer runtime.ObjectTyper
|
|||
|
||||
}
|
||||
|
||||
type updateAdmissionFunc func(updatedObject runtime.Object) error
|
||||
type updateAdmissionFunc func(updatedObject runtime.Object, currentObject runtime.Object) error
|
||||
|
||||
// patchResource divides PatchResource for easier unit testing
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
var (
|
||||
originalObjJS []byte
|
||||
originalPatchedObjJS []byte
|
||||
lastConflictErr error
|
||||
)
|
||||
|
||||
originalObjJS, err := runtime.Encode(codec, original)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
originalPatchedObjJS, err := getPatchedJS(patchType, originalObjJS, patchJS, versionedObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
objToUpdate := patcher.New()
|
||||
if err := runtime.DecodeInto(codec, originalPatchedObjJS, objToUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := checkName(objToUpdate, name, namespace, namer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return finishRequest(timeout, func() (runtime.Object, error) {
|
||||
if err := admit(objToUpdate); err != nil {
|
||||
// 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)
|
||||
}
|
||||
|
||||
// update should never create as previous get would fail
|
||||
updateObject, _, updateErr := patcher.Update(ctx, objToUpdate)
|
||||
for i := 0; i < MaxPatchConflicts && (errors.IsConflict(updateErr)); i++ {
|
||||
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
|
||||
}
|
||||
|
||||
if js, err := getPatchedJS(patchType, originalObjJS, patchJS, versionedObj); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
originalPatchedObjJS = js
|
||||
}
|
||||
|
||||
objToUpdate := patcher.New()
|
||||
if err := runtime.DecodeInto(codec, originalPatchedObjJS, objToUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := checkName(objToUpdate, name, namespace, namer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return objToUpdate, nil
|
||||
|
||||
default:
|
||||
// on a conflict,
|
||||
// 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
|
||||
}
|
||||
|
||||
updateObject, _, updateErr = patcher.Update(ctx, objToUpdate)
|
||||
return objToUpdate, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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
|
||||
}
|
||||
transformers = append(transformers, func(ctx api.Context, newObj, oldObj runtime.Object) (runtime.Object, error) {
|
||||
userInfo, _ := api.UserFrom(ctx)
|
||||
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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -238,46 +238,40 @@ func (e *Store) Create(ctx api.Context, obj runtime.Object) (runtime.Object, err
|
|||
// Update performs an atomic update and set of the object. Returns the result of the update
|
||||
// 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
|
||||
}
|
||||
// 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
|
||||
|
||||
var (
|
||||
creatingObj runtime.Object
|
||||
creating = false
|
||||
)
|
||||
|
||||
storagePreconditions := &storage.Preconditions{}
|
||||
if preconditions := objInfo.Preconditions(); preconditions != nil {
|
||||
storagePreconditions.UID = preconditions.UID
|
||||
}
|
||||
doUnconditionalUpdate := resourceVersion == 0 && e.UpdateStrategy.AllowUnconditionalUpdate()
|
||||
// TODO: expose TTL
|
||||
creating := false
|
||||
|
||||
out := e.NewFunc()
|
||||
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)
|
||||
|
||||
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, nil, err
|
||||
}
|
||||
doUnconditionalUpdate := resourceVersion == 0 && e.UpdateStrategy.AllowUnconditionalUpdate()
|
||||
|
||||
version, err := e.Storage.Versioner().ObjectResourceVersion(existing)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@ -287,6 +281,7 @@ func (e *Store) Update(ctx api.Context, obj runtime.Object) (runtime.Object, boo
|
|||
return nil, nil, kubeerr.NewNotFound(e.QualifiedResource, name)
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue