mirror of https://github.com/k3s-io/k3s
dry-run: Use dry-runnable structure
parent
dab04dc6e0
commit
68937c4934
|
@ -59,6 +59,7 @@ go_library(
|
||||||
"//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/storage:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage/errors:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/storage/errors:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/util/dryrun:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
"k8s.io/apiserver/pkg/storage"
|
"k8s.io/apiserver/pkg/storage"
|
||||||
storeerr "k8s.io/apiserver/pkg/storage/errors"
|
storeerr "k8s.io/apiserver/pkg/storage/errors"
|
||||||
|
"k8s.io/apiserver/pkg/util/dryrun"
|
||||||
appsv1beta1 "k8s.io/kubernetes/pkg/apis/apps/v1beta1"
|
appsv1beta1 "k8s.io/kubernetes/pkg/apis/apps/v1beta1"
|
||||||
appsv1beta2 "k8s.io/kubernetes/pkg/apis/apps/v1beta2"
|
appsv1beta2 "k8s.io/kubernetes/pkg/apis/apps/v1beta2"
|
||||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||||
|
@ -171,7 +172,7 @@ func (r *RollbackREST) Create(ctx context.Context, obj runtime.Object, createVal
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the Deployment with information in DeploymentRollback to trigger rollback
|
// Update the Deployment with information in DeploymentRollback to trigger rollback
|
||||||
err := r.rollbackDeployment(ctx, rollback.Name, &rollback.RollbackTo, rollback.UpdatedAnnotations)
|
err := r.rollbackDeployment(ctx, rollback.Name, &rollback.RollbackTo, rollback.UpdatedAnnotations, dryrun.IsDryRun(options.DryRun))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -182,8 +183,8 @@ func (r *RollbackREST) Create(ctx context.Context, obj runtime.Object, createVal
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RollbackREST) rollbackDeployment(ctx context.Context, deploymentID string, config *extensions.RollbackConfig, annotations map[string]string) error {
|
func (r *RollbackREST) rollbackDeployment(ctx context.Context, deploymentID string, config *extensions.RollbackConfig, annotations map[string]string, dryRun bool) error {
|
||||||
if _, err := r.setDeploymentRollback(ctx, deploymentID, config, annotations); err != nil {
|
if _, err := r.setDeploymentRollback(ctx, deploymentID, config, annotations, dryRun); err != nil {
|
||||||
err = storeerr.InterpretGetError(err, extensions.Resource("deployments"), deploymentID)
|
err = storeerr.InterpretGetError(err, extensions.Resource("deployments"), deploymentID)
|
||||||
err = storeerr.InterpretUpdateError(err, extensions.Resource("deployments"), deploymentID)
|
err = storeerr.InterpretUpdateError(err, extensions.Resource("deployments"), deploymentID)
|
||||||
if _, ok := err.(*errors.StatusError); !ok {
|
if _, ok := err.(*errors.StatusError); !ok {
|
||||||
|
@ -194,7 +195,7 @@ func (r *RollbackREST) rollbackDeployment(ctx context.Context, deploymentID stri
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RollbackREST) setDeploymentRollback(ctx context.Context, deploymentID string, config *extensions.RollbackConfig, annotations map[string]string) (*extensions.Deployment, error) {
|
func (r *RollbackREST) setDeploymentRollback(ctx context.Context, deploymentID string, config *extensions.RollbackConfig, annotations map[string]string, dryRun bool) (*extensions.Deployment, error) {
|
||||||
dKey, err := r.store.KeyFunc(ctx, deploymentID)
|
dKey, err := r.store.KeyFunc(ctx, deploymentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -214,7 +215,7 @@ func (r *RollbackREST) setDeploymentRollback(ctx context.Context, deploymentID s
|
||||||
d.Spec.RollbackTo = config
|
d.Spec.RollbackTo = config
|
||||||
finalDeployment = d
|
finalDeployment = d
|
||||||
return d, nil
|
return d, nil
|
||||||
}))
|
}), dryRun)
|
||||||
return finalDeployment, err
|
return finalDeployment, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -205,7 +205,7 @@ func TestScaleGet(t *testing.T) {
|
||||||
var deployment extensions.Deployment
|
var deployment extensions.Deployment
|
||||||
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace)
|
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace)
|
||||||
key := "/deployments/" + namespace + "/" + name
|
key := "/deployments/" + namespace + "/" + name
|
||||||
if err := storage.Deployment.Storage.Create(ctx, key, &validDeployment, &deployment, 0); err != nil {
|
if err := storage.Deployment.Storage.Create(ctx, key, &validDeployment, &deployment, 0, false); err != nil {
|
||||||
t.Fatalf("error setting new deployment (key: %s) %v: %v", key, validDeployment, err)
|
t.Fatalf("error setting new deployment (key: %s) %v: %v", key, validDeployment, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,7 +246,7 @@ func TestScaleUpdate(t *testing.T) {
|
||||||
var deployment extensions.Deployment
|
var deployment extensions.Deployment
|
||||||
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace)
|
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace)
|
||||||
key := "/deployments/" + namespace + "/" + name
|
key := "/deployments/" + namespace + "/" + name
|
||||||
if err := storage.Deployment.Storage.Create(ctx, key, &validDeployment, &deployment, 0); err != nil {
|
if err := storage.Deployment.Storage.Create(ctx, key, &validDeployment, &deployment, 0, false); err != nil {
|
||||||
t.Fatalf("error setting new deployment (key: %s) %v: %v", key, validDeployment, err)
|
t.Fatalf("error setting new deployment (key: %s) %v: %v", key, validDeployment, err)
|
||||||
}
|
}
|
||||||
replicas := int32(12)
|
replicas := int32(12)
|
||||||
|
@ -283,7 +283,7 @@ func TestStatusUpdate(t *testing.T) {
|
||||||
defer storage.Deployment.Store.DestroyFunc()
|
defer storage.Deployment.Store.DestroyFunc()
|
||||||
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace)
|
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace)
|
||||||
key := "/deployments/" + namespace + "/" + name
|
key := "/deployments/" + namespace + "/" + name
|
||||||
if err := storage.Deployment.Storage.Create(ctx, key, &validDeployment, nil, 0); err != nil {
|
if err := storage.Deployment.Storage.Create(ctx, key, &validDeployment, nil, 0, false); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
update := extensions.Deployment{
|
update := extensions.Deployment{
|
||||||
|
|
|
@ -260,7 +260,7 @@ func TestScaleGet(t *testing.T) {
|
||||||
var rs extensions.ReplicaSet
|
var rs extensions.ReplicaSet
|
||||||
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
||||||
key := "/replicasets/" + metav1.NamespaceDefault + "/" + name
|
key := "/replicasets/" + metav1.NamespaceDefault + "/" + name
|
||||||
if err := storage.ReplicaSet.Storage.Create(ctx, key, &validReplicaSet, &rs, 0); err != nil {
|
if err := storage.ReplicaSet.Storage.Create(ctx, key, &validReplicaSet, &rs, 0, false); err != nil {
|
||||||
t.Fatalf("error setting new replica set (key: %s) %v: %v", key, validReplicaSet, err)
|
t.Fatalf("error setting new replica set (key: %s) %v: %v", key, validReplicaSet, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,7 +305,7 @@ func TestScaleUpdate(t *testing.T) {
|
||||||
var rs extensions.ReplicaSet
|
var rs extensions.ReplicaSet
|
||||||
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
||||||
key := "/replicasets/" + metav1.NamespaceDefault + "/" + name
|
key := "/replicasets/" + metav1.NamespaceDefault + "/" + name
|
||||||
if err := storage.ReplicaSet.Storage.Create(ctx, key, &validReplicaSet, &rs, 0); err != nil {
|
if err := storage.ReplicaSet.Storage.Create(ctx, key, &validReplicaSet, &rs, 0, false); err != nil {
|
||||||
t.Fatalf("error setting new replica set (key: %s) %v: %v", key, validReplicaSet, err)
|
t.Fatalf("error setting new replica set (key: %s) %v: %v", key, validReplicaSet, err)
|
||||||
}
|
}
|
||||||
replicas := 12
|
replicas := 12
|
||||||
|
@ -347,7 +347,7 @@ func TestStatusUpdate(t *testing.T) {
|
||||||
|
|
||||||
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
||||||
key := "/replicasets/" + metav1.NamespaceDefault + "/foo"
|
key := "/replicasets/" + metav1.NamespaceDefault + "/foo"
|
||||||
if err := storage.ReplicaSet.Storage.Create(ctx, key, &validReplicaSet, nil, 0); err != nil {
|
if err := storage.ReplicaSet.Storage.Create(ctx, key, &validReplicaSet, nil, 0, false); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
update := extensions.ReplicaSet{
|
update := extensions.ReplicaSet{
|
||||||
|
|
|
@ -102,7 +102,7 @@ func TestStatusUpdate(t *testing.T) {
|
||||||
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
||||||
key := "/statefulsets/" + metav1.NamespaceDefault + "/foo"
|
key := "/statefulsets/" + metav1.NamespaceDefault + "/foo"
|
||||||
validStatefulSet := validNewStatefulSet()
|
validStatefulSet := validNewStatefulSet()
|
||||||
if err := storage.StatefulSet.Storage.Create(ctx, key, validStatefulSet, nil, 0); err != nil {
|
if err := storage.StatefulSet.Storage.Create(ctx, key, validStatefulSet, nil, 0, false); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
update := apps.StatefulSet{
|
update := apps.StatefulSet{
|
||||||
|
@ -210,7 +210,7 @@ func TestScaleGet(t *testing.T) {
|
||||||
var sts apps.StatefulSet
|
var sts apps.StatefulSet
|
||||||
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
||||||
key := "/statefulsets/" + metav1.NamespaceDefault + "/" + name
|
key := "/statefulsets/" + metav1.NamespaceDefault + "/" + name
|
||||||
if err := storage.StatefulSet.Storage.Create(ctx, key, &validStatefulSet, &sts, 0); err != nil {
|
if err := storage.StatefulSet.Storage.Create(ctx, key, &validStatefulSet, &sts, 0, false); err != nil {
|
||||||
t.Fatalf("error setting new statefulset (key: %s) %v: %v", key, validStatefulSet, err)
|
t.Fatalf("error setting new statefulset (key: %s) %v: %v", key, validStatefulSet, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ func TestScaleUpdate(t *testing.T) {
|
||||||
var sts apps.StatefulSet
|
var sts apps.StatefulSet
|
||||||
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
||||||
key := "/statefulsets/" + metav1.NamespaceDefault + "/" + name
|
key := "/statefulsets/" + metav1.NamespaceDefault + "/" + name
|
||||||
if err := storage.StatefulSet.Storage.Create(ctx, key, &validStatefulSet, &sts, 0); err != nil {
|
if err := storage.StatefulSet.Storage.Create(ctx, key, &validStatefulSet, &sts, 0, false); err != nil {
|
||||||
t.Fatalf("error setting new statefulset (key: %s) %v: %v", key, validStatefulSet, err)
|
t.Fatalf("error setting new statefulset (key: %s) %v: %v", key, validStatefulSet, err)
|
||||||
}
|
}
|
||||||
replicas := 12
|
replicas := 12
|
||||||
|
|
|
@ -177,7 +177,7 @@ func TestUpdateStatus(t *testing.T) {
|
||||||
ctx := genericapirequest.NewDefaultContext()
|
ctx := genericapirequest.NewDefaultContext()
|
||||||
key, _ := storage.KeyFunc(ctx, "foo")
|
key, _ := storage.KeyFunc(ctx, "foo")
|
||||||
autoscalerStart := validNewHorizontalPodAutoscaler("foo")
|
autoscalerStart := validNewHorizontalPodAutoscaler("foo")
|
||||||
err := storage.Storage.Create(ctx, key, autoscalerStart, nil, 0)
|
err := storage.Storage.Create(ctx, key, autoscalerStart, nil, 0, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ go_library(
|
||||||
"//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/storage:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage/errors:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/storage/errors:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/util/dryrun:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
"k8s.io/apiserver/pkg/storage"
|
"k8s.io/apiserver/pkg/storage"
|
||||||
storageerr "k8s.io/apiserver/pkg/storage/errors"
|
storageerr "k8s.io/apiserver/pkg/storage/errors"
|
||||||
|
"k8s.io/apiserver/pkg/util/dryrun"
|
||||||
|
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/printers"
|
"k8s.io/kubernetes/pkg/printers"
|
||||||
|
@ -190,6 +191,7 @@ func (r *REST) Delete(ctx context.Context, name string, options *metav1.DeleteOp
|
||||||
}
|
}
|
||||||
return existingNamespace, nil
|
return existingNamespace, nil
|
||||||
}),
|
}),
|
||||||
|
dryrun.IsDryRun(options.DryRun),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -156,7 +156,7 @@ func TestDeleteNamespaceWithIncompleteFinalizers(t *testing.T) {
|
||||||
},
|
},
|
||||||
Status: api.NamespaceStatus{Phase: api.NamespaceActive},
|
Status: api.NamespaceStatus{Phase: api.NamespaceActive},
|
||||||
}
|
}
|
||||||
if err := storage.store.Storage.Create(ctx, key, namespace, nil, 0); err != nil {
|
if err := storage.store.Storage.Create(ctx, key, namespace, nil, 0, false); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if _, _, err := storage.Delete(ctx, "foo", nil); err == nil {
|
if _, _, err := storage.Delete(ctx, "foo", nil); err == nil {
|
||||||
|
@ -181,7 +181,7 @@ func TestDeleteNamespaceWithCompleteFinalizers(t *testing.T) {
|
||||||
},
|
},
|
||||||
Status: api.NamespaceStatus{Phase: api.NamespaceActive},
|
Status: api.NamespaceStatus{Phase: api.NamespaceActive},
|
||||||
}
|
}
|
||||||
if err := storage.store.Storage.Create(ctx, key, namespace, nil, 0); err != nil {
|
if err := storage.store.Storage.Create(ctx, key, namespace, nil, 0, false); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if _, _, err := storage.Delete(ctx, "foo", nil); err != nil {
|
if _, _, err := storage.Delete(ctx, "foo", nil); err != nil {
|
||||||
|
|
|
@ -169,7 +169,7 @@ func TestUpdateStatus(t *testing.T) {
|
||||||
ctx := genericapirequest.NewContext()
|
ctx := genericapirequest.NewContext()
|
||||||
key, _ := storage.KeyFunc(ctx, "foo")
|
key, _ := storage.KeyFunc(ctx, "foo")
|
||||||
pvStart := validNewPersistentVolume("foo")
|
pvStart := validNewPersistentVolume("foo")
|
||||||
err := storage.Storage.Create(ctx, key, pvStart, nil, 0)
|
err := storage.Storage.Create(ctx, key, pvStart, nil, 0, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,7 +159,7 @@ func TestUpdateStatus(t *testing.T) {
|
||||||
|
|
||||||
key, _ := storage.KeyFunc(ctx, "foo")
|
key, _ := storage.KeyFunc(ctx, "foo")
|
||||||
pvcStart := validNewPersistentVolumeClaim("foo", metav1.NamespaceDefault)
|
pvcStart := validNewPersistentVolumeClaim("foo", metav1.NamespaceDefault)
|
||||||
err := storage.Storage.Create(ctx, key, pvcStart, nil, 0)
|
err := storage.Storage.Create(ctx, key, pvcStart, nil, 0, false)
|
||||||
|
|
||||||
pvc := &api.PersistentVolumeClaim{
|
pvc := &api.PersistentVolumeClaim{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
|
|
@ -33,7 +33,7 @@ func TestPodLogValidates(t *testing.T) {
|
||||||
s, destroyFunc := generic.NewRawStorage(config)
|
s, destroyFunc := generic.NewRawStorage(config)
|
||||||
defer destroyFunc()
|
defer destroyFunc()
|
||||||
store := &genericregistry.Store{
|
store := &genericregistry.Store{
|
||||||
Storage: s,
|
Storage: genericregistry.DryRunnableStorage{Storage: s},
|
||||||
}
|
}
|
||||||
logRest := &LogREST{Store: store, KubeletConn: nil}
|
logRest := &LogREST{Store: store, KubeletConn: nil}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ go_test(
|
||||||
"//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/features:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/features:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/registry/generic/registry:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/registry/generic/testing:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/registry/generic/testing:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/storage:go_default_library",
|
||||||
|
@ -66,6 +67,7 @@ go_library(
|
||||||
"//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/storage:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage/errors:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/storage/errors:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/util/dryrun:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/util/retry:go_default_library",
|
"//staging/src/k8s.io/client-go/util/retry:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
"k8s.io/apiserver/pkg/storage"
|
"k8s.io/apiserver/pkg/storage"
|
||||||
storeerr "k8s.io/apiserver/pkg/storage/errors"
|
storeerr "k8s.io/apiserver/pkg/storage/errors"
|
||||||
|
"k8s.io/apiserver/pkg/util/dryrun"
|
||||||
podutil "k8s.io/kubernetes/pkg/api/pod"
|
podutil "k8s.io/kubernetes/pkg/api/pod"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||||
|
@ -148,7 +149,7 @@ func (r *BindingREST) Create(ctx context.Context, obj runtime.Object, createVali
|
||||||
return nil, errs.ToAggregate()
|
return nil, errs.ToAggregate()
|
||||||
}
|
}
|
||||||
|
|
||||||
err = r.assignPod(ctx, binding.Name, binding.Target.Name, binding.Annotations)
|
err = r.assignPod(ctx, binding.Name, binding.Target.Name, binding.Annotations, dryrun.IsDryRun(options.DryRun))
|
||||||
out = &metav1.Status{Status: metav1.StatusSuccess}
|
out = &metav1.Status{Status: metav1.StatusSuccess}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -156,7 +157,7 @@ func (r *BindingREST) Create(ctx context.Context, obj runtime.Object, createVali
|
||||||
// setPodHostAndAnnotations sets the given pod's host to 'machine' if and only if it was
|
// setPodHostAndAnnotations sets the given pod's host to 'machine' if and only if it was
|
||||||
// previously 'oldMachine' and merges the provided annotations with those of the pod.
|
// previously 'oldMachine' and merges the provided annotations with those of the pod.
|
||||||
// Returns the current state of the pod, or an error.
|
// Returns the current state of the pod, or an error.
|
||||||
func (r *BindingREST) setPodHostAndAnnotations(ctx context.Context, podID, oldMachine, machine string, annotations map[string]string) (finalPod *api.Pod, err error) {
|
func (r *BindingREST) setPodHostAndAnnotations(ctx context.Context, podID, oldMachine, machine string, annotations map[string]string, dryRun bool) (finalPod *api.Pod, err error) {
|
||||||
podKey, err := r.store.KeyFunc(ctx, podID)
|
podKey, err := r.store.KeyFunc(ctx, podID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -185,13 +186,13 @@ func (r *BindingREST) setPodHostAndAnnotations(ctx context.Context, podID, oldMa
|
||||||
})
|
})
|
||||||
finalPod = pod
|
finalPod = pod
|
||||||
return pod, nil
|
return pod, nil
|
||||||
}))
|
}), dryRun)
|
||||||
return finalPod, err
|
return finalPod, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// assignPod assigns the given pod to the given machine.
|
// assignPod assigns the given pod to the given machine.
|
||||||
func (r *BindingREST) assignPod(ctx context.Context, podID string, machine string, annotations map[string]string) (err error) {
|
func (r *BindingREST) assignPod(ctx context.Context, podID string, machine string, annotations map[string]string, dryRun bool) (err error) {
|
||||||
if _, err = r.setPodHostAndAnnotations(ctx, podID, "", machine, annotations); err != nil {
|
if _, err = r.setPodHostAndAnnotations(ctx, podID, "", machine, annotations, dryRun); err != nil {
|
||||||
err = storeerr.InterpretGetError(err, api.Resource("pods"), podID)
|
err = storeerr.InterpretGetError(err, api.Resource("pods"), podID)
|
||||||
err = storeerr.InterpretUpdateError(err, api.Resource("pods"), podID)
|
err = storeerr.InterpretUpdateError(err, api.Resource("pods"), podID)
|
||||||
if _, ok := err.(*errors.StatusError); !ok {
|
if _, ok := err.(*errors.StatusError); !ok {
|
||||||
|
|
|
@ -34,6 +34,7 @@ import (
|
||||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||||
"k8s.io/apiserver/pkg/features"
|
"k8s.io/apiserver/pkg/features"
|
||||||
"k8s.io/apiserver/pkg/registry/generic"
|
"k8s.io/apiserver/pkg/registry/generic"
|
||||||
|
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||||
genericregistrytest "k8s.io/apiserver/pkg/registry/generic/testing"
|
genericregistrytest "k8s.io/apiserver/pkg/registry/generic/testing"
|
||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
"k8s.io/apiserver/pkg/storage"
|
"k8s.io/apiserver/pkg/storage"
|
||||||
|
@ -170,7 +171,7 @@ func newFailDeleteStorage(t *testing.T, called *bool) (*REST, *etcdtesting.EtcdT
|
||||||
ResourcePrefix: "pods",
|
ResourcePrefix: "pods",
|
||||||
}
|
}
|
||||||
storage := NewStorage(restOptions, nil, nil, nil)
|
storage := NewStorage(restOptions, nil, nil, nil)
|
||||||
storage.Pod.Store.Storage = FailDeletionStorage{storage.Pod.Store.Storage, called}
|
storage.Pod.Store.Storage = genericregistry.DryRunnableStorage{Storage: FailDeletionStorage{storage.Pod.Store.Storage.Storage, called}}
|
||||||
return storage.Pod, server
|
return storage.Pod, server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,7 +341,7 @@ func TestResourceLocation(t *testing.T) {
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
storage, _, _, server := newStorage(t)
|
storage, _, _, server := newStorage(t)
|
||||||
key, _ := storage.KeyFunc(ctx, tc.pod.Name)
|
key, _ := storage.KeyFunc(ctx, tc.pod.Name)
|
||||||
if err := storage.Storage.Create(ctx, key, &tc.pod, nil, 0); err != nil {
|
if err := storage.Storage.Create(ctx, key, &tc.pod, nil, 0, false); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -825,7 +826,7 @@ func TestEtcdUpdateScheduled(t *testing.T) {
|
||||||
SecurityContext: &api.PodSecurityContext{},
|
SecurityContext: &api.PodSecurityContext{},
|
||||||
SchedulerName: api.DefaultSchedulerName,
|
SchedulerName: api.DefaultSchedulerName,
|
||||||
},
|
},
|
||||||
}, nil, 1)
|
}, nil, 1, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -897,7 +898,7 @@ func TestEtcdUpdateStatus(t *testing.T) {
|
||||||
SchedulerName: api.DefaultSchedulerName,
|
SchedulerName: api.DefaultSchedulerName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := storage.Storage.Create(ctx, key, &podStart, nil, 0)
|
err := storage.Storage.Create(ctx, key, &podStart, nil, 0, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,7 +162,7 @@ func TestUpdateStatus(t *testing.T) {
|
||||||
|
|
||||||
key, _ := storage.KeyFunc(ctx, "foo")
|
key, _ := storage.KeyFunc(ctx, "foo")
|
||||||
resourcequotaStart := validNewResourceQuota()
|
resourcequotaStart := validNewResourceQuota()
|
||||||
err := storage.Storage.Create(ctx, key, resourcequotaStart, nil, 0)
|
err := storage.Storage.Create(ctx, key, resourcequotaStart, nil, 0, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,7 +174,7 @@ func NewTestRESTWithPods(t *testing.T, endpoints *api.EndpointsList, pods *api.P
|
||||||
ctx := genericapirequest.NewDefaultContext()
|
ctx := genericapirequest.NewDefaultContext()
|
||||||
for ix := range pods.Items {
|
for ix := range pods.Items {
|
||||||
key, _ := podStorage.Pod.KeyFunc(ctx, pods.Items[ix].Name)
|
key, _ := podStorage.Pod.KeyFunc(ctx, pods.Items[ix].Name)
|
||||||
if err := podStorage.Pod.Storage.Create(ctx, key, &pods.Items[ix], nil, 0); err != nil {
|
if err := podStorage.Pod.Storage.Create(ctx, key, &pods.Items[ix], nil, 0, false); err != nil {
|
||||||
t.Fatalf("Couldn't create pod: %v", err)
|
t.Fatalf("Couldn't create pod: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,7 @@ func NewTestRESTWithPods(t *testing.T, endpoints *api.EndpointsList, pods *api.P
|
||||||
ctx := genericapirequest.NewDefaultContext()
|
ctx := genericapirequest.NewDefaultContext()
|
||||||
for ix := range endpoints.Items {
|
for ix := range endpoints.Items {
|
||||||
key, _ := endpointStorage.KeyFunc(ctx, endpoints.Items[ix].Name)
|
key, _ := endpointStorage.KeyFunc(ctx, endpoints.Items[ix].Name)
|
||||||
if err := endpointStorage.Store.Storage.Create(ctx, key, &endpoints.Items[ix], nil, 0); err != nil {
|
if err := endpointStorage.Store.Storage.Create(ctx, key, &endpoints.Items[ix], nil, 0, false); err != nil {
|
||||||
t.Fatalf("Couldn't create endpoint: %v", err)
|
t.Fatalf("Couldn't create endpoint: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ func TestStatusUpdate(t *testing.T) {
|
||||||
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
||||||
key := "/poddisruptionbudgets/" + metav1.NamespaceDefault + "/foo"
|
key := "/poddisruptionbudgets/" + metav1.NamespaceDefault + "/foo"
|
||||||
validPodDisruptionBudget := validNewPodDisruptionBudget()
|
validPodDisruptionBudget := validNewPodDisruptionBudget()
|
||||||
if err := storage.Storage.Create(ctx, key, validPodDisruptionBudget, nil, 0); err != nil {
|
if err := storage.Storage.Create(ctx, key, validPodDisruptionBudget, nil, 0, false); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,7 @@ func TestDeleteSystemPriorityClass(t *testing.T) {
|
||||||
key := "test/system-node-critical"
|
key := "test/system-node-critical"
|
||||||
ctx := genericapirequest.NewContext()
|
ctx := genericapirequest.NewContext()
|
||||||
pc := scheduling.SystemPriorityClasses()[0]
|
pc := scheduling.SystemPriorityClasses()[0]
|
||||||
if err := storage.Store.Storage.Create(ctx, key, pc, nil, 0); err != nil {
|
if err := storage.Store.Storage.Create(ctx, key, pc, nil, 0, false); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if _, _, err := storage.Delete(ctx, pc.Name, nil); err == nil {
|
if _, _, err := storage.Delete(ctx, pc.Name, nil); err == nil {
|
||||||
|
|
|
@ -93,6 +93,7 @@ filegroup(
|
||||||
"//staging/src/k8s.io/apiserver/pkg/registry:all-srcs",
|
"//staging/src/k8s.io/apiserver/pkg/registry:all-srcs",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/server:all-srcs",
|
"//staging/src/k8s.io/apiserver/pkg/server:all-srcs",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage:all-srcs",
|
"//staging/src/k8s.io/apiserver/pkg/storage:all-srcs",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/util/dryrun:all-srcs",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:all-srcs",
|
"//staging/src/k8s.io/apiserver/pkg/util/feature:all-srcs",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/util/flag:all-srcs",
|
"//staging/src/k8s.io/apiserver/pkg/util/flag:all-srcs",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/util/flushwriter:all-srcs",
|
"//staging/src/k8s.io/apiserver/pkg/util/flushwriter:all-srcs",
|
||||||
|
|
|
@ -1462,6 +1462,10 @@
|
||||||
"ImportPath": "k8s.io/apiserver/pkg/storage/value",
|
"ImportPath": "k8s.io/apiserver/pkg/storage/value",
|
||||||
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "k8s.io/apiserver/pkg/util/dryrun",
|
||||||
|
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "k8s.io/apiserver/pkg/util/feature",
|
"ImportPath": "k8s.io/apiserver/pkg/util/feature",
|
||||||
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
|
@ -2282,6 +2286,10 @@
|
||||||
"ImportPath": "k8s.io/apiserver/pkg/storage/storagebackend",
|
"ImportPath": "k8s.io/apiserver/pkg/storage/storagebackend",
|
||||||
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "k8s.io/apiserver/pkg/util/dryrun",
|
||||||
|
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "k8s.io/apiserver/pkg/util/feature",
|
"ImportPath": "k8s.io/apiserver/pkg/util/feature",
|
||||||
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
|
|
|
@ -254,7 +254,7 @@ func TestColumns(t *testing.T) {
|
||||||
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
||||||
key := "/noxus/" + metav1.NamespaceDefault + "/foo"
|
key := "/noxus/" + metav1.NamespaceDefault + "/foo"
|
||||||
validCustomResource := validNewCustomResource()
|
validCustomResource := validNewCustomResource()
|
||||||
if err := storage.CustomResource.Storage.Create(ctx, key, validCustomResource, nil, 0); err != nil {
|
if err := storage.CustomResource.Storage.Create(ctx, key, validCustomResource, nil, 0, false); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,7 +324,7 @@ func TestStatusUpdate(t *testing.T) {
|
||||||
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
||||||
key := "/noxus/" + metav1.NamespaceDefault + "/foo"
|
key := "/noxus/" + metav1.NamespaceDefault + "/foo"
|
||||||
validCustomResource := validNewCustomResource()
|
validCustomResource := validNewCustomResource()
|
||||||
if err := storage.CustomResource.Storage.Create(ctx, key, validCustomResource, nil, 0); err != nil {
|
if err := storage.CustomResource.Storage.Create(ctx, key, validCustomResource, nil, 0, false); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,7 +375,7 @@ func TestScaleGet(t *testing.T) {
|
||||||
var cr unstructured.Unstructured
|
var cr unstructured.Unstructured
|
||||||
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
||||||
key := "/noxus/" + metav1.NamespaceDefault + "/" + name
|
key := "/noxus/" + metav1.NamespaceDefault + "/" + name
|
||||||
if err := storage.CustomResource.Storage.Create(ctx, key, &validCustomResource, &cr, 0); err != nil {
|
if err := storage.CustomResource.Storage.Create(ctx, key, &validCustomResource, &cr, 0, false); err != nil {
|
||||||
t.Fatalf("error setting new custom resource (key: %s) %v: %v", key, validCustomResource, err)
|
t.Fatalf("error setting new custom resource (key: %s) %v: %v", key, validCustomResource, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,7 +415,7 @@ func TestScaleGetWithoutSpecReplicas(t *testing.T) {
|
||||||
key := "/noxus/" + metav1.NamespaceDefault + "/" + name
|
key := "/noxus/" + metav1.NamespaceDefault + "/" + name
|
||||||
withoutSpecReplicas := validCustomResource.DeepCopy()
|
withoutSpecReplicas := validCustomResource.DeepCopy()
|
||||||
unstructured.RemoveNestedField(withoutSpecReplicas.Object, "spec", "replicas")
|
unstructured.RemoveNestedField(withoutSpecReplicas.Object, "spec", "replicas")
|
||||||
if err := storage.CustomResource.Storage.Create(ctx, key, withoutSpecReplicas, &cr, 0); err != nil {
|
if err := storage.CustomResource.Storage.Create(ctx, key, withoutSpecReplicas, &cr, 0, false); err != nil {
|
||||||
t.Fatalf("error setting new custom resource (key: %s) %v: %v", key, withoutSpecReplicas, err)
|
t.Fatalf("error setting new custom resource (key: %s) %v: %v", key, withoutSpecReplicas, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,7 +438,7 @@ func TestScaleUpdate(t *testing.T) {
|
||||||
var cr unstructured.Unstructured
|
var cr unstructured.Unstructured
|
||||||
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
||||||
key := "/noxus/" + metav1.NamespaceDefault + "/" + name
|
key := "/noxus/" + metav1.NamespaceDefault + "/" + name
|
||||||
if err := storage.CustomResource.Storage.Create(ctx, key, &validCustomResource, &cr, 0); err != nil {
|
if err := storage.CustomResource.Storage.Create(ctx, key, &validCustomResource, &cr, 0, false); err != nil {
|
||||||
t.Fatalf("error setting new custom resource (key: %s) %v: %v", key, validCustomResource, err)
|
t.Fatalf("error setting new custom resource (key: %s) %v: %v", key, validCustomResource, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,7 +492,7 @@ func TestScaleUpdateWithoutSpecReplicas(t *testing.T) {
|
||||||
key := "/noxus/" + metav1.NamespaceDefault + "/" + name
|
key := "/noxus/" + metav1.NamespaceDefault + "/" + name
|
||||||
withoutSpecReplicas := validCustomResource.DeepCopy()
|
withoutSpecReplicas := validCustomResource.DeepCopy()
|
||||||
unstructured.RemoveNestedField(withoutSpecReplicas.Object, "spec", "replicas")
|
unstructured.RemoveNestedField(withoutSpecReplicas.Object, "spec", "replicas")
|
||||||
if err := storage.CustomResource.Storage.Create(ctx, key, withoutSpecReplicas, &cr, 0); err != nil {
|
if err := storage.CustomResource.Storage.Create(ctx, key, withoutSpecReplicas, &cr, 0, false); err != nil {
|
||||||
t.Fatalf("error setting new custom resource (key: %s) %v: %v", key, withoutSpecReplicas, err)
|
t.Fatalf("error setting new custom resource (key: %s) %v: %v", key, withoutSpecReplicas, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ go_library(
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/storage:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage/errors:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/storage/errors:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/util/dryrun:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
"k8s.io/apiserver/pkg/storage"
|
"k8s.io/apiserver/pkg/storage"
|
||||||
storageerr "k8s.io/apiserver/pkg/storage/errors"
|
storageerr "k8s.io/apiserver/pkg/storage/errors"
|
||||||
|
"k8s.io/apiserver/pkg/util/dryrun"
|
||||||
)
|
)
|
||||||
|
|
||||||
// rest implements a RESTStorage for API services against etcd
|
// rest implements a RESTStorage for API services against etcd
|
||||||
|
@ -129,6 +130,7 @@ func (r *REST) Delete(ctx context.Context, name string, options *metav1.DeleteOp
|
||||||
})
|
})
|
||||||
return existingCRD, nil
|
return existingCRD, nil
|
||||||
}),
|
}),
|
||||||
|
dryrun.IsDryRun(options.DryRun),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -10,6 +10,7 @@ go_test(
|
||||||
name = "go_default_test",
|
name = "go_default_test",
|
||||||
srcs = [
|
srcs = [
|
||||||
"decorated_watcher_test.go",
|
"decorated_watcher_test.go",
|
||||||
|
"dryrun_test.go",
|
||||||
"store_test.go",
|
"store_test.go",
|
||||||
],
|
],
|
||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
|
@ -20,12 +21,14 @@ go_test(
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/internalversion:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/internalversion:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/selection:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/selection:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||||
|
@ -53,6 +56,7 @@ go_library(
|
||||||
srcs = [
|
srcs = [
|
||||||
"decorated_watcher.go",
|
"decorated_watcher.go",
|
||||||
"doc.go",
|
"doc.go",
|
||||||
|
"dryrun.go",
|
||||||
"storage_factory.go",
|
"storage_factory.go",
|
||||||
"store.go",
|
"store.go",
|
||||||
],
|
],
|
||||||
|
@ -84,6 +88,7 @@ go_library(
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage/etcd/metrics:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/storage/etcd/metrics:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage/storagebackend:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/storage/storagebackend:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/storage/storagebackend/factory:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/storage/storagebackend/factory:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/util/dryrun:go_default_library",
|
||||||
"//vendor/github.com/golang/glog:go_default_library",
|
"//vendor/github.com/golang/glog:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -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"
|
"k8s.io/apiserver/pkg/storage"
|
||||||
storeerr "k8s.io/apiserver/pkg/storage/errors"
|
storeerr "k8s.io/apiserver/pkg/storage/errors"
|
||||||
"k8s.io/apiserver/pkg/storage/etcd/metrics"
|
"k8s.io/apiserver/pkg/storage/etcd/metrics"
|
||||||
|
"k8s.io/apiserver/pkg/util/dryrun"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
@ -172,8 +173,10 @@ type Store struct {
|
||||||
// of items into tabular output. If unset, the default will be used.
|
// of items into tabular output. If unset, the default will be used.
|
||||||
TableConvertor rest.TableConvertor
|
TableConvertor rest.TableConvertor
|
||||||
|
|
||||||
// Storage is the interface for the underlying storage for the resource.
|
// Storage is the interface for the underlying storage for the
|
||||||
Storage storage.Interface
|
// 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.
|
// Called to cleanup clients used by the underlying Storage; optional.
|
||||||
DestroyFunc func()
|
DestroyFunc func()
|
||||||
}
|
}
|
||||||
|
@ -348,7 +351,7 @@ func (e *Store) Create(ctx context.Context, obj runtime.Object, createValidation
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
out := e.NewFunc()
|
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 = storeerr.InterpretCreateError(err, qualifiedResource, name)
|
||||||
err = rest.CheckGeneratedNameError(e.CreateStrategy, err, obj)
|
err = rest.CheckGeneratedNameError(e.CreateStrategy, err, obj)
|
||||||
if !kubeerr.IsAlreadyExists(err) {
|
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.
|
// deleteWithoutFinalizers handles deleting an object ignoring its finalizer list.
|
||||||
// Used for objects that are either been finalized or have never initialized.
|
// 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()
|
out := e.NewFunc()
|
||||||
glog.V(6).Infof("going to delete %s from registry, triggered by update", name)
|
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
|
// Deletion is racy, i.e., there could be multiple update
|
||||||
// requests to remove all finalizers from the object, so we
|
// requests to remove all finalizers from the object, so we
|
||||||
// ignore the NotFound error.
|
// 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, &ttl, nil
|
||||||
}
|
}
|
||||||
return obj, nil, nil
|
return obj, nil, nil
|
||||||
})
|
}, dryrun.IsDryRun(options.DryRun))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// delete the object
|
// delete the object
|
||||||
if err == errEmptiedFinalizers {
|
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 {
|
if creating {
|
||||||
err = storeerr.InterpretCreateError(err, qualifiedResource, name)
|
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) {
|
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 {
|
if creating {
|
||||||
|
@ -919,6 +922,7 @@ func (e *Store) updateForGracefulDeletionAndFinalizers(ctx context.Context, name
|
||||||
lastExisting = existing
|
lastExisting = existing
|
||||||
return existing, nil
|
return existing, nil
|
||||||
}),
|
}),
|
||||||
|
dryrun.IsDryRun(options.DryRun),
|
||||||
)
|
)
|
||||||
switch err {
|
switch err {
|
||||||
case nil:
|
case nil:
|
||||||
|
@ -1000,10 +1004,15 @@ func (e *Store) Delete(ctx context.Context, name string, options *metav1.DeleteO
|
||||||
return out, false, err
|
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
|
// delete immediately, or no graceful deletion supported
|
||||||
glog.V(6).Infof("going to delete %s from registry: ", name)
|
glog.V(6).Infof("going to delete %s from registry: ", name)
|
||||||
out = e.NewFunc()
|
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
|
// Please refer to the place where we set ignoreNotFound for the reason
|
||||||
// why we ignore the NotFound error .
|
// why we ignore the NotFound error .
|
||||||
if storage.IsNotFound(err) && ignoreNotFound && lastExisting != nil {
|
if storage.IsNotFound(err) && ignoreNotFound && lastExisting != nil {
|
||||||
|
@ -1364,8 +1373,9 @@ func (e *Store) CompleteWithOptions(options *generic.StoreOptions) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.Storage == nil {
|
if e.Storage.Storage == nil {
|
||||||
e.Storage, e.DestroyFunc = opts.Decorator(
|
e.Storage.Codec = opts.StorageConfig.Codec
|
||||||
|
e.Storage.Storage, e.DestroyFunc = opts.Decorator(
|
||||||
opts.StorageConfig,
|
opts.StorageConfig,
|
||||||
e.NewFunc(),
|
e.NewFunc(),
|
||||||
prefix,
|
prefix,
|
||||||
|
|
|
@ -213,7 +213,7 @@ func TestStoreList(t *testing.T) {
|
||||||
destroyFunc, registry := NewTestGenericStoreRegistry(t)
|
destroyFunc, registry := NewTestGenericStoreRegistry(t)
|
||||||
|
|
||||||
if item.in != nil {
|
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)
|
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 {
|
if err != nil {
|
||||||
return err
|
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 {
|
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)
|
t.tester.Errorf("unable to clear collection: %v", err)
|
||||||
return nil
|
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)
|
t.tester.Errorf("unexpected error: %v", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = ["dryrun.go"],
|
||||||
|
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/util/dryrun",
|
||||||
|
importpath = "k8s.io/apiserver/pkg/util/dryrun",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
|
@ -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
|
||||||
|
}
|
|
@ -1134,6 +1134,10 @@
|
||||||
"ImportPath": "k8s.io/apiserver/pkg/storage/value",
|
"ImportPath": "k8s.io/apiserver/pkg/storage/value",
|
||||||
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "k8s.io/apiserver/pkg/util/dryrun",
|
||||||
|
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "k8s.io/apiserver/pkg/util/feature",
|
"ImportPath": "k8s.io/apiserver/pkg/util/feature",
|
||||||
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
|
|
|
@ -1106,6 +1106,10 @@
|
||||||
"ImportPath": "k8s.io/apiserver/pkg/storage/value",
|
"ImportPath": "k8s.io/apiserver/pkg/storage/value",
|
||||||
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "k8s.io/apiserver/pkg/util/dryrun",
|
||||||
|
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "k8s.io/apiserver/pkg/util/feature",
|
"ImportPath": "k8s.io/apiserver/pkg/util/feature",
|
||||||
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
|
|
Loading…
Reference in New Issue