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] Please ensure kubelet is stopped manually")
} else {
fmt.Println("[reset] Stopping the kubelet service")
if err := initSystem.ServiceStop("kubelet"); err != nil {
klog.Warningf("[reset] The kubelet service could not be stopped by kubeadm: [%v]\n", err)
klog.Warningln("[reset] Please ensure kubelet is stopped manually")
if !r.DryRun() {
fmt.Println("[reset] Stopping the kubelet service")
if err := initSystem.ServiceStop("kubelet"); err != nil {
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
fmt.Printf("[reset] Unmounting mounted directories in %q\n", kubeadmconstants.KubeletRunDirectory)
// In case KubeletRunDirectory holds a symbolic link, evaluate it
kubeletRunDir, err := absoluteKubeletRunDirectory()
if err == nil {
// Only clean absoluteKubeletRunDirectory if umountDirsCmd passed without error
r.AddDirsToClean(kubeletRunDir)
if !r.DryRun() {
// Try to unmount mounted directories under kubeadmconstants.KubeletRunDirectory in order to be able to remove the kubeadmconstants.KubeletRunDirectory directory later
fmt.Printf("[reset] Unmounting mounted directories in %q\n", kubeadmconstants.KubeletRunDirectory)
// In case KubeletRunDirectory holds a symbolic link, evaluate it
kubeletRunDir, err := absoluteKubeletRunDirectory()
if err == nil {
// 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 err := removeContainers(utilsexec.New(), r.CRISocketPath()); err != nil {
klog.Warningf("[reset] Failed to remove containers: %v\n", err)
if !r.DryRun() {
klog.V(1).Info("[reset] Removing Kubernetes-managed containers")
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")
// 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 {
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) {
klog.V(1).Infoln("[reset] Removing users and groups created for rootless control-plane")
if err := users.RemoveUsersAndGroups(); err != nil {
klog.Warningf("[reset] Failed to remove users and groups: %v\n", err)
if !r.DryRun() {
klog.V(1).Infoln("[reset] Removing users and groups created for rootless control-plane")
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/.
func resetConfigDir(configPathDir, pkiPathDir string) {
func resetConfigDir(configPathDir, pkiPathDir string, isDryRun bool) {
dirsToClean := []string{
filepath.Join(configPathDir, kubeadmconstants.ManifestsSubDirName),
pkiPathDir,
}
fmt.Printf("[reset] Deleting contents of config directories: %v\n", dirsToClean)
for _, dir := range dirsToClean {
if err := CleanDir(dir); err != nil {
klog.Warningf("[reset] Failed to delete contents of %q directory: %v", dir, err)
if !isDryRun {
fmt.Printf("[reset] Deleting contents of directories: %v\n", dirsToClean)
for _, dir := range dirsToClean {
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{
@ -149,11 +168,16 @@ func resetConfigDir(configPathDir, pkiPathDir string) {
filepath.Join(configPathDir, kubeadmconstants.ControllerManagerKubeConfigFileName),
filepath.Join(configPathDir, kubeadmconstants.SchedulerKubeConfigFileName),
}
fmt.Printf("[reset] Deleting files: %v\n", filesToClean)
for _, path := range filesToClean {
if err := os.RemoveAll(path); err != nil {
klog.Warningf("[reset] Failed to remove file: %q [%v]\n", path, err)
if !isDryRun {
fmt.Printf("[reset] Deleting files: %v\n", filesToClean)
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 == "" {
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:
assertExists(t, tmpDir)

View File

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

View File

@ -58,8 +58,12 @@ func runRemoveETCDMemberPhase(c workflow.RunData) error {
if err == nil {
r.AddDirsToClean(etcdDataDir)
if cfg != nil {
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)
if !r.DryRun() {
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 {

View File

@ -64,6 +64,7 @@ type resetOptions struct {
forceReset bool
ignorePreflightErrors []string
kubeconfigPath string
dryRun bool
}
// resetData defines all the runtime information used when running the kubeadm reset workflow;
@ -78,6 +79,7 @@ type resetData struct {
outputWriter io.Writer
cfg *kubeadmapi.InitConfiguration
dirsToClean []string
dryRun bool
}
// 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,
outputWriter: out,
cfg: cfg,
dryRun: options.dryRun,
}, nil
}
@ -154,6 +157,10 @@ func AddResetFlags(flagSet *flag.FlagSet, resetOptions *resetOptions) {
&resetOptions.forceReset, options.ForceReset, "f", false,
"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.AddIgnorePreflightErrorsFlag(flagSet, &resetOptions.ignorePreflightErrors)
@ -214,6 +221,11 @@ func newCmdReset(in io.Reader, out io.Writer, resetOptions *resetOptions) *cobra
}
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)
for _, dir := range data.dirsToClean {
klog.V(1).Infof("[reset] Deleting contents of %s", dir)
@ -228,6 +240,11 @@ func (r *resetData) Cfg() *kubeadmapi.InitConfiguration {
return r.cfg
}
// DryRun returns the DryRun flag.
func (r *resetData) DryRun() bool {
return r.dryRun
}
// CertificatesDir returns the CertificatesDir.
func (r *resetData) CertificatesDir() string {
return r.certificatesDir