Skip to content

Commit f1a6a55

Browse files
authored
Merge pull request #87 from onepanelio/feat/onepanel.delete
feat: cli delete command
2 parents a7b7f1e + fe77f35 commit f1a6a55

File tree

6 files changed

+169
-7
lines changed

6 files changed

+169
-7
lines changed

cmd/apply.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ var applyCmd = &cobra.Command{
3535
return
3636
}
3737

38-
overlayComponentFirst := filepath.Join("common/application/base")
38+
overlayComponentFirst := filepath.Join("common", "application", "base")
3939
baseOverlayComponent := config.GetOverlayComponent(overlayComponentFirst)
4040
applicationBaseKustomizeTemplate := TemplateFromSimpleOverlayedComponents(baseOverlayComponent)
4141
applicationResult, err := GenerateKustomizeResult(*config, applicationBaseKustomizeTemplate)
@@ -44,11 +44,11 @@ var applyCmd = &cobra.Command{
4444
return
4545
}
4646

47-
applicationKubernetesYamlFilePath := filepath.Join(".onepanel/application.kubernetes.yaml")
47+
applicationKubernetesYamlFilePath := filepath.Join(".onepanel", "application.kubernetes.yaml")
4848

4949
existsApp, err := files.Exists(applicationKubernetesYamlFilePath)
5050
if err != nil {
51-
log.Printf("Unable to check if file %v exists", applicationKubernetesYamlFilePath)
51+
log.Printf("Unable to check if file '%v' exists", applicationKubernetesYamlFilePath)
5252
return
5353
}
5454

