-
Notifications
You must be signed in to change notification settings - Fork 5k
Added option to delete all profiles #4780
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
db6b0a5
08b6edc
6887128
6f2390b
6c4749b
f9e8490
13f40f4
dd9afd1
1d2ead5
72a9493
925e803
3c4b1b1
f0e707c
d0e749b
019ee1f
9e73f6e
09d8143
42a5850
af57143
4c6af02
70f4cb9
48bd69c
e237a13
45161fa
cb58974
6d9ae13
6dcb45a
1ef11bf
96ef740
d4d8cc4
6f81089
a4fd885
d7d05b7
1d9a61f
59eb974
fa0cdbf
342584a
a1d73a7
50329ed
6ed4262
f0dd5a7
229c9b7
4835945
d5bfa87
ba67c85
da1f935
5289e1f
b3741bd
2c6f659
808477a
ea20ba3
0dc7f8d
24d4eda
5b1528b
71a6cb5
01dd044
79e8250
02bea60
42c017f
5cabb01
d52730a
3ec82dd
47ec8d3
c8c4491
e8c997d
4551a17
3396f5b
1efdf11
280e118
8a4b3b9
ae6f47d
ee97b87
b8abe56
0c9cd49
5610849
c4107ae
a0c844e
ae731d4
09ce93f
d13f58f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,6 +42,8 @@ import ( | |
"k8s.io/minikube/pkg/minikube/out" | ||
) | ||
|
||
var deleteAll bool | ||
|
||
// deleteCmd represents the delete command | ||
var deleteCmd = &cobra.Command{ | ||
Use: "delete", | ||
|
@@ -51,26 +53,121 @@ associated files.`, | |
Run: runDelete, | ||
} | ||
|
||
type typeOfError int | ||
|
||
const ( | ||
Fatal typeOfError = 0 | ||
MissingProfile typeOfError = 1 | ||
MissingCluster typeOfError = 2 | ||
) | ||
|
||
type DeletionError struct { | ||
Err error | ||
Errtype typeOfError | ||
} | ||
|
||
func (error DeletionError) Error() string { | ||
return error.Err.Error() | ||
} | ||
|
||
// runDelete handles the executes the flow of "minikube delete" | ||
func runDelete(cmd *cobra.Command, args []string) { | ||
if len(args) > 0 { | ||
exit.UsageT("Usage: minikube delete") | ||
} | ||
profile := viper.GetString(pkg_config.MachineProfile) | ||
profileFlag, err := cmd.Flags().GetString("profile") | ||
if err != nil { | ||
exit.WithError("Could not get profile flag", err) | ||
} | ||
|
||
if deleteAll { | ||
if profileFlag != constants.DefaultMachineName { | ||
exit.UsageT("usage: minikube delete --all") | ||
} | ||
|
||
validProfiles, invalidProfiles, err := pkg_config.ListProfiles() | ||
profilesToDelete := append(validProfiles, invalidProfiles...) | ||
|
||
if err != nil { | ||
exit.WithError("Error getting profiles to delete", err) | ||
} | ||
|
||
errs := DeleteProfiles(profilesToDelete) | ||
if len(errs) > 0 { | ||
HandleDeletionErrors(errs) | ||
} else { | ||
out.T(out.DeletingHost, "Successfully deleted all profiles") | ||
} | ||
} else { | ||
if len(args) > 0 { | ||
exit.UsageT("usage: minikube delete") | ||
} | ||
|
||
profileName := viper.GetString(pkg_config.MachineProfile) | ||
profile, err := pkg_config.LoadProfile(profileName) | ||
if err != nil { | ||
out.ErrT(out.Meh, `"{{.name}}" profile does not exist`, out.V{"name": profileName}) | ||
} | ||
|
||
errs := DeleteProfiles([]*pkg_config.Profile{profile}) | ||
if len(errs) > 0 { | ||
HandleDeletionErrors(errs) | ||
} else { | ||
out.T(out.DeletingHost, "Successfully deleted profile \"{{.name}}\"", out.V{"name": profileName}) | ||
} | ||
} | ||
} | ||
|
||
// Deletes one or more profiles | ||
func DeleteProfiles(profiles []*pkg_config.Profile) []error { | ||
var errs []error | ||
for _, profile := range profiles { | ||
err := deleteProfile(profile) | ||
|
||
if err != nil { | ||
mm, loadErr := cluster.LoadMachine(profile.Name) | ||
|
||
if !profile.IsValid() || (loadErr != nil || !mm.IsValid()) { | ||
invalidProfileDeletionErrs := deleteInvalidProfile(profile) | ||
if len(invalidProfileDeletionErrs) > 0 { | ||
errs = append(errs, invalidProfileDeletionErrs...) | ||
} | ||
} else { | ||
errs = append(errs, err) | ||
} | ||
} | ||
} | ||
return errs | ||
} | ||
|
||
func deleteProfile(profile *pkg_config.Profile) error { | ||
viper.Set(pkg_config.MachineProfile, profile.Name) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What was the reason to set the profile ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I needed to set it because cluster.DeleteHost relies on cfg.GetMachineName(), which uses viper.GetString(MachineProfile). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I don't set it, the fallback machinename "minikube" is used. |
||
|
||
api, err := machine.NewAPIClient() | ||
if err != nil { | ||
exit.WithError("Error getting client", err) | ||
delErr := profileDeletionErr(profile.Name, fmt.Sprintf("error getting client %v", err)) | ||
return DeletionError{Err: delErr, Errtype: Fatal} | ||
} | ||
defer api.Close() | ||
|
||
cc, err := pkg_config.Load() | ||
if err != nil && !os.IsNotExist(err) { | ||
out.ErrT(out.Sad, "Error loading profile {{.name}}: {{.error}}", out.V{"name": profile, "error": err}) | ||
delErr := profileDeletionErr(profile.Name, fmt.Sprintf("error loading profile config: %v", err)) | ||
return DeletionError{Err: delErr, Errtype: MissingProfile} | ||
} | ||
|
||
// In the case of "none", we want to uninstall Kubernetes as there is no VM to delete | ||
if err == nil && cc.MachineConfig.VMDriver == constants.DriverNone { | ||
uninstallKubernetes(api, cc.KubernetesConfig, viper.GetString(cmdcfg.Bootstrapper)) | ||
if err := uninstallKubernetes(api, cc.KubernetesConfig, viper.GetString(cmdcfg.Bootstrapper)); err != nil { | ||
deletionError, ok := err.(DeletionError) | ||
if ok { | ||
delErr := profileDeletionErr(profile.Name, fmt.Sprintf("%v", err)) | ||
deletionError.Err = delErr | ||
return deletionError | ||
} | ||
return err | ||
} | ||
} | ||
|
||
if err := killMountProcess(); err != nil { | ||
|
@@ -83,39 +180,111 @@ func runDelete(cmd *cobra.Command, args []string) { | |
out.T(out.Meh, `"{{.name}}" cluster does not exist. Proceeding ahead with cleanup.`, out.V{"name": profile}) | ||
default: | ||
out.T(out.FailureType, "Failed to delete cluster: {{.error}}", out.V{"error": err}) | ||
out.T(out.Notice, `You may need to manually remove the "{{.name}}" VM from your hypervisor`, out.V{"name": profile}) | ||
out.T(out.Notice, `You may need to manually remove the "{{.name}}" VM from your hypervisor`, out.V{"name": profile.Name}) | ||
} | ||
} | ||
|
||
// In case DeleteHost didn't complete the job. | ||
deleteProfileDirectory(profile) | ||
deleteProfileDirectory(profile.Name) | ||
|
||
if err := pkg_config.DeleteProfile(profile); err != nil { | ||
if err := pkg_config.DeleteProfile(profile.Name); err != nil { | ||
if os.IsNotExist(err) { | ||
out.T(out.Meh, `"{{.name}}" profile does not exist`, out.V{"name": profile}) | ||
os.Exit(0) | ||
delErr := profileDeletionErr(profile.Name, fmt.Sprintf("\"%s\" profile does not exist", profile.Name)) | ||
return DeletionError{Err: delErr, Errtype: MissingProfile} | ||
} | ||
exit.WithError("Failed to remove profile", err) | ||
delErr := profileDeletionErr(profile.Name, fmt.Sprintf("failed to remove profile %v", err)) | ||
return DeletionError{Err: delErr, Errtype: Fatal} | ||
} | ||
out.T(out.Crushed, `The "{{.name}}" cluster has been deleted.`, out.V{"name": profile}) | ||
|
||
out.T(out.Crushed, `The "{{.name}}" cluster has been deleted.`, out.V{"name": profile.Name}) | ||
|
||
machineName := pkg_config.GetMachineName() | ||
if err := kubeconfig.DeleteContext(constants.KubeconfigPath, machineName); err != nil { | ||
exit.WithError("update config", err) | ||
return DeletionError{Err: fmt.Errorf("update config: %v", err), Errtype: Fatal} | ||
} | ||
|
||
if err := cmdcfg.Unset(pkg_config.MachineProfile); err != nil { | ||
exit.WithError("unset minikube profile", err) | ||
return DeletionError{Err: fmt.Errorf("unset minikube profile: %v", err), Errtype: Fatal} | ||
} | ||
return nil | ||
} | ||
|
||
func uninstallKubernetes(api libmachine.API, kc pkg_config.KubernetesConfig, bsName string) { | ||
func deleteInvalidProfile(profile *pkg_config.Profile) []error { | ||
out.T(out.DeletingHost, "Trying to delete invalid profile {{.profile}}", out.V{"profile": profile.Name}) | ||
|
||
var errs []error | ||
pathToProfile := pkg_config.ProfileFolderPath(profile.Name, localpath.MiniPath()) | ||
if _, err := os.Stat(pathToProfile); !os.IsNotExist(err) { | ||
err := os.RemoveAll(pathToProfile) | ||
if err != nil { | ||
errs = append(errs, DeletionError{err, Fatal}) | ||
} | ||
} | ||
|
||
pathToMachine := cluster.MachinePath(profile.Name, localpath.MiniPath()) | ||
if _, err := os.Stat(pathToMachine); !os.IsNotExist(err) { | ||
err := os.RemoveAll(pathToMachine) | ||
if err != nil { | ||
errs = append(errs, DeletionError{err, Fatal}) | ||
} | ||
} | ||
return errs | ||
} | ||
|
||
func profileDeletionErr(profileName string, additionalInfo string) error { | ||
return fmt.Errorf("error deleting profile \"%s\": %s", profileName, additionalInfo) | ||
} | ||
|
||
func uninstallKubernetes(api libmachine.API, kc pkg_config.KubernetesConfig, bsName string) error { | ||
out.T(out.Resetting, "Uninstalling Kubernetes {{.kubernetes_version}} using {{.bootstrapper_name}} ...", out.V{"kubernetes_version": kc.KubernetesVersion, "bootstrapper_name": bsName}) | ||
clusterBootstrapper, err := getClusterBootstrapper(api, bsName) | ||
if err != nil { | ||
out.ErrT(out.Empty, "Unable to get bootstrapper: {{.error}}", out.V{"error": err}) | ||
return DeletionError{Err: fmt.Errorf("unable to get bootstrapper: %v", err), Errtype: Fatal} | ||
} else if err = clusterBootstrapper.DeleteCluster(kc); err != nil { | ||
out.ErrT(out.Empty, "Failed to delete cluster: {{.error}}", out.V{"error": err}) | ||
return DeletionError{Err: fmt.Errorf("failed to delete cluster: %v", err), Errtype: Fatal} | ||
} | ||
return nil | ||
} | ||
|
||
// Handles deletion error from DeleteProfiles | ||
func HandleDeletionErrors(errors []error) { | ||
if len(errors) == 1 { | ||
handleSingleDeletionError(errors[0]) | ||
} else { | ||
handleMultipleDeletionErrors(errors) | ||
} | ||
} | ||
|
||
func handleSingleDeletionError(err error) { | ||
deletionError, ok := err.(DeletionError) | ||
|
||
if ok { | ||
switch deletionError.Errtype { | ||
case Fatal: | ||
out.FatalT(deletionError.Error()) | ||
case MissingProfile: | ||
out.ErrT(out.Sad, deletionError.Error()) | ||
case MissingCluster: | ||
out.ErrT(out.Meh, deletionError.Error()) | ||
default: | ||
out.FatalT(deletionError.Error()) | ||
} | ||
} else { | ||
exit.WithError("Could not process error from failed deletion", err) | ||
} | ||
} | ||
|
||
func handleMultipleDeletionErrors(errors []error) { | ||
out.ErrT(out.Sad, "Multiple errors deleting profiles") | ||
|
||
for _, err := range errors { | ||
deletionError, ok := err.(DeletionError) | ||
|
||
if ok { | ||
glog.Errorln(deletionError.Error()) | ||
} else { | ||
exit.WithError("Could not process errors from failed deletion", err) | ||
} | ||
} | ||
} | ||
|
||
|
@@ -177,3 +346,8 @@ func killMountProcess() error { | |
} | ||
return nil | ||
} | ||
|
||
func init() { | ||
deleteCmd.Flags().BoolVar(&deleteAll, "all", false, "Set flag to delete all profiles") | ||
RootCmd.AddCommand(deleteCmd) | ||
} |
Uh oh!
There was an error while loading. Please reload this page.