mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-28 05:57:25 +00:00
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:
commit
163b848abe
@ -32,7 +32,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewKubeadmCommand return cobra.Command to run kubeadm command
|
// 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{
|
cmds := &cobra.Command{
|
||||||
Use: "kubeadm",
|
Use: "kubeadm",
|
||||||
Short: "kubeadm: easily bootstrap a secure Kubernetes cluster",
|
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(NewCmdConfig(out))
|
||||||
cmds.AddCommand(NewCmdInit(out))
|
cmds.AddCommand(NewCmdInit(out))
|
||||||
cmds.AddCommand(NewCmdJoin(out))
|
cmds.AddCommand(NewCmdJoin(out))
|
||||||
cmds.AddCommand(NewCmdReset(out))
|
cmds.AddCommand(NewCmdReset(in, out))
|
||||||
cmds.AddCommand(NewCmdVersion(out))
|
cmds.AddCommand(NewCmdVersion(out))
|
||||||
cmds.AddCommand(NewCmdToken(out, err))
|
cmds.AddCommand(NewCmdToken(out, err))
|
||||||
cmds.AddCommand(upgrade.NewCmdUpgrade(out))
|
cmds.AddCommand(upgrade.NewCmdUpgrade(out))
|
||||||
|
@ -17,6 +17,8 @@ limitations under the License.
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
@ -44,11 +46,12 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewCmdReset returns the "kubeadm reset" command
|
// 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 skipPreFlight bool
|
||||||
var certsDir string
|
var certsDir string
|
||||||
var criSocketPath string
|
var criSocketPath string
|
||||||
var ignorePreflightErrors []string
|
var ignorePreflightErrors []string
|
||||||
|
var forceReset bool
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "reset",
|
Use: "reset",
|
||||||
@ -57,7 +60,7 @@ func NewCmdReset(out io.Writer) *cobra.Command {
|
|||||||
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(ignorePreflightErrors, skipPreFlight)
|
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(ignorePreflightErrors, skipPreFlight)
|
||||||
kubeadmutil.CheckErr(err)
|
kubeadmutil.CheckErr(err)
|
||||||
|
|
||||||
r, err := NewReset(ignorePreflightErrorsSet, certsDir, criSocketPath)
|
r, err := NewReset(in, ignorePreflightErrorsSet, forceReset, certsDir, criSocketPath)
|
||||||
kubeadmutil.CheckErr(err)
|
kubeadmutil.CheckErr(err)
|
||||||
kubeadmutil.CheckErr(r.Run(out))
|
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.",
|
"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
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,9 +101,21 @@ type Reset struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewReset instantiate Reset struct
|
// NewReset instantiate Reset struct
|
||||||
func NewReset(ignorePreflightErrors sets.String, certsDir, criSocketPath string) (*Reset, error) {
|
func NewReset(in io.Reader, ignorePreflightErrors sets.String, forceReset bool, certsDir, criSocketPath string) (*Reset, error) {
|
||||||
glog.Infoln("[preflight] running pre-flight checks")
|
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 {
|
if err := preflight.RunRootCheckOnly(ignorePreflightErrors); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -56,28 +56,31 @@ func assertDirEmpty(t *testing.T, path string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewReset(t *testing.T) {
|
func TestNewReset(t *testing.T) {
|
||||||
|
var in io.Reader
|
||||||
certsDir := kubeadmapiext.DefaultCertificatesDir
|
certsDir := kubeadmapiext.DefaultCertificatesDir
|
||||||
criSocketPath := "/var/run/dockershim.sock"
|
criSocketPath := "/var/run/dockershim.sock"
|
||||||
skipPreFlight := false
|
skipPreFlight := false
|
||||||
|
forceReset := true
|
||||||
|
|
||||||
ignorePreflightErrors := []string{"all"}
|
ignorePreflightErrors := []string{"all"}
|
||||||
ignorePreflightErrorsSet, _ := validation.ValidateIgnorePreflightErrors(ignorePreflightErrors, skipPreFlight)
|
ignorePreflightErrorsSet, _ := validation.ValidateIgnorePreflightErrors(ignorePreflightErrors, skipPreFlight)
|
||||||
NewReset(ignorePreflightErrorsSet, certsDir, criSocketPath)
|
NewReset(in, ignorePreflightErrorsSet, forceReset, certsDir, criSocketPath)
|
||||||
|
|
||||||
ignorePreflightErrors = []string{}
|
ignorePreflightErrors = []string{}
|
||||||
ignorePreflightErrorsSet, _ = validation.ValidateIgnorePreflightErrors(ignorePreflightErrors, skipPreFlight)
|
ignorePreflightErrorsSet, _ = validation.ValidateIgnorePreflightErrors(ignorePreflightErrors, skipPreFlight)
|
||||||
NewReset(ignorePreflightErrorsSet, certsDir, criSocketPath)
|
NewReset(in, ignorePreflightErrorsSet, forceReset, certsDir, criSocketPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewCmdReset(t *testing.T) {
|
func TestNewCmdReset(t *testing.T) {
|
||||||
var out io.Writer
|
var out io.Writer
|
||||||
cmd := NewCmdReset(out)
|
var in io.Reader
|
||||||
|
cmd := NewCmdReset(in, out)
|
||||||
|
|
||||||
tmpDir, err := ioutil.TempDir("", "kubeadm-reset-test")
|
tmpDir, err := ioutil.TempDir("", "kubeadm-reset-test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unable to create temporary directory: %v", err)
|
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)
|
cmd.SetArgs(args)
|
||||||
if err := cmd.Execute(); err != nil {
|
if err := cmd.Execute(); err != nil {
|
||||||
t.Errorf("Cannot execute reset command: %v", err)
|
t.Errorf("Cannot execute reset command: %v", err)
|
||||||
|
Loading…
Reference in New Issue
Block a user