@@ -77,9 +77,9 @@ var applyCmd = &cobra.Command{
7777

7878
resApp, errResApp, err = applyKubernetesFile(applicationKubernetesYamlFilePath)
7979

80-
log.Printf("%v", resApp)
80+
log.Printf("res: %v", resApp)
8181
if errResApp != "" {
82-
log.Printf("%v", errResApp)
82+
log.Printf("err: %v", errResApp)
8383
}
8484

8585
if err != nil {
@@ -130,7 +130,7 @@ var applyCmd = &cobra.Command{
130130
return
131131
}
132132

133-
finalKubernetesYamlFilePath := filepath.Join(".onepanel/kubernetes.yaml")
133+
finalKubernetesYamlFilePath := filepath.Join(".onepanel", "kubernetes.yaml")
134134

135135
exists, err := files.Exists(finalKubernetesYamlFilePath)
136136
if err != nil {

cmd/build.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ func GenerateKustomizeResult(config opConfig.Config, kustomizeTemplate template.
8181
}
8282

8383
manifestPath := config.Spec.ManifestsRepo
84-
localManifestsCopyPath := filepath.Join(".onepanel/manifests/cache")
84+
localManifestsCopyPath := filepath.Join(".onepanel", "manifests", "cache")
8585

8686
exists, err := files.Exists(localManifestsCopyPath)
8787
if err != nil {
@@ -614,6 +614,8 @@ func HumanizeKustomizeError(err error) string {
614614
switch paramsError.ErrorType {
615615
case "missing":
616616
return fmt.Sprintf("%s is missing in your params.yaml", paramsError.Key)
617+
case "parameter":
618+
return fmt.Sprintf("%s can not be '%s', please enter a namespace", paramsError.Key, *paramsError.Value)
617619
case "blank":
618620
return fmt.Sprintf("%s can not be blank, please use a different namespace in your params.yaml", paramsError.Key)
619621
case "reserved":

cmd/delete.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
opConfig "github.com/onepanelio/cli/config"
6+
"github.com/onepanelio/cli/files"
7+
"github.com/onepanelio/cli/util"
8+
"github.com/spf13/cobra"
9+
"path/filepath"
10+
)
11+
12+
var (
13+
// skipConfirmDelete if true, will skip the confirmation prompt of the delete command
14+
skipConfirmDelete bool
15+
)
16+
17+
var deleteCmd = &cobra.Command{
18+
Use: "delete",
19+
Short: "Deletes onepanel cluster resources",
20+
Long: "Delete all onepanel kubernetes cluster resources. Does not delete database unless it is in-cluster.",
21+
Example: "delete",
22+
Run: func(cmd *cobra.Command, args []string) {
23+
if skipConfirmDelete == false {
24+
fmt.Print("Are you sure you want to delete onepanel? ('y' or 'yes' to confirm. Anything else to cancel): ")
25+
userInput := ""
26+
if _, err := fmt.Scanln(&userInput); err != nil {
27+
fmt.Printf("Unable to get response\n")
28+
return
29+
}
30+
31+
if userInput != "y" && userInput != "yes" {
32+
return
33+
}
34+
}
35+
36+
config, err := opConfig.FromFile("config.yaml")
37+
if err != nil {
38+
fmt.Printf("Unable to read configuration file: %v", err.Error())
39+
return
40+
}
41+
42+
paramsYamlFile, err := util.LoadDynamicYamlFromFile(config.Spec.Params)
43+
if err != nil {
44+
fmt.Println("Error parsing configuration file.")
45+
return
46+
}
47+
48+
defaultNamespaceNode := paramsYamlFile.GetValue("application.defaultNamespace")
49+
if defaultNamespaceNode == nil {
50+
fmt.Printf("application.defaultNamespace is missing from your '%s' file\n", config.Spec.Params)
51+
return
52+
}
53+
54+
if defaultNamespaceNode.Value == "default" {
55+
fmt.Println("Unable to delete onepanel in the 'default' namespace")
56+
return
57+
}
58+
59+
if defaultNamespaceNode.Value == "<namespace>" {
60+
fmt.Println("Unable to delete onepanel. No namespace set.")
61+
return
62+
}
63+
64+
filesToDelete := []string{
65+
filepath.Join(".onepanel", "kubernetes.yaml"),
66+
filepath.Join(".onepanel", "application.kubernetes.yaml"),
67+
}
68+
69+
for _, filePath := range filesToDelete {
70+
exists, err := files.Exists(filePath)
71+
if err != nil {
72+
fmt.Printf("Error checking if onepanel files exist: %v\n", err.Error())
73+
return
74+
}
75+
76+
if !exists {
77+
fmt.Printf("'%v' file does not exist. Are you in the directory where you ran 'opctl init'?\n", filePath)
78+
return
79+
}
80+
}
81+
82+
fmt.Printf("Deleting onepanel from your cluster...\n")
83+
for _, filePath := range filesToDelete {
84+
if err := util.KubectlDelete(filePath); err != nil {
85+
fmt.Printf("Unable to delete: %v\n", err.Error())
86+
return
87+
}
88+
}
89+
},
90+
}
91+
92+
func init() {
93+
rootCmd.AddCommand(deleteCmd)
94+
deleteCmd.Flags().BoolVarP(&skipConfirmDelete, "yes", "y", false, "Add this in to skip the confirmation prompt")
95+
}

manifest/manifest.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ func Validate(manifest *util.DynamicYaml) error {
134134
if defaultNamespace.Value == "" {
135135
return &ParamsError{Key: "application.defaultNamespace", ErrorType: "blank"}
136136
}
137+
if defaultNamespace.Value == "<namespace>" {
138+
return &ParamsError{Key: "application.defaultNamespace", Value: &defaultNamespace.Value, ErrorType: "parameter"}
139+
}
137140
if _, ok := reservedNamespaces[defaultNamespace.Value]; ok {
138141
return &ParamsError{Key: "application.defaultNamespace", Value: &defaultNamespace.Value, ErrorType: "reserved"}
139142
}

util/kubectl.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@ import (
66
"fmt"
77
opConfig "github.com/onepanelio/cli/config"
88
"github.com/spf13/cobra"
9+
k8error "k8s.io/apimachinery/pkg/util/errors"
910
"k8s.io/cli-runtime/pkg/genericclioptions"
1011
_ "k8s.io/client-go/plugin/pkg/client/auth/azure"
1112
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
1213
"k8s.io/kubectl/pkg/cmd/apply"
14+
k8delete "k8s.io/kubectl/pkg/cmd/delete"
1315
"k8s.io/kubectl/pkg/cmd/get"
1416
cmdutil "k8s.io/kubectl/pkg/cmd/util"
1517
"os"
1618
"runtime"
1719
"strconv"
20+
"strings"
1821
)
1922

2023
func KubectlGet(resource string, resourceName string, namespace string, extraArgs []string, flags map[string]interface{}) (stdout string, stderr string, err error) {
@@ -125,6 +128,64 @@ func KubectlApply(filePath string) (stdout string, stderr string, err error) {
125128
return
126129
}
127130

131+
// KubectlDelete run's kubectl delete using the input filePath
132+
func KubectlDelete(filePath string) (err error) {
133+
kubeConfigFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag()
134+
matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags)
135+
136+
f := cmdutil.NewFactory(matchVersionKubeConfigFlags)
137+
ioStreams := genericclioptions.IOStreams{
138+
In: os.Stdin,
139+
Out: os.Stdout,
140+
ErrOut: os.Stderr,
141+
}
142+
cmd := k8delete.NewCmdDelete(f, ioStreams)
143+
144+
deleteOptions := k8delete.DeleteOptions{IOStreams: ioStreams}
145+
deleteOptions.Filenames = []string{filePath}
146+
err = cmd.Flags().Set("filename", filePath)
147+
if err != nil {
148+
return err
149+
}
150+
151+
if err := deleteOptions.Complete(f, []string{}, cmd); err != nil {
152+
return err
153+
}
154+
155+
if err := deleteOptions.RunDelete(f); err != nil {
156+
errorAggregate, ok := err.(k8error.Aggregate)
157+
if ok {
158+
finalErrors := make([]error, 0)
159+
// Skip any errors that mean "not found"
160+
for _, errItem := range errorAggregate.Errors() {
161+
if strings.Contains(errItem.Error(), "not found") {
162+
continue
163+
}
164+
165+
if strings.Contains(errItem.Error(), "no matches for kind") {
166+
continue
167+
}
168+
169+
if strings.Contains(errItem.Error(), "the server could not find the requested resource") {
170+
continue
171+
}
172+
173+
finalErrors = append(finalErrors, errItem)
174+
}
175+
176+
if len(finalErrors) == 0 {
177+
return nil
178+
}
179+
180+
return k8error.NewAggregate(finalErrors)
181+
}
182+
183+
return err
184+
}
185+
186+
return
187+
}
188+
128189
func validateArgs(cmd *cobra.Command, args []string) error {
129190
if len(args) != 0 {
130191
return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)

util/status.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ func DeploymentStatus(yamlFile *DynamicYaml) (ready bool, err error) {
1212
namespacesToCheck["application-system"] = true
1313
namespacesToCheck["onepanel"] = true
1414
namespacesToCheck["istio-system"] = true
15+
namespacesToCheck["default"] = true
1516

1617
if yamlFile.HasKey("certManager") {
1718
namespacesToCheck["cert-manager"] = true

0 commit comments

Comments
 (0)