Skip to content

Commit

Permalink
Remove MemberClusterAnnounce if ClusterSet deleted (#4026)
Browse files Browse the repository at this point in the history
Add a step to ensure that member ClusterSet controller will
clean up MemberClusterAnnounce in the leader cluster if
the ClusterSet in the member is deleted.

Signed-off-by: Lan Luo <[email protected]>
  • Loading branch information
luolanzone authored Jul 21, 2022
1 parent b70635e commit 9f76f8e
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 7 deletions.
12 changes: 6 additions & 6 deletions docs/multicluster/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ mode, and all member clusters in a ClusterSet must use the same tunnel type.

Run the following commands to deploy Multi-cluster Controller for the leader
into Namespace `antrea-multicluster` (Namespace `antrea-multicluster` will be
created by the commands), and Multi-cluster Controller for the member into
created by the commands), and Multi-cluster Controller for the member into
Namepsace `kube-system`.

```bash
Expand Down Expand Up @@ -84,13 +84,13 @@ to access the leader cluster (cluster A in our case) apiserver.

```bash
$kubectl apply -f https://raw.githubusercontent.com/antrea-io/antrea/$TAG/multicluster/config/samples/clusterset_init/multicluster_clusterset_template.yaml
$kubectl apply -f https://raw.githubusercontent.com/antrea-io/antrea/$TAG/multicluster/config/samples/clusterset_init/multicluster_leader_access_token_template.yaml
$kubectl get secret leader-access-token -n antrea-multicluster -o yaml | grep -w -e '^apiVersion' -e '^data' -e '^metadata' -e '^ *name:' -e '^kind' -e ' ca.crt' -e ' token:' -e '^type' -e ' namespace' | sed -e 's/kubernetes.io\/service-account-token/Opaque/g' -e 's/antrea-multicluster/kube-system/g' > leader-access-token.yml
$kubectl apply -f https://raw.githubusercontent.com/antrea-io/antrea/$TAG/multicluster/config/samples/clusterset_init/multicluster_leader_access_token_template.yaml
$kubectl get secret leader-access-token -n antrea-multicluster -o yaml | grep -w -e '^apiVersion' -e '^data' -e '^metadata' -e '^ *name:' -e '^kind' -e ' ca.crt' -e ' token:' -e '^type' -e ' namespace' | sed -e 's/kubernetes.io\/service-account-token/Opaque/g' -e 's/antrea-multicluster/kube-system/g' > leader-access-token.yml
```

The last command saves the ServiceAccount token to `leader-access-token.yml`
which will be needed for member clusters to join the ClusterSet. Note, in this
guide, we use a shared default ServiceAccount `antrea-mc-member-access-sa` for
guide, we use a shared default ServiceAccount `antrea-mc-member-access-sa` for
all member clusters. If you want to create a separate ServiceAccount for each
member cluster for security considerations, you can follow the instructions in
the [Multi-cluster User Guide](user-guide.md#set-up-access-to-leader-cluster).
Expand All @@ -100,7 +100,7 @@ member:

```bash
$kubectl apply -f leader-access-token.yml
$curl -L https://raw.githubusercontent.com/antrea-io/antrea/v1.7.0/multicluster/config/samples/clusterset_init/multicluster_membercluster_template.yaml > multicluster_membercluster.yaml
$curl -L https://raw.githubusercontent.com/antrea-io/antrea/v1.7.0/multicluster/config/samples/clusterset_init/multicluster_membercluster_template.yaml > multicluster_membercluster.yaml
$sed -e 's/test-cluster-member/test-cluster-leader/g' -e 's/<LEADER_CLUSTER_IP>/172.10.0.11/g' multicluster_membercluster.yaml | kubectl apply -f -
```

Expand Down Expand Up @@ -156,7 +156,7 @@ Run the following commands to make cluster B join the ClusterSet:

```bash
$kubectl apply -f leader-access-token.yml
$curl -L https://raw.githubusercontent.com/antrea-io/antrea/$TAG/multicluster/config/samples/clusterset_init/multicluster_membercluster_template.yaml > multicluster_membercluster.yaml
$curl -L https://raw.githubusercontent.com/antrea-io/antrea/$TAG/multicluster/config/samples/clusterset_init/multicluster_membercluster_template.yaml > multicluster_membercluster.yaml
$sed -e 's/<LEADER_CLUSTER_IP>/172.10.0.11/g' multicluster_membercluster.yaml | kubectl apply -f -
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ func (r *MemberClusterSetReconciler) Reconcile(ctx context.Context, req ctrl.Req
}
klog.InfoS("Received ClusterSet delete", "clusterset", req.NamespacedName)
if r.remoteCommonArea != nil {
if err := r.deleteMemberClusterAnnounce(ctx); err != nil {
return ctrl.Result{}, fmt.Errorf("failed to delete MemberClusterAnnounce in the leader cluster: %v", err)
}
r.remoteCommonArea.Stop()
r.remoteCommonArea = nil
r.clusterSetConfig = nil
Expand Down Expand Up @@ -133,6 +136,19 @@ func (r *MemberClusterSetReconciler) Reconcile(ctx context.Context, req ctrl.Req
return ctrl.Result{}, nil
}

func (r *MemberClusterSetReconciler) deleteMemberClusterAnnounce(ctx context.Context) error {
memberClusterAnnounce := &multiclusterv1alpha1.MemberClusterAnnounce{
ObjectMeta: metav1.ObjectMeta{
Name: "member-announce-from-" + r.remoteCommonArea.GetLocalClusterID(),
Namespace: r.remoteCommonArea.GetNamespace(),
},
}
if err := r.remoteCommonArea.Delete(ctx, memberClusterAnnounce, &client.DeleteOptions{}); err != nil {
return client.IgnoreNotFound(err)
}
return nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *MemberClusterSetReconciler) SetupWithManager(mgr ctrl.Manager) error {
// Update status periodically
Expand All @@ -152,9 +168,13 @@ func (r *MemberClusterSetReconciler) SetupWithManager(mgr ctrl.Manager) error {
}
namespacePredicate := predicate.NewPredicateFuncs(namespaceFilter)

// Ignore status update event via GenerationChangedPredicate
generationPredicate := predicate.GenerationChangedPredicate{}
filter := predicate.And(generationPredicate, namespacePredicate)

return ctrl.NewControllerManagedBy(mgr).
For(&multiclusterv1alpha1.ClusterSet{}).
WithEventFilter(namespacePredicate).
WithEventFilter(filter).
WithOptions(controller.Options{
MaxConcurrentReconciles: common.DefaultWorkerCount,
}).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2022 Antrea 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 multicluster

import (
"testing"

apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

mcsv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1"
"antrea.io/antrea/multicluster/controllers/multicluster/commonarea"
)

func TestMemberClusterDelete(t *testing.T) {
existingMemberClusterAnnounce := &mcsv1alpha1.MemberClusterAnnounce{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "member-announce-from-cluster-a",
Generation: 1,
},
}
fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects().Build()
fakeRemoteClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existingMemberClusterAnnounce).Build()
commonArea := commonarea.NewFakeRemoteCommonArea(scheme, fakeRemoteClient, "leader-cluster", localClusterID, "default")

reconciler := MemberClusterSetReconciler{
Client: fakeClient,
remoteCommonArea: commonArea,
}
if _, err := reconciler.Reconcile(ctx, reconcile.Request{
NamespacedName: types.NamespacedName{
Namespace: "default",
Name: "clusterset1",
}}); err != nil {
t.Errorf("Member ClusterSet Reconciler should handle delete event successfully but got error = %v", err)
} else {
memberClusterAnnounce := &mcsv1alpha1.MemberClusterAnnounce{}
err := fakeClient.Get(ctx, types.NamespacedName{
Namespace: "default",
Name: "member-announce-from-cluster-a",
}, memberClusterAnnounce)
if !apierrors.IsNotFound(err) {
t.Errorf("Member ClusterSet Reconciler should remove MemberClusterAnnounce successfully but got error = %v", err)
}
}
}

0 comments on commit 9f76f8e

Please sign in to comment.