Skip to content

Commit d823fa2

Browse files
authored
Merge pull request kubernetes#77847 from yagonobre/reset-phase
Add phase runner to kubeadm reset
2 parents 6fff760 + 97e22fb commit d823fa2

File tree

5 files changed

+163
-79
lines changed

5 files changed

+163
-79
lines changed

cmd/kubeadm/app/cmd/BUILD

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ go_test(
8686
deps = [
8787
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
8888
"//cmd/kubeadm/app/apis/kubeadm/v1beta2:go_default_library",
89-
"//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library",
9089
"//cmd/kubeadm/app/cmd/options:go_default_library",
9190
"//cmd/kubeadm/app/componentconfigs:go_default_library",
9291
"//cmd/kubeadm/app/constants:go_default_library",

cmd/kubeadm/app/cmd/cmd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func NewKubeadmCommand(in io.Reader, out, err io.Writer) *cobra.Command {
8484
cmds.AddCommand(NewCmdConfig(out))
8585
cmds.AddCommand(NewCmdInit(out, nil))
8686
cmds.AddCommand(NewCmdJoin(out, nil))
87-
cmds.AddCommand(NewCmdReset(in, out))
87+
cmds.AddCommand(NewCmdReset(in, out, nil))
8888
cmds.AddCommand(NewCmdVersion(out))
8989
cmds.AddCommand(NewCmdToken(out, err))
9090
cmds.AddCommand(upgrade.NewCmdUpgrade(out))

cmd/kubeadm/app/cmd/options/constant.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,7 @@ const (
127127

128128
// SkipCertificateKeyPrint flag instruct kubeadm to skip printing certificate key used to encrypt certs by 'kubeadm init'.
129129
SkipCertificateKeyPrint = "skip-certificate-key-print"
130+
131+
// ForceReset flag instruct kubeadm to reset the node without prompting for confirmation
132+
ForceReset = "force"
130133
)

cmd/kubeadm/app/cmd/reset.go

Lines changed: 159 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ import (
2828
"github.com/lithammer/dedent"
2929
"github.com/pkg/errors"
3030
"github.com/spf13/cobra"
31+
flag "github.com/spf13/pflag"
3132
"k8s.io/apimachinery/pkg/util/sets"
3233
clientset "k8s.io/client-go/kubernetes"
3334
"k8s.io/klog"
3435
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
3536
kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2"
3637
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
3738
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
39+
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
3840
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
3941
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
4042
etcdphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd"
@@ -48,99 +50,197 @@ import (
4850
utilsexec "k8s.io/utils/exec"
4951
)
5052

51-
// NewCmdReset returns the "kubeadm reset" command
52-
func NewCmdReset(in io.Reader, out io.Writer) *cobra.Command {
53-
var certsDir string
53+
// resetOptions defines all the options exposed via flags by kubeadm reset.
54+
type resetOptions struct {
55+
certificatesDir string
56+
criSocketPath string
57+
forceReset bool
58+
ignorePreflightErrors []string
59+
kubeconfigPath string
60+
}
61+
62+
// resetData defines all the runtime information used when running the kubeadm reset worklow;
63+
// this data is shared across all the phases that are included in the workflow.
64+
type resetData struct {
65+
certificatesDir string
66+
client clientset.Interface
67+
criSocketPath string
68+
forceReset bool
69+
ignorePreflightErrors sets.String
70+
inputReader io.Reader
71+
outputWriter io.Writer
72+
cfg *kubeadmapi.InitConfiguration
73+
}
74+
75+
// newResetOptions returns a struct ready for being used for creating cmd join flags.
76+
func newResetOptions() *resetOptions {
77+
return &resetOptions{
78+
certificatesDir: kubeadmapiv1beta2.DefaultCertificatesDir,
79+
forceReset: false,
80+
kubeconfigPath: kubeadmconstants.GetAdminKubeConfigPath(),
81+
}
82+
}
83+
84+
// newResetData returns a new resetData struct to be used for the execution of the kubeadm reset workflow.
85+
func newResetData(cmd *cobra.Command, options *resetOptions, in io.Reader, out io.Writer) (*resetData, error) {
86+
var cfg *kubeadmapi.InitConfiguration
87+
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(options.ignorePreflightErrors)
88+
if err != nil {
89+
return nil, err
90+
}
91+
92+
client, err := getClientset(options.kubeconfigPath, false)
93+
if err == nil {
94+
klog.V(1).Infof("[reset] Loaded client set from kubeconfig file: %s", options.kubeconfigPath)
95+
cfg, err = configutil.FetchInitConfigurationFromCluster(client, out, "reset", false)
96+
if err != nil {
97+
klog.Warningf("[reset] Unable to fetch the kubeadm-config ConfigMap from cluster: %v", err)
98+
}
99+
} else {
100+
klog.V(1).Infof("[reset] Could not obtain a client set from the kubeconfig file: %s", options.kubeconfigPath)
101+
}
102+
54103
var criSocketPath string
55-
var ignorePreflightErrors []string
56-
var forceReset bool
57-
var client clientset.Interface
58-
kubeConfigFile := kubeadmconstants.GetAdminKubeConfigPath()
104+
if options.criSocketPath == "" {
105+
criSocketPath, err = resetDetectCRISocket(cfg)
106+
if err != nil {
107+
return nil, err
108+
}
109+
klog.V(1).Infof("[reset] Detected and using CRI socket: %s", criSocketPath)
110+
}
111+
112+
return &resetData{
113+
certificatesDir: options.certificatesDir,
114+
client: client,
115+
criSocketPath: criSocketPath,
116+
forceReset: options.forceReset,
117+
ignorePreflightErrors: ignorePreflightErrorsSet,
118+
inputReader: in,
119+
outputWriter: out,
120+
cfg: cfg,
121+
}, nil
122+
}
123+
124+
// AddResetFlags adds reset flags
125+
func AddResetFlags(flagSet *flag.FlagSet, resetOptions *resetOptions) {
126+
flagSet.StringVar(
127+
&resetOptions.certificatesDir, options.CertificatesDir, resetOptions.certificatesDir,
128+
`The path to the directory where the certificates are stored. If specified, clean this directory.`,
129+
)
130+
flagSet.BoolVarP(
131+
&resetOptions.forceReset, options.ForceReset, "f", false,
132+
"Reset the node without prompting for confirmation.",
133+
)
134+
135+
options.AddKubeConfigFlag(flagSet, &resetOptions.kubeconfigPath)
136+
options.AddIgnorePreflightErrorsFlag(flagSet, &resetOptions.ignorePreflightErrors)
137+
cmdutil.AddCRISocketFlag(flagSet, &resetOptions.criSocketPath)
138+
}
139+
140+
// NewCmdReset returns the "kubeadm reset" command
141+
func NewCmdReset(in io.Reader, out io.Writer, resetOptions *resetOptions) *cobra.Command {
142+
if resetOptions == nil {
143+
resetOptions = newResetOptions()
144+
}
145+
resetRunner := workflow.NewRunner()
59146

60147
cmd := &cobra.Command{
61148
Use: "reset",
62149
Short: "Run this to revert any changes made to this host by 'kubeadm init' or 'kubeadm join'",
63150
Run: func(cmd *cobra.Command, args []string) {
64-
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(ignorePreflightErrors)
151+
c, err := resetRunner.InitData(args)
65152
kubeadmutil.CheckErr(err)
66153

67-
var cfg *kubeadmapi.InitConfiguration
68-
client, err = getClientset(kubeConfigFile, false)
69-
if err == nil {
70-
klog.V(1).Infof("[reset] Loaded client set from kubeconfig file: %s", kubeConfigFile)
71-
cfg, err = configutil.FetchInitConfigurationFromCluster(client, os.Stdout, "reset", false)
72-
if err != nil {
73-
klog.Warningf("[reset] Unable to fetch the kubeadm-config ConfigMap from cluster: %v", err)
74-
}
75-
} else {
76-
klog.V(1).Infof("[reset] Could not obtain a client set from the kubeconfig file: %s", kubeConfigFile)
77-
}
78-
79-
if criSocketPath == "" {
80-
criSocketPath, err = resetDetectCRISocket(cfg)
81-
kubeadmutil.CheckErr(err)
82-
klog.V(1).Infof("[reset] Detected and using CRI socket: %s", criSocketPath)
83-
}
84-
85-
r, err := NewReset(in, ignorePreflightErrorsSet, forceReset, certsDir, criSocketPath)
154+
err = resetRunner.Run(args)
86155
kubeadmutil.CheckErr(err)
87-
kubeadmutil.CheckErr(r.Run(out, client, cfg))
156+
// TODO: remove this once we have all phases in place.
157+
// the method joinData.Run() itself should be removed too.
158+
data := c.(*resetData)
159+
kubeadmutil.CheckErr(data.Run())
88160
},
89161
}
90162

91-
options.AddIgnorePreflightErrorsFlag(cmd.PersistentFlags(), &ignorePreflightErrors)
92-
options.AddKubeConfigFlag(cmd.PersistentFlags(), &kubeConfigFile)
163+
AddResetFlags(cmd.Flags(), resetOptions)
93164

94-
cmd.PersistentFlags().StringVar(
95-
&certsDir, "cert-dir", kubeadmapiv1beta2.DefaultCertificatesDir,
96-
"The path to the directory where the certificates are stored. If specified, clean this directory.",
97-
)
165+
// initialize the workflow runner with the list of phases
166+
// TODO: append phases here
98167

99-
cmdutil.AddCRISocketFlag(cmd.PersistentFlags(), &criSocketPath)
168+
// sets the data builder function, that will be used by the runner
169+
// both when running the entire workflow or single phases
170+
resetRunner.SetDataInitializer(func(cmd *cobra.Command, args []string) (workflow.RunData, error) {
171+
return newResetData(cmd, resetOptions, in, out)
172+
})
100173

101-
cmd.PersistentFlags().BoolVarP(
102-
&forceReset, "force", "f", false,
103-
"Reset the node without prompting for confirmation.",
104-
)
174+
// binds the Runner to kubeadm init command by altering
175+
// command help, adding --skip-phases flag and by adding phases subcommands
176+
resetRunner.BindToCommand(cmd)
105177

106178
return cmd
107179
}
108180

109-
// Reset defines struct used for kubeadm reset command
110-
type Reset struct {
111-
certsDir string
112-
criSocketPath string
181+
// Cfg returns the InitConfiguration.
182+
func (r *resetData) Cfg() *kubeadmapi.InitConfiguration {
183+
return r.cfg
184+
}
185+
186+
// CertificatesDir returns the CertificatesDir.
187+
func (r *resetData) CertificatesDir() string {
188+
return r.certificatesDir
189+
}
190+
191+
// Client returns the Client for accessing the cluster.
192+
func (r *resetData) Client() clientset.Interface {
193+
return r.client
194+
}
195+
196+
// ForceReset returns the forceReset flag.
197+
func (r *resetData) ForceReset() bool {
198+
return r.forceReset
113199
}
114200

115-
// NewReset instantiate Reset struct
116-
func NewReset(in io.Reader, ignorePreflightErrors sets.String, forceReset bool, certsDir, criSocketPath string) (*Reset, error) {
117-
if !forceReset {
201+
// InputReader returns the io.reader used to read messages.
202+
func (r *resetData) InputReader() io.Reader {
203+
return r.inputReader
204+
}
205+
206+
// IgnorePreflightErrors returns the list of preflight errors to ignore.
207+
func (r *resetData) IgnorePreflightErrors() sets.String {
208+
return r.ignorePreflightErrors
209+
}
210+
211+
func (r *resetData) preflight() error {
212+
if !r.ForceReset() {
118213
fmt.Println("[reset] WARNING: Changes made to this host by 'kubeadm init' or 'kubeadm join' will be reverted.")
119214
fmt.Print("[reset] Are you sure you want to proceed? [y/N]: ")
120-
s := bufio.NewScanner(in)
215+
s := bufio.NewScanner(r.InputReader())
121216
s.Scan()
122217
if err := s.Err(); err != nil {
123-
return nil, err
218+
return err
124219
}
125220
if strings.ToLower(s.Text()) != "y" {
126-
return nil, errors.New("Aborted reset operation")
221+
return errors.New("Aborted reset operation")
127222
}
128223
}
129224

130225
fmt.Println("[preflight] Running pre-flight checks")
131-
if err := preflight.RunRootCheckOnly(ignorePreflightErrors); err != nil {
132-
return nil, err
226+
if err := preflight.RunRootCheckOnly(r.IgnorePreflightErrors()); err != nil {
227+
return err
133228
}
134229

135-
return &Reset{
136-
certsDir: certsDir,
137-
criSocketPath: criSocketPath,
138-
}, nil
230+
return nil
139231
}
140232

141233
// Run reverts any changes made to this host by "kubeadm init" or "kubeadm join".
142-
func (r *Reset) Run(out io.Writer, client clientset.Interface, cfg *kubeadmapi.InitConfiguration) error {
234+
func (r *resetData) Run() error {
143235
var dirsToClean []string
236+
cfg := r.Cfg()
237+
certsDir := r.CertificatesDir()
238+
client := r.Client()
239+
240+
err := r.preflight()
241+
if err != nil {
242+
return err
243+
}
144244

145245
// Reset the ClusterStatus for a given control-plane node.
146246
if isControlPlane() && cfg != nil {
@@ -203,10 +303,10 @@ func (r *Reset) Run(out io.Writer, client clientset.Interface, cfg *kubeadmapi.I
203303

204304
// Remove contents from the config and pki directories
205305
klog.V(1).Infoln("[reset] Removing contents from the config and pki directories")
206-
if r.certsDir != kubeadmapiv1beta2.DefaultCertificatesDir {
207-
klog.Warningf("[reset] WARNING: Cleaning a non-default certificates directory: %q\n", r.certsDir)
306+
if certsDir != kubeadmapiv1beta2.DefaultCertificatesDir {
307+
klog.Warningf("[reset] WARNING: Cleaning a non-default certificates directory: %q\n", certsDir)
208308
}
209-
resetConfigDir(kubeadmconstants.KubernetesDir, r.certsDir)
309+
resetConfigDir(kubeadmconstants.KubernetesDir, certsDir)
210310

211311
// Output help text instructing user how to remove iptables rules
212312
msg := dedent.Dedent(`

cmd/kubeadm/app/cmd/reset_test.go

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ limitations under the License.
1717
package cmd
1818

1919
import (
20-
"io"
2120
"io/ioutil"
2221
"os"
2322
"path/filepath"
@@ -26,8 +25,6 @@ import (
2625
"github.com/lithammer/dedent"
2726

2827
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
29-
kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2"
30-
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
3128
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
3229
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
3330
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
@@ -85,21 +82,6 @@ func assertDirEmpty(t *testing.T, path string) {
8582
}
8683
}
8784

88-
func TestNewReset(t *testing.T) {
89-
var in io.Reader
90-
certsDir := kubeadmapiv1beta2.DefaultCertificatesDir
91-
criSocketPath := kubeadmconstants.DefaultDockerCRISocket
92-
forceReset := true
93-
94-
ignorePreflightErrors := []string{"all"}
95-
ignorePreflightErrorsSet, _ := validation.ValidateIgnorePreflightErrors(ignorePreflightErrors)
96-
NewReset(in, ignorePreflightErrorsSet, forceReset, certsDir, criSocketPath)
97-
98-
ignorePreflightErrors = []string{}
99-
ignorePreflightErrorsSet, _ = validation.ValidateIgnorePreflightErrors(ignorePreflightErrors)
100-
NewReset(in, ignorePreflightErrorsSet, forceReset, certsDir, criSocketPath)
101-
}
102-
10385
func TestConfigDirCleaner(t *testing.T) {
10486
tests := map[string]struct {
10587
resetDir string

0 commit comments

Comments
 (0)