Skip to content

Commit 0933bfe

Browse files
authored
Merge pull request #359 from rxinui/new/358
✨ add kflex ctx delete command
2 parents 2c1e3e7 + 5b94ea1 commit 0933bfe

File tree

11 files changed

+257
-71
lines changed

11 files changed

+257
-71
lines changed

cmd/kflex/common/flags.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,21 @@ package common
1919
import "k8s.io/client-go/tools/clientcmd"
2020

2121
const (
22-
KubeconfigFlag = clientcmd.RecommendedConfigPathFlag
23-
ChattyStatusFlag = "chatty-status"
24-
VerbosityFlag = "verbosity"
25-
PostCreateHookFlag = "postcreate-hook"
26-
SetFlag = "set"
22+
KubeconfigFlag = clientcmd.RecommendedConfigPathFlag // String flag
23+
ChattyStatusFlag = "chatty-status" // Boolean flag
24+
VerbosityFlag = "verbosity" // Int flag
25+
PostCreateHookFlag = "postcreate-hook" // String flag
26+
SetFlag = "set" // []String flag
2727
)
2828

2929
// Version injected by makefile:LDFLAGS
3030
var Version string
3131

3232
// BuildDate injected by makefile:LDFLAGS
3333
var BuildDate string
34+
35+
type KflexGlobalOptions interface {
36+
WithChattyStatus(chattyStatus bool)
37+
WithVerbosity(verbosity int)
38+
WithKubeconfig(kubeconfig string)
39+
}

cmd/kflex/ctx/ctx.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func Command() *cobra.Command {
7171
flagset := command.Flags()
7272
flagset.BoolP(OverwriteExistingContextFlag, "o", false, "Overwrite of hosting cluster context with new control plane context")
7373
flagset.BoolP(SetCurrentForHostingFlag, "c", false, "Set current context as hosting cluster context")
74-
command.AddCommand(CommandGet(), CommandList(), CommandRename())
74+
command.AddCommand(CommandGet(), CommandList(), CommandRename(), CommandDelete())
7575
return command
7676
}
7777

@@ -115,7 +115,7 @@ func (cpCtx *CPCtx) ExecuteCtx(chattyStatus, failIfNone, overwriteExistingCtx, s
115115
// Switch to given context
116116
if overwriteExistingCtx {
117117
util.PrintStatus("Overwriting existing context for control plane", done, &wg, chattyStatus)
118-
if err = kubeconfig.DeleteContext(kconf, cpCtx.Name); err != nil {
118+
if err = kubeconfig.DeleteAll(kconf, cpCtx.Name); err != nil {
119119
fmt.Fprintf(os.Stderr, "no kubeconfig context for %s was found: %s\n", cpCtx.Name, err)
120120
}
121121
done <- true

cmd/kflex/ctx/ctx_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
Copyright 2023 The KubeStellar Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package ctx
18+
19+
import (
20+
"fmt"
21+
"os"
22+
23+
"github.com/kubestellar/kubeflex/pkg/certs"
24+
"github.com/kubestellar/kubeflex/pkg/kubeconfig"
25+
"k8s.io/client-go/tools/clientcmd/api"
26+
)
27+
28+
var kubeconfigPath string = "./testconfig"
29+
var hostingClusterContextMock = "default"
30+
31+
// Setup mock kubeconfig file with context,cluster,authinfo
32+
func setupMockContext(kubeconfigPath string, ctxName string) error {
33+
kconf := api.NewConfig()
34+
kconf.Contexts[certs.GenerateContextName(ctxName)] = &api.Context{
35+
Cluster: certs.GenerateClusterName(ctxName),
36+
AuthInfo: certs.GenerateAuthInfoAdminName(ctxName),
37+
}
38+
kconf.Clusters[certs.GenerateClusterName(ctxName)] = api.NewCluster()
39+
kconf.AuthInfos[certs.GenerateAuthInfoAdminName(ctxName)] = api.NewAuthInfo()
40+
kconf.CurrentContext = hostingClusterContextMock
41+
kubeconfig.SetHostingClusterContextPreference(kconf, nil)
42+
if err := kubeconfig.WriteKubeconfig(kubeconfigPath, kconf); err != nil {
43+
return fmt.Errorf("error writing kubeconfig: %v", err)
44+
}
45+
return nil
46+
}
47+
48+
// Delete mock kubeconfig file
49+
func teardown(kubeconfigPath string) error {
50+
return os.Remove(kubeconfigPath)
51+
}

cmd/kflex/ctx/delete.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
Copyright 2023 The KubeStellar Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package ctx
18+
19+
import (
20+
"fmt"
21+
"sync"
22+
23+
// "sync"
24+
25+
"github.com/kubestellar/kubeflex/cmd/kflex/common"
26+
"github.com/kubestellar/kubeflex/pkg/kubeconfig"
27+
"github.com/kubestellar/kubeflex/pkg/util"
28+
"github.com/spf13/cobra"
29+
)
30+
31+
func CommandDelete() *cobra.Command {
32+
return &cobra.Command{
33+
Use: "delete CONTEXT",
34+
Short: "Delete a context",
35+
Long: `Delete a context in the kubeconfig file`,
36+
Args: cobra.ExactArgs(1),
37+
RunE: func(cmd *cobra.Command, args []string) error {
38+
cmd.SilenceUsage = true
39+
kubeconfig, _ := cmd.Flags().GetString(common.KubeconfigFlag)
40+
chattyStatus, _ := cmd.Flags().GetBool(common.ChattyStatusFlag)
41+
cp := common.NewCP(kubeconfig)
42+
return ExecuteCtxDelete(cp, args[0], chattyStatus)
43+
},
44+
}
45+
}
46+
47+
// Execute kflex ctx delete
48+
func ExecuteCtxDelete(cp common.CP, ctxName string, chattyStatus bool) error {
49+
var wg sync.WaitGroup
50+
done := make(chan bool)
51+
util.PrintStatus("Deleting context", done, &wg, chattyStatus)
52+
kconf, err := kubeconfig.LoadKubeconfig(cp.Kubeconfig)
53+
if err != nil {
54+
return fmt.Errorf("error loading kubeconfig: %v", err)
55+
}
56+
if err = kubeconfig.DeleteAll(kconf, ctxName); err != nil {
57+
return fmt.Errorf("error deleting context %s from kubeconfig: %v", ctxName, err)
58+
}
59+
if kconf.CurrentContext == ctxName {
60+
fmt.Printf("prepare the switch to hosting cluster context")
61+
kubeconfig.SwitchToHostingClusterContext(kconf, false)
62+
}
63+
if err = kubeconfig.WriteKubeconfig(cp.Kubeconfig, kconf); err != nil {
64+
return fmt.Errorf("error writing kubeconfig: %v", err)
65+
}
66+
done <- true
67+
wg.Wait()
68+
return nil
69+
}

cmd/kflex/ctx/delete_test.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
Copyright 2023 The KubeStellar Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package ctx
18+
19+
import (
20+
"testing"
21+
22+
"github.com/kubestellar/kubeflex/cmd/kflex/common"
23+
"github.com/kubestellar/kubeflex/pkg/certs"
24+
"github.com/kubestellar/kubeflex/pkg/kubeconfig"
25+
)
26+
27+
// Test delete a context that exist and checks that it is removed
28+
// from the kubeconfig
29+
func TestDeleteOk(t *testing.T) {
30+
ctxName := "cptobedeleted"
31+
setupMockContext(kubeconfigPath, ctxName)
32+
defer teardown(kubeconfigPath)
33+
34+
// Start test
35+
cp := common.NewCP(kubeconfigPath, common.WithName(ctxName))
36+
err := ExecuteCtxDelete(cp, ctxName, false)
37+
if err != nil {
38+
t.Errorf("failed to run 'kflex ctx delete %s': %v", ctxName, err)
39+
}
40+
kconf, err := kubeconfig.LoadKubeconfig(kubeconfigPath)
41+
if err != nil {
42+
t.Errorf("error loading kubeconfig: %v", err)
43+
}
44+
clusterName := certs.GenerateClusterName(ctxName)
45+
authInfoName := certs.GenerateAuthInfoAdminName(ctxName)
46+
if c, ok := kconf.Contexts[ctxName]; ok {
47+
t.Errorf("context '%v' still present in kubeconfig", c)
48+
}
49+
if c, ok := kconf.Clusters[clusterName]; ok {
50+
t.Errorf("cluster '%v' still present in kubeconfig", c)
51+
}
52+
if c, ok := kconf.AuthInfos[authInfoName]; ok {
53+
t.Errorf("user '%v' still present in kubeconfig", c)
54+
}
55+
if kconf.CurrentContext == ctxName {
56+
t.Errorf("current context must not be set as the deleted context %s", ctxName)
57+
}
58+
}
59+
60+
// Test delete on non-existent context and checks that the kubeconfig is unchanged
61+
func TestDeleteNonExistentContext(t *testing.T) {
62+
ctxName := "cptobedeleted"
63+
noneCtxName := "none"
64+
setupMockContext(kubeconfigPath, ctxName)
65+
defer teardown(kubeconfigPath)
66+
67+
// Start test
68+
cp := common.NewCP(kubeconfigPath, common.WithName(ctxName))
69+
kconf, err := kubeconfig.LoadKubeconfig(kubeconfigPath)
70+
if err != nil {
71+
t.Errorf("error loading kubeconfig: %v", err)
72+
}
73+
nCtx := len(kconf.Contexts)
74+
err = ExecuteCtxDelete(cp, noneCtxName, false)
75+
if err == nil {
76+
t.Errorf("expect ExecuteCtxDelete to fail but it succeeded")
77+
}
78+
if nCtx != len(kconf.Contexts) {
79+
t.Errorf("expect ExecuteCtxDelete to not delete any context but it did")
80+
}
81+
}

cmd/kflex/ctx/rename.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,8 @@ func ExecuteCtxRename(cp common.CP, ctxName string, newCtxName string, toSwitch
7676
newAuthInfo := *authInfo
7777
kconf.AuthInfos[newAuthInfoAdminName] = &newAuthInfo
7878
}
79-
fmt.Printf("kconf-clusters: %v\n", kconf.Clusters)
80-
fmt.Printf("kconf-auths: %v\n", kconf.AuthInfos)
8179
fmt.Fprintf(os.Stdout, "renaming context from %s to %s\n", ctxName, newCtxName)
82-
if err = kubeconfig.DeleteContext(kconf, ctxName); err != nil {
80+
if err = kubeconfig.DeleteAll(kconf, ctxName); err != nil {
8381
return fmt.Errorf("cannot delete context %s from kubeconfig: %v", ctxName, err)
8482
}
8583
fmt.Fprintf(os.Stdout, "context %s is deleted\n", ctxName)

cmd/kflex/ctx/rename_test.go

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,39 +18,13 @@ package ctx
1818

1919
import (
2020
"fmt"
21-
"os"
2221
"testing"
2322

2423
"github.com/kubestellar/kubeflex/cmd/kflex/common"
2524
"github.com/kubestellar/kubeflex/pkg/certs"
2625
"github.com/kubestellar/kubeflex/pkg/kubeconfig"
27-
"k8s.io/client-go/tools/clientcmd/api"
2826
)
2927

30-
var kubeconfigPath string = "./testconfig"
31-
var hostingClusterContextMock = "default"
32-
33-
func setupMockContext(kubeconfigPath string, ctxName string) error {
34-
kconf := api.NewConfig()
35-
kconf.Contexts[certs.GenerateContextName(ctxName)] = &api.Context{
36-
Cluster: certs.GenerateClusterName(ctxName),
37-
AuthInfo: certs.GenerateAuthInfoAdminName(ctxName),
38-
}
39-
kconf.Clusters[certs.GenerateClusterName(ctxName)] = api.NewCluster()
40-
kconf.AuthInfos[certs.GenerateAuthInfoAdminName(ctxName)] = api.NewAuthInfo()
41-
kconf.CurrentContext = hostingClusterContextMock
42-
kubeconfig.SetHostingClusterContextPreference(kconf, nil)
43-
if err := kubeconfig.WriteKubeconfig(kubeconfigPath, kconf); err != nil {
44-
return fmt.Errorf("error writing kubeconfig: %v", err)
45-
}
46-
return nil
47-
}
48-
49-
func teardown(kubeconfigPath string) error {
50-
os.Remove(kubeconfigPath)
51-
return nil
52-
}
53-
5428
func TestRenameOk(t *testing.T) {
5529
// Mock data
5630
ctxName := "testcp"

0 commit comments

Comments
 (0)