Skip to content

Commit

Permalink
fetch and delete token command line
Browse files Browse the repository at this point in the history
Signed-off-by: Bangqi Zhu <zbangqi@vmware.com>
  • Loading branch information
Bangqi Zhu committed Oct 10, 2022
1 parent 1e31a78 commit 5c81866
Show file tree
Hide file tree
Showing 11 changed files with 727 additions and 20 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ require (
github.com/golang/protobuf v1.5.2
github.com/google/btree v1.1.2
github.com/google/uuid v1.3.0
github.com/hashicorp/memberlist v0.4.0
github.com/hashicorp/memberlist v0.5.0
github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.1.1
github.com/k8snetworkplumbingwg/sriov-cni v2.1.0+incompatible
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -559,8 +559,8 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/memberlist v0.4.0 h1:k3uda5gZcltmafuFF+UFqNEl5PrH+yPZ4zkjp1f/H/8=
github.com/hashicorp/memberlist v0.4.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=
github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM=
github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
Expand Down
6 changes: 6 additions & 0 deletions pkg/antctl/antctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,12 @@ $ antctl get podmulticaststats pod -n namespace`,
supportController: false,
commandGroup: mc,
},
{
cobraCommand: multicluster.DeleteCmd,
supportAgent: false,
supportController: false,
commandGroup: mc,
},
{
cobraCommand: set.SetCmd,
supportAgent: false,
Expand Down
8 changes: 8 additions & 0 deletions pkg/antctl/raw/multicluster/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/spf13/cobra"

"antrea.io/antrea/pkg/antctl/raw/multicluster/create"
"antrea.io/antrea/pkg/antctl/raw/multicluster/delete"
"antrea.io/antrea/pkg/antctl/raw/multicluster/deploy"
"antrea.io/antrea/pkg/antctl/raw/multicluster/get"
)
Expand All @@ -37,6 +38,11 @@ var DeployCmd = &cobra.Command{
Short: "Deploy Antrea Multi-cluster Controller to a leader or member cluster",
}

var DeleteCmd = &cobra.Command{
Use: "delete",
Short: "Delete multi-cluster resources",
}

var JoinCmd = NewJoinCommand()
var LeaveCmd = NewLeaveCommand()
var InitCmd = NewInitCommand()
Expand All @@ -46,7 +52,9 @@ func init() {
GetCmd.AddCommand(get.NewClusterSetCommand())
GetCmd.AddCommand(get.NewResourceImportCommand())
GetCmd.AddCommand(get.NewResourceExportCommand())
GetCmd.AddCommand(get.NewTokenCommand())
CreateCmd.AddCommand(create.NewAccessTokenCmd())
DeployCmd.AddCommand(deploy.NewLeaderClusterCmd())
DeployCmd.AddCommand(deploy.NewMemberClusterCmd())
DeleteCmd.AddCommand(delete.NewDeleteTokenCmd())
}
117 changes: 106 additions & 11 deletions pkg/antctl/raw/multicluster/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (

multiclusterv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1"
multiclusterv1alpha2 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha2"
"antrea.io/antrea/pkg/antctl/output"
"antrea.io/antrea/pkg/antctl/raw"
multiclusterscheme "antrea.io/antrea/pkg/antctl/raw/multicluster/scheme"
)
Expand Down Expand Up @@ -213,6 +214,21 @@ func deleteServiceAccounts(cmd *cobra.Command, k8sClient client.Client, namespac
}
}

func GetTokenSecret(secret *corev1.Secret) *corev1.Secret {
s := &corev1.Secret{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "Secret",
},
ObjectMeta: metav1.ObjectMeta{
Name: secret.Name,
},
Data: secret.Data,
Type: corev1.SecretTypeOpaque,
}
return s
}

func CreateMemberToken(cmd *cobra.Command, k8sClient client.Client, name string, namespace string, file *os.File, createdRes *[]map[string]interface{}) error {
var createErr error
serviceAccount := newServiceAccount(name, namespace)
Expand Down Expand Up @@ -273,17 +289,8 @@ func CreateMemberToken(cmd *cobra.Command, k8sClient client.Client, name string,
if err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: namespace}, secret); err != nil {
return err
}
s := &corev1.Secret{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "Secret",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Data: secret.Data,
Type: corev1.SecretTypeOpaque,
}

s := GetTokenSecret(secret)

b, err := yaml.Marshal(s)
if err != nil {
Expand All @@ -303,6 +310,94 @@ func CreateMemberToken(cmd *cobra.Command, k8sClient client.Client, name string,
return nil
}

func GetMemberToken(cmd *cobra.Command, k8sClient client.Client, name string, namespace string, file *os.File) error {
secret := &corev1.Secret{}
if err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: namespace}, secret); err != nil {
return err
}

if secret.Annotations[CreateByAntctlAnnotation] == "true" {
s := GetTokenSecret(secret)

if file != nil {
b, err := yaml.Marshal(s)
if err != nil {
return err
}
if _, err := file.Write([]byte("---\n")); err != nil {
return err
}
if _, err := file.Write(b); err != nil {
return err
}
fmt.Fprintf(cmd.OutOrStdout(), "Member token saved to %s\n", file.Name())
} else {
output.YamlOutput(s, cmd.OutOrStdout())
}
return nil
}
fmt.Fprintf(cmd.OutOrStdout(), "\033[1;31;40m Warning: Token %s created by antctl is not found\033[0m\n", name)
return nil
}

func DeleteMemberToken(cmd *cobra.Command, k8sClient client.Client, name string, namespace string) {
secret := &corev1.Secret{}
getErr := k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: name}, secret)
if getErr != nil {
fmt.Fprintf(cmd.OutOrStderr(), "Error from server: Secret \"%s\", error: %s\n", name, getErr)
}
if secret.Annotations[CreateByAntctlAnnotation] == "true" {
deleteErr := k8sClient.Delete(context.TODO(), &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: name,
}}, &client.DeleteOptions{})
if deleteErr != nil {
fmt.Fprintf(cmd.OutOrStderr(), "Failed to delete Secret \"%s\", error: %s\n", name, deleteErr)
} else {
fmt.Fprintf(cmd.OutOrStdout(), "Token %s deleted successfully", name)
}
}

roleBinding := &rbacv1.RoleBinding{}
getErr = k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: name}, roleBinding)
if getErr != nil {
fmt.Fprintf(cmd.OutOrStderr(), "Error from server: RoleBinding \"%s\", error: %s\n", name, getErr)
}
if roleBinding.Annotations[CreateByAntctlAnnotation] == "true" {
deleteErr := k8sClient.Delete(context.TODO(), &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: name,
}}, &client.DeleteOptions{})

if deleteErr != nil {
fmt.Fprintf(cmd.OutOrStderr(), "Failed to delete RoleBinding \"%s\", error: %s\n", name, deleteErr)
} else {
fmt.Fprintf(cmd.OutOrStdout(), "RoleBinding %s deleted successfully", name)
}
}

serviceAccount := &corev1.ServiceAccount{}
getErr = k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: name}, serviceAccount)
if getErr != nil {
fmt.Fprintf(cmd.OutOrStderr(), "Error from server: ServiceAccount \"%s\", error: %s\n", name, getErr)
}
if serviceAccount.Annotations[CreateByAntctlAnnotation] == "true" {
deleteErr := k8sClient.Delete(context.TODO(), &corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: name,
}}, &client.DeleteOptions{})

if deleteErr != nil {
fmt.Fprintf(cmd.OutOrStderr(), "Failed to delete ServiceAccount \"%s\", error: %s\n", name, deleteErr)
} else {
fmt.Fprintf(cmd.OutOrStdout(), "ServiceAccount %s deleted successfully", name)
}
}
}

func waitForSecretReady(client client.Client, secretName string, namespace string) error {
return wait.PollImmediate(
1*time.Second,
Expand Down
181 changes: 181 additions & 0 deletions pkg/antctl/raw/multicluster/common/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -429,3 +429,184 @@ func TestCreateMemberToken(t *testing.T) {
})
}
}

func TestDeleteMemberToken(t *testing.T) {
secretContent := []byte(`apiVersion: v1
kind: Secret
metadata:
name: default-member-token
data:
ca.crt: YWJjZAo=
namespace: ZGVmYXVsdAo=
token: YWJjZAo=
type: Opaque`)

existingSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "default-member-token",
Annotations: map[string]string{
CreateByAntctlAnnotation: "true",
},
},
Data: map[string][]byte{"token": secretContent},
}

existingSecretNoAnnotation := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "default-member-token",
},
Data: map[string][]byte{"token": secretContent},
}

existingSecret1 := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "default-member-token-1",
Annotations: map[string]string{
CreateByAntctlAnnotation: "true",
},
},
Data: map[string][]byte{"token": secretContent},
}

existingRolebinding := &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "default-member-token",
Annotations: map[string]string{
CreateByAntctlAnnotation: "true",
},
},
}

existingRolebinding1 := &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "default-member-token-notexist",
Annotations: map[string]string{
CreateByAntctlAnnotation: "true",
},
},
}

existingServiceAccount := &corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "default-member-token",
Annotations: map[string]string{
CreateByAntctlAnnotation: "true",
},
},
}

existingServiceAccount1 := &corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "default-member-token-notexist",
Annotations: map[string]string{
CreateByAntctlAnnotation: "true",
},
},
}

tests := []struct {
name string
namespace string
tokenName string
serviceAccount *corev1.ServiceAccount
rolebinding *rbacv1.RoleBinding
secret *corev1.Secret
numsOfServiceAccount int
numsOfRolebinding int
numsOfSecret int
expectedOutput string
}{
{
name: "delete successfully",
tokenName: "default-member-token",
namespace: "default",
secret: existingSecret,
rolebinding: existingRolebinding,
serviceAccount: existingServiceAccount,
numsOfServiceAccount: 0,
numsOfRolebinding: 0,
numsOfSecret: 0,
expectedOutput: "",
},
{
name: "failed to delete because of wrong secret name",
tokenName: "default-member-token",
namespace: "default",
secret: existingSecret1,
rolebinding: existingRolebinding,
serviceAccount: existingServiceAccount,
numsOfSecret: 1,
numsOfRolebinding: 0,
numsOfServiceAccount: 0,
expectedOutput: "Error from server: Secret",
},
{
name: "failed to delete because of wrong rolebinding name",
tokenName: "default-member-token",
namespace: "default",
secret: existingSecret,
rolebinding: existingRolebinding1,
serviceAccount: existingServiceAccount,
numsOfSecret: 0,
numsOfRolebinding: 1,
numsOfServiceAccount: 0,
expectedOutput: "Error from server: RoleBinding",
},
{
name: "failed to delete because of wrong serviceaccount name",
tokenName: "default-member-token",
namespace: "default",
secret: existingSecret,
rolebinding: existingRolebinding,
serviceAccount: existingServiceAccount1,
numsOfSecret: 0,
numsOfRolebinding: 0,
numsOfServiceAccount: 1,
expectedOutput: "Error from server: ServiceAccount",
},
{
name: "the secret does not have the require annotation",
tokenName: "default-member-token",
namespace: "default",
secret: existingSecretNoAnnotation,
rolebinding: existingRolebinding,
serviceAccount: existingServiceAccount,
numsOfServiceAccount: 0,
numsOfRolebinding: 0,
numsOfSecret: 1,
expectedOutput: "",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := &cobra.Command{}
fakeClient := fake.NewClientBuilder().WithScheme(multiclusterscheme.Scheme).WithObjects(tt.secret, tt.rolebinding, tt.serviceAccount).Build()
buf := new(bytes.Buffer)
cmd.SetOutput(buf)
cmd.SetOut(buf)
cmd.SetErr(buf)

DeleteMemberToken(cmd, fakeClient, tt.tokenName, tt.namespace)

assert.Contains(t, buf.String(), tt.expectedOutput)

remainSecrets := &corev1.SecretList{}
fakeClient.List(context.Background(), remainSecrets, &client.ListOptions{})
assert.Equal(t, tt.numsOfSecret, len(remainSecrets.Items))
remainRoleBinding := &rbacv1.RoleBindingList{}
fakeClient.List(context.Background(), remainRoleBinding, &client.ListOptions{})
assert.Equal(t, tt.numsOfRolebinding, len(remainRoleBinding.Items))
remainServiceAccount := &corev1.ServiceAccountList{}
fakeClient.List(context.Background(), remainServiceAccount, &client.ListOptions{})
assert.Equal(t, tt.numsOfServiceAccount, len(remainServiceAccount.Items))
})
}
}
Loading

0 comments on commit 5c81866

Please sign in to comment.