Merge pull request #107512 from SataQiu/support-reset-dryrun-20220113

kubeadm reset: add support for dry-run
This commit is contained in:
Kubernetes Prow Robot 2022-01-14 06:01:49 -08:00 committed by GitHub
commit 19a37027dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 77 additions and 31 deletions

View File

@ -63,40 +63,55 @@ func runCleanupNode(c workflow.RunData) error {
klog.Warningln("[reset] The kubelet service could not be stopped by kubeadm. Unable to detect a supported init system!") klog.Warningln("[reset] The kubelet service could not be stopped by kubeadm. Unable to detect a supported init system!")
klog.Warningln("[reset] Please ensure kubelet is stopped manually") klog.Warningln("[reset] Please ensure kubelet is stopped manually")
} else { } else {
fmt.Println("[reset] Stopping the kubelet service") if !r.DryRun() {
if err := initSystem.ServiceStop("kubelet"); err != nil { fmt.Println("[reset] Stopping the kubelet service")
klog.Warningf("[reset] The kubelet service could not be stopped by kubeadm: [%v]\n", err) if err := initSystem.ServiceStop("kubelet"); err != nil {
klog.Warningln("[reset] Please ensure kubelet is stopped manually") klog.Warningf("[reset] The kubelet service could not be stopped by kubeadm: [%v]\n", err)
klog.Warningln("[reset] Please ensure kubelet is stopped manually")
}
} else {
fmt.Println("[reset] Would stop the kubelet service")
} }
} }
// Try to unmount mounted directories under kubeadmconstants.KubeletRunDirectory in order to be able to remove the kubeadmconstants.KubeletRunDirectory directory later if !r.DryRun() {
fmt.Printf("[reset] Unmounting mounted directories in %q\n", kubeadmconstants.KubeletRunDirectory) // Try to unmount mounted directories under kubeadmconstants.KubeletRunDirectory in order to be able to remove the kubeadmconstants.KubeletRunDirectory directory later
// In case KubeletRunDirectory holds a symbolic link, evaluate it fmt.Printf("[reset] Unmounting mounted directories in %q\n", kubeadmconstants.KubeletRunDirectory)
kubeletRunDir, err := absoluteKubeletRunDirectory() // In case KubeletRunDirectory holds a symbolic link, evaluate it
if err == nil { kubeletRunDir, err := absoluteKubeletRunDirectory()
// Only clean absoluteKubeletRunDirectory if umountDirsCmd passed without error if err == nil {
r.AddDirsToClean(kubeletRunDir) // Only clean absoluteKubeletRunDirectory if umountDirsCmd passed without error
r.AddDirsToClean(kubeletRunDir)
}
} else {
fmt.Printf("[reset] Would unmount mounted directories in %q\n", kubeadmconstants.KubeletRunDirectory)
} }
klog.V(1).Info("[reset] Removing Kubernetes-managed containers") if !r.DryRun() {
if err := removeContainers(utilsexec.New(), r.CRISocketPath()); err != nil { klog.V(1).Info("[reset] Removing Kubernetes-managed containers")
klog.Warningf("[reset] Failed to remove containers: %v\n", err) if err := removeContainers(utilsexec.New(), r.CRISocketPath()); err != nil {
klog.Warningf("[reset] Failed to remove containers: %v\n", err)
}
} else {
fmt.Println("[reset] Would remove Kubernetes-managed containers")
} }
r.AddDirsToClean("/var/lib/dockershim", "/var/run/kubernetes", "/var/lib/cni") r.AddDirsToClean("/var/lib/dockershim", "/var/run/kubernetes", "/var/lib/cni")
// Remove contents from the config and pki directories // Remove contents from the config and pki directories
klog.V(1).Infoln("[reset] Removing contents from the config and pki directories")
if certsDir != kubeadmapiv1.DefaultCertificatesDir { if certsDir != kubeadmapiv1.DefaultCertificatesDir {
klog.Warningf("[reset] WARNING: Cleaning a non-default certificates directory: %q\n", certsDir) klog.Warningf("[reset] WARNING: Cleaning a non-default certificates directory: %q\n", certsDir)
} }
resetConfigDir(kubeadmconstants.KubernetesDir, certsDir) resetConfigDir(kubeadmconstants.KubernetesDir, certsDir, r.DryRun())
if r.Cfg() != nil && features.Enabled(r.Cfg().FeatureGates, features.RootlessControlPlane) { if r.Cfg() != nil && features.Enabled(r.Cfg().FeatureGates, features.RootlessControlPlane) {
klog.V(1).Infoln("[reset] Removing users and groups created for rootless control-plane") if !r.DryRun() {
if err := users.RemoveUsersAndGroups(); err != nil { klog.V(1).Infoln("[reset] Removing users and groups created for rootless control-plane")
klog.Warningf("[reset] Failed to remove users and groups: %v\n", err) if err := users.RemoveUsersAndGroups(); err != nil {
klog.Warningf("[reset] Failed to remove users and groups: %v\n", err)
}
} else {
fmt.Println("[reset] Would remove users and groups created for rootless control-plane")
} }
} }
@ -130,16 +145,20 @@ func removeContainers(execer utilsexec.Interface, criSocketPath string) error {
} }
// resetConfigDir is used to cleanup the files kubeadm writes in /etc/kubernetes/. // resetConfigDir is used to cleanup the files kubeadm writes in /etc/kubernetes/.
func resetConfigDir(configPathDir, pkiPathDir string) { func resetConfigDir(configPathDir, pkiPathDir string, isDryRun bool) {
dirsToClean := []string{ dirsToClean := []string{
filepath.Join(configPathDir, kubeadmconstants.ManifestsSubDirName), filepath.Join(configPathDir, kubeadmconstants.ManifestsSubDirName),
pkiPathDir, pkiPathDir,
} }
fmt.Printf("[reset] Deleting contents of config directories: %v\n", dirsToClean) if !isDryRun {
for _, dir := range dirsToClean { fmt.Printf("[reset] Deleting contents of directories: %v\n", dirsToClean)
if err := CleanDir(dir); err != nil { for _, dir := range dirsToClean {
klog.Warningf("[reset] Failed to delete contents of %q directory: %v", dir, err) if err := CleanDir(dir); err != nil {
klog.Warningf("[reset] Failed to delete contents of %q directory: %v", dir, err)
}
} }
} else {
fmt.Printf("[reset] Would delete contents of directories: %v\n", dirsToClean)
} }
filesToClean := []string{ filesToClean := []string{
@ -149,11 +168,16 @@ func resetConfigDir(configPathDir, pkiPathDir string) {
filepath.Join(configPathDir, kubeadmconstants.ControllerManagerKubeConfigFileName), filepath.Join(configPathDir, kubeadmconstants.ControllerManagerKubeConfigFileName),
filepath.Join(configPathDir, kubeadmconstants.SchedulerKubeConfigFileName), filepath.Join(configPathDir, kubeadmconstants.SchedulerKubeConfigFileName),
} }
fmt.Printf("[reset] Deleting files: %v\n", filesToClean)
for _, path := range filesToClean { if !isDryRun {
if err := os.RemoveAll(path); err != nil { fmt.Printf("[reset] Deleting files: %v\n", filesToClean)
klog.Warningf("[reset] Failed to remove file: %q [%v]\n", path, err) for _, path := range filesToClean {
if err := os.RemoveAll(path); err != nil {
klog.Warningf("[reset] Failed to remove file: %q [%v]\n", path, err)
}
} }
} else {
fmt.Printf("[reset] Would delete files: %v\n", filesToClean)
} }
} }

View File

@ -174,7 +174,7 @@ func TestConfigDirCleaner(t *testing.T) {
if test.resetDir == "" { if test.resetDir == "" {
test.resetDir = "pki" test.resetDir = "pki"
} }
resetConfigDir(tmpDir, filepath.Join(tmpDir, test.resetDir)) resetConfigDir(tmpDir, filepath.Join(tmpDir, test.resetDir), false)
// Verify the files we cleanup implicitly in every test: // Verify the files we cleanup implicitly in every test:
assertExists(t, tmpDir) assertExists(t, tmpDir)

View File

@ -32,6 +32,7 @@ type resetData interface {
InputReader() io.Reader InputReader() io.Reader
IgnorePreflightErrors() sets.String IgnorePreflightErrors() sets.String
Cfg() *kubeadmapi.InitConfiguration Cfg() *kubeadmapi.InitConfiguration
DryRun() bool
Client() clientset.Interface Client() clientset.Interface
AddDirsToClean(dirs ...string) AddDirsToClean(dirs ...string)
CertificatesDir() string CertificatesDir() string

View File

@ -58,8 +58,12 @@ func runRemoveETCDMemberPhase(c workflow.RunData) error {
if err == nil { if err == nil {
r.AddDirsToClean(etcdDataDir) r.AddDirsToClean(etcdDataDir)
if cfg != nil { if cfg != nil {
if err := etcdphase.RemoveStackedEtcdMemberFromCluster(r.Client(), cfg); err != nil { if !r.DryRun() {
klog.Warningf("[reset] failed to remove etcd member: %v, please manually remove this etcd member using etcdctl", err) if err := etcdphase.RemoveStackedEtcdMemberFromCluster(r.Client(), cfg); err != nil {
klog.Warningf("[reset] Failed to remove etcd member: %v, please manually remove this etcd member using etcdctl", err)
}
} else {
fmt.Println("[reset] Would remove the etcd member on this node from the etcd cluster")
} }
} }
} else { } else {

View File

@ -64,6 +64,7 @@ type resetOptions struct {
forceReset bool forceReset bool
ignorePreflightErrors []string ignorePreflightErrors []string
kubeconfigPath string kubeconfigPath string
dryRun bool
} }
// resetData defines all the runtime information used when running the kubeadm reset workflow; // resetData defines all the runtime information used when running the kubeadm reset workflow;
@ -78,6 +79,7 @@ type resetData struct {
outputWriter io.Writer outputWriter io.Writer
cfg *kubeadmapi.InitConfiguration cfg *kubeadmapi.InitConfiguration
dirsToClean []string dirsToClean []string
dryRun bool
} }
// newResetOptions returns a struct ready for being used for creating cmd join flags. // newResetOptions returns a struct ready for being used for creating cmd join flags.
@ -134,6 +136,7 @@ func newResetData(cmd *cobra.Command, options *resetOptions, in io.Reader, out i
inputReader: in, inputReader: in,
outputWriter: out, outputWriter: out,
cfg: cfg, cfg: cfg,
dryRun: options.dryRun,
}, nil }, nil
} }
@ -154,6 +157,10 @@ func AddResetFlags(flagSet *flag.FlagSet, resetOptions *resetOptions) {
&resetOptions.forceReset, options.ForceReset, "f", false, &resetOptions.forceReset, options.ForceReset, "f", false,
"Reset the node without prompting for confirmation.", "Reset the node without prompting for confirmation.",
) )
flagSet.BoolVar(
&resetOptions.dryRun, options.DryRun, resetOptions.dryRun,
"Don't apply any changes; just output what would be done.",
)
options.AddKubeConfigFlag(flagSet, &resetOptions.kubeconfigPath) options.AddKubeConfigFlag(flagSet, &resetOptions.kubeconfigPath)
options.AddIgnorePreflightErrorsFlag(flagSet, &resetOptions.ignorePreflightErrors) options.AddIgnorePreflightErrorsFlag(flagSet, &resetOptions.ignorePreflightErrors)
@ -214,6 +221,11 @@ func newCmdReset(in io.Reader, out io.Writer, resetOptions *resetOptions) *cobra
} }
func cleanDirs(data *resetData) { func cleanDirs(data *resetData) {
if data.DryRun() {
fmt.Printf("[reset] Would delete contents of stateful directories: %v\n", data.dirsToClean)
return
}
fmt.Printf("[reset] Deleting contents of stateful directories: %v\n", data.dirsToClean) fmt.Printf("[reset] Deleting contents of stateful directories: %v\n", data.dirsToClean)
for _, dir := range data.dirsToClean { for _, dir := range data.dirsToClean {
klog.V(1).Infof("[reset] Deleting contents of %s", dir) klog.V(1).Infof("[reset] Deleting contents of %s", dir)
@ -228,6 +240,11 @@ func (r *resetData) Cfg() *kubeadmapi.InitConfiguration {
return r.cfg return r.cfg
} }
// DryRun returns the DryRun flag.
func (r *resetData) DryRun() bool {
return r.dryRun
}
// CertificatesDir returns the CertificatesDir. // CertificatesDir returns the CertificatesDir.
func (r *resetData) CertificatesDir() string { func (r *resetData) CertificatesDir() string {
return r.certificatesDir return r.certificatesDir