Merge pull request #59115 from alexbrand/kubeadm-confirm-reset-2

Automatic merge from submit-queue (batch tested with PRs 59965, 59115, 63076, 63059). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

kubeadm: prompt for confirmation when resetting a master

Signed-off-by: Alexander Brand <alexbrand09@gmail.com>



**What this PR does / why we need it**:
This PR implements a confirmation prompt when running `kubeadm reset` on a master node. This is to prevent users from mistakenly resetting a master node.

**Which issue(s) this PR fixes**:
Fixes https://github.com/kubernetes/kubeadm/issues/673

**Special notes for your reviewer**:
I am somewhat torn on the approach on how to detect that kubeadm is running on a master node. I went with checking for the apiserver manfiest file on the local filesystem, as it seems like a simpler approach when compared to getting a k8s client, getting a list of nodes, finding the current node, and checking if it has the master taint. I am happy to rework if the latter is more desirable.

Sample runs:
```
# ./kubeadm reset
[Warning] Are you sure you want to reset this master node? Type the word "confirm" to continue: no
Aborted reset operation on master node

# ./kubeadm reset
[Warning] Are you sure you want to reset this master node? Type the word "confirm" to continue: confirm
[preflight] Running pre-flight checks.
[reset] Stopping the kubelet service.
[reset] WARNING: The kubelet service could not be stopped by kubeadm: [exit status 1]
[reset] WARNING: Please ensure kubelet is stopped manually.
[reset] Unmounting mounted directories in "/var/lib/kubelet"
........

# ./kubeadm reset
[Warning] Are you sure you want to reset this master node? Type the word "confirm" to continue:
Aborted reset operation on master node
# ./kubeadm reset --confirm
[preflight] Running pre-flight checks.
[reset] Stopping the kubelet service.
[reset] WARNING: The kubelet service could not be stopped by kubeadm: [exit status 1]
[reset] WARNING: Please ensure kubelet is stopped manually.
[reset] Unmounting mounted directories in "/var/lib/kubelet"
........
```

**Release note**:

```release-note
kubeadm: prompt the user for confirmation when resetting a master node
```
This commit is contained in:
Kubernetes Submit Queue 2018-04-25 17:07:12 -07:00 committed by GitHub
commit 163b848abe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 33 additions and 10 deletions

View File

@ -32,7 +32,7 @@ import (
)
// NewKubeadmCommand return cobra.Command to run kubeadm command
func NewKubeadmCommand(_ io.Reader, out, err io.Writer) *cobra.Command {
func NewKubeadmCommand(in io.Reader, out, err io.Writer) *cobra.Command {
cmds := &cobra.Command{
Use: "kubeadm",
Short: "kubeadm: easily bootstrap a secure Kubernetes cluster",
@ -77,7 +77,7 @@ func NewKubeadmCommand(_ io.Reader, out, err io.Writer) *cobra.Command {
cmds.AddCommand(NewCmdConfig(out))
cmds.AddCommand(NewCmdInit(out))
cmds.AddCommand(NewCmdJoin(out))
cmds.AddCommand(NewCmdReset(out))
cmds.AddCommand(NewCmdReset(in, out))
cmds.AddCommand(NewCmdVersion(out))
cmds.AddCommand(NewCmdToken(out, err))
cmds.AddCommand(upgrade.NewCmdUpgrade(out))

View File

@ -17,6 +17,8 @@ limitations under the License.
package cmd
import (
"bufio"
"errors"
"fmt"
"io"
"os"
@ -44,11 +46,12 @@ var (
)
// NewCmdReset returns the "kubeadm reset" command
func NewCmdReset(out io.Writer) *cobra.Command {
func NewCmdReset(in io.Reader, out io.Writer) *cobra.Command {
var skipPreFlight bool
var certsDir string
var criSocketPath string
var ignorePreflightErrors []string
var forceReset bool
cmd := &cobra.Command{
Use: "reset",
@ -57,7 +60,7 @@ func NewCmdReset(out io.Writer) *cobra.Command {
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(ignorePreflightErrors, skipPreFlight)
kubeadmutil.CheckErr(err)
r, err := NewReset(ignorePreflightErrorsSet, certsDir, criSocketPath)
r, err := NewReset(in, ignorePreflightErrorsSet, forceReset, certsDir, criSocketPath)
kubeadmutil.CheckErr(err)
kubeadmutil.CheckErr(r.Run(out))
},
@ -83,6 +86,11 @@ func NewCmdReset(out io.Writer) *cobra.Command {
"The path to the CRI socket to use with crictl when cleaning up containers.",
)
cmd.PersistentFlags().BoolVar(
&forceReset, "force", false,
"Reset the node without prompting for confirmation.",
)
return cmd
}
@ -93,9 +101,21 @@ type Reset struct {
}
// NewReset instantiate Reset struct
func NewReset(ignorePreflightErrors sets.String, certsDir, criSocketPath string) (*Reset, error) {
glog.Infoln("[preflight] running pre-flight checks")
func NewReset(in io.Reader, ignorePreflightErrors sets.String, forceReset bool, certsDir, criSocketPath string) (*Reset, error) {
if !forceReset {
fmt.Println("[reset] WARNING: changes made to this host by 'kubeadm init' or 'kubeadm join' will be reverted.")
fmt.Print("[reset] are you sure you want to proceed? [y/N]: ")
s := bufio.NewScanner(in)
s.Scan()
if err := s.Err(); err != nil {
return nil, err
}
if strings.ToLower(s.Text()) != "y" {
return nil, errors.New("Aborted reset operation")
}
}
glog.Infoln("[preflight] running pre-flight checks")
if err := preflight.RunRootCheckOnly(ignorePreflightErrors); err != nil {
return nil, err
}

View File

@ -56,28 +56,31 @@ func assertDirEmpty(t *testing.T, path string) {
}
func TestNewReset(t *testing.T) {
var in io.Reader
certsDir := kubeadmapiext.DefaultCertificatesDir
criSocketPath := "/var/run/dockershim.sock"
skipPreFlight := false
forceReset := true
ignorePreflightErrors := []string{"all"}
ignorePreflightErrorsSet, _ := validation.ValidateIgnorePreflightErrors(ignorePreflightErrors, skipPreFlight)
NewReset(ignorePreflightErrorsSet, certsDir, criSocketPath)
NewReset(in, ignorePreflightErrorsSet, forceReset, certsDir, criSocketPath)
ignorePreflightErrors = []string{}
ignorePreflightErrorsSet, _ = validation.ValidateIgnorePreflightErrors(ignorePreflightErrors, skipPreFlight)
NewReset(ignorePreflightErrorsSet, certsDir, criSocketPath)
NewReset(in, ignorePreflightErrorsSet, forceReset, certsDir, criSocketPath)
}
func TestNewCmdReset(t *testing.T) {
var out io.Writer
cmd := NewCmdReset(out)
var in io.Reader
cmd := NewCmdReset(in, out)
tmpDir, err := ioutil.TempDir("", "kubeadm-reset-test")
if err != nil {
t.Errorf("Unable to create temporary directory: %v", err)
}
args := []string{"--ignore-preflight-errors=all", "--cert-dir=" + tmpDir}
args := []string{"--ignore-preflight-errors=all", "--cert-dir=" + tmpDir, "--force"}
cmd.SetArgs(args)
if err := cmd.Execute(); err != nil {
t.Errorf("Cannot execute reset command: %v", err)