mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 04:33:26 +00:00
Delete resources in federated namespce
This commit is contained in:
parent
23147d30e9
commit
091b843b4a
@ -251,7 +251,12 @@ func (nc *NamespaceController) reconcileNamespace(namespace string) {
|
|||||||
}
|
}
|
||||||
baseNamespace := baseNamespaceObj.(*api_v1.Namespace)
|
baseNamespace := baseNamespaceObj.(*api_v1.Namespace)
|
||||||
if baseNamespace.DeletionTimestamp != nil {
|
if baseNamespace.DeletionTimestamp != nil {
|
||||||
nc.delete(baseNamespace)
|
if err := nc.delete(baseNamespace); err != nil {
|
||||||
|
glog.Errorf("Failed to delete %s: %v", namespace, err)
|
||||||
|
nc.eventRecorder.Eventf(baseNamespace, api.EventTypeNormal, "DeleteFailed",
|
||||||
|
"Namespace delete failed: %v", err)
|
||||||
|
nc.deliverNamespace(namespace, 0, true)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,7 +325,8 @@ func (nc *NamespaceController) reconcileNamespace(namespace string) {
|
|||||||
nc.deliverNamespace(namespace, nc.namespaceReviewDelay, false)
|
nc.deliverNamespace(namespace, nc.namespaceReviewDelay, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nc *NamespaceController) delete(namespace *api_v1.Namespace) {
|
// delete deletes the given namespace or returns error if the deletion was not complete.
|
||||||
|
func (nc *NamespaceController) delete(namespace *api_v1.Namespace) error {
|
||||||
// Set Terminating status.
|
// Set Terminating status.
|
||||||
updatedNamespace := &api_v1.Namespace{
|
updatedNamespace := &api_v1.Namespace{
|
||||||
ObjectMeta: namespace.ObjectMeta,
|
ObjectMeta: namespace.ObjectMeta,
|
||||||
@ -333,13 +339,33 @@ func (nc *NamespaceController) delete(namespace *api_v1.Namespace) {
|
|||||||
nc.eventRecorder.Event(namespace, api.EventTypeNormal, "DeleteNamespace", fmt.Sprintf("Marking for deletion"))
|
nc.eventRecorder.Event(namespace, api.EventTypeNormal, "DeleteNamespace", fmt.Sprintf("Marking for deletion"))
|
||||||
_, err := nc.federatedApiClient.Core().Namespaces().Update(updatedNamespace)
|
_, err := nc.federatedApiClient.Core().Namespaces().Update(updatedNamespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to update namespace %s: %v", updatedNamespace.Name, err)
|
return fmt.Errorf("failed to update namespace: %v", err)
|
||||||
nc.deliverNamespace(namespace.Name, 0, true)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: delete all namespace content.
|
// Right now there is just 5 types of objects: ReplicaSet, Secret, Ingress, Events and Service.
|
||||||
|
// Temporarly these items are simply deleted one by one to squeeze this code into 1.4.
|
||||||
|
// TODO: Make it generic (like in the regular namespace controller) and parallel.
|
||||||
|
err := nc.federatedApiClient.Core().Services(namespace.Name).DeleteCollection(&api.DeleteOptions{}, api.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to delete service list: %v", err)
|
||||||
|
}
|
||||||
|
err = nc.federatedApiClient.Extensions().ReplicaSets(namespace.Name).DeleteCollection(&api.DeleteOptions{}, api.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to delete replicaset list from namespace: %v", err)
|
||||||
|
}
|
||||||
|
err = nc.federatedApiClient.Core().Secrets(namespace.Name).DeleteCollection(&api.DeleteOptions{}, api.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to delete secret list from namespace: %v", err)
|
||||||
|
}
|
||||||
|
err = nc.federatedApiClient.Extensions().Ingresses(namespace.Name).DeleteCollection(&api.DeleteOptions{}, api.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to delete ingresses list from namespace: %v", err)
|
||||||
|
}
|
||||||
|
err = nc.federatedApiClient.Core().Events(namespace.Name).DeleteCollection(&api.DeleteOptions{}, api.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to delete events list from namespace: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Remove kube_api.FinalzerKubernetes
|
// Remove kube_api.FinalzerKubernetes
|
||||||
if len(updatedNamespace.Spec.Finalizers) != 0 {
|
if len(updatedNamespace.Spec.Finalizers) != 0 {
|
||||||
@ -355,21 +381,19 @@ func (nc *NamespaceController) delete(namespace *api_v1.Namespace) {
|
|||||||
}
|
}
|
||||||
_, err := nc.federatedApiClient.Core().Namespaces().Finalize(updatedNamespace)
|
_, err := nc.federatedApiClient.Core().Namespaces().Finalize(updatedNamespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to update namespace %s: %v", updatedNamespace.Name, err)
|
return fmt.Errorf("failed to finalize namespace: %v", err)
|
||||||
nc.deliverNamespace(namespace.Name, 0, true)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: What about namespaces in subclusters ???
|
// TODO: What about namespaces in subclusters ???
|
||||||
err := nc.federatedApiClient.Core().Namespaces().Delete(updatedNamespace.Name, &api.DeleteOptions{})
|
err = nc.federatedApiClient.Core().Namespaces().Delete(updatedNamespace.Name, &api.DeleteOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Its all good if the error is not found error. That means it is deleted already and we do not have to do anything.
|
// Its all good if the error is not found error. That means it is deleted already and we do not have to do anything.
|
||||||
// This is expected when we are processing an update as a result of namespace finalizer deletion.
|
// This is expected when we are processing an update as a result of namespace finalizer deletion.
|
||||||
// The process that deleted the last finalizer is also going to delete the namespace and we do not have to do anything.
|
// The process that deleted the last finalizer is also going to delete the namespace and we do not have to do anything.
|
||||||
if !errors.IsNotFound(err) {
|
if !errors.IsNotFound(err) {
|
||||||
glog.Errorf("Failed to delete namespace %s: %v", namespace.Name, err)
|
return fmt.Errorf("failed to delete namespace: %v", err)
|
||||||
nc.deliverNamespace(namespace.Name, 0, true)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,12 @@ import (
|
|||||||
federation_api "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
federation_api "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||||
fake_federation_release_1_4 "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_4/fake"
|
fake_federation_release_1_4 "k8s.io/kubernetes/federation/client/clientset_generated/federation_release_1_4/fake"
|
||||||
. "k8s.io/kubernetes/federation/pkg/federation-controller/util/test"
|
. "k8s.io/kubernetes/federation/pkg/federation-controller/util/test"
|
||||||
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
api_v1 "k8s.io/kubernetes/pkg/api/v1"
|
api_v1 "k8s.io/kubernetes/pkg/api/v1"
|
||||||
|
extensionsv1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||||
kube_release_1_4 "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_4"
|
kube_release_1_4 "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_4"
|
||||||
fake_kube_release_1_4 "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_4/fake"
|
fake_kube_release_1_4 "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_4/fake"
|
||||||
|
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -35,6 +38,12 @@ import (
|
|||||||
func TestNamespaceController(t *testing.T) {
|
func TestNamespaceController(t *testing.T) {
|
||||||
cluster1 := NewCluster("cluster1", api_v1.ConditionTrue)
|
cluster1 := NewCluster("cluster1", api_v1.ConditionTrue)
|
||||||
cluster2 := NewCluster("cluster2", api_v1.ConditionTrue)
|
cluster2 := NewCluster("cluster2", api_v1.ConditionTrue)
|
||||||
|
ns1 := api_v1.Namespace{
|
||||||
|
ObjectMeta: api_v1.ObjectMeta{
|
||||||
|
Name: "test-namespace",
|
||||||
|
SelfLink: "/api/v1/namespaces/test-namespace",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
fakeClient := &fake_federation_release_1_4.Clientset{}
|
fakeClient := &fake_federation_release_1_4.Clientset{}
|
||||||
RegisterFakeList("clusters", &fakeClient.Fake, &federation_api.ClusterList{Items: []federation_api.Cluster{*cluster1}})
|
RegisterFakeList("clusters", &fakeClient.Fake, &federation_api.ClusterList{Items: []federation_api.Cluster{*cluster1}})
|
||||||
@ -53,6 +62,29 @@ func TestNamespaceController(t *testing.T) {
|
|||||||
RegisterFakeList("namespaces", &cluster2Client.Fake, &api_v1.NamespaceList{Items: []api_v1.Namespace{}})
|
RegisterFakeList("namespaces", &cluster2Client.Fake, &api_v1.NamespaceList{Items: []api_v1.Namespace{}})
|
||||||
cluster2CreateChan := RegisterFakeCopyOnCreate("namespaces", &cluster2Client.Fake, cluster2Watch)
|
cluster2CreateChan := RegisterFakeCopyOnCreate("namespaces", &cluster2Client.Fake, cluster2Watch)
|
||||||
|
|
||||||
|
RegisterFakeList("replicasets", &fakeClient.Fake, &extensionsv1.ReplicaSetList{Items: []extensionsv1.ReplicaSet{
|
||||||
|
{
|
||||||
|
ObjectMeta: api_v1.ObjectMeta{
|
||||||
|
Name: "test-rs",
|
||||||
|
Namespace: ns1.Namespace,
|
||||||
|
}}}})
|
||||||
|
RegisterFakeList("secrets", &fakeClient.Fake, &api_v1.SecretList{Items: []api_v1.Secret{
|
||||||
|
{
|
||||||
|
ObjectMeta: api_v1.ObjectMeta{
|
||||||
|
Name: "test-secret",
|
||||||
|
Namespace: ns1.Namespace,
|
||||||
|
}}}})
|
||||||
|
RegisterFakeList("services", &fakeClient.Fake, &api_v1.ServiceList{Items: []api_v1.Service{
|
||||||
|
{
|
||||||
|
ObjectMeta: api_v1.ObjectMeta{
|
||||||
|
Name: "test-service",
|
||||||
|
Namespace: ns1.Namespace,
|
||||||
|
}}}})
|
||||||
|
nsDeleteChan := RegisterDelete(&fakeClient.Fake, "namespaces")
|
||||||
|
rsDeleteChan := RegisterDeleteCollection(&fakeClient.Fake, "replicasets")
|
||||||
|
serviceDeleteChan := RegisterDeleteCollection(&fakeClient.Fake, "services")
|
||||||
|
secretDeleteChan := RegisterDeleteCollection(&fakeClient.Fake, "secrets")
|
||||||
|
|
||||||
namespaceController := NewNamespaceController(fakeClient)
|
namespaceController := NewNamespaceController(fakeClient)
|
||||||
informer := ToFederatedInformerForTestOnly(namespaceController.namespaceFederatedInformer)
|
informer := ToFederatedInformerForTestOnly(namespaceController.namespaceFederatedInformer)
|
||||||
informer.SetClientFactory(func(cluster *federation_api.Cluster) (kube_release_1_4.Interface, error) {
|
informer.SetClientFactory(func(cluster *federation_api.Cluster) (kube_release_1_4.Interface, error) {
|
||||||
@ -73,13 +105,6 @@ func TestNamespaceController(t *testing.T) {
|
|||||||
stop := make(chan struct{})
|
stop := make(chan struct{})
|
||||||
namespaceController.Run(stop)
|
namespaceController.Run(stop)
|
||||||
|
|
||||||
ns1 := api_v1.Namespace{
|
|
||||||
ObjectMeta: api_v1.ObjectMeta{
|
|
||||||
Name: "test-namespace",
|
|
||||||
SelfLink: "/api/v1/namespaces/test-namespace",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test add federated namespace.
|
// Test add federated namespace.
|
||||||
namespaceWatch.Add(&ns1)
|
namespaceWatch.Add(&ns1)
|
||||||
createdNamespace := GetNamespaceFromChan(cluster1CreateChan)
|
createdNamespace := GetNamespaceFromChan(cluster1CreateChan)
|
||||||
@ -103,9 +128,44 @@ func TestNamespaceController(t *testing.T) {
|
|||||||
assert.Equal(t, ns1.Name, createdNamespace2.Name)
|
assert.Equal(t, ns1.Name, createdNamespace2.Name)
|
||||||
// assert.Contains(t, createdNamespace2.Annotations, "A")
|
// assert.Contains(t, createdNamespace2.Annotations, "A")
|
||||||
|
|
||||||
|
ns1.DeletionTimestamp = &unversioned.Time{Time: time.Now()}
|
||||||
|
namespaceWatch.Modify(&ns1)
|
||||||
|
assert.Equal(t, ns1.Name, GetStringFromChan(nsDeleteChan))
|
||||||
|
assert.Equal(t, "all", GetStringFromChan(rsDeleteChan))
|
||||||
|
assert.Equal(t, "all", GetStringFromChan(serviceDeleteChan))
|
||||||
|
assert.Equal(t, "all", GetStringFromChan(secretDeleteChan))
|
||||||
|
|
||||||
close(stop)
|
close(stop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RegisterDeleteCollection(client *core.Fake, resource string) chan string {
|
||||||
|
deleteChan := make(chan string, 100)
|
||||||
|
client.AddReactor("delete-collection", resource, func(action core.Action) (bool, runtime.Object, error) {
|
||||||
|
deleteChan <- "all"
|
||||||
|
return true, nil, nil
|
||||||
|
})
|
||||||
|
return deleteChan
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterDelete(client *core.Fake, resource string) chan string {
|
||||||
|
deleteChan := make(chan string, 100)
|
||||||
|
client.AddReactor("delete", resource, func(action core.Action) (bool, runtime.Object, error) {
|
||||||
|
deleteAction := action.(core.DeleteAction)
|
||||||
|
deleteChan <- deleteAction.GetName()
|
||||||
|
return true, nil, nil
|
||||||
|
})
|
||||||
|
return deleteChan
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetStringFromChan(c chan string) string {
|
||||||
|
select {
|
||||||
|
case str := <-c:
|
||||||
|
return str
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func GetNamespaceFromChan(c chan runtime.Object) *api_v1.Namespace {
|
func GetNamespaceFromChan(c chan runtime.Object) *api_v1.Namespace {
|
||||||
namespace := GetObjectFromChan(c).(*api_v1.Namespace)
|
namespace := GetObjectFromChan(c).(*api_v1.Namespace)
|
||||||
return namespace
|
return namespace
|
||||||
|
Loading…
Reference in New Issue
Block a user