mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 18:28:13 +00:00 
			
		
		
		
	API
This commit is contained in:
		| @@ -104,7 +104,7 @@ func TestConfigMapController(t *testing.T) { | |||||||
| 	// There should be 2 updates to add both the finalizers. | 	// There should be 2 updates to add both the finalizers. | ||||||
| 	updatedConfigMap := GetConfigMapFromChan(configmapUpdateChan) | 	updatedConfigMap := GetConfigMapFromChan(configmapUpdateChan) | ||||||
| 	assert.True(t, configmapController.hasFinalizerFunc(updatedConfigMap, deletionhelper.FinalizerDeleteFromUnderlyingClusters)) | 	assert.True(t, configmapController.hasFinalizerFunc(updatedConfigMap, deletionhelper.FinalizerDeleteFromUnderlyingClusters)) | ||||||
| 	assert.True(t, configmapController.hasFinalizerFunc(updatedConfigMap, metav1.FinalizerOrphan)) | 	assert.True(t, configmapController.hasFinalizerFunc(updatedConfigMap, metav1.FinalizerOrphanDependents)) | ||||||
|  |  | ||||||
| 	// Verify that the configmap is created in underlying cluster1. | 	// Verify that the configmap is created in underlying cluster1. | ||||||
| 	createdConfigMap := GetConfigMapFromChan(cluster1CreateChan) | 	createdConfigMap := GetConfigMapFromChan(cluster1CreateChan) | ||||||
|   | |||||||
| @@ -105,7 +105,7 @@ func TestDaemonSetController(t *testing.T) { | |||||||
| 	// There should be an update to add both the finalizers. | 	// There should be an update to add both the finalizers. | ||||||
| 	updatedDaemonSet := GetDaemonSetFromChan(daemonsetUpdateChan) | 	updatedDaemonSet := GetDaemonSetFromChan(daemonsetUpdateChan) | ||||||
| 	assert.True(t, daemonsetController.hasFinalizerFunc(updatedDaemonSet, deletionhelper.FinalizerDeleteFromUnderlyingClusters)) | 	assert.True(t, daemonsetController.hasFinalizerFunc(updatedDaemonSet, deletionhelper.FinalizerDeleteFromUnderlyingClusters)) | ||||||
| 	assert.True(t, daemonsetController.hasFinalizerFunc(updatedDaemonSet, metav1.FinalizerOrphan)) | 	assert.True(t, daemonsetController.hasFinalizerFunc(updatedDaemonSet, metav1.FinalizerOrphanDependents)) | ||||||
| 	daemonset1 = *updatedDaemonSet | 	daemonset1 = *updatedDaemonSet | ||||||
|  |  | ||||||
| 	createdDaemonSet := GetDaemonSetFromChan(cluster1CreateChan) | 	createdDaemonSet := GetDaemonSetFromChan(cluster1CreateChan) | ||||||
|   | |||||||
| @@ -146,7 +146,7 @@ func TestIngressController(t *testing.T) { | |||||||
| 	// There should be an update to add both the finalizers. | 	// There should be an update to add both the finalizers. | ||||||
| 	updatedIngress := GetIngressFromChan(t, fedIngressUpdateChan) | 	updatedIngress := GetIngressFromChan(t, fedIngressUpdateChan) | ||||||
| 	assert.True(t, ingressController.hasFinalizerFunc(updatedIngress, deletionhelper.FinalizerDeleteFromUnderlyingClusters)) | 	assert.True(t, ingressController.hasFinalizerFunc(updatedIngress, deletionhelper.FinalizerDeleteFromUnderlyingClusters)) | ||||||
| 	assert.True(t, ingressController.hasFinalizerFunc(updatedIngress, metav1.FinalizerOrphan), fmt.Sprintf("ingress does not have the orphan finalizer: %v", updatedIngress)) | 	assert.True(t, ingressController.hasFinalizerFunc(updatedIngress, metav1.FinalizerOrphanDependents), fmt.Sprintf("ingress does not have the orphan finalizer: %v", updatedIngress)) | ||||||
| 	fedIngress = *updatedIngress | 	fedIngress = *updatedIngress | ||||||
|  |  | ||||||
| 	t.Log("Checking that Ingress was correctly created in cluster 1") | 	t.Log("Checking that Ingress was correctly created in cluster 1") | ||||||
| @@ -319,7 +319,7 @@ func WaitForFinalizersInFederationStore(ingressController *IngressController, st | |||||||
| 			return false, err | 			return false, err | ||||||
| 		} | 		} | ||||||
| 		ingress := obj.(*extensionsv1beta1.Ingress) | 		ingress := obj.(*extensionsv1beta1.Ingress) | ||||||
| 		if ingressController.hasFinalizerFunc(ingress, metav1.FinalizerOrphan) && | 		if ingressController.hasFinalizerFunc(ingress, metav1.FinalizerOrphanDependents) && | ||||||
| 			ingressController.hasFinalizerFunc(ingress, deletionhelper.FinalizerDeleteFromUnderlyingClusters) { | 			ingressController.hasFinalizerFunc(ingress, deletionhelper.FinalizerDeleteFromUnderlyingClusters) { | ||||||
| 			return true, nil | 			return true, nil | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -133,7 +133,7 @@ func TestNamespaceController(t *testing.T) { | |||||||
| 	// Delete the namespace with orphan finalizer (let namespaces | 	// Delete the namespace with orphan finalizer (let namespaces | ||||||
| 	// in underlying clusters be as is). | 	// in underlying clusters be as is). | ||||||
| 	// TODO: Add a test without orphan finalizer. | 	// TODO: Add a test without orphan finalizer. | ||||||
| 	ns1.ObjectMeta.Finalizers = append(ns1.ObjectMeta.Finalizers, metav1.FinalizerOrphan) | 	ns1.ObjectMeta.Finalizers = append(ns1.ObjectMeta.Finalizers, metav1.FinalizerOrphanDependents) | ||||||
| 	ns1.DeletionTimestamp = &metav1.Time{Time: time.Now()} | 	ns1.DeletionTimestamp = &metav1.Time{Time: time.Now()} | ||||||
| 	namespaceWatch.Modify(&ns1) | 	namespaceWatch.Modify(&ns1) | ||||||
| 	assert.Equal(t, ns1.Name, GetStringFromChan(nsDeleteChan)) | 	assert.Equal(t, ns1.Name, GetStringFromChan(nsDeleteChan)) | ||||||
|   | |||||||
| @@ -105,7 +105,7 @@ func TestSecretController(t *testing.T) { | |||||||
| 	// There should be an update to add both the finalizers. | 	// There should be an update to add both the finalizers. | ||||||
| 	updatedSecret := GetSecretFromChan(secretUpdateChan) | 	updatedSecret := GetSecretFromChan(secretUpdateChan) | ||||||
| 	assert.True(t, secretController.hasFinalizerFunc(updatedSecret, deletionhelper.FinalizerDeleteFromUnderlyingClusters)) | 	assert.True(t, secretController.hasFinalizerFunc(updatedSecret, deletionhelper.FinalizerDeleteFromUnderlyingClusters)) | ||||||
| 	assert.True(t, secretController.hasFinalizerFunc(updatedSecret, metav1.FinalizerOrphan)) | 	assert.True(t, secretController.hasFinalizerFunc(updatedSecret, metav1.FinalizerOrphanDependents)) | ||||||
| 	secret1 = *updatedSecret | 	secret1 = *updatedSecret | ||||||
|  |  | ||||||
| 	// Verify that the secret is created in underlying cluster1. | 	// Verify that the secret is created in underlying cluster1. | ||||||
|   | |||||||
| @@ -93,8 +93,8 @@ func (dh *DeletionHelper) EnsureFinalizers(obj runtime.Object) ( | |||||||
| 	if !dh.hasFinalizerFunc(obj, FinalizerDeleteFromUnderlyingClusters) { | 	if !dh.hasFinalizerFunc(obj, FinalizerDeleteFromUnderlyingClusters) { | ||||||
| 		finalizers = append(finalizers, FinalizerDeleteFromUnderlyingClusters) | 		finalizers = append(finalizers, FinalizerDeleteFromUnderlyingClusters) | ||||||
| 	} | 	} | ||||||
| 	if !dh.hasFinalizerFunc(obj, metav1.FinalizerOrphan) { | 	if !dh.hasFinalizerFunc(obj, metav1.FinalizerOrphanDependents) { | ||||||
| 		finalizers = append(finalizers, metav1.FinalizerOrphan) | 		finalizers = append(finalizers, metav1.FinalizerOrphanDependents) | ||||||
| 	} | 	} | ||||||
| 	if len(finalizers) != 0 { | 	if len(finalizers) != 0 { | ||||||
| 		glog.V(2).Infof("Adding finalizers %v to %s", finalizers, dh.objNameFunc(obj)) | 		glog.V(2).Infof("Adding finalizers %v to %s", finalizers, dh.objNameFunc(obj)) | ||||||
| @@ -117,7 +117,7 @@ func (dh *DeletionHelper) HandleObjectInUnderlyingClusters(obj runtime.Object) ( | |||||||
| 		glog.V(2).Infof("obj does not have %s finalizer. Nothing to do", FinalizerDeleteFromUnderlyingClusters) | 		glog.V(2).Infof("obj does not have %s finalizer. Nothing to do", FinalizerDeleteFromUnderlyingClusters) | ||||||
| 		return obj, nil | 		return obj, nil | ||||||
| 	} | 	} | ||||||
| 	hasOrphanFinalizer := dh.hasFinalizerFunc(obj, metav1.FinalizerOrphan) | 	hasOrphanFinalizer := dh.hasFinalizerFunc(obj, metav1.FinalizerOrphanDependents) | ||||||
| 	if hasOrphanFinalizer { | 	if hasOrphanFinalizer { | ||||||
| 		glog.V(2).Infof("Found finalizer orphan. Nothing to do, just remove the finalizer") | 		glog.V(2).Infof("Found finalizer orphan. Nothing to do, just remove the finalizer") | ||||||
| 		// If the obj has FinalizerOrphan finalizer, then we need to orphan the | 		// If the obj has FinalizerOrphan finalizer, then we need to orphan the | ||||||
| @@ -127,7 +127,7 @@ func (dh *DeletionHelper) HandleObjectInUnderlyingClusters(obj runtime.Object) ( | |||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return obj, err | 			return obj, err | ||||||
| 		} | 		} | ||||||
| 		return dh.removeFinalizerFunc(obj, metav1.FinalizerOrphan) | 		return dh.removeFinalizerFunc(obj, metav1.FinalizerOrphanDependents) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	glog.V(2).Infof("Deleting obj %s from underlying clusters", objName) | 	glog.V(2).Infof("Deleting obj %s from underlying clusters", objName) | ||||||
|   | |||||||
| @@ -244,7 +244,7 @@ func IsServiceIPRequested(service *Service) bool { | |||||||
|  |  | ||||||
| var standardFinalizers = sets.NewString( | var standardFinalizers = sets.NewString( | ||||||
| 	string(FinalizerKubernetes), | 	string(FinalizerKubernetes), | ||||||
| 	metav1.FinalizerOrphan, | 	metav1.FinalizerOrphanDependents, | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // HasAnnotation returns a bool if passed in annotation exists | // HasAnnotation returns a bool if passed in annotation exists | ||||||
|   | |||||||
| @@ -20,8 +20,6 @@ import ( | |||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/google/gofuzz" |  | ||||||
|  |  | ||||||
| 	"k8s.io/apimachinery/pkg/api/meta" | 	"k8s.io/apimachinery/pkg/api/meta" | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/runtime" | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
| @@ -31,50 +29,6 @@ import ( | |||||||
|  |  | ||||||
| var _ metav1.Object = &metav1.ObjectMeta{} | var _ metav1.Object = &metav1.ObjectMeta{} | ||||||
|  |  | ||||||
| func getObjectMetaAndOwnerReferences() (objectMeta metav1.ObjectMeta, metaOwnerReferences []metav1.OwnerReference) { |  | ||||||
| 	fuzz.New().NilChance(.5).NumElements(1, 5).Fuzz(&objectMeta) |  | ||||||
| 	references := objectMeta.OwnerReferences |  | ||||||
| 	metaOwnerReferences = make([]metav1.OwnerReference, 0) |  | ||||||
| 	for i := 0; i < len(references); i++ { |  | ||||||
| 		metaOwnerReferences = append(metaOwnerReferences, metav1.OwnerReference{ |  | ||||||
| 			Kind:       references[i].Kind, |  | ||||||
| 			Name:       references[i].Name, |  | ||||||
| 			UID:        references[i].UID, |  | ||||||
| 			APIVersion: references[i].APIVersion, |  | ||||||
| 			Controller: references[i].Controller, |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 	if len(references) == 0 { |  | ||||||
| 		objectMeta.OwnerReferences = make([]metav1.OwnerReference, 0) |  | ||||||
| 	} |  | ||||||
| 	return objectMeta, metaOwnerReferences |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func testGetOwnerReferences(t *testing.T) { |  | ||||||
| 	meta, expected := getObjectMetaAndOwnerReferences() |  | ||||||
| 	refs := meta.GetOwnerReferences() |  | ||||||
| 	if !reflect.DeepEqual(refs, expected) { |  | ||||||
| 		t.Errorf("expect %v\n got %v", expected, refs) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func testSetOwnerReferences(t *testing.T) { |  | ||||||
| 	expected, newRefs := getObjectMetaAndOwnerReferences() |  | ||||||
| 	objectMeta := &metav1.ObjectMeta{} |  | ||||||
| 	objectMeta.SetOwnerReferences(newRefs) |  | ||||||
| 	if !reflect.DeepEqual(expected.OwnerReferences, objectMeta.OwnerReferences) { |  | ||||||
| 		t.Errorf("expect: %#v\n got: %#v", expected.OwnerReferences, objectMeta.OwnerReferences) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestAccessOwnerReferences(t *testing.T) { |  | ||||||
| 	fuzzIter := 5 |  | ||||||
| 	for i := 0; i < fuzzIter; i++ { |  | ||||||
| 		testGetOwnerReferences(t) |  | ||||||
| 		testSetOwnerReferences(t) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestAccessorImplementations(t *testing.T) { | func TestAccessorImplementations(t *testing.T) { | ||||||
| 	for _, gv := range api.Registry.EnabledVersions() { | 	for _, gv := range api.Registry.EnabledVersions() { | ||||||
| 		internalGV := schema.GroupVersion{Group: gv.Group, Version: runtime.APIVersionInternal} | 		internalGV := schema.GroupVersion{Group: gv.Group, Version: runtime.APIVersionInternal} | ||||||
|   | |||||||
| @@ -3000,6 +3000,20 @@ type Preconditions struct { | |||||||
| 	UID *types.UID | 	UID *types.UID | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // DeletionPropagation decides whether and how garbage collection will be performed. | ||||||
|  | type DeletionPropagation string | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	// Orphans the dependents. | ||||||
|  | 	DeletePropagationOrphan DeletionPropagation = "Orphan" | ||||||
|  | 	// Deletes the object from the key-value store, the garbage collector will delete the dependents in the background. | ||||||
|  | 	DeletePropagationBackground DeletionPropagation = "Background" | ||||||
|  | 	// The object exists in the key-value store until the garbage collector deletes all the dependents whose ownerReference.blockOwnerDeletion=true from the key-value store. | ||||||
|  | 	// API sever will put the "DeletingDependents" finalizer on the object, and sets its deletionTimestamp. | ||||||
|  | 	// This policy is cascading, i.e., the dependents will be deleted with Foreground. | ||||||
|  | 	DeletePropagationForeground DeletionPropagation = "Foreground" | ||||||
|  | ) | ||||||
|  |  | ||||||
| // DeleteOptions may be provided when deleting an API object | // DeleteOptions may be provided when deleting an API object | ||||||
| // DEPRECATED: This type has been moved to meta/v1 and will be removed soon. | // DEPRECATED: This type has been moved to meta/v1 and will be removed soon. | ||||||
| type DeleteOptions struct { | type DeleteOptions struct { | ||||||
| @@ -3016,10 +3030,18 @@ type DeleteOptions struct { | |||||||
| 	// +optional | 	// +optional | ||||||
| 	Preconditions *Preconditions | 	Preconditions *Preconditions | ||||||
|  |  | ||||||
|  | 	// Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. | ||||||
| 	// Should the dependent objects be orphaned. If true/false, the "orphan" | 	// Should the dependent objects be orphaned. If true/false, the "orphan" | ||||||
| 	// finalizer will be added to/removed from the object's finalizers list. | 	// finalizer will be added to/removed from the object's finalizers list. | ||||||
|  | 	// Either this field or PropagationPolicy may be set, but not both. | ||||||
| 	// +optional | 	// +optional | ||||||
| 	OrphanDependents *bool | 	OrphanDependents *bool | ||||||
|  |  | ||||||
|  | 	// Whether and how garbage collection will be performed. | ||||||
|  | 	// Defaults to Default. | ||||||
|  | 	// Either this field or OrphanDependents may be set, but not both. | ||||||
|  | 	// +optional | ||||||
|  | 	PropagationPolicy *DeletionPropagation | ||||||
| } | } | ||||||
|  |  | ||||||
| // ListOptions is the query options to a standard REST list call, and has future support for | // ListOptions is the query options to a standard REST list call, and has future support for | ||||||
|   | |||||||
| @@ -84,7 +84,7 @@ func IsServiceIPRequested(service *Service) bool { | |||||||
|  |  | ||||||
| var standardFinalizers = sets.NewString( | var standardFinalizers = sets.NewString( | ||||||
| 	string(FinalizerKubernetes), | 	string(FinalizerKubernetes), | ||||||
| 	metav1.FinalizerOrphan, | 	metav1.FinalizerOrphanDependents, | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func IsStandardFinalizerName(str string) bool { | func IsStandardFinalizerName(str string) bool { | ||||||
|   | |||||||
| @@ -63,6 +63,10 @@ func (meta *ObjectMeta) GetOwnerReferences() []metav1.OwnerReference { | |||||||
| 			value := *meta.OwnerReferences[i].Controller | 			value := *meta.OwnerReferences[i].Controller | ||||||
| 			ret[i].Controller = &value | 			ret[i].Controller = &value | ||||||
| 		} | 		} | ||||||
|  | 		if meta.OwnerReferences[i].BlockOwnerDeletion != nil { | ||||||
|  | 			value := *meta.OwnerReferences[i].BlockOwnerDeletion | ||||||
|  | 			ret[i].BlockOwnerDeletion = &value | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	return ret | 	return ret | ||||||
| } | } | ||||||
| @@ -78,6 +82,10 @@ func (meta *ObjectMeta) SetOwnerReferences(references []metav1.OwnerReference) { | |||||||
| 			value := *references[i].Controller | 			value := *references[i].Controller | ||||||
| 			newReferences[i].Controller = &value | 			newReferences[i].Controller = &value | ||||||
| 		} | 		} | ||||||
|  | 		if references[i].BlockOwnerDeletion != nil { | ||||||
|  | 			value := *references[i].BlockOwnerDeletion | ||||||
|  | 			newReferences[i].BlockOwnerDeletion = &value | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	meta.OwnerReferences = newReferences | 	meta.OwnerReferences = newReferences | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3432,6 +3432,20 @@ type Preconditions struct { | |||||||
| 	UID *types.UID `json:"uid,omitempty" protobuf:"bytes,1,opt,name=uid,casttype=k8s.io/apimachinery/pkg/types.UID"` | 	UID *types.UID `json:"uid,omitempty" protobuf:"bytes,1,opt,name=uid,casttype=k8s.io/apimachinery/pkg/types.UID"` | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // DeletionPropagation decides if a deletion will propagate to the dependents of the object, and how the garbage collector will handle the propagation. | ||||||
|  | type DeletionPropagation string | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	// Orphans the dependents. | ||||||
|  | 	DeletePropagationOrphan DeletionPropagation = "Orphan" | ||||||
|  | 	// Deletes the object from the key-value store, the garbage collector will delete the dependents in the background. | ||||||
|  | 	DeletePropagationBackground DeletionPropagation = "Background" | ||||||
|  | 	// The object exists in the key-value store until the garbage collector deletes all the dependents whose ownerReference.blockOwnerDeletion=true from the key-value store. | ||||||
|  | 	// API sever will put the "DeletingDependents" finalizer on the object, and sets its deletionTimestamp. | ||||||
|  | 	// This policy is cascading, i.e., the dependents will be deleted with Foreground. | ||||||
|  | 	DeletePropagationForeground DeletionPropagation = "Foreground" | ||||||
|  | ) | ||||||
|  |  | ||||||
| // DeleteOptions may be provided when deleting an API object | // DeleteOptions may be provided when deleting an API object | ||||||
| // DEPRECATED: This type has been moved to meta/v1 and will be removed soon. | // DEPRECATED: This type has been moved to meta/v1 and will be removed soon. | ||||||
| // +k8s:openapi-gen=false | // +k8s:openapi-gen=false | ||||||
| @@ -3450,10 +3464,18 @@ type DeleteOptions struct { | |||||||
| 	// +optional | 	// +optional | ||||||
| 	Preconditions *Preconditions `json:"preconditions,omitempty" protobuf:"bytes,2,opt,name=preconditions"` | 	Preconditions *Preconditions `json:"preconditions,omitempty" protobuf:"bytes,2,opt,name=preconditions"` | ||||||
|  |  | ||||||
|  | 	// Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. | ||||||
| 	// Should the dependent objects be orphaned. If true/false, the "orphan" | 	// Should the dependent objects be orphaned. If true/false, the "orphan" | ||||||
| 	// finalizer will be added to/removed from the object's finalizers list. | 	// finalizer will be added to/removed from the object's finalizers list. | ||||||
|  | 	// Either this field or PropagationPolicy may be set, but not both. | ||||||
| 	// +optional | 	// +optional | ||||||
| 	OrphanDependents *bool `json:"orphanDependents,omitempty" protobuf:"varint,3,opt,name=orphanDependents"` | 	OrphanDependents *bool `json:"orphanDependents,omitempty" protobuf:"varint,3,opt,name=orphanDependents"` | ||||||
|  |  | ||||||
|  | 	// Whether and how garbage collection will be performed. | ||||||
|  | 	// Defaults to Default. | ||||||
|  | 	// Either this field or OrphanDependents may be set, but not both. | ||||||
|  | 	// +optional | ||||||
|  | 	PropagationPolicy *DeletionPropagation | ||||||
| } | } | ||||||
|  |  | ||||||
| // ListOptions is the query options to a standard REST list call. | // ListOptions is the query options to a standard REST list call. | ||||||
|   | |||||||
| @@ -295,7 +295,6 @@ func ValidateObjectMeta(meta *metav1.ObjectMeta, requiresNamespace bool, nameFn | |||||||
| 	for i := range meta.Finalizers { | 	for i := range meta.Finalizers { | ||||||
| 		allErrs = append(allErrs, validateKubeFinalizerName(string(meta.Finalizers[i]), fldPath.Child("finalizers").Index(i))...) | 		allErrs = append(allErrs, validateKubeFinalizerName(string(meta.Finalizers[i]), fldPath.Child("finalizers").Index(i))...) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return allErrs | 	return allErrs | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -335,7 +335,7 @@ type MyAPIObject2 struct { | |||||||
| 	metav1.ObjectMeta | 	metav1.ObjectMeta | ||||||
| } | } | ||||||
|  |  | ||||||
| func getObjectMetaAndOwnerRefereneces() (myAPIObject2 MyAPIObject2, metaOwnerReferences []metav1.OwnerReference) { | func getObjectMetaAndOwnerReferences() (myAPIObject2 MyAPIObject2, metaOwnerReferences []metav1.OwnerReference) { | ||||||
| 	fuzz.New().NilChance(.5).NumElements(1, 5).Fuzz(&myAPIObject2) | 	fuzz.New().NilChance(.5).NumElements(1, 5).Fuzz(&myAPIObject2) | ||||||
| 	references := myAPIObject2.ObjectMeta.OwnerReferences | 	references := myAPIObject2.ObjectMeta.OwnerReferences | ||||||
| 	// This is necessary for the test to pass because the getter will return a | 	// This is necessary for the test to pass because the getter will return a | ||||||
| @@ -343,11 +343,12 @@ func getObjectMetaAndOwnerRefereneces() (myAPIObject2 MyAPIObject2, metaOwnerRef | |||||||
| 	metaOwnerReferences = make([]metav1.OwnerReference, 0) | 	metaOwnerReferences = make([]metav1.OwnerReference, 0) | ||||||
| 	for i := 0; i < len(references); i++ { | 	for i := 0; i < len(references); i++ { | ||||||
| 		metaOwnerReferences = append(metaOwnerReferences, metav1.OwnerReference{ | 		metaOwnerReferences = append(metaOwnerReferences, metav1.OwnerReference{ | ||||||
| 			Kind:       references[i].Kind, | 			Kind:               references[i].Kind, | ||||||
| 			Name:       references[i].Name, | 			Name:               references[i].Name, | ||||||
| 			UID:        references[i].UID, | 			UID:                references[i].UID, | ||||||
| 			APIVersion: references[i].APIVersion, | 			APIVersion:         references[i].APIVersion, | ||||||
| 			Controller: references[i].Controller, | 			Controller:         references[i].Controller, | ||||||
|  | 			BlockOwnerDeletion: references[i].BlockOwnerDeletion, | ||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| 	if len(references) == 0 { | 	if len(references) == 0 { | ||||||
| @@ -359,7 +360,7 @@ func getObjectMetaAndOwnerRefereneces() (myAPIObject2 MyAPIObject2, metaOwnerRef | |||||||
| } | } | ||||||
|  |  | ||||||
| func testGetOwnerReferences(t *testing.T) { | func testGetOwnerReferences(t *testing.T) { | ||||||
| 	obj, expected := getObjectMetaAndOwnerRefereneces() | 	obj, expected := getObjectMetaAndOwnerReferences() | ||||||
| 	accessor, err := meta.Accessor(&obj) | 	accessor, err := meta.Accessor(&obj) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Error(err) | 		t.Error(err) | ||||||
| @@ -371,7 +372,7 @@ func testGetOwnerReferences(t *testing.T) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func testSetOwnerReferences(t *testing.T) { | func testSetOwnerReferences(t *testing.T) { | ||||||
| 	expected, references := getObjectMetaAndOwnerRefereneces() | 	expected, references := getObjectMetaAndOwnerReferences() | ||||||
| 	obj := MyAPIObject2{} | 	obj := MyAPIObject2{} | ||||||
| 	accessor, err := meta.Accessor(&obj) | 	accessor, err := meta.Accessor(&obj) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|   | |||||||
| @@ -123,6 +123,7 @@ func TestDecode(t *testing.T) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func TestUnstructuredGetters(t *testing.T) { | func TestUnstructuredGetters(t *testing.T) { | ||||||
|  | 	trueVar := true | ||||||
| 	unstruct := unstructured.Unstructured{ | 	unstruct := unstructured.Unstructured{ | ||||||
| 		Object: map[string]interface{}{ | 		Object: map[string]interface{}{ | ||||||
| 			"kind":       "test_kind", | 			"kind":       "test_kind", | ||||||
| @@ -154,6 +155,10 @@ func TestUnstructuredGetters(t *testing.T) { | |||||||
| 						"name":       "podb", | 						"name":       "podb", | ||||||
| 						"apiVersion": "v1", | 						"apiVersion": "v1", | ||||||
| 						"uid":        "2", | 						"uid":        "2", | ||||||
|  | 						// though these fields are of type *bool, but when | ||||||
|  | 						// decoded from JSON, they are unmarshalled as bool. | ||||||
|  | 						"controller":         true, | ||||||
|  | 						"blockOwnerDeletion": true, | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 				"finalizers": []interface{}{ | 				"finalizers": []interface{}{ | ||||||
| @@ -221,10 +226,12 @@ func TestUnstructuredGetters(t *testing.T) { | |||||||
| 			UID:        "1", | 			UID:        "1", | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			Kind:       "Pod", | 			Kind:               "Pod", | ||||||
| 			Name:       "podb", | 			Name:               "podb", | ||||||
| 			APIVersion: "v1", | 			APIVersion:         "v1", | ||||||
| 			UID:        "2", | 			UID:                "2", | ||||||
|  | 			Controller:         &trueVar, | ||||||
|  | 			BlockOwnerDeletion: &trueVar, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 	if got, want := refs, expectedOwnerReferences; !reflect.DeepEqual(got, want) { | 	if got, want := refs, expectedOwnerReferences; !reflect.DeepEqual(got, want) { | ||||||
| @@ -263,18 +270,20 @@ func TestUnstructuredSetters(t *testing.T) { | |||||||
| 				}, | 				}, | ||||||
| 				"ownerReferences": []map[string]interface{}{ | 				"ownerReferences": []map[string]interface{}{ | ||||||
| 					{ | 					{ | ||||||
| 						"kind":       "Pod", | 						"kind":               "Pod", | ||||||
| 						"name":       "poda", | 						"name":               "poda", | ||||||
| 						"apiVersion": "v1", | 						"apiVersion":         "v1", | ||||||
| 						"uid":        "1", | 						"uid":                "1", | ||||||
| 						"controller": (*bool)(nil), | 						"controller":         (*bool)(nil), | ||||||
|  | 						"blockOwnerDeletion": (*bool)(nil), | ||||||
| 					}, | 					}, | ||||||
| 					{ | 					{ | ||||||
| 						"kind":       "Pod", | 						"kind":               "Pod", | ||||||
| 						"name":       "podb", | 						"name":               "podb", | ||||||
| 						"apiVersion": "v1", | 						"apiVersion":         "v1", | ||||||
| 						"uid":        "2", | 						"uid":                "2", | ||||||
| 						"controller": &trueVar, | 						"controller":         &trueVar, | ||||||
|  | 						"blockOwnerDeletion": &trueVar, | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 				"finalizers": []interface{}{ | 				"finalizers": []interface{}{ | ||||||
| @@ -307,11 +316,12 @@ func TestUnstructuredSetters(t *testing.T) { | |||||||
| 			UID:        "1", | 			UID:        "1", | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			Kind:       "Pod", | 			Kind:               "Pod", | ||||||
| 			Name:       "podb", | 			Name:               "podb", | ||||||
| 			APIVersion: "v1", | 			APIVersion:         "v1", | ||||||
| 			UID:        "2", | 			UID:                "2", | ||||||
| 			Controller: &trueVar, | 			Controller:         &trueVar, | ||||||
|  | 			BlockOwnerDeletion: &trueVar, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 	unstruct.SetOwnerReferences(newOwnerReferences) | 	unstruct.SetOwnerReferences(newOwnerReferences) | ||||||
|   | |||||||
| @@ -143,7 +143,7 @@ func (r *REST) Delete(ctx genericapirequest.Context, name string, options *metav | |||||||
| 					newFinalizers := []string{} | 					newFinalizers := []string{} | ||||||
| 					for i := range existingNamespace.ObjectMeta.Finalizers { | 					for i := range existingNamespace.ObjectMeta.Finalizers { | ||||||
| 						finalizer := existingNamespace.ObjectMeta.Finalizers[i] | 						finalizer := existingNamespace.ObjectMeta.Finalizers[i] | ||||||
| 						if string(finalizer) != metav1.FinalizerOrphan { | 						if string(finalizer) != metav1.FinalizerOrphanDependents { | ||||||
| 							newFinalizers = append(newFinalizers, finalizer) | 							newFinalizers = append(newFinalizers, finalizer) | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
|   | |||||||
| @@ -334,6 +334,14 @@ func extractFromOwnerReference(v reflect.Value, o *metav1.OwnerReference) error | |||||||
| 		controller := *controllerPtr | 		controller := *controllerPtr | ||||||
| 		o.Controller = &controller | 		o.Controller = &controller | ||||||
| 	} | 	} | ||||||
|  | 	var blockOwnerDeletionPtr *bool | ||||||
|  | 	if err := runtime.Field(v, "BlockOwnerDeletion", &blockOwnerDeletionPtr); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if blockOwnerDeletionPtr != nil { | ||||||
|  | 		block := *blockOwnerDeletionPtr | ||||||
|  | 		o.BlockOwnerDeletion = &block | ||||||
|  | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -357,6 +365,12 @@ func setOwnerReference(v reflect.Value, o *metav1.OwnerReference) error { | |||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	if o.BlockOwnerDeletion != nil { | ||||||
|  | 		block := *(o.BlockOwnerDeletion) | ||||||
|  | 		if err := runtime.SetField(&block, v, "BlockOwnerDeletion"); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -171,8 +171,26 @@ func ValidateObjectMeta(meta *metav1.ObjectMeta, requiresNamespace bool, nameFn | |||||||
| 	allErrs = append(allErrs, v1validation.ValidateLabels(meta.Labels, fldPath.Child("labels"))...) | 	allErrs = append(allErrs, v1validation.ValidateLabels(meta.Labels, fldPath.Child("labels"))...) | ||||||
| 	allErrs = append(allErrs, ValidateAnnotations(meta.Annotations, fldPath.Child("annotations"))...) | 	allErrs = append(allErrs, ValidateAnnotations(meta.Annotations, fldPath.Child("annotations"))...) | ||||||
| 	allErrs = append(allErrs, ValidateOwnerReferences(meta.OwnerReferences, fldPath.Child("ownerReferences"))...) | 	allErrs = append(allErrs, ValidateOwnerReferences(meta.OwnerReferences, fldPath.Child("ownerReferences"))...) | ||||||
| 	for _, finalizer := range meta.Finalizers { | 	allErrs = append(allErrs, ValidateFinalizers(meta.Finalizers, fldPath.Child("finalizers"))...) | ||||||
| 		allErrs = append(allErrs, ValidateFinalizerName(finalizer, fldPath.Child("finalizers"))...) | 	return allErrs | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ValidateFinalizers tests if the finalizers name are valid, and if there are conflicting finalizers. | ||||||
|  | func ValidateFinalizers(finalizers []string, fldPath *field.Path) field.ErrorList { | ||||||
|  | 	allErrs := field.ErrorList{} | ||||||
|  | 	hasFinalizerOrphanDependents := false | ||||||
|  | 	hasFinalizerDeleteDependents := false | ||||||
|  | 	for _, finalizer := range finalizers { | ||||||
|  | 		allErrs = append(allErrs, ValidateFinalizerName(finalizer, fldPath)...) | ||||||
|  | 		if finalizer == metav1.FinalizerOrphanDependents { | ||||||
|  | 			hasFinalizerOrphanDependents = true | ||||||
|  | 		} | ||||||
|  | 		if finalizer == metav1.FinalizerDeleteDependents { | ||||||
|  | 			hasFinalizerDeleteDependents = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if hasFinalizerDeleteDependents && hasFinalizerOrphanDependents { | ||||||
|  | 		allErrs = append(allErrs, field.Invalid(fldPath, finalizers, fmt.Sprintf("finalizer %s and %s cannot be both set", metav1.FinalizerOrphanDependents, metav1.FinalizerDeleteDependents))) | ||||||
| 	} | 	} | ||||||
| 	return allErrs | 	return allErrs | ||||||
| } | } | ||||||
|   | |||||||
| @@ -277,6 +277,28 @@ func TestValidateFinalizersUpdate(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func TestValidateFinalizersPreventConflictingFinalizers(t *testing.T) { | ||||||
|  | 	testcases := map[string]struct { | ||||||
|  | 		ObjectMeta  metav1.ObjectMeta | ||||||
|  | 		ExpectedErr string | ||||||
|  | 	}{ | ||||||
|  | 		"conflicting finalizers": { | ||||||
|  | 			ObjectMeta:  metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Finalizers: []string{metav1.FinalizerOrphanDependents, metav1.FinalizerDeleteDependents}}, | ||||||
|  | 			ExpectedErr: "cannot be both set", | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	for name, tc := range testcases { | ||||||
|  | 		errs := ValidateObjectMeta(&tc.ObjectMeta, false, NameIsDNSSubdomain, field.NewPath("field")) | ||||||
|  | 		if len(errs) == 0 { | ||||||
|  | 			if len(tc.ExpectedErr) != 0 { | ||||||
|  | 				t.Errorf("case: %q, expected error to contain %q", name, tc.ExpectedErr) | ||||||
|  | 			} | ||||||
|  | 		} else if e, a := tc.ExpectedErr, errs.ToAggregate().Error(); !strings.Contains(a, e) { | ||||||
|  | 			t.Errorf("case: %q, expected error to contain %q, got error %q", name, e, a) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| func TestValidateObjectMetaUpdatePreventsDeletionFieldMutation(t *testing.T) { | func TestValidateObjectMetaUpdatePreventsDeletionFieldMutation(t *testing.T) { | ||||||
| 	now := metav1.NewTime(time.Unix(1000, 0).UTC()) | 	now := metav1.NewTime(time.Unix(1000, 0).UTC()) | ||||||
| 	later := metav1.NewTime(time.Unix(2000, 0).UTC()) | 	later := metav1.NewTime(time.Unix(2000, 0).UTC()) | ||||||
|   | |||||||
| @@ -174,6 +174,10 @@ func (meta *ObjectMeta) GetOwnerReferences() []OwnerReference { | |||||||
| 			value := *meta.OwnerReferences[i].Controller | 			value := *meta.OwnerReferences[i].Controller | ||||||
| 			ret[i].Controller = &value | 			ret[i].Controller = &value | ||||||
| 		} | 		} | ||||||
|  | 		if meta.OwnerReferences[i].BlockOwnerDeletion != nil { | ||||||
|  | 			value := *meta.OwnerReferences[i].BlockOwnerDeletion | ||||||
|  | 			ret[i].BlockOwnerDeletion = &value | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	return ret | 	return ret | ||||||
| } | } | ||||||
| @@ -189,6 +193,10 @@ func (meta *ObjectMeta) SetOwnerReferences(references []OwnerReference) { | |||||||
| 			value := *references[i].Controller | 			value := *references[i].Controller | ||||||
| 			newReferences[i].Controller = &value | 			newReferences[i].Controller = &value | ||||||
| 		} | 		} | ||||||
|  | 		if references[i].BlockOwnerDeletion != nil { | ||||||
|  | 			value := *references[i].BlockOwnerDeletion | ||||||
|  | 			newReferences[i].BlockOwnerDeletion = &value | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	meta.OwnerReferences = newReferences | 	meta.OwnerReferences = newReferences | ||||||
| } | } | ||||||
|   | |||||||
| @@ -73,7 +73,8 @@ type ListMeta struct { | |||||||
|  |  | ||||||
| // These are internal finalizer values for Kubernetes-like APIs, must be qualified name unless defined here | // These are internal finalizer values for Kubernetes-like APIs, must be qualified name unless defined here | ||||||
| const ( | const ( | ||||||
| 	FinalizerOrphan string = "orphan" | 	FinalizerOrphanDependents string = "orphan" | ||||||
|  | 	FinalizerDeleteDependents string = "foregroundDeletion" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // ObjectMeta is metadata that all persisted resources must have, which includes all objects | // ObjectMeta is metadata that all persisted resources must have, which includes all objects | ||||||
| @@ -255,6 +256,14 @@ type OwnerReference struct { | |||||||
| 	// If true, this reference points to the managing controller. | 	// If true, this reference points to the managing controller. | ||||||
| 	// +optional | 	// +optional | ||||||
| 	Controller *bool `json:"controller,omitempty" protobuf:"varint,6,opt,name=controller"` | 	Controller *bool `json:"controller,omitempty" protobuf:"varint,6,opt,name=controller"` | ||||||
|  | 	// If true, AND if the owner has the "foregroundDeletion" finalizer, then | ||||||
|  | 	// the owner cannot be deleted from the key-value store until this | ||||||
|  | 	// reference is removed. | ||||||
|  | 	// Defaults to false. | ||||||
|  | 	// To set this field, a user needs "delete" permission of the owner, | ||||||
|  | 	// otherwise 422 (Unprocessable Entity) will be returned. | ||||||
|  | 	// +optional | ||||||
|  | 	BlockOwnerDeletion *bool `json:"blockOwnerDeletion,omitempty" protobuf:"varint,7,opt,name=blockOwnerDeletion"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // ListOptions is the query options to a standard REST list call. | // ListOptions is the query options to a standard REST list call. | ||||||
| @@ -305,6 +314,24 @@ type GetOptions struct { | |||||||
| 	ResourceVersion string `json:"resourceVersion,omitempty" protobuf:"bytes,1,opt,name=resourceVersion"` | 	ResourceVersion string `json:"resourceVersion,omitempty" protobuf:"bytes,1,opt,name=resourceVersion"` | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // DeletionPropagation decides if a deletion will propagate to the dependents of | ||||||
|  | // the object, and how the garbage collector will handle the propagation. | ||||||
|  | type DeletionPropagation string | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	// Orphans the dependents. | ||||||
|  | 	DeletePropagationOrphan DeletionPropagation = "Orphan" | ||||||
|  | 	// Deletes the object from the key-value store, the garbage collector will | ||||||
|  | 	// delete the dependents in the background. | ||||||
|  | 	DeletePropagationBackground DeletionPropagation = "Background" | ||||||
|  | 	// The object exists in the key-value store until the garbage collector | ||||||
|  | 	// deletes all the dependents whose ownerReference.blockOwnerDeletion=true | ||||||
|  | 	// from the key-value store.  API sever will put the "foregroundDeletion" | ||||||
|  | 	// finalizer on the object, and sets its deletionTimestamp.  This policy is | ||||||
|  | 	// cascading, i.e., the dependents will be deleted with Foreground. | ||||||
|  | 	DeletePropagationForeground DeletionPropagation = "Foreground" | ||||||
|  | ) | ||||||
|  |  | ||||||
| // DeleteOptions may be provided when deleting an API object. | // DeleteOptions may be provided when deleting an API object. | ||||||
| type DeleteOptions struct { | type DeleteOptions struct { | ||||||
| 	TypeMeta `json:",inline"` | 	TypeMeta `json:",inline"` | ||||||
| @@ -321,10 +348,18 @@ type DeleteOptions struct { | |||||||
| 	// +optional | 	// +optional | ||||||
| 	Preconditions *Preconditions `json:"preconditions,omitempty" protobuf:"bytes,2,opt,name=preconditions"` | 	Preconditions *Preconditions `json:"preconditions,omitempty" protobuf:"bytes,2,opt,name=preconditions"` | ||||||
|  |  | ||||||
|  | 	// Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. | ||||||
| 	// Should the dependent objects be orphaned. If true/false, the "orphan" | 	// Should the dependent objects be orphaned. If true/false, the "orphan" | ||||||
| 	// finalizer will be added to/removed from the object's finalizers list. | 	// finalizer will be added to/removed from the object's finalizers list. | ||||||
|  | 	// Either this field or PropagationPolicy may be set, but not both. | ||||||
| 	// +optional | 	// +optional | ||||||
| 	OrphanDependents *bool `json:"orphanDependents,omitempty" protobuf:"varint,3,opt,name=orphanDependents"` | 	OrphanDependents *bool `json:"orphanDependents,omitempty" protobuf:"varint,3,opt,name=orphanDependents"` | ||||||
|  |  | ||||||
|  | 	// Whether and how garbage collection will be performed. | ||||||
|  | 	// Defaults to Default. | ||||||
|  | 	// Either this field or OrphanDependents may be set, but not both. | ||||||
|  | 	// +optional | ||||||
|  | 	PropagationPolicy *DeletionPropagation `json:"propagationPolicy,omitempty" protobuf:"varint,4,opt,name=propagationPolicy"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // Preconditions must be fulfilled before an operation (update, delete, etc.) is carried out. | // Preconditions must be fulfilled before an operation (update, delete, etc.) is carried out. | ||||||
|   | |||||||
| @@ -204,21 +204,31 @@ func (u *Unstructured) setNestedMap(value map[string]string, fields ...string) { | |||||||
|  |  | ||||||
| func extractOwnerReference(src interface{}) metav1.OwnerReference { | func extractOwnerReference(src interface{}) metav1.OwnerReference { | ||||||
| 	v := src.(map[string]interface{}) | 	v := src.(map[string]interface{}) | ||||||
| 	controllerPtr, ok := (getNestedField(v, "controller")).(*bool) | 	// though this field is a *bool, but when decoded from JSON, it's | ||||||
|  | 	// unmarshalled as bool. | ||||||
|  | 	var controllerPtr *bool | ||||||
|  | 	controller, ok := (getNestedField(v, "controller")).(bool) | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		controllerPtr = nil | 		controllerPtr = nil | ||||||
| 	} else { | 	} else { | ||||||
| 		if controllerPtr != nil { | 		controllerCopy := controller | ||||||
| 			controller := *controllerPtr | 		controllerPtr = &controllerCopy | ||||||
| 			controllerPtr = &controller | 	} | ||||||
| 		} | 	var blockOwnerDeletionPtr *bool | ||||||
|  | 	blockOwnerDeletion, ok := (getNestedField(v, "blockOwnerDeletion")).(bool) | ||||||
|  | 	if !ok { | ||||||
|  | 		blockOwnerDeletionPtr = nil | ||||||
|  | 	} else { | ||||||
|  | 		blockOwnerDeletionCopy := blockOwnerDeletion | ||||||
|  | 		blockOwnerDeletionPtr = &blockOwnerDeletionCopy | ||||||
| 	} | 	} | ||||||
| 	return metav1.OwnerReference{ | 	return metav1.OwnerReference{ | ||||||
| 		Kind:       getNestedString(v, "kind"), | 		Kind:               getNestedString(v, "kind"), | ||||||
| 		Name:       getNestedString(v, "name"), | 		Name:               getNestedString(v, "name"), | ||||||
| 		APIVersion: getNestedString(v, "apiVersion"), | 		APIVersion:         getNestedString(v, "apiVersion"), | ||||||
| 		UID:        (types.UID)(getNestedString(v, "uid")), | 		UID:                (types.UID)(getNestedString(v, "uid")), | ||||||
| 		Controller: controllerPtr, | 		Controller:         controllerPtr, | ||||||
|  | 		BlockOwnerDeletion: blockOwnerDeletionPtr, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -229,11 +239,17 @@ func setOwnerReference(src metav1.OwnerReference) map[string]interface{} { | |||||||
| 		controller := *controllerPtr | 		controller := *controllerPtr | ||||||
| 		controllerPtr = &controller | 		controllerPtr = &controller | ||||||
| 	} | 	} | ||||||
|  | 	blockOwnerDeletionPtr := src.BlockOwnerDeletion | ||||||
|  | 	if blockOwnerDeletionPtr != nil { | ||||||
|  | 		blockOwnerDeletion := *blockOwnerDeletionPtr | ||||||
|  | 		blockOwnerDeletionPtr = &blockOwnerDeletion | ||||||
|  | 	} | ||||||
| 	setNestedField(ret, src.Kind, "kind") | 	setNestedField(ret, src.Kind, "kind") | ||||||
| 	setNestedField(ret, src.Name, "name") | 	setNestedField(ret, src.Name, "name") | ||||||
| 	setNestedField(ret, src.APIVersion, "apiVersion") | 	setNestedField(ret, src.APIVersion, "apiVersion") | ||||||
| 	setNestedField(ret, string(src.UID), "uid") | 	setNestedField(ret, string(src.UID), "uid") | ||||||
| 	setNestedField(ret, controllerPtr, "controller") | 	setNestedField(ret, controllerPtr, "controller") | ||||||
|  | 	setNestedField(ret, blockOwnerDeletionPtr, "blockOwnerDeletion") | ||||||
| 	return ret | 	return ret | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,6 +17,8 @@ limitations under the License. | |||||||
| package validation | package validation | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
|  |  | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/util/validation" | 	"k8s.io/apimachinery/pkg/util/validation" | ||||||
| 	"k8s.io/apimachinery/pkg/util/validation/field" | 	"k8s.io/apimachinery/pkg/util/validation/field" | ||||||
| @@ -72,3 +74,17 @@ func ValidateLabels(labels map[string]string, fldPath *field.Path) field.ErrorLi | |||||||
| 	} | 	} | ||||||
| 	return allErrs | 	return allErrs | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func ValidateDeleteOptions(options *metav1.DeleteOptions) field.ErrorList { | ||||||
|  | 	allErrs := field.ErrorList{} | ||||||
|  | 	if options.OrphanDependents != nil && options.PropagationPolicy != nil { | ||||||
|  | 		allErrs = append(allErrs, field.Invalid(field.NewPath(""), options, "OrphanDependents and DeletionPropagation cannot be both set")) | ||||||
|  | 	} | ||||||
|  | 	if options.PropagationPolicy != nil && | ||||||
|  | 		*options.PropagationPolicy != metav1.DeletePropagationForeground && | ||||||
|  | 		*options.PropagationPolicy != metav1.DeletePropagationBackground && | ||||||
|  | 		*options.PropagationPolicy != metav1.DeletePropagationOrphan { | ||||||
|  | 		allErrs = append(allErrs, field.Invalid(field.NewPath(""), options, fmt.Sprintf("DeletionPropagation need to be one of %q, %q, %q or nil", metav1.DeletePropagationForeground, metav1.DeletePropagationBackground, metav1.DeletePropagationOrphan))) | ||||||
|  | 	} | ||||||
|  | 	return allErrs | ||||||
|  | } | ||||||
|   | |||||||
| @@ -244,7 +244,7 @@ func IsServiceIPRequested(service *Service) bool { | |||||||
|  |  | ||||||
| var standardFinalizers = sets.NewString( | var standardFinalizers = sets.NewString( | ||||||
| 	string(FinalizerKubernetes), | 	string(FinalizerKubernetes), | ||||||
| 	metav1.FinalizerOrphan, | 	metav1.FinalizerOrphanDependents, | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // HasAnnotation returns a bool if passed in annotation exists | // HasAnnotation returns a bool if passed in annotation exists | ||||||
|   | |||||||
| @@ -84,7 +84,7 @@ func IsServiceIPRequested(service *Service) bool { | |||||||
|  |  | ||||||
| var standardFinalizers = sets.NewString( | var standardFinalizers = sets.NewString( | ||||||
| 	string(FinalizerKubernetes), | 	string(FinalizerKubernetes), | ||||||
| 	metav1.FinalizerOrphan, | 	metav1.FinalizerOrphanDependents, | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func IsStandardFinalizerName(str string) bool { | func IsStandardFinalizerName(str string) bool { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Chao Xu
					Chao Xu