dry-run: Use dry-runnable structure
Kubernetes-commit: 68937c4934013739a1efc1b051820667d6d6349d
This commit is contained in:
parent
3e8b2477c1
commit
dbac430f68
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package registry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/apiserver/pkg/storage"
|
||||
)
|
||||
|
||||
type DryRunnableStorage struct {
|
||||
Storage storage.Interface
|
||||
Codec runtime.Codec
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) Versioner() storage.Versioner {
|
||||
return s.Storage.Versioner()
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) Create(ctx context.Context, key string, obj, out runtime.Object, ttl uint64, dryRun bool) error {
|
||||
if dryRun {
|
||||
if err := s.Storage.Get(ctx, key, "", out, false); err == nil {
|
||||
return storage.NewKeyExistsError(key, 0)
|
||||
}
|
||||
s.copyInto(obj, out)
|
||||
return nil
|
||||
}
|
||||
return s.Storage.Create(ctx, key, obj, out, ttl)
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) Delete(ctx context.Context, key string, out runtime.Object, preconditions *storage.Preconditions, dryRun bool) error {
|
||||
if dryRun {
|
||||
if err := s.Storage.Get(ctx, key, "", out, false); err != nil {
|
||||
return err
|
||||
}
|
||||
return checkPreconditions(key, preconditions, out)
|
||||
}
|
||||
return s.Storage.Delete(ctx, key, out, preconditions)
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) Watch(ctx context.Context, key string, resourceVersion string, p storage.SelectionPredicate) (watch.Interface, error) {
|
||||
return s.Storage.Watch(ctx, key, resourceVersion, p)
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) WatchList(ctx context.Context, key string, resourceVersion string, p storage.SelectionPredicate) (watch.Interface, error) {
|
||||
return s.Storage.WatchList(ctx, key, resourceVersion, p)
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) Get(ctx context.Context, key string, resourceVersion string, objPtr runtime.Object, ignoreNotFound bool) error {
|
||||
return s.Storage.Get(ctx, key, resourceVersion, objPtr, ignoreNotFound)
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) GetToList(ctx context.Context, key string, resourceVersion string, p storage.SelectionPredicate, listObj runtime.Object) error {
|
||||
return s.Storage.GetToList(ctx, key, resourceVersion, p, listObj)
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) List(ctx context.Context, key string, resourceVersion string, p storage.SelectionPredicate, listObj runtime.Object) error {
|
||||
return s.Storage.List(ctx, key, resourceVersion, p, listObj)
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) GuaranteedUpdate(
|
||||
ctx context.Context, key string, ptrToType runtime.Object, ignoreNotFound bool,
|
||||
preconditions *storage.Preconditions, tryUpdate storage.UpdateFunc, dryRun bool, suggestion ...runtime.Object) error {
|
||||
if dryRun {
|
||||
err := s.Storage.Get(ctx, key, "", ptrToType, ignoreNotFound)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = checkPreconditions(key, preconditions, ptrToType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rev, err := s.Versioner().ObjectResourceVersion(ptrToType)
|
||||
out, _, err := tryUpdate(ptrToType, storage.ResponseMeta{ResourceVersion: rev})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.copyInto(out, ptrToType)
|
||||
return nil
|
||||
}
|
||||
return s.Storage.GuaranteedUpdate(ctx, key, ptrToType, ignoreNotFound, preconditions, tryUpdate, suggestion...)
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) Count(key string) (int64, error) {
|
||||
return s.Storage.Count(key)
|
||||
}
|
||||
|
||||
func checkPreconditions(key string, preconditions *storage.Preconditions, obj runtime.Object) error {
|
||||
if preconditions == nil {
|
||||
return nil
|
||||
}
|
||||
objMeta, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return storage.NewInternalErrorf("can't enforce preconditions %v on un-introspectable object %v, got error: %v", *preconditions, obj, err)
|
||||
}
|
||||
if preconditions.UID != nil && *preconditions.UID != objMeta.GetUID() {
|
||||
errMsg := fmt.Sprintf("Precondition failed: UID in precondition: %v, UID in object meta: %v", *preconditions.UID, objMeta.GetUID())
|
||||
return storage.NewInvalidObjError(key, errMsg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) copyInto(in, out runtime.Object) error {
|
||||
var data []byte
|
||||
|
||||
data, err := runtime.Encode(s.Codec, in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _, err = s.Codec.Decode(data, nil, out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
|
@ -0,0 +1,304 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package registry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/apitesting"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
examplev1 "k8s.io/apiserver/pkg/apis/example/v1"
|
||||
"k8s.io/apiserver/pkg/storage"
|
||||
etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend/factory"
|
||||
)
|
||||
|
||||
func NewDryRunnableTestStorage(t *testing.T) (DryRunnableStorage, func()) {
|
||||
server, sc := etcdtesting.NewUnsecuredEtcd3TestClientServer(t)
|
||||
sc.Codec = apitesting.TestStorageCodec(codecs, examplev1.SchemeGroupVersion)
|
||||
s, destroy, err := factory.Create(*sc)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating storage: %v", err)
|
||||
}
|
||||
return DryRunnableStorage{Storage: s, Codec: sc.Codec}, func() {
|
||||
destroy()
|
||||
server.Terminate(t)
|
||||
}
|
||||
}
|
||||
|
||||
func UnstructuredOrDie(j string) *unstructured.Unstructured {
|
||||
m := map[string]interface{}{}
|
||||
err := json.Unmarshal([]byte(j), &m)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Failed to unmarshal into Unstructured: %v", err))
|
||||
}
|
||||
return &unstructured.Unstructured{Object: m}
|
||||
}
|
||||
|
||||
func TestDryRunCreateDoesntCreate(t *testing.T) {
|
||||
s, destroy := NewDryRunnableTestStorage(t)
|
||||
defer destroy()
|
||||
|
||||
obj := UnstructuredOrDie(`{"kind": "Pod"}`)
|
||||
out := UnstructuredOrDie(`{}`)
|
||||
|
||||
err := s.Create(context.Background(), "key", obj, out, 0, true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create new dry-run object: %v", err)
|
||||
}
|
||||
|
||||
err = s.Get(context.Background(), "key", "", out, false)
|
||||
if e, ok := err.(*storage.StorageError); !ok || e.Code != storage.ErrCodeKeyNotFound {
|
||||
t.Errorf("Expected key to be not found, error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDryRunCreateReturnsObject(t *testing.T) {
|
||||
s, destroy := NewDryRunnableTestStorage(t)
|
||||
defer destroy()
|
||||
|
||||
obj := UnstructuredOrDie(`{"kind": "Pod"}`)
|
||||
out := UnstructuredOrDie(`{}`)
|
||||
|
||||
err := s.Create(context.Background(), "key", obj, out, 0, true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create new dry-run object: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(obj, out) {
|
||||
t.Errorf("Returned object different from input object:\nExpected: %v\nGot: %v", obj, out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDryRunCreateExistingObjectFails(t *testing.T) {
|
||||
s, destroy := NewDryRunnableTestStorage(t)
|
||||
defer destroy()
|
||||
|
||||
obj := UnstructuredOrDie(`{"kind": "Pod"}`)
|
||||
out := UnstructuredOrDie(`{}`)
|
||||
|
||||
err := s.Create(context.Background(), "key", obj, out, 0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create new object: %v", err)
|
||||
}
|
||||
|
||||
err = s.Create(context.Background(), "key", obj, out, 0, true)
|
||||
if e, ok := err.(*storage.StorageError); !ok || e.Code != storage.ErrCodeKeyExists {
|
||||
t.Errorf("Expected KeyExists error: %v", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestDryRunUpdateMissingObjectFails(t *testing.T) {
|
||||
s, destroy := NewDryRunnableTestStorage(t)
|
||||
defer destroy()
|
||||
|
||||
obj := UnstructuredOrDie(`{"kind": "Pod"}`)
|
||||
|
||||
updateFunc := func(input runtime.Object, res storage.ResponseMeta) (output runtime.Object, ttl *uint64, err error) {
|
||||
return input, nil, errors.New("UpdateFunction shouldn't be called")
|
||||
}
|
||||
|
||||
err := s.GuaranteedUpdate(context.Background(), "key", obj, false, nil, updateFunc, true)
|
||||
if e, ok := err.(*storage.StorageError); !ok || e.Code != storage.ErrCodeKeyNotFound {
|
||||
t.Errorf("Expected key to be not found, error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDryRunUpdatePreconditions(t *testing.T) {
|
||||
s, destroy := NewDryRunnableTestStorage(t)
|
||||
defer destroy()
|
||||
|
||||
obj := UnstructuredOrDie(`{"kind": "Pod", "metadata": {"uid": "my-uid"}}`)
|
||||
out := UnstructuredOrDie(`{}`)
|
||||
err := s.Create(context.Background(), "key", obj, out, 0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create new object: %v", err)
|
||||
}
|
||||
|
||||
updateFunc := func(input runtime.Object, res storage.ResponseMeta) (output runtime.Object, ttl *uint64, err error) {
|
||||
u, ok := input.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return input, nil, errors.New("Input object is not unstructured")
|
||||
}
|
||||
unstructured.SetNestedField(u.Object, "value", "field")
|
||||
return u, nil, nil
|
||||
}
|
||||
wrongID := types.UID("wrong-uid")
|
||||
myID := types.UID("my-uid")
|
||||
err = s.GuaranteedUpdate(context.Background(), "key", obj, false, &storage.Preconditions{UID: &wrongID}, updateFunc, true)
|
||||
if e, ok := err.(*storage.StorageError); !ok || e.Code != storage.ErrCodeInvalidObj {
|
||||
t.Errorf("Expected invalid object, error: %v", err)
|
||||
}
|
||||
|
||||
err = s.GuaranteedUpdate(context.Background(), "key", obj, false, &storage.Preconditions{UID: &myID}, updateFunc, true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to update with valid precondition: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDryRunUpdateDoesntUpdate(t *testing.T) {
|
||||
s, destroy := NewDryRunnableTestStorage(t)
|
||||
defer destroy()
|
||||
|
||||
obj := UnstructuredOrDie(`{"kind": "Pod"}`)
|
||||
created := UnstructuredOrDie(`{}`)
|
||||
|
||||
err := s.Create(context.Background(), "key", obj, created, 0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create new object: %v", err)
|
||||
}
|
||||
|
||||
updateFunc := func(input runtime.Object, res storage.ResponseMeta) (output runtime.Object, ttl *uint64, err error) {
|
||||
u, ok := input.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return input, nil, errors.New("Input object is not unstructured")
|
||||
}
|
||||
unstructured.SetNestedField(u.Object, "value", "field")
|
||||
return u, nil, nil
|
||||
}
|
||||
|
||||
err = s.GuaranteedUpdate(context.Background(), "key", obj, false, nil, updateFunc, true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to dry-run update: %v", err)
|
||||
}
|
||||
out := UnstructuredOrDie(`{}`)
|
||||
err = s.Get(context.Background(), "key", "", out, false)
|
||||
if !reflect.DeepEqual(created, out) {
|
||||
t.Fatalf("Returned object %q different from expected %q", created, out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDryRunUpdateReturnsObject(t *testing.T) {
|
||||
s, destroy := NewDryRunnableTestStorage(t)
|
||||
defer destroy()
|
||||
|
||||
obj := UnstructuredOrDie(`{"kind": "Pod"}`)
|
||||
out := UnstructuredOrDie(`{}`)
|
||||
|
||||
err := s.Create(context.Background(), "key", obj, out, 0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create new object: %v", err)
|
||||
}
|
||||
|
||||
updateFunc := func(input runtime.Object, res storage.ResponseMeta) (output runtime.Object, ttl *uint64, err error) {
|
||||
u, ok := input.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return input, nil, errors.New("Input object is not unstructured")
|
||||
}
|
||||
unstructured.SetNestedField(u.Object, "value", "field")
|
||||
return u, nil, nil
|
||||
}
|
||||
|
||||
err = s.GuaranteedUpdate(context.Background(), "key", obj, false, nil, updateFunc, true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to dry-run update: %v", err)
|
||||
}
|
||||
out = UnstructuredOrDie(`{"field": "value", "kind": "Pod", "metadata": {"resourceVersion": "2", "selfLink": ""}}`)
|
||||
if !reflect.DeepEqual(obj, out) {
|
||||
t.Fatalf("Returned object %#v different from expected %#v", obj, out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDryRunDeleteDoesntDelete(t *testing.T) {
|
||||
s, destroy := NewDryRunnableTestStorage(t)
|
||||
defer destroy()
|
||||
|
||||
obj := UnstructuredOrDie(`{"kind": "Pod"}`)
|
||||
out := UnstructuredOrDie(`{}`)
|
||||
|
||||
err := s.Create(context.Background(), "key", obj, out, 0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create new object: %v", err)
|
||||
}
|
||||
|
||||
err = s.Delete(context.Background(), "key", out, nil, true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to dry-run delete the object: %v", err)
|
||||
}
|
||||
|
||||
err = s.Get(context.Background(), "key", "", out, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to retrieve dry-run deleted object: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDryRunDeleteMissingObjectFails(t *testing.T) {
|
||||
s, destroy := NewDryRunnableTestStorage(t)
|
||||
defer destroy()
|
||||
|
||||
out := UnstructuredOrDie(`{}`)
|
||||
err := s.Delete(context.Background(), "key", out, nil, true)
|
||||
if e, ok := err.(*storage.StorageError); !ok || e.Code != storage.ErrCodeKeyNotFound {
|
||||
t.Errorf("Expected key to be not found, error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDryRunDeleteReturnsObject(t *testing.T) {
|
||||
s, destroy := NewDryRunnableTestStorage(t)
|
||||
defer destroy()
|
||||
|
||||
obj := UnstructuredOrDie(`{"kind": "Pod"}`)
|
||||
out := UnstructuredOrDie(`{}`)
|
||||
|
||||
err := s.Create(context.Background(), "key", obj, out, 0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create new object: %v", err)
|
||||
}
|
||||
|
||||
out = UnstructuredOrDie(`{}`)
|
||||
expected := UnstructuredOrDie(`{"kind": "Pod", "metadata": {"resourceVersion": "2", "selfLink": ""}}`)
|
||||
err = s.Delete(context.Background(), "key", out, nil, true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to delete with valid precondition: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(expected, out) {
|
||||
t.Fatalf("Returned object %q doesn't match expected: %q", out, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDryRunDeletePreconditions(t *testing.T) {
|
||||
s, destroy := NewDryRunnableTestStorage(t)
|
||||
defer destroy()
|
||||
|
||||
obj := UnstructuredOrDie(`{"kind": "Pod", "metadata": {"uid": "my-uid"}}`)
|
||||
out := UnstructuredOrDie(`{}`)
|
||||
|
||||
err := s.Create(context.Background(), "key", obj, out, 0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create new object: %v", err)
|
||||
}
|
||||
|
||||
wrongID := types.UID("wrong-uid")
|
||||
myID := types.UID("my-uid")
|
||||
err = s.Delete(context.Background(), "key", out, &storage.Preconditions{UID: &wrongID}, true)
|
||||
if e, ok := err.(*storage.StorageError); !ok || e.Code != storage.ErrCodeInvalidObj {
|
||||
t.Errorf("Expected invalid object, error: %v", err)
|
||||
}
|
||||
|
||||
err = s.Delete(context.Background(), "key", out, &storage.Preconditions{UID: &myID}, true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to delete with valid precondition: %v", err)
|
||||
}
|
||||
}
|
|
@ -45,6 +45,7 @@ import (
|
|||
"k8s.io/apiserver/pkg/storage"
|
||||
storeerr "k8s.io/apiserver/pkg/storage/errors"
|
||||
"k8s.io/apiserver/pkg/storage/etcd/metrics"
|
||||
"k8s.io/apiserver/pkg/util/dryrun"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
@ -172,8 +173,10 @@ type Store struct {
|
|||
// of items into tabular output. If unset, the default will be used.
|
||||
TableConvertor rest.TableConvertor
|
||||
|
||||
// Storage is the interface for the underlying storage for the resource.
|
||||
Storage storage.Interface
|
||||
// Storage is the interface for the underlying storage for the
|
||||
// resource. It is wrapped into a "DryRunnableStorage" that will
|
||||
// either pass-through or simply dry-run.
|
||||
Storage DryRunnableStorage
|
||||
// Called to cleanup clients used by the underlying Storage; optional.
|
||||
DestroyFunc func()
|
||||
}
|
||||
|
@ -348,7 +351,7 @@ func (e *Store) Create(ctx context.Context, obj runtime.Object, createValidation
|
|||
return nil, err
|
||||
}
|
||||
out := e.NewFunc()
|
||||
if err := e.Storage.Create(ctx, key, obj, out, ttl); err != nil {
|
||||
if err := e.Storage.Create(ctx, key, obj, out, ttl, dryrun.IsDryRun(options.DryRun)); err != nil {
|
||||
err = storeerr.InterpretCreateError(err, qualifiedResource, name)
|
||||
err = rest.CheckGeneratedNameError(e.CreateStrategy, err, obj)
|
||||
if !kubeerr.IsAlreadyExists(err) {
|
||||
|
@ -496,10 +499,10 @@ func (e *Store) shouldDeleteForFailedInitialization(ctx context.Context, obj run
|
|||
|
||||
// deleteWithoutFinalizers handles deleting an object ignoring its finalizer list.
|
||||
// Used for objects that are either been finalized or have never initialized.
|
||||
func (e *Store) deleteWithoutFinalizers(ctx context.Context, name, key string, obj runtime.Object, preconditions *storage.Preconditions) (runtime.Object, bool, error) {
|
||||
func (e *Store) deleteWithoutFinalizers(ctx context.Context, name, key string, obj runtime.Object, preconditions *storage.Preconditions, dryRun bool) (runtime.Object, bool, error) {
|
||||
out := e.NewFunc()
|
||||
glog.V(6).Infof("going to delete %s from registry, triggered by update", name)
|
||||
if err := e.Storage.Delete(ctx, key, out, preconditions); err != nil {
|
||||
if err := e.Storage.Delete(ctx, key, out, preconditions, dryRun); err != nil {
|
||||
// Deletion is racy, i.e., there could be multiple update
|
||||
// requests to remove all finalizers from the object, so we
|
||||
// ignore the NotFound error.
|
||||
|
@ -633,12 +636,12 @@ func (e *Store) Update(ctx context.Context, name string, objInfo rest.UpdatedObj
|
|||
return obj, &ttl, nil
|
||||
}
|
||||
return obj, nil, nil
|
||||
})
|
||||
}, dryrun.IsDryRun(options.DryRun))
|
||||
|
||||
if err != nil {
|
||||
// delete the object
|
||||
if err == errEmptiedFinalizers {
|
||||
return e.deleteWithoutFinalizers(ctx, name, key, deleteObj, storagePreconditions)
|
||||
return e.deleteWithoutFinalizers(ctx, name, key, deleteObj, storagePreconditions, dryrun.IsDryRun(options.DryRun))
|
||||
}
|
||||
if creating {
|
||||
err = storeerr.InterpretCreateError(err, qualifiedResource, name)
|
||||
|
@ -650,7 +653,7 @@ func (e *Store) Update(ctx context.Context, name string, objInfo rest.UpdatedObj
|
|||
}
|
||||
|
||||
if e.shouldDeleteForFailedInitialization(ctx, out) {
|
||||
return e.deleteWithoutFinalizers(ctx, name, key, out, storagePreconditions)
|
||||
return e.deleteWithoutFinalizers(ctx, name, key, out, storagePreconditions, dryrun.IsDryRun(options.DryRun))
|
||||
}
|
||||
|
||||
if creating {
|
||||
|
@ -919,6 +922,7 @@ func (e *Store) updateForGracefulDeletionAndFinalizers(ctx context.Context, name
|
|||
lastExisting = existing
|
||||
return existing, nil
|
||||
}),
|
||||
dryrun.IsDryRun(options.DryRun),
|
||||
)
|
||||
switch err {
|
||||
case nil:
|
||||
|
@ -1000,10 +1004,15 @@ func (e *Store) Delete(ctx context.Context, name string, options *metav1.DeleteO
|
|||
return out, false, err
|
||||
}
|
||||
|
||||
// If dry-run, then just return the object as just saved.
|
||||
if dryrun.IsDryRun(options.DryRun) {
|
||||
return out, true, nil
|
||||
}
|
||||
|
||||
// delete immediately, or no graceful deletion supported
|
||||
glog.V(6).Infof("going to delete %s from registry: ", name)
|
||||
out = e.NewFunc()
|
||||
if err := e.Storage.Delete(ctx, key, out, &preconditions); err != nil {
|
||||
if err := e.Storage.Delete(ctx, key, out, &preconditions, dryrun.IsDryRun(options.DryRun)); err != nil {
|
||||
// Please refer to the place where we set ignoreNotFound for the reason
|
||||
// why we ignore the NotFound error .
|
||||
if storage.IsNotFound(err) && ignoreNotFound && lastExisting != nil {
|
||||
|
@ -1364,8 +1373,9 @@ func (e *Store) CompleteWithOptions(options *generic.StoreOptions) error {
|
|||
}
|
||||
}
|
||||
|
||||
if e.Storage == nil {
|
||||
e.Storage, e.DestroyFunc = opts.Decorator(
|
||||
if e.Storage.Storage == nil {
|
||||
e.Storage.Codec = opts.StorageConfig.Codec
|
||||
e.Storage.Storage, e.DestroyFunc = opts.Decorator(
|
||||
opts.StorageConfig,
|
||||
e.NewFunc(),
|
||||
prefix,
|
||||
|
|
|
@ -213,7 +213,7 @@ func TestStoreList(t *testing.T) {
|
|||
destroyFunc, registry := NewTestGenericStoreRegistry(t)
|
||||
|
||||
if item.in != nil {
|
||||
if err := storagetesting.CreateList("/pods", registry.Storage, item.in); err != nil {
|
||||
if err := storagetesting.CreateList("/pods", registry.Storage.Storage, item.in); err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
}
|
||||
|
@ -1901,7 +1901,7 @@ func newTestGenericStoreRegistry(t *testing.T, scheme *runtime.Scheme, hasCacheE
|
|||
},
|
||||
}
|
||||
},
|
||||
Storage: s,
|
||||
Storage: DryRunnableStorage{Storage: s},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ func (t *Tester) createObject(ctx context.Context, obj runtime.Object) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.storage.Storage.Create(ctx, key, obj, nil, 0)
|
||||
return t.storage.Storage.Create(ctx, key, obj, nil, 0, false)
|
||||
}
|
||||
|
||||
func (t *Tester) setObjectsForList(objects []runtime.Object) []runtime.Object {
|
||||
|
@ -173,7 +173,7 @@ func (t *Tester) setObjectsForList(objects []runtime.Object) []runtime.Object {
|
|||
t.tester.Errorf("unable to clear collection: %v", err)
|
||||
return nil
|
||||
}
|
||||
if err := storagetesting.CreateObjList(key, t.storage.Storage, objects); err != nil {
|
||||
if err := storagetesting.CreateObjList(key, t.storage.Storage.Storage, objects); err != nil {
|
||||
t.tester.Errorf("unexpected error: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dryrun
|
||||
|
||||
// IsDryRun returns true if the DryRun flag is an actual dry-run.
|
||||
func IsDryRun(flag []string) bool {
|
||||
return len(flag) > 0
|
||||
}
|
Loading…
Reference in New Issue