From 5d96a719fb3b2dad97c8388fea04306333f47ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20K=C3=A4ldstr=C3=B6m?= Date: Tue, 12 Jun 2018 18:59:34 +0300 Subject: [PATCH 1/2] kubeadm: Fix a couple of small-ish bugs for v1.11 --- .../app/apis/kubeadm/v1alpha1/conversion.go | 1 + .../app/apis/kubeadm/v1alpha2/types.go | 4 +- .../app/apis/kubeadm/validation/validation.go | 16 ++----- .../kubeadm/validation/validation_test.go | 33 ++++++++----- cmd/kubeadm/app/cmd/init.go | 22 +++++---- cmd/kubeadm/app/cmd/options/token.go | 7 ++- cmd/kubeadm/app/cmd/reset.go | 4 +- cmd/kubeadm/app/cmd/token.go | 2 +- cmd/kubeadm/app/cmd/upgrade/apply.go | 37 ++++++++++----- cmd/kubeadm/app/cmd/upgrade/common.go | 7 +-- cmd/kubeadm/app/cmd/upgrade/common_test.go | 8 +--- cmd/kubeadm/app/cmd/upgrade/diff.go | 17 ++++--- cmd/kubeadm/app/cmd/upgrade/diff_test.go | 7 +-- cmd/kubeadm/app/cmd/upgrade/node.go | 24 ++++------ cmd/kubeadm/app/cmd/upgrade/plan.go | 23 +++++---- cmd/kubeadm/app/cmd/upgrade/upgrade.go | 39 ++++++++------- cmd/kubeadm/app/kubeadm.go | 15 ++++-- cmd/kubeadm/app/phases/kubelet/config.go | 6 +++ cmd/kubeadm/app/phases/upgrade/postupgrade.go | 47 ++++++++++++++++--- .../app/phases/upgrade/staticpods_test.go | 5 +- .../phases/uploadconfig/uploadconfig_test.go | 9 ++++ cmd/kubeadm/app/preflight/checks.go | 16 +++---- .../app/util/apiclient/clientbacked_dryrun.go | 9 ++++ cmd/kubeadm/app/util/apiclient/init_dryrun.go | 19 +------- 24 files changed, 221 insertions(+), 156 deletions(-) diff --git a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/conversion.go b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/conversion.go index a4fb369da9a..1c8820d532e 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1alpha1/conversion.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1alpha1/conversion.go @@ -116,6 +116,7 @@ func UpgradeCloudProvider(in *MasterConfiguration, out *kubeadm.MasterConfigurat out.APIServerExtraArgs["cloud-provider"] = in.CloudProvider out.ControllerManagerExtraArgs["cloud-provider"] = in.CloudProvider + out.NodeRegistration.KubeletExtraArgs["cloud-provider"] = in.CloudProvider } } diff --git a/cmd/kubeadm/app/apis/kubeadm/v1alpha2/types.go b/cmd/kubeadm/app/apis/kubeadm/v1alpha2/types.go index b68184150ca..7af1f79bea3 100644 --- a/cmd/kubeadm/app/apis/kubeadm/v1alpha2/types.go +++ b/cmd/kubeadm/app/apis/kubeadm/v1alpha2/types.go @@ -131,10 +131,10 @@ type NodeRegistrationOptions struct { // Name is the `.Metadata.Name` field of the Node API object that will be created in this `kubeadm init` or `kubeadm joiń` operation. // This field is also used in the CommonName field of the kubelet's client certificate to the API server. // Defaults to the hostname of the node if not provided. - Name string `json:"name"` + Name string `json:"name,omitempty"` // CRISocket is used to retrieve container runtime info. This information will be annotated to the Node API object, for later re-use - CRISocket string `json:"criSocket"` + CRISocket string `json:"criSocket,omitempty"` // Taints specifies the taints the Node API object should be registered with. If this field is unset, i.e. nil, in the `kubeadm init` process // it will be defaulted to []v1.Taint{'node-role.kubernetes.io/master=""'}. If you don't want to taint your master node, set this field to an diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go index ad542f36f00..a85ba40a04f 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go +++ b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go @@ -44,7 +44,6 @@ import ( kubeproxyconfigv1alpha1 "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1" proxyvalidation "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/validation" "k8s.io/kubernetes/pkg/registry/core/service/ipallocator" - "k8s.io/kubernetes/pkg/util/node" ) // ValidateMasterConfiguration validates master configuration and collects all encountered errors @@ -92,7 +91,11 @@ func ValidateNodeConfiguration(c *kubeadm.NodeConfiguration) field.ErrorList { // ValidateNodeRegistrationOptions validates the NodeRegistrationOptions object func ValidateNodeRegistrationOptions(nro *kubeadm.NodeRegistrationOptions, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} - allErrs = append(allErrs, ValidateNodeName(nro.Name, fldPath.Child("name"))...) + if len(nro.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath, "--node-name or .nodeRegistration.name in the config file is a required value. It seems like this value couldn't be automatically detected in your environment, please specify the desired value using the CLI or config file.")) + } else { + allErrs = append(allErrs, apivalidation.ValidateDNS1123Subdomain(nro.Name, field.NewPath("name"))...) + } allErrs = append(allErrs, ValidateAbsolutePath(nro.CRISocket, fldPath.Child("criSocket"))...) // TODO: Maybe validate .Taints as well in the future using something like validateNodeTaints() in pkg/apis/core/validation return allErrs @@ -356,15 +359,6 @@ func ValidateAbsolutePath(path string, fldPath *field.Path) field.ErrorList { return allErrs } -// ValidateNodeName validates the name of a node -func ValidateNodeName(nodename string, fldPath *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - if node.GetHostname(nodename) != nodename { - allErrs = append(allErrs, field.Invalid(fldPath, nodename, "nodename is not valid, must be lower case")) - } - return allErrs -} - // ValidateMixedArguments validates passed arguments func ValidateMixedArguments(flag *pflag.FlagSet) error { // If --config isn't set, we have nothing to validate diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go b/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go index d4454fb4655..151cde50b0a 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go +++ b/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go @@ -104,24 +104,31 @@ func TestValidateTokenGroups(t *testing.T) { } } -func TestValidateNodeName(t *testing.T) { +func TestValidateNodeRegistrationOptions(t *testing.T) { var tests = []struct { - s string - f *field.Path - expected bool + nodeName string + criSocket string + expectedErrors bool }{ - {"", nil, false}, // ok if not provided - {"1234", nil, true}, // supported - {"valid-nodename", nil, true}, // supported - {"INVALID-NODENAME", nil, false}, // Upper cases is invalid + {"", "/some/path", true}, // node name can't be empty + {"valid-nodename", "", true}, // crisocket can't be empty + {"INVALID-NODENAME", "/some/path", true}, // Upper cases is invalid + {"invalid-nodename-", "/some/path", true}, // Can't have trailing dashes + {"invalid-node?name", "/some/path", true}, // Unsupported characters + {"valid-nodename", "relative/path", true}, // crisocket must be an absolute path + {"valid-nodename", "/some/path", false}, // supported + {"valid-nodename-with-numbers01234", "/some/path/with/numbers/01234/", false}, // supported, with numbers as well } for _, rt := range tests { - actual := ValidateNodeName(rt.s, rt.f) - if (len(actual) == 0) != rt.expected { + nro := kubeadm.NodeRegistrationOptions{Name: rt.nodeName, CRISocket: rt.criSocket} + actual := ValidateNodeRegistrationOptions(&nro, field.NewPath("nodeRegistration")) + actualErrors := len(actual) > 0 + if actualErrors != rt.expectedErrors { t.Errorf( - "failed ValidateNodeRegistration: kubeadm.NodeRegistrationOptions{Name:\n\texpected: %t\n\t actual: %t", - rt.expected, - (len(actual) == 0), + "failed ValidateNodeRegistrationOptions: value: %v\n\texpected: %t\n\t actual: %t", + nro, + rt.expectedErrors, + actualErrors, ) } } diff --git a/cmd/kubeadm/app/cmd/init.go b/cmd/kubeadm/app/cmd/init.go index 2459025b9fe..d764080a78c 100644 --- a/cmd/kubeadm/app/cmd/init.go +++ b/cmd/kubeadm/app/cmd/init.go @@ -291,8 +291,10 @@ func (i *Init) Run(out io.Writer) error { // First off, configure the kubelet. In this short timeframe, kubeadm is trying to stop/restart the kubelet // Try to stop the kubelet service so no race conditions occur when configuring it - glog.V(1).Infof("Stopping the kubelet") - preflight.TryStopKubelet(i.ignorePreflightErrors) + if !i.dryRun { + glog.V(1).Infof("Stopping the kubelet") + preflight.TryStopKubelet(i.ignorePreflightErrors) + } // Write env file with flags for the kubelet to use. We do not need to write the --register-with-taints for the master, // as we handle that ourselves in the markmaster phase @@ -306,9 +308,11 @@ func (i *Init) Run(out io.Writer) error { return fmt.Errorf("error writing kubelet configuration to disk: %v", err) } - // Try to start the kubelet service in case it's inactive - glog.V(1).Infof("Starting the kubelet") - preflight.TryStartKubelet(i.ignorePreflightErrors) + if !i.dryRun { + // Try to start the kubelet service in case it's inactive + glog.V(1).Infof("Starting the kubelet") + preflight.TryStartKubelet(i.ignorePreflightErrors) + } // certsDirToWriteTo is gonna equal cfg.CertificatesDir in the normal case, but gonna be a temp directory if dryrunning i.cfg.CertificatesDir = certsDirToWriteTo @@ -601,9 +605,10 @@ func getWaiter(i *Init, client clientset.Interface) apiclient.Waiter { return dryrunutil.NewWaiter() } - // TODO: List images locally using `crictl` and pull in preflight checks if not available - // When we do that, we can always assume the images exist at this point and have a shorter timeout. - timeout := 30 * time.Minute + // We know that the images should be cached locally already as we have pulled them using + // crictl in the preflight checks. Hence we can have a pretty short timeout for the kubelet + // to start creating Static Pods. + timeout := 4 * time.Minute return apiclient.NewKubeWaiter(client, timeout, os.Stdout) } @@ -614,6 +619,7 @@ func waitForKubeletAndFunc(waiter apiclient.Waiter, f func() error) error { go func(errC chan error, waiter apiclient.Waiter) { // This goroutine can only make kubeadm init fail. If this check succeeds, it won't do anything special + // TODO: Make 10248 a constant somewhere if err := waiter.WaitForHealthyKubelet(40*time.Second, "http://localhost:10248/healthz"); err != nil { errC <- err } diff --git a/cmd/kubeadm/app/cmd/options/token.go b/cmd/kubeadm/app/cmd/options/token.go index 2b793f14322..d875eb9d5a5 100644 --- a/cmd/kubeadm/app/cmd/options/token.go +++ b/cmd/kubeadm/app/cmd/options/token.go @@ -52,8 +52,13 @@ func (bto *BootstrapTokenOptions) AddTokenFlag(fs *pflag.FlagSet) { // AddTTLFlag adds the --token-ttl flag to the given flagset func (bto *BootstrapTokenOptions) AddTTLFlag(fs *pflag.FlagSet) { + bto.AddTTLFlagWithName(fs, "token-ttl") +} + +// AddTTLFlagWithName adds the --token-ttl flag with a custom flag name given flagset +func (bto *BootstrapTokenOptions) AddTTLFlagWithName(fs *pflag.FlagSet, flagName string) { fs.DurationVar( - &bto.TTL.Duration, "token-ttl", bto.TTL.Duration, + &bto.TTL.Duration, flagName, bto.TTL.Duration, "The duration before the token is automatically deleted (e.g. 1s, 2m, 3h). If set to '0', the token will never expire", ) } diff --git a/cmd/kubeadm/app/cmd/reset.go b/cmd/kubeadm/app/cmd/reset.go index b7939664062..0dfee95e739 100644 --- a/cmd/kubeadm/app/cmd/reset.go +++ b/cmd/kubeadm/app/cmd/reset.go @@ -80,8 +80,8 @@ func NewCmdReset(in io.Reader, 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, + cmd.PersistentFlags().BoolVarP( + &forceReset, "force", "f", false, "Reset the node without prompting for confirmation.", ) diff --git a/cmd/kubeadm/app/cmd/token.go b/cmd/kubeadm/app/cmd/token.go index 4b52ecafe02..9368a656a84 100644 --- a/cmd/kubeadm/app/cmd/token.go +++ b/cmd/kubeadm/app/cmd/token.go @@ -138,7 +138,7 @@ func NewCmdToken(out io.Writer, errW io.Writer) *cobra.Command { "config", cfgPath, "Path to kubeadm config file (WARNING: Usage of a configuration file is experimental)") createCmd.Flags().BoolVar(&printJoinCommand, "print-join-command", false, "Instead of printing only the token, print the full 'kubeadm join' flag needed to join the cluster using the token.") - bto.AddTTLFlag(createCmd.Flags()) + bto.AddTTLFlagWithName(createCmd.Flags(), "ttl") bto.AddUsagesFlag(createCmd.Flags()) bto.AddGroupsFlag(createCmd.Flags()) bto.AddDescriptionFlag(createCmd.Flags()) diff --git a/cmd/kubeadm/app/cmd/upgrade/apply.go b/cmd/kubeadm/app/cmd/upgrade/apply.go index d54c3f8ef15..e5922edb97a 100644 --- a/cmd/kubeadm/app/cmd/upgrade/apply.go +++ b/cmd/kubeadm/app/cmd/upgrade/apply.go @@ -43,18 +43,22 @@ import ( const ( upgradeManifestTimeout = 5 * time.Minute + + defaultImagePullTimeout = 15 * time.Minute ) // applyFlags holds the information about the flags that can be passed to apply type applyFlags struct { + *applyPlanFlags + nonInteractiveMode bool force bool dryRun bool etcdUpgrade bool + criSocket string newK8sVersionStr string newK8sVersion *version.Version imagePullTimeout time.Duration - parent *cmdUpgradeFlags } // SessionIsInteractive returns true if the session is of an interactive type (the default, can be opted out of with -y, -f or --dry-run) @@ -63,11 +67,12 @@ func (f *applyFlags) SessionIsInteractive() bool { } // NewCmdApply returns the cobra command for `kubeadm upgrade apply` -func NewCmdApply(parentFlags *cmdUpgradeFlags) *cobra.Command { +func NewCmdApply(apf *applyPlanFlags) *cobra.Command { flags := &applyFlags{ - parent: parentFlags, - imagePullTimeout: 15 * time.Minute, + applyPlanFlags: apf, + imagePullTimeout: defaultImagePullTimeout, etcdUpgrade: true, + criSocket: kubeadmapiv1alpha2.DefaultCRISocket, } cmd := &cobra.Command{ @@ -76,18 +81,18 @@ func NewCmdApply(parentFlags *cmdUpgradeFlags) *cobra.Command { Short: "Upgrade your Kubernetes cluster to the specified version.", Run: func(cmd *cobra.Command, args []string) { var err error - flags.parent.ignorePreflightErrorsSet, err = validation.ValidateIgnorePreflightErrors(flags.parent.ignorePreflightErrors, flags.parent.skipPreFlight) + flags.ignorePreflightErrorsSet, err = validation.ValidateIgnorePreflightErrors(flags.ignorePreflightErrors, flags.skipPreFlight) kubeadmutil.CheckErr(err) // Ensure the user is root glog.V(1).Infof("running preflight checks") - err = runPreflightChecks(flags.parent.ignorePreflightErrorsSet) + err = runPreflightChecks(flags.ignorePreflightErrorsSet) kubeadmutil.CheckErr(err) // If the version is specified in config file, pick up that value. - if flags.parent.cfgPath != "" { - glog.V(1).Infof("fetching configuration from file", flags.parent.cfgPath) - cfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(parentFlags.cfgPath, &kubeadmapiv1alpha2.MasterConfiguration{}) + if flags.cfgPath != "" { + glog.V(1).Infof("fetching configuration from file", flags.cfgPath) + cfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(flags.cfgPath, &kubeadmapiv1alpha2.MasterConfiguration{}) kubeadmutil.CheckErr(err) if cfg.KubernetesVersion != "" { @@ -115,13 +120,16 @@ func NewCmdApply(parentFlags *cmdUpgradeFlags) *cobra.Command { }, } + // Register the common flags for apply and plan + addApplyPlanFlags(cmd.Flags(), flags.applyPlanFlags) // Specify the valid flags specific for apply cmd.Flags().BoolVarP(&flags.nonInteractiveMode, "yes", "y", flags.nonInteractiveMode, "Perform the upgrade and do not prompt for confirmation (non-interactive mode).") cmd.Flags().BoolVarP(&flags.force, "force", "f", flags.force, "Force upgrading although some requirements might not be met. This also implies non-interactive mode.") cmd.Flags().BoolVar(&flags.dryRun, "dry-run", flags.dryRun, "Do not change any state, just output what actions would be performed.") cmd.Flags().BoolVar(&flags.etcdUpgrade, "etcd-upgrade", flags.etcdUpgrade, "Perform the upgrade of etcd.") cmd.Flags().DurationVar(&flags.imagePullTimeout, "image-pull-timeout", flags.imagePullTimeout, "The maximum amount of time to wait for the control plane pods to be downloaded.") - + // TODO: Register this flag in a generic place + cmd.Flags().StringVar(&flags.criSocket, "cri-socket", flags.criSocket, "Specify the CRI socket to connect to.") return cmd } @@ -142,11 +150,16 @@ func RunApply(flags *applyFlags) error { // Start with the basics, verify that the cluster is healthy and get the configuration from the cluster (using the ConfigMap) glog.V(1).Infof("[upgrade/apply] verifying health of cluster") glog.V(1).Infof("[upgrade/apply] retrieving configuration from cluster") - upgradeVars, err := enforceRequirements(flags.parent, flags.dryRun, flags.newK8sVersionStr) + upgradeVars, err := enforceRequirements(flags.applyPlanFlags, flags.dryRun, flags.newK8sVersionStr) if err != nil { return err } + if len(flags.criSocket) != 0 { + fmt.Println("[upgrade/apply] Respecting the --cri-socket flag that is set with higher priority than the config file.") + upgradeVars.cfg.NodeRegistration.CRISocket = flags.criSocket + } + // Validate requested and validate actual version glog.V(1).Infof("[upgrade/apply] validating requested and actual version") if err := configutil.NormalizeKubernetesVersion(upgradeVars.cfg); err != nil { @@ -228,7 +241,7 @@ func SetImplicitFlags(flags *applyFlags) error { func EnforceVersionPolicies(flags *applyFlags, versionGetter upgrade.VersionGetter) error { fmt.Printf("[upgrade/version] You have chosen to change the cluster version to %q\n", flags.newK8sVersionStr) - versionSkewErrs := upgrade.EnforceVersionPolicies(versionGetter, flags.newK8sVersionStr, flags.newK8sVersion, flags.parent.allowExperimentalUpgrades, flags.parent.allowRCUpgrades) + versionSkewErrs := upgrade.EnforceVersionPolicies(versionGetter, flags.newK8sVersionStr, flags.newK8sVersion, flags.allowExperimentalUpgrades, flags.allowRCUpgrades) if versionSkewErrs != nil { if len(versionSkewErrs.Mandatory) > 0 { diff --git a/cmd/kubeadm/app/cmd/upgrade/common.go b/cmd/kubeadm/app/cmd/upgrade/common.go index 23269ec9ddf..9480c46611f 100644 --- a/cmd/kubeadm/app/cmd/upgrade/common.go +++ b/cmd/kubeadm/app/cmd/upgrade/common.go @@ -53,12 +53,7 @@ type upgradeVariables struct { } // enforceRequirements verifies that it's okay to upgrade and then returns the variables needed for the rest of the procedure -func enforceRequirements(flags *cmdUpgradeFlags, dryRun bool, newK8sVersion string) (*upgradeVariables, error) { - - // Set the default for the kubeconfig path if the user didn't override with the flags - if flags.kubeConfigPath == "" { - flags.kubeConfigPath = "/etc/kubernetes/admin.conf" - } +func enforceRequirements(flags *applyPlanFlags, dryRun bool, newK8sVersion string) (*upgradeVariables, error) { client, err := getClient(flags.kubeConfigPath, dryRun) if err != nil { diff --git a/cmd/kubeadm/app/cmd/upgrade/common_test.go b/cmd/kubeadm/app/cmd/upgrade/common_test.go index 19b32e09806..7c0465515b5 100644 --- a/cmd/kubeadm/app/cmd/upgrade/common_test.go +++ b/cmd/kubeadm/app/cmd/upgrade/common_test.go @@ -65,9 +65,7 @@ func TestPrintConfiguration(t *testing.T) { dnsDomain: "" podSubnet: "" serviceSubnet: "" - nodeRegistration: - criSocket: "" - name: "" + nodeRegistration: {} unifiedControlPlaneImage: "" `), }, @@ -109,9 +107,7 @@ func TestPrintConfiguration(t *testing.T) { dnsDomain: "" podSubnet: "" serviceSubnet: 10.96.0.1/12 - nodeRegistration: - criSocket: "" - name: "" + nodeRegistration: {} unifiedControlPlaneImage: "" `), }, diff --git a/cmd/kubeadm/app/cmd/upgrade/diff.go b/cmd/kubeadm/app/cmd/upgrade/diff.go index cf87756c678..47180a54f09 100644 --- a/cmd/kubeadm/app/cmd/upgrade/diff.go +++ b/cmd/kubeadm/app/cmd/upgrade/diff.go @@ -18,6 +18,7 @@ package upgrade import ( "fmt" + "io" "io/ioutil" "github.com/golang/glog" @@ -39,7 +40,8 @@ type diffFlags struct { schedulerManifestPath string newK8sVersionStr string contextLines int - parent *cmdUpgradeFlags + cfgPath string + out io.Writer } var ( @@ -49,19 +51,22 @@ var ( ) // NewCmdDiff returns the cobra command for `kubeadm upgrade diff` -func NewCmdDiff(parentflags *cmdUpgradeFlags) *cobra.Command { +func NewCmdDiff(out io.Writer) *cobra.Command { flags := &diffFlags{ - parent: parentflags, + out: out, } cmd := &cobra.Command{ Use: "diff [version]", Short: "Show what differences would be applied to existing static pod manifests. See also: kubeadm upgrade apply --dry-run", Run: func(cmd *cobra.Command, args []string) { + // TODO: Run preflight checks for diff to check that the manifests already exist. kubeadmutil.CheckErr(runDiff(flags, args)) }, } + // TODO: Use the generic options.AddConfigFlag method instead + cmd.Flags().StringVar(&flags.cfgPath, "config", flags.cfgPath, "Path to kubeadm config file. WARNING: Usage of a configuration file is experimental!") cmd.Flags().StringVar(&flags.apiServerManifestPath, "api-server-manifest", defaultAPIServerManifestPath, "path to API server manifest") cmd.Flags().StringVar(&flags.controllerManagerManifestPath, "controller-manager-manifest", defaultControllerManagerManifestPath, "path to controller manifest") cmd.Flags().StringVar(&flags.schedulerManifestPath, "scheduler-manifest", defaultSchedulerManifestPath, "path to scheduler manifest") @@ -73,8 +78,8 @@ func NewCmdDiff(parentflags *cmdUpgradeFlags) *cobra.Command { func runDiff(flags *diffFlags, args []string) error { // If the version is specified in config file, pick up that value. - glog.V(1).Infof("fetching configuration from file", flags.parent.cfgPath) - cfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(flags.parent.cfgPath, &kubeadmv1alpha2.MasterConfiguration{}) + glog.V(1).Infof("fetching configuration from file", flags.cfgPath) + cfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(flags.cfgPath, &kubeadmv1alpha2.MasterConfiguration{}) if err != nil { return err } @@ -136,7 +141,7 @@ func runDiff(flags *diffFlags, args []string) error { Context: flags.contextLines, } - difflib.WriteUnifiedDiff(flags.parent.out, diff) + difflib.WriteUnifiedDiff(flags.out, diff) } return nil } diff --git a/cmd/kubeadm/app/cmd/upgrade/diff_test.go b/cmd/kubeadm/app/cmd/upgrade/diff_test.go index 2c7e2834399..a4de23b1048 100644 --- a/cmd/kubeadm/app/cmd/upgrade/diff_test.go +++ b/cmd/kubeadm/app/cmd/upgrade/diff_test.go @@ -27,13 +27,10 @@ const ( ) func TestRunDiff(t *testing.T) { - parentFlags := &cmdUpgradeFlags{ + flags := &diffFlags{ cfgPath: "", out: ioutil.Discard, } - flags := &diffFlags{ - parent: parentFlags, - } testCases := []struct { name string @@ -79,7 +76,7 @@ func TestRunDiff(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - parentFlags.cfgPath = tc.cfgPath + flags.cfgPath = tc.cfgPath if tc.setManifestPath { flags.apiServerManifestPath = tc.manifestPath flags.controllerManagerManifestPath = tc.manifestPath diff --git a/cmd/kubeadm/app/cmd/upgrade/node.go b/cmd/kubeadm/app/cmd/upgrade/node.go index 28415640d73..0c51d7cb7d0 100644 --- a/cmd/kubeadm/app/cmd/upgrade/node.go +++ b/cmd/kubeadm/app/cmd/upgrade/node.go @@ -51,28 +51,29 @@ var ( ) type nodeUpgradeFlags struct { - parent *cmdUpgradeFlags + kubeConfigPath string kubeletVersionStr string dryRun bool } // NewCmdNode returns the cobra command for `kubeadm upgrade node` -func NewCmdNode(parentFlags *cmdUpgradeFlags) *cobra.Command { +func NewCmdNode() *cobra.Command { cmd := &cobra.Command{ Use: "node", Short: "Upgrade commands for a node in the cluster. Currently only supports upgrading the configuration, not the kubelet itself.", RunE: cmdutil.SubCmdRunE("node"), } - cmd.AddCommand(NewCmdUpgradeNodeConfig(parentFlags)) + cmd.AddCommand(NewCmdUpgradeNodeConfig()) return cmd } // NewCmdUpgradeNodeConfig returns the cobra.Command for downloading the new/upgrading the kubelet configuration from the kubelet-config-1.X // ConfigMap in the cluster -func NewCmdUpgradeNodeConfig(parentFlags *cmdUpgradeFlags) *cobra.Command { +func NewCmdUpgradeNodeConfig() *cobra.Command { flags := &nodeUpgradeFlags{ - parent: parentFlags, + kubeConfigPath: constants.GetKubeletKubeConfigPath(), kubeletVersionStr: "", + dryRun: false, } cmd := &cobra.Command{ @@ -86,7 +87,8 @@ func NewCmdUpgradeNodeConfig(parentFlags *cmdUpgradeFlags) *cobra.Command { }, } - // TODO: Unify the registration of common flags + // TODO: Unify the registration of common flags and e.g. use the generic options.AddKubeConfigFlag method instead + cmd.Flags().StringVar(&flags.kubeConfigPath, "kubeconfig", flags.kubeConfigPath, "The KubeConfig file to use when talking to the cluster.") cmd.Flags().BoolVar(&flags.dryRun, "dry-run", flags.dryRun, "Do not change any state, just output the actions that would be performed.") cmd.Flags().StringVar(&flags.kubeletVersionStr, "kubelet-version", flags.kubeletVersionStr, "The *desired* version for the kubelet after the upgrade.") return cmd @@ -104,15 +106,9 @@ func RunUpgradeNodeConfig(flags *nodeUpgradeFlags) error { return err } - // Set the default for the kubeconfig path if the user didn't override with the flags - // TODO: Be smarter about this and be able to load multiple kubeconfig files in different orders of precedence - if flags.parent.kubeConfigPath == "" { - flags.parent.kubeConfigPath = constants.GetKubeletKubeConfigPath() - } - - client, err := getClient(flags.parent.kubeConfigPath, flags.dryRun) + client, err := getClient(flags.kubeConfigPath, flags.dryRun) if err != nil { - return fmt.Errorf("couldn't create a Kubernetes client from file %q: %v", flags.parent.kubeConfigPath, err) + return fmt.Errorf("couldn't create a Kubernetes client from file %q: %v", flags.kubeConfigPath, err) } // Parse the desired kubelet version diff --git a/cmd/kubeadm/app/cmd/upgrade/plan.go b/cmd/kubeadm/app/cmd/upgrade/plan.go index b769709f370..c0409229cdd 100644 --- a/cmd/kubeadm/app/cmd/upgrade/plan.go +++ b/cmd/kubeadm/app/cmd/upgrade/plan.go @@ -36,14 +36,15 @@ import ( ) type planFlags struct { + *applyPlanFlags + newK8sVersionStr string - parent *cmdUpgradeFlags } // NewCmdPlan returns the cobra command for `kubeadm upgrade plan` -func NewCmdPlan(parentFlags *cmdUpgradeFlags) *cobra.Command { +func NewCmdPlan(apf *applyPlanFlags) *cobra.Command { flags := &planFlags{ - parent: parentFlags, + applyPlanFlags: apf, } cmd := &cobra.Command{ @@ -51,16 +52,16 @@ func NewCmdPlan(parentFlags *cmdUpgradeFlags) *cobra.Command { Short: "Check which versions are available to upgrade to and validate whether your current cluster is upgradeable. To skip the internet check, pass in the optional [version] parameter.", Run: func(_ *cobra.Command, args []string) { var err error - parentFlags.ignorePreflightErrorsSet, err = validation.ValidateIgnorePreflightErrors(parentFlags.ignorePreflightErrors, parentFlags.skipPreFlight) + flags.ignorePreflightErrorsSet, err = validation.ValidateIgnorePreflightErrors(flags.ignorePreflightErrors, flags.skipPreFlight) kubeadmutil.CheckErr(err) // Ensure the user is root - err = runPreflightChecks(parentFlags.ignorePreflightErrorsSet) + err = runPreflightChecks(flags.ignorePreflightErrorsSet) kubeadmutil.CheckErr(err) // If the version is specified in config file, pick up that value. - if parentFlags.cfgPath != "" { - glog.V(1).Infof("fetching configuration from file", parentFlags.cfgPath) - cfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(parentFlags.cfgPath, &kubeadmapiv1alpha2.MasterConfiguration{}) + if flags.cfgPath != "" { + glog.V(1).Infof("fetching configuration from file", flags.cfgPath) + cfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(flags.cfgPath, &kubeadmapiv1alpha2.MasterConfiguration{}) kubeadmutil.CheckErr(err) if cfg.KubernetesVersion != "" { @@ -77,6 +78,8 @@ func NewCmdPlan(parentFlags *cmdUpgradeFlags) *cobra.Command { }, } + // Register the common flags for apply and plan + addApplyPlanFlags(cmd.Flags(), flags.applyPlanFlags) return cmd } @@ -85,7 +88,7 @@ func RunPlan(flags *planFlags) error { // Start with the basics, verify that the cluster is healthy, build a client and a versionGetter. Never dry-run when planning. glog.V(1).Infof("[upgrade/plan] verifying health of cluster") glog.V(1).Infof("[upgrade/plan] retrieving configuration from cluster") - upgradeVars, err := enforceRequirements(flags.parent, false, flags.newK8sVersionStr) + upgradeVars, err := enforceRequirements(flags.applyPlanFlags, false, flags.newK8sVersionStr) if err != nil { return err } @@ -119,7 +122,7 @@ func RunPlan(flags *planFlags) error { // Compute which upgrade possibilities there are glog.V(1).Infof("[upgrade/plan] computing upgrade possibilities") - availUpgrades, err := upgrade.GetAvailableUpgrades(upgradeVars.versionGetter, flags.parent.allowExperimentalUpgrades, flags.parent.allowRCUpgrades, etcdClient, upgradeVars.cfg.FeatureGates, upgradeVars.client) + availUpgrades, err := upgrade.GetAvailableUpgrades(upgradeVars.versionGetter, flags.allowExperimentalUpgrades, flags.allowRCUpgrades, etcdClient, upgradeVars.cfg.FeatureGates, upgradeVars.client) if err != nil { return fmt.Errorf("[upgrade/versions] FATAL: %v", err) } diff --git a/cmd/kubeadm/app/cmd/upgrade/upgrade.go b/cmd/kubeadm/app/cmd/upgrade/upgrade.go index ad2c59b0c2d..f361be6029e 100644 --- a/cmd/kubeadm/app/cmd/upgrade/upgrade.go +++ b/cmd/kubeadm/app/cmd/upgrade/upgrade.go @@ -21,13 +21,15 @@ import ( "strings" "github.com/spf13/cobra" + "github.com/spf13/pflag" + "k8s.io/apimachinery/pkg/util/sets" cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util" "k8s.io/kubernetes/cmd/kubeadm/app/features" ) -// cmdUpgradeFlags holds the values for the common flags in `kubeadm upgrade` -type cmdUpgradeFlags struct { +// applyPlanFlags holds the values for the common flags in `kubeadm upgrade apply` and `kubeadm upgrade plan` +type applyPlanFlags struct { kubeConfigPath string cfgPath string featureGatesString string @@ -42,7 +44,7 @@ type cmdUpgradeFlags struct { // NewCmdUpgrade returns the cobra command for `kubeadm upgrade` func NewCmdUpgrade(out io.Writer) *cobra.Command { - flags := &cmdUpgradeFlags{ + flags := &applyPlanFlags{ kubeConfigPath: "/etc/kubernetes/admin.conf", cfgPath: "", featureGatesString: "", @@ -60,21 +62,24 @@ func NewCmdUpgrade(out io.Writer) *cobra.Command { RunE: cmdutil.SubCmdRunE("upgrade"), } - cmd.PersistentFlags().StringVar(&flags.kubeConfigPath, "kubeconfig", flags.kubeConfigPath, "The KubeConfig file to use when talking to the cluster.") - cmd.PersistentFlags().StringVar(&flags.cfgPath, "config", flags.cfgPath, "Path to kubeadm config file. WARNING: Usage of a configuration file is experimental!") - cmd.PersistentFlags().BoolVar(&flags.allowExperimentalUpgrades, "allow-experimental-upgrades", flags.allowExperimentalUpgrades, "Show unstable versions of Kubernetes as an upgrade alternative and allow upgrading to an alpha/beta/release candidate versions of Kubernetes.") - cmd.PersistentFlags().BoolVar(&flags.allowRCUpgrades, "allow-release-candidate-upgrades", flags.allowRCUpgrades, "Show release candidate versions of Kubernetes as an upgrade alternative and allow upgrading to a release candidate versions of Kubernetes.") - cmd.PersistentFlags().BoolVar(&flags.printConfig, "print-config", flags.printConfig, "Specifies whether the configuration file that will be used in the upgrade should be printed or not.") - cmd.PersistentFlags().StringSliceVar(&flags.ignorePreflightErrors, "ignore-preflight-errors", flags.ignorePreflightErrors, "A list of checks whose errors will be shown as warnings. Example: 'IsPrivilegedUser,Swap'. Value 'all' ignores errors from all checks.") - cmd.PersistentFlags().BoolVar(&flags.skipPreFlight, "skip-preflight-checks", flags.skipPreFlight, "Skip preflight checks that normally run before modifying the system.") - cmd.PersistentFlags().MarkDeprecated("skip-preflight-checks", "it is now equivalent to --ignore-preflight-errors=all") - cmd.PersistentFlags().StringVar(&flags.featureGatesString, "feature-gates", flags.featureGatesString, "A set of key=value pairs that describe feature gates for various features."+ - "Options are:\n"+strings.Join(features.KnownFeatures(&features.InitFeatureGates), "\n")) - cmd.AddCommand(NewCmdApply(flags)) cmd.AddCommand(NewCmdPlan(flags)) - cmd.AddCommand(NewCmdDiff(flags)) - cmd.AddCommand(NewCmdNode(flags)) - + cmd.AddCommand(NewCmdDiff(out)) + cmd.AddCommand(NewCmdNode()) return cmd } + +func addApplyPlanFlags(fs *pflag.FlagSet, flags *applyPlanFlags) { + // TODO: Use the generic options.AddKubeConfigFlag and options.AddConfigFlag methods instead + fs.StringVar(&flags.kubeConfigPath, "kubeconfig", flags.kubeConfigPath, "The KubeConfig file to use when talking to the cluster.") + fs.StringVar(&flags.cfgPath, "config", flags.cfgPath, "Path to kubeadm config file. WARNING: Usage of a configuration file is experimental!") + + fs.BoolVar(&flags.allowExperimentalUpgrades, "allow-experimental-upgrades", flags.allowExperimentalUpgrades, "Show unstable versions of Kubernetes as an upgrade alternative and allow upgrading to an alpha/beta/release candidate versions of Kubernetes.") + fs.BoolVar(&flags.allowRCUpgrades, "allow-release-candidate-upgrades", flags.allowRCUpgrades, "Show release candidate versions of Kubernetes as an upgrade alternative and allow upgrading to a release candidate versions of Kubernetes.") + fs.BoolVar(&flags.printConfig, "print-config", flags.printConfig, "Specifies whether the configuration file that will be used in the upgrade should be printed or not.") + fs.StringSliceVar(&flags.ignorePreflightErrors, "ignore-preflight-errors", flags.ignorePreflightErrors, "A list of checks whose errors will be shown as warnings. Example: 'IsPrivilegedUser,Swap'. Value 'all' ignores errors from all checks.") + fs.BoolVar(&flags.skipPreFlight, "skip-preflight-checks", flags.skipPreFlight, "Skip preflight checks that normally run before modifying the system.") + fs.MarkDeprecated("skip-preflight-checks", "it is now equivalent to --ignore-preflight-errors=all") + fs.StringVar(&flags.featureGatesString, "feature-gates", flags.featureGatesString, "A set of key=value pairs that describe feature gates for various features."+ + "Options are:\n"+strings.Join(features.KnownFeatures(&features.InitFeatureGates), "\n")) +} diff --git a/cmd/kubeadm/app/kubeadm.go b/cmd/kubeadm/app/kubeadm.go index 1e2b79b3c92..fddda590260 100644 --- a/cmd/kubeadm/app/kubeadm.go +++ b/cmd/kubeadm/app/kubeadm.go @@ -29,14 +29,21 @@ import ( // Run creates and executes new kubeadm command func Run() error { - // We do not want these flags to show up in --help - pflag.CommandLine.MarkHidden("version") - pflag.CommandLine.MarkHidden("google-json-key") - pflag.CommandLine.MarkHidden("log-flush-frequency") pflag.CommandLine.SetNormalizeFunc(utilflag.WordSepNormalizeFunc) pflag.CommandLine.AddGoFlagSet(flag.CommandLine) pflag.Set("logtostderr", "true") + // We do not want these flags to show up in --help + // These MarkHidden calls must be after the lines above + pflag.CommandLine.MarkHidden("version") + pflag.CommandLine.MarkHidden("google-json-key") + pflag.CommandLine.MarkHidden("log-flush-frequency") + pflag.CommandLine.MarkHidden("alsologtostderr") + pflag.CommandLine.MarkHidden("log-backtrace-at") + pflag.CommandLine.MarkHidden("log-dir") + pflag.CommandLine.MarkHidden("logtostderr") + pflag.CommandLine.MarkHidden("stderrthreshold") + pflag.CommandLine.MarkHidden("vmodule") cmd := cmd.NewKubeadmCommand(os.Stdin, os.Stdout, os.Stderr) return cmd.Execute() diff --git a/cmd/kubeadm/app/phases/kubelet/config.go b/cmd/kubeadm/app/phases/kubelet/config.go index c177b98e864..2f09b5347be 100644 --- a/cmd/kubeadm/app/phases/kubelet/config.go +++ b/cmd/kubeadm/app/phases/kubelet/config.go @@ -24,6 +24,7 @@ import ( "k8s.io/api/core/v1" rbac "k8s.io/api/rbac/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" clientset "k8s.io/client-go/kubernetes" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" @@ -130,6 +131,11 @@ func DownloadConfig(client clientset.Interface, kubeletVersion *version.Version, configMapName, metav1.NamespaceSystem) kubeletCfg, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(configMapName, metav1.GetOptions{}) + // If the ConfigMap wasn't found and the kubelet version is v1.10.x, where we didn't support the config file yet + // just return, don't error out + if apierrors.IsNotFound(err) && kubeletVersion.Minor() == 10 { + return nil + } if err != nil { return err } diff --git a/cmd/kubeadm/app/phases/upgrade/postupgrade.go b/cmd/kubeadm/app/phases/upgrade/postupgrade.go index 47a20ef70cb..d7e15b5faa1 100644 --- a/cmd/kubeadm/app/phases/upgrade/postupgrade.go +++ b/cmd/kubeadm/app/phases/upgrade/postupgrade.go @@ -18,6 +18,7 @@ package upgrade import ( "fmt" + "io/ioutil" "os" "path/filepath" "time" @@ -37,6 +38,7 @@ import ( nodebootstraptoken "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node" certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs" kubeletphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet" + patchnodephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/patchnode" "k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting" "k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig" "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient" @@ -58,6 +60,34 @@ func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.MasterC errs = append(errs, err) } + // Create the new, version-branched kubelet ComponentConfig ConfigMap + if err := kubeletphase.CreateConfigMap(cfg, client); err != nil { + errs = append(errs, fmt.Errorf("error creating kubelet configuration ConfigMap: %v", err)) + } + + kubeletDir, err := getKubeletDir(dryRun) + if err == nil { + // Write the configuration for the kubelet down to disk so the upgraded kubelet can start with fresh config + if err := kubeletphase.DownloadConfig(client, newK8sVer, kubeletDir); err != nil { + // Tolerate the error being NotFound when dryrunning, as there is a pretty common scenario: the dryrun process + // *would* post the new kubelet-config-1.X configmap that doesn't exist now when we're trying to download it + // again. + if !(apierrors.IsNotFound(err) && dryRun) { + errs = append(errs, fmt.Errorf("error downloading kubelet configuration from the ConfigMap: %v", err)) + } + } + } else { + // The error here should never occur in reality, would only be thrown if /tmp doesn't exist on the machine. + errs = append(errs, err) + } + + // Annotate the node with the crisocket information, sourced either from the MasterConfiguration struct or + // --cri-socket. + // TODO: In the future we want to use something more official like NodeStatus or similar for detecting this properly + if err := patchnodephase.AnnotateCRISocket(client, cfg.NodeRegistration.Name, cfg.NodeRegistration.CRISocket); err != nil { + errs = append(errs, fmt.Errorf("error uploading crisocket: %v", err)) + } + // Create/update RBAC rules that makes the bootstrap tokens able to post CSRs if err := nodebootstraptoken.AllowBootstrapTokensToPostCSRs(client); err != nil { errs = append(errs, err) @@ -94,6 +124,7 @@ func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.MasterC if err != nil { fmt.Printf("[postupgrade] WARNING: failed to determine to backup kube-apiserver cert and key: %v", err) } else if shouldBackup { + // TODO: Make sure this works in dry-run mode as well // Don't fail the upgrade phase if failing to backup kube-apiserver cert and key. if err := backupAPIServerCertAndKey(certAndKeyDir); err != nil { fmt.Printf("[postupgrade] WARNING: failed to backup kube-apiserver cert and key: %v", err) @@ -103,17 +134,12 @@ func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.MasterC } } - // Create the new, version-branched kubelet ComponentConfig ConfigMap - if err := kubeletphase.CreateConfigMap(cfg, client); err != nil { - errs = append(errs, fmt.Errorf("error creating kubelet configuration ConfigMap: %v", err)) - } - // Upgrade kube-dns/CoreDNS and kube-proxy if err := dns.EnsureDNSAddon(cfg, client); err != nil { errs = append(errs, err) } // Remove the old DNS deployment if a new DNS service is now used (kube-dns to CoreDNS or vice versa) - if !dryRun { + if !dryRun { // TODO: Remove dryrun here and make it work if err := removeOldDNSDeploymentIfAnotherDNSIsUsed(cfg, client); err != nil { errs = append(errs, err) } @@ -172,6 +198,15 @@ func getWaiter(dryRun bool, client clientset.Interface) apiclient.Waiter { return apiclient.NewKubeWaiter(client, 30*time.Minute, os.Stdout) } +// getKubeletDir gets the kubelet directory based on whether the user is dry-running this command or not. +// TODO: Consolidate this with similar funcs? +func getKubeletDir(dryRun bool) (string, error) { + if dryRun { + return ioutil.TempDir("", "kubeadm-upgrade-dryrun") + } + return kubeadmconstants.KubeletRunDirectory, nil +} + // backupAPIServerCertAndKey backups the old cert and key of kube-apiserver to a specified directory. func backupAPIServerCertAndKey(certAndKeyDir string) error { subDir := filepath.Join(certAndKeyDir, "expired") diff --git a/cmd/kubeadm/app/phases/upgrade/staticpods_test.go b/cmd/kubeadm/app/phases/upgrade/staticpods_test.go index f8b85d89c59..9a4fe92f9ae 100644 --- a/cmd/kubeadm/app/phases/upgrade/staticpods_test.go +++ b/cmd/kubeadm/app/phases/upgrade/staticpods_test.go @@ -210,10 +210,7 @@ func (spm *fakeStaticPodPathManager) CleanupDirs() error { if err := os.RemoveAll(spm.BackupManifestDir()); err != nil { return err } - if err := os.RemoveAll(spm.BackupEtcdDir()); err != nil { - return err - } - return nil + return os.RemoveAll(spm.BackupEtcdDir()) } type fakeTLSEtcdClient struct{ TLS bool } diff --git a/cmd/kubeadm/app/phases/uploadconfig/uploadconfig_test.go b/cmd/kubeadm/app/phases/uploadconfig/uploadconfig_test.go index accaff0904e..327f4f9e2b4 100644 --- a/cmd/kubeadm/app/phases/uploadconfig/uploadconfig_test.go +++ b/cmd/kubeadm/app/phases/uploadconfig/uploadconfig_test.go @@ -72,6 +72,10 @@ func TestUploadConfiguration(t *testing.T) { }, }, }, + NodeRegistration: kubeadmapi.NodeRegistrationOptions{ + Name: "node-foo", + CRISocket: "/var/run/custom-cri.sock", + }, } client := clientsetfake.NewSimpleClientset() if tt.errOnCreate != nil { @@ -122,6 +126,11 @@ func TestUploadConfiguration(t *testing.T) { t.Errorf("Decoded value contains .BootstrapTokens (sensitive info), decoded = %#v, expected = empty", decodedCfg.BootstrapTokens) } + // Make sure no information from NodeRegistrationOptions was uploaded. + if decodedCfg.NodeRegistration.Name == cfg.NodeRegistration.Name || decodedCfg.NodeRegistration.CRISocket != kubeadmapiv1alpha2.DefaultCRISocket { + t.Errorf("Decoded value contains .NodeRegistration (node-specific info shouldn't be uploaded), decoded = %#v, expected = empty", decodedCfg.NodeRegistration) + } + if decodedExtCfg.Kind != "MasterConfiguration" { t.Errorf("Expected kind MasterConfiguration, got %v", decodedExtCfg.Kind) } diff --git a/cmd/kubeadm/app/preflight/checks.go b/cmd/kubeadm/app/preflight/checks.go index 389bda55cef..de9f29b40de 100644 --- a/cmd/kubeadm/app/preflight/checks.go +++ b/cmd/kubeadm/app/preflight/checks.go @@ -19,6 +19,8 @@ package preflight import ( "bufio" "bytes" + "crypto/tls" + "crypto/x509" "encoding/json" "errors" "fmt" @@ -26,28 +28,23 @@ import ( "io/ioutil" "net" "net/http" + "net/url" "os" "path/filepath" "runtime" "strings" "time" - "crypto/tls" - "crypto/x509" - "github.com/PuerkitoBio/purell" "github.com/blang/semver" "github.com/golang/glog" - "net/url" - netutil "k8s.io/apimachinery/pkg/util/net" "k8s.io/apimachinery/pkg/util/sets" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmdefaults "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/images" - "k8s.io/kubernetes/pkg/apis/core/validation" "k8s.io/kubernetes/pkg/registry/core/service/ipallocator" "k8s.io/kubernetes/pkg/util/initsystem" ipvsutil "k8s.io/kubernetes/pkg/util/ipvs" @@ -411,12 +408,9 @@ func (HostnameCheck) Name() string { // Check validates if hostname match dns sub domain regex. func (hc HostnameCheck) Check() (warnings, errors []error) { - glog.V(1).Infof("validating if hostname match dns sub domain") + glog.V(1).Infof("checking whether the given node name is reachable using net.LookupHost") errors = []error{} warnings = []error{} - for _, msg := range validation.ValidateNodeName(hc.nodeName, false) { - errors = append(errors, fmt.Errorf("hostname \"%s\" %s", hc.nodeName, msg)) - } addr, err := net.LookupHost(hc.nodeName) if addr == nil { warnings = append(warnings, fmt.Errorf("hostname \"%s\" could not be reached", hc.nodeName)) @@ -976,6 +970,7 @@ func addCommonChecks(execer utilsexec.Interface, cfg kubeadmapi.CommonConfigurat FileContentCheck{Path: bridgenf, Content: []byte{'1'}}, FileContentCheck{Path: ipv4Forward, Content: []byte{'1'}}, SwapCheck{}, + InPathCheck{executable: "crictl", mandatory: true, exec: execer}, InPathCheck{executable: "ip", mandatory: true, exec: execer}, InPathCheck{executable: "iptables", mandatory: true, exec: execer}, InPathCheck{executable: "mount", mandatory: true, exec: execer}, @@ -1057,6 +1052,7 @@ func RunChecks(checks []Checker, ww io.Writer, ignorePreflightErrors sets.String } // TryStartKubelet attempts to bring up kubelet service +// TODO: Move these kubelet start/stop functions to some other place, e.g. phases/kubelet func TryStartKubelet(ignorePreflightErrors sets.String) { if setHasItemOrAll(ignorePreflightErrors, "StartKubelet") { return diff --git a/cmd/kubeadm/app/util/apiclient/clientbacked_dryrun.go b/cmd/kubeadm/app/util/apiclient/clientbacked_dryrun.go index 34b20dc38d9..3841a715fce 100644 --- a/cmd/kubeadm/app/util/apiclient/clientbacked_dryrun.go +++ b/cmd/kubeadm/app/util/apiclient/clientbacked_dryrun.go @@ -20,6 +20,7 @@ import ( "encoding/json" "fmt" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/dynamic" @@ -72,6 +73,8 @@ func NewClientBackedDryRunGetterFromKubeconfig(file string) (*ClientBackedDryRun // HandleGetAction handles GET actions to the dryrun clientset this interface supports func (clg *ClientBackedDryRunGetter) HandleGetAction(action core.GetAction) (bool, runtime.Object, error) { unstructuredObj, err := clg.dynamicClient.Resource(action.GetResource()).Namespace(action.GetNamespace()).Get(action.GetName(), metav1.GetOptions{}) + // Inform the user that the requested object wasn't found. + printIfNotExists(err) if err != nil { return true, nil, err } @@ -120,3 +123,9 @@ func decodeUnstructuredIntoAPIObject(action core.Action, unstructuredObj runtime } return newObj, nil } + +func printIfNotExists(err error) { + if apierrors.IsNotFound(err) { + fmt.Println("[dryrun] The GET request didn't yield any result, the API Server returned a NotFound error.") + } +} diff --git a/cmd/kubeadm/app/util/apiclient/init_dryrun.go b/cmd/kubeadm/app/util/apiclient/init_dryrun.go index 875ff3f6aee..f4da31f8c3c 100644 --- a/cmd/kubeadm/app/util/apiclient/init_dryrun.go +++ b/cmd/kubeadm/app/util/apiclient/init_dryrun.go @@ -61,7 +61,6 @@ func (idr *InitDryRunGetter) HandleGetAction(action core.GetAction) (bool, runti idr.handleGetNode, idr.handleSystemNodesClusterRoleBinding, idr.handleGetBootstrapToken, - idr.handleGetKubeDNSConfigMap, } for _, f := range funcs { handled, obj, err := f(action) @@ -133,6 +132,7 @@ func (idr *InitDryRunGetter) handleGetNode(action core.GetAction) (bool, runtime Labels: map[string]string{ "kubernetes.io/hostname": idr.masterName, }, + Annotations: map[string]string{}, }, }, nil } @@ -158,20 +158,3 @@ func (idr *InitDryRunGetter) handleGetBootstrapToken(action core.GetAction) (boo // We can safely return a NotFound error here as the code will just proceed normally and create the Bootstrap Token return true, nil, apierrors.NewNotFound(action.GetResource().GroupResource(), "secret not found") } - -// handleGetKubeDNSConfigMap handles the case where kubeadm init will try to read the kube-dns ConfigMap in the cluster -// in order to transform information there to core-dns configuration. We can safely return an empty configmap here -func (idr *InitDryRunGetter) handleGetKubeDNSConfigMap(action core.GetAction) (bool, runtime.Object, error) { - if !strings.HasPrefix(action.GetName(), "kube-dns") || action.GetNamespace() != metav1.NamespaceSystem || action.GetResource().Resource != "configmaps" { - // We can't handle this event - return false, nil, nil - } - // We can safely return an empty configmap here, as we don't have any kube-dns specific config to convert to coredns config - return true, &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "kube-dns", - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{}, - }, nil -} From f126f78266ae0c27d099b4796dcc50d3dfdc61b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20K=C3=A4ldstr=C3=B6m?= Date: Tue, 12 Jun 2018 19:00:15 +0300 Subject: [PATCH 2/2] autogenerated --- cmd/kubeadm/app/apis/kubeadm/validation/BUILD | 1 - cmd/kubeadm/app/cmd/upgrade/BUILD | 1 + cmd/kubeadm/app/phases/kubelet/BUILD | 1 + cmd/kubeadm/app/phases/upgrade/BUILD | 1 + cmd/kubeadm/app/preflight/BUILD | 1 - 5 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/BUILD b/cmd/kubeadm/app/apis/kubeadm/validation/BUILD index 253e2a1c4fb..abff6526c40 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/BUILD +++ b/cmd/kubeadm/app/apis/kubeadm/validation/BUILD @@ -19,7 +19,6 @@ go_library( "//pkg/proxy/apis/kubeproxyconfig/v1alpha1:go_default_library", "//pkg/proxy/apis/kubeproxyconfig/validation:go_default_library", "//pkg/registry/core/service/ipallocator:go_default_library", - "//pkg/util/node:go_default_library", "//vendor/github.com/spf13/pflag:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library", diff --git a/cmd/kubeadm/app/cmd/upgrade/BUILD b/cmd/kubeadm/app/cmd/upgrade/BUILD index 254d16c0872..c55c9c6d1a3 100644 --- a/cmd/kubeadm/app/cmd/upgrade/BUILD +++ b/cmd/kubeadm/app/cmd/upgrade/BUILD @@ -35,6 +35,7 @@ go_library( "//vendor/github.com/golang/glog:go_default_library", "//vendor/github.com/pmezard/go-difflib/difflib:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library", + "//vendor/github.com/spf13/pflag:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/cmd/kubeadm/app/phases/kubelet/BUILD b/cmd/kubeadm/app/phases/kubelet/BUILD index 171771d880c..ef5848e5a9e 100644 --- a/cmd/kubeadm/app/phases/kubelet/BUILD +++ b/cmd/kubeadm/app/phases/kubelet/BUILD @@ -25,6 +25,7 @@ go_library( "//vendor/github.com/golang/glog:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/api/rbac/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", "//vendor/k8s.io/client-go/kubernetes:go_default_library", diff --git a/cmd/kubeadm/app/phases/upgrade/BUILD b/cmd/kubeadm/app/phases/upgrade/BUILD index 7f8d4efac9e..81a36153a82 100644 --- a/cmd/kubeadm/app/phases/upgrade/BUILD +++ b/cmd/kubeadm/app/phases/upgrade/BUILD @@ -28,6 +28,7 @@ go_library( "//cmd/kubeadm/app/phases/controlplane:go_default_library", "//cmd/kubeadm/app/phases/etcd:go_default_library", "//cmd/kubeadm/app/phases/kubelet:go_default_library", + "//cmd/kubeadm/app/phases/patchnode:go_default_library", "//cmd/kubeadm/app/phases/selfhosting:go_default_library", "//cmd/kubeadm/app/phases/uploadconfig:go_default_library", "//cmd/kubeadm/app/preflight:go_default_library", diff --git a/cmd/kubeadm/app/preflight/BUILD b/cmd/kubeadm/app/preflight/BUILD index 93d117e21b7..aae4c5d45d0 100644 --- a/cmd/kubeadm/app/preflight/BUILD +++ b/cmd/kubeadm/app/preflight/BUILD @@ -53,7 +53,6 @@ go_library( "//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library", "//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/images:go_default_library", - "//pkg/apis/core/validation:go_default_library", "//pkg/registry/core/service/ipallocator:go_default_library", "//pkg/util/initsystem:go_default_library", "//pkg/util/ipvs:go_default_library",