forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Detect if a TPR update represents a soft delete (openshift#836)
* detect if a TPR update represents a soft delete if it does, then intercept the PUT, remove the deletion timestamp and deletion grace period, and add a finalizer this commit also splits some of the CRUD actions into common functions, so they can be reused * adding more finalizer-related metadata funcs * modify the delete function to remove finalizers * modify a delete test to check for finalizers * fixing final test for deletion * adding tests for the metadata accessors * modifying the update to check for deletion flags earlier also modifying the delete func to accept a code * fixing format string directive * change the fake REST client to return the expected HTTP response code deleting other resources in Kubernetes shows that the endpoint returns a 200. For example, here’s deleting a namespace: ```console ENG000656:service-catalog aaronschlesinger$ k delete ns catalog -v 10 I0511 16:43:04.375166 54273 loader.go:354] Config loaded from file /Users/aaronschlesinger/.kube/config I0511 16:43:04.379679 54273 cached_discovery.go:71] returning cached discovery info from /Users/aaronschlesinger/.kube/cache/discovery/192.168.99.100_8443/autosc aling/v1/serverresources.json <snip> I0511 16:43:04.383012 54273 round_trippers.go:398] curl -k -v -XDELETE -H "Accept: application/json" -H "User-Agent: kubectl/v0.0.0 (darwin/amd64) kubernetes/$Format" https://192.168.99.100:8443/api/v1/namespaces/catalog I0511 16:43:04.412668 54273 round_trippers.go:417] DELETE https://192.168.99.100:8443/api/v1/namespaces/catalog 200 OK in 29 milliseconds ``` * Moving metadata functions to a new package and using the new package everywhere * fixing typo in comment * improving error messages from binding tests * updating the rest client to soft-delete * adding more functions to the deletion metadata suite * refactoring the storage interface's update func so that it does complete updates for soft deletion, and has better docs * returning the appropriate content types from the fake server * fetching codecs in a type-agnostic way * ensuring that deletion timestamp can't be changed instead of preventing it from being passed at all * returning errors properly in the rest client * returning errors properly in the storage interface * renaming headers util file * fixing deletion timestamp deletion timestamp equality checks * fixing a unit test * adding the option to make the TPR storage interface hard-delete this is necessary for service class resources * adding missing godoc * fixing test compile errors * removing test regression and commenting * fixing format string value * remove incorrect, early return from the update func * splitting functions and test into more logical files * implementing remaining TODO tests * fix compile error the generated code has changed, and this field name has also changed * adding docs for the singular and list funcs * removing unused arg * fixing test compile errs * Adding more godoc to the RemoveFinalizer func
- Loading branch information
Showing
25 changed files
with
1,093 additions
and
191 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/* | ||
Copyright 2017 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 meta | ||
|
||
import ( | ||
"errors" | ||
"time" | ||
|
||
"k8s.io/apimachinery/pkg/api/meta" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
) | ||
|
||
var ( | ||
// ErrNoDeletionTimestamp is the error returned by GetDeletionTimestamp when there is no | ||
// deletion timestamp set on the object | ||
ErrNoDeletionTimestamp = errors.New("no deletion timestamp set") | ||
) | ||
|
||
// DeletionTimestampExists returns true if a deletion timestamp exists on obj, or a non-nil | ||
// error if that couldn't be reliably determined | ||
func DeletionTimestampExists(obj runtime.Object) (bool, error) { | ||
_, err := GetDeletionTimestamp(obj) | ||
if err == ErrNoDeletionTimestamp { | ||
// if GetDeletionTimestamp reported that no deletion timestamp exists, return false | ||
// and no error | ||
return false, nil | ||
} | ||
if err != nil { | ||
// otherwise, if GetDeletionTimestamp returned an unknown error, return the error | ||
return false, err | ||
} | ||
return true, nil | ||
} | ||
|
||
// GetDeletionTimestamp returns the deletion timestamp on obj, or a non-nil error if there was | ||
// an error getting it or it isn't set. Returns ErrNoDeletionTimestamp if there was none set | ||
func GetDeletionTimestamp(obj runtime.Object) (*metav1.Time, error) { | ||
accessor, err := meta.Accessor(obj) | ||
if err != nil { | ||
return nil, err | ||
} | ||
t := accessor.GetDeletionTimestamp() | ||
if t == nil { | ||
return nil, ErrNoDeletionTimestamp | ||
} | ||
return t, nil | ||
} | ||
|
||
// SetDeletionTimestamp sets the deletion timestamp on obj to t | ||
func SetDeletionTimestamp(obj runtime.Object, t time.Time) error { | ||
accessor, err := meta.Accessor(obj) | ||
if err != nil { | ||
return err | ||
} | ||
metaTime := metav1.NewTime(t) | ||
accessor.SetDeletionTimestamp(&metaTime) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/* | ||
Copyright 2017 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 meta | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
sc "github.com/kubernetes-incubator/service-catalog/pkg/apis/servicecatalog" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
func TestDeletionTimestampExists(t *testing.T) { | ||
obj := &sc.Instance{ | ||
ObjectMeta: metav1.ObjectMeta{}, | ||
} | ||
exists, err := DeletionTimestampExists(obj) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if exists { | ||
t.Fatalf("deletion timestamp reported as exists when it didn't") | ||
} | ||
tme := metav1.NewTime(time.Now()) | ||
obj.DeletionTimestamp = &tme | ||
exists, err = DeletionTimestampExists(obj) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if !exists { | ||
t.Fatal("deletion timestamp reported as missing when it isn't") | ||
} | ||
} | ||
|
||
func TestRoundTripDeletionTimestamp(t *testing.T) { | ||
t1 := metav1.NewTime(time.Now()) | ||
t2 := metav1.NewTime(time.Now().Add(1 * time.Hour)) | ||
obj := &sc.Instance{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
DeletionTimestamp: &t1, | ||
}, | ||
} | ||
t1Ret, err := GetDeletionTimestamp(obj) | ||
if err != nil { | ||
t.Fatalf("error getting 1st deletion timestamp (%s)", err) | ||
} | ||
if !t1.Equal(*t1Ret) { | ||
t.Fatalf("expected deletion timestamp %s, got %s", t1, *t1Ret) | ||
} | ||
if err := SetDeletionTimestamp(obj, t2.Time); err != nil { | ||
t.Fatalf("error setting deletion timestamp (%s)", err) | ||
} | ||
t2Ret, err := GetDeletionTimestamp(obj) | ||
if err != nil { | ||
t.Fatalf("error getting 2nd deletion timestamp (%s)", err) | ||
} | ||
if !t2.Equal(*t2Ret) { | ||
t.Fatalf("expected deletion timestamp %s, got %s", t2, *t2Ret) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/* | ||
Copyright 2017 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 meta | ||
|
||
import ( | ||
"k8s.io/apimachinery/pkg/api/meta" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
) | ||
|
||
// GetFinalizers gets the list of finalizers on obj | ||
func GetFinalizers(obj runtime.Object) ([]string, error) { | ||
accessor, err := meta.Accessor(obj) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return accessor.GetFinalizers(), nil | ||
} | ||
|
||
// AddFinalizer adds value to the list of finalizers on obj | ||
func AddFinalizer(obj runtime.Object, value string) error { | ||
accessor, err := meta.Accessor(obj) | ||
if err != nil { | ||
return err | ||
} | ||
finalizers := append(accessor.GetFinalizers(), value) | ||
accessor.SetFinalizers(finalizers) | ||
return nil | ||
} | ||
|
||
// RemoveFinalizer removes the given value from the list of finalizers in obj, then returns the list | ||
// of finalizers after value has been removed. The returned slice will have the same ordering as | ||
// the list of finalizers that was in obj. | ||
// | ||
// If value doesn't exist in the finalizers in obj, the returned slice is the same as the finalizers | ||
// that were in obj. | ||
// | ||
// All of the finalizers that match value will be removed from the list in obj. | ||
func RemoveFinalizer(obj runtime.Object, value string) ([]string, error) { | ||
accessor, err := meta.Accessor(obj) | ||
if err != nil { | ||
return nil, err | ||
} | ||
finalizers := accessor.GetFinalizers() | ||
newFinalizers := []string{} | ||
for _, finalizer := range finalizers { | ||
if finalizer == value { | ||
continue | ||
} | ||
newFinalizers = append(newFinalizers, finalizer) | ||
} | ||
accessor.SetFinalizers(newFinalizers) | ||
return newFinalizers, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* | ||
Copyright 2017 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 meta | ||
|
||
import ( | ||
"testing" | ||
|
||
sc "github.com/kubernetes-incubator/service-catalog/pkg/apis/servicecatalog" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
const ( | ||
testFinalizer = "testfinalizer" | ||
) | ||
|
||
func TestGetFinalizers(t *testing.T) { | ||
obj := &sc.Instance{ | ||
ObjectMeta: metav1.ObjectMeta{Finalizers: []string{testFinalizer}}, | ||
} | ||
finalizers, err := GetFinalizers(obj) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if len(finalizers) != 1 { | ||
t.Fatalf("expected 1 finalizer, got %d", len(finalizers)) | ||
} | ||
if finalizers[0] != testFinalizer { | ||
t.Fatalf("expected finalizer %s, got %s", testFinalizer, finalizers[0]) | ||
} | ||
} | ||
|
||
func TestAddFinalizer(t *testing.T) { | ||
obj := &sc.Instance{ | ||
ObjectMeta: metav1.ObjectMeta{}, | ||
} | ||
if err := AddFinalizer(obj, testFinalizer); err != nil { | ||
t.Fatal(err) | ||
} | ||
if len(obj.Finalizers) != 1 { | ||
t.Fatalf("expected 1 finalizer, got %d", len(obj.Finalizers)) | ||
} | ||
if obj.Finalizers[0] != testFinalizer { | ||
t.Fatalf("expected finalizer %s, got %s", testFinalizer, obj.Finalizers[0]) | ||
} | ||
} | ||
|
||
func TestRemoveFinalizer(t *testing.T) { | ||
obj := &sc.Instance{ | ||
ObjectMeta: metav1.ObjectMeta{Finalizers: []string{testFinalizer}}, | ||
} | ||
newFinalizers, err := RemoveFinalizer(obj, testFinalizer+"-noexist") | ||
if err != nil { | ||
t.Fatalf("error removing non-existent finalizer (%s)", err) | ||
} | ||
if len(newFinalizers) != 1 { | ||
t.Fatalf("number of returned finalizers wasn't 1") | ||
} | ||
if len(obj.Finalizers) != 1 { | ||
t.Fatalf("finalizer was removed when it shouldn't have been") | ||
} | ||
if obj.Finalizers[0] != testFinalizer { | ||
t.Fatalf("expected finalizer %s, got %s", testFinalizer, obj.Finalizers[0]) | ||
} | ||
newFinalizers, err = RemoveFinalizer(obj, testFinalizer) | ||
if err != nil { | ||
t.Fatalf("error removing existent finalizer (%s)", err) | ||
} | ||
if len(newFinalizers) != 0 { | ||
t.Fatalf("number of returned finalizers wasn't 0") | ||
} | ||
if len(obj.Finalizers) != 0 { | ||
t.Fatalf("expected no finalizers, got %d", len(obj.Finalizers)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
Copyright 2017 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 meta | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func TestGetAccessor(t *testing.T) { | ||
if GetAccessor() != accessor { | ||
t.Fatalf("GetAccessor didn't return the pre-initialized accessor") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
Copyright 2017 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 meta | ||
|
||
import ( | ||
"k8s.io/apimachinery/pkg/runtime" | ||
) | ||
|
||
// GetNamespace returns the namespace for the given object, if there is one. If not, returns | ||
// the empty string and a non-nil error | ||
func GetNamespace(obj runtime.Object) (string, error) { | ||
return selfLinker.Namespace(obj) | ||
} |
Oops, something went wrong.