mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 14:37:00 +00:00
kubeadm: Fix a couple of small-ish bugs for v1.11
This commit is contained in:
parent
7f00fe4c3b
commit
5d96a719fb
@ -116,6 +116,7 @@ func UpgradeCloudProvider(in *MasterConfiguration, out *kubeadm.MasterConfigurat
|
|||||||
|
|
||||||
out.APIServerExtraArgs["cloud-provider"] = in.CloudProvider
|
out.APIServerExtraArgs["cloud-provider"] = in.CloudProvider
|
||||||
out.ControllerManagerExtraArgs["cloud-provider"] = in.CloudProvider
|
out.ControllerManagerExtraArgs["cloud-provider"] = in.CloudProvider
|
||||||
|
out.NodeRegistration.KubeletExtraArgs["cloud-provider"] = in.CloudProvider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
// 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.
|
// 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.
|
// 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 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
|
// 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
|
// 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
|
||||||
|
@ -44,7 +44,6 @@ import (
|
|||||||
kubeproxyconfigv1alpha1 "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1"
|
kubeproxyconfigv1alpha1 "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/v1alpha1"
|
||||||
proxyvalidation "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/validation"
|
proxyvalidation "k8s.io/kubernetes/pkg/proxy/apis/kubeproxyconfig/validation"
|
||||||
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
|
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
|
||||||
"k8s.io/kubernetes/pkg/util/node"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidateMasterConfiguration validates master configuration and collects all encountered errors
|
// 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
|
// ValidateNodeRegistrationOptions validates the NodeRegistrationOptions object
|
||||||
func ValidateNodeRegistrationOptions(nro *kubeadm.NodeRegistrationOptions, fldPath *field.Path) field.ErrorList {
|
func ValidateNodeRegistrationOptions(nro *kubeadm.NodeRegistrationOptions, fldPath *field.Path) field.ErrorList {
|
||||||
allErrs := 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"))...)
|
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
|
// TODO: Maybe validate .Taints as well in the future using something like validateNodeTaints() in pkg/apis/core/validation
|
||||||
return allErrs
|
return allErrs
|
||||||
@ -356,15 +359,6 @@ func ValidateAbsolutePath(path string, fldPath *field.Path) field.ErrorList {
|
|||||||
return allErrs
|
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
|
// ValidateMixedArguments validates passed arguments
|
||||||
func ValidateMixedArguments(flag *pflag.FlagSet) error {
|
func ValidateMixedArguments(flag *pflag.FlagSet) error {
|
||||||
// If --config isn't set, we have nothing to validate
|
// If --config isn't set, we have nothing to validate
|
||||||
|
@ -104,24 +104,31 @@ func TestValidateTokenGroups(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateNodeName(t *testing.T) {
|
func TestValidateNodeRegistrationOptions(t *testing.T) {
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
s string
|
nodeName string
|
||||||
f *field.Path
|
criSocket string
|
||||||
expected bool
|
expectedErrors bool
|
||||||
}{
|
}{
|
||||||
{"", nil, false}, // ok if not provided
|
{"", "/some/path", true}, // node name can't be empty
|
||||||
{"1234", nil, true}, // supported
|
{"valid-nodename", "", true}, // crisocket can't be empty
|
||||||
{"valid-nodename", nil, true}, // supported
|
{"INVALID-NODENAME", "/some/path", true}, // Upper cases is invalid
|
||||||
{"INVALID-NODENAME", nil, false}, // 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 {
|
for _, rt := range tests {
|
||||||
actual := ValidateNodeName(rt.s, rt.f)
|
nro := kubeadm.NodeRegistrationOptions{Name: rt.nodeName, CRISocket: rt.criSocket}
|
||||||
if (len(actual) == 0) != rt.expected {
|
actual := ValidateNodeRegistrationOptions(&nro, field.NewPath("nodeRegistration"))
|
||||||
|
actualErrors := len(actual) > 0
|
||||||
|
if actualErrors != rt.expectedErrors {
|
||||||
t.Errorf(
|
t.Errorf(
|
||||||
"failed ValidateNodeRegistration: kubeadm.NodeRegistrationOptions{Name:\n\texpected: %t\n\t actual: %t",
|
"failed ValidateNodeRegistrationOptions: value: %v\n\texpected: %t\n\t actual: %t",
|
||||||
rt.expected,
|
nro,
|
||||||
(len(actual) == 0),
|
rt.expectedErrors,
|
||||||
|
actualErrors,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
// 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
|
// Try to stop the kubelet service so no race conditions occur when configuring it
|
||||||
glog.V(1).Infof("Stopping the kubelet")
|
if !i.dryRun {
|
||||||
preflight.TryStopKubelet(i.ignorePreflightErrors)
|
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,
|
// 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
|
// 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)
|
return fmt.Errorf("error writing kubelet configuration to disk: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to start the kubelet service in case it's inactive
|
if !i.dryRun {
|
||||||
glog.V(1).Infof("Starting the kubelet")
|
// Try to start the kubelet service in case it's inactive
|
||||||
preflight.TryStartKubelet(i.ignorePreflightErrors)
|
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
|
// certsDirToWriteTo is gonna equal cfg.CertificatesDir in the normal case, but gonna be a temp directory if dryrunning
|
||||||
i.cfg.CertificatesDir = certsDirToWriteTo
|
i.cfg.CertificatesDir = certsDirToWriteTo
|
||||||
@ -601,9 +605,10 @@ func getWaiter(i *Init, client clientset.Interface) apiclient.Waiter {
|
|||||||
return dryrunutil.NewWaiter()
|
return dryrunutil.NewWaiter()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: List images locally using `crictl` and pull in preflight checks if not available
|
// We know that the images should be cached locally already as we have pulled them using
|
||||||
// When we do that, we can always assume the images exist at this point and have a shorter timeout.
|
// crictl in the preflight checks. Hence we can have a pretty short timeout for the kubelet
|
||||||
timeout := 30 * time.Minute
|
// to start creating Static Pods.
|
||||||
|
timeout := 4 * time.Minute
|
||||||
return apiclient.NewKubeWaiter(client, timeout, os.Stdout)
|
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) {
|
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
|
// 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 {
|
if err := waiter.WaitForHealthyKubelet(40*time.Second, "http://localhost:10248/healthz"); err != nil {
|
||||||
errC <- err
|
errC <- err
|
||||||
}
|
}
|
||||||
|
@ -52,8 +52,13 @@ func (bto *BootstrapTokenOptions) AddTokenFlag(fs *pflag.FlagSet) {
|
|||||||
|
|
||||||
// AddTTLFlag adds the --token-ttl flag to the given flagset
|
// AddTTLFlag adds the --token-ttl flag to the given flagset
|
||||||
func (bto *BootstrapTokenOptions) AddTTLFlag(fs *pflag.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(
|
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",
|
"The duration before the token is automatically deleted (e.g. 1s, 2m, 3h). If set to '0', the token will never expire",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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.",
|
"The path to the CRI socket to use with crictl when cleaning up containers.",
|
||||||
)
|
)
|
||||||
|
|
||||||
cmd.PersistentFlags().BoolVar(
|
cmd.PersistentFlags().BoolVarP(
|
||||||
&forceReset, "force", false,
|
&forceReset, "force", "f", false,
|
||||||
"Reset the node without prompting for confirmation.",
|
"Reset the node without prompting for confirmation.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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)")
|
"config", cfgPath, "Path to kubeadm config file (WARNING: Usage of a configuration file is experimental)")
|
||||||
createCmd.Flags().BoolVar(&printJoinCommand,
|
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.")
|
"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.AddUsagesFlag(createCmd.Flags())
|
||||||
bto.AddGroupsFlag(createCmd.Flags())
|
bto.AddGroupsFlag(createCmd.Flags())
|
||||||
bto.AddDescriptionFlag(createCmd.Flags())
|
bto.AddDescriptionFlag(createCmd.Flags())
|
||||||
|
@ -43,18 +43,22 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
upgradeManifestTimeout = 5 * time.Minute
|
upgradeManifestTimeout = 5 * time.Minute
|
||||||
|
|
||||||
|
defaultImagePullTimeout = 15 * time.Minute
|
||||||
)
|
)
|
||||||
|
|
||||||
// applyFlags holds the information about the flags that can be passed to apply
|
// applyFlags holds the information about the flags that can be passed to apply
|
||||||
type applyFlags struct {
|
type applyFlags struct {
|
||||||
|
*applyPlanFlags
|
||||||
|
|
||||||
nonInteractiveMode bool
|
nonInteractiveMode bool
|
||||||
force bool
|
force bool
|
||||||
dryRun bool
|
dryRun bool
|
||||||
etcdUpgrade bool
|
etcdUpgrade bool
|
||||||
|
criSocket string
|
||||||
newK8sVersionStr string
|
newK8sVersionStr string
|
||||||
newK8sVersion *version.Version
|
newK8sVersion *version.Version
|
||||||
imagePullTimeout time.Duration
|
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)
|
// 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`
|
// NewCmdApply returns the cobra command for `kubeadm upgrade apply`
|
||||||
func NewCmdApply(parentFlags *cmdUpgradeFlags) *cobra.Command {
|
func NewCmdApply(apf *applyPlanFlags) *cobra.Command {
|
||||||
flags := &applyFlags{
|
flags := &applyFlags{
|
||||||
parent: parentFlags,
|
applyPlanFlags: apf,
|
||||||
imagePullTimeout: 15 * time.Minute,
|
imagePullTimeout: defaultImagePullTimeout,
|
||||||
etcdUpgrade: true,
|
etcdUpgrade: true,
|
||||||
|
criSocket: kubeadmapiv1alpha2.DefaultCRISocket,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
@ -76,18 +81,18 @@ func NewCmdApply(parentFlags *cmdUpgradeFlags) *cobra.Command {
|
|||||||
Short: "Upgrade your Kubernetes cluster to the specified version.",
|
Short: "Upgrade your Kubernetes cluster to the specified version.",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
var err error
|
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)
|
kubeadmutil.CheckErr(err)
|
||||||
|
|
||||||
// Ensure the user is root
|
// Ensure the user is root
|
||||||
glog.V(1).Infof("running preflight checks")
|
glog.V(1).Infof("running preflight checks")
|
||||||
err = runPreflightChecks(flags.parent.ignorePreflightErrorsSet)
|
err = runPreflightChecks(flags.ignorePreflightErrorsSet)
|
||||||
kubeadmutil.CheckErr(err)
|
kubeadmutil.CheckErr(err)
|
||||||
|
|
||||||
// If the version is specified in config file, pick up that value.
|
// If the version is specified in config file, pick up that value.
|
||||||
if flags.parent.cfgPath != "" {
|
if flags.cfgPath != "" {
|
||||||
glog.V(1).Infof("fetching configuration from file", flags.parent.cfgPath)
|
glog.V(1).Infof("fetching configuration from file", flags.cfgPath)
|
||||||
cfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(parentFlags.cfgPath, &kubeadmapiv1alpha2.MasterConfiguration{})
|
cfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(flags.cfgPath, &kubeadmapiv1alpha2.MasterConfiguration{})
|
||||||
kubeadmutil.CheckErr(err)
|
kubeadmutil.CheckErr(err)
|
||||||
|
|
||||||
if cfg.KubernetesVersion != "" {
|
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
|
// 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.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().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.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().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.")
|
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
|
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)
|
// 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] verifying health of cluster")
|
||||||
glog.V(1).Infof("[upgrade/apply] retrieving configuration from 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 {
|
if err != nil {
|
||||||
return err
|
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
|
// Validate requested and validate actual version
|
||||||
glog.V(1).Infof("[upgrade/apply] validating requested and actual version")
|
glog.V(1).Infof("[upgrade/apply] validating requested and actual version")
|
||||||
if err := configutil.NormalizeKubernetesVersion(upgradeVars.cfg); err != nil {
|
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 {
|
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)
|
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 versionSkewErrs != nil {
|
||||||
|
|
||||||
if len(versionSkewErrs.Mandatory) > 0 {
|
if len(versionSkewErrs.Mandatory) > 0 {
|
||||||
|
@ -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
|
// 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) {
|
func enforceRequirements(flags *applyPlanFlags, 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"
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := getClient(flags.kubeConfigPath, dryRun)
|
client, err := getClient(flags.kubeConfigPath, dryRun)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -65,9 +65,7 @@ func TestPrintConfiguration(t *testing.T) {
|
|||||||
dnsDomain: ""
|
dnsDomain: ""
|
||||||
podSubnet: ""
|
podSubnet: ""
|
||||||
serviceSubnet: ""
|
serviceSubnet: ""
|
||||||
nodeRegistration:
|
nodeRegistration: {}
|
||||||
criSocket: ""
|
|
||||||
name: ""
|
|
||||||
unifiedControlPlaneImage: ""
|
unifiedControlPlaneImage: ""
|
||||||
`),
|
`),
|
||||||
},
|
},
|
||||||
@ -109,9 +107,7 @@ func TestPrintConfiguration(t *testing.T) {
|
|||||||
dnsDomain: ""
|
dnsDomain: ""
|
||||||
podSubnet: ""
|
podSubnet: ""
|
||||||
serviceSubnet: 10.96.0.1/12
|
serviceSubnet: 10.96.0.1/12
|
||||||
nodeRegistration:
|
nodeRegistration: {}
|
||||||
criSocket: ""
|
|
||||||
name: ""
|
|
||||||
unifiedControlPlaneImage: ""
|
unifiedControlPlaneImage: ""
|
||||||
`),
|
`),
|
||||||
},
|
},
|
||||||
|
@ -18,6 +18,7 @@ package upgrade
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
@ -39,7 +40,8 @@ type diffFlags struct {
|
|||||||
schedulerManifestPath string
|
schedulerManifestPath string
|
||||||
newK8sVersionStr string
|
newK8sVersionStr string
|
||||||
contextLines int
|
contextLines int
|
||||||
parent *cmdUpgradeFlags
|
cfgPath string
|
||||||
|
out io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -49,19 +51,22 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewCmdDiff returns the cobra command for `kubeadm upgrade diff`
|
// NewCmdDiff returns the cobra command for `kubeadm upgrade diff`
|
||||||
func NewCmdDiff(parentflags *cmdUpgradeFlags) *cobra.Command {
|
func NewCmdDiff(out io.Writer) *cobra.Command {
|
||||||
flags := &diffFlags{
|
flags := &diffFlags{
|
||||||
parent: parentflags,
|
out: out,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "diff [version]",
|
Use: "diff [version]",
|
||||||
Short: "Show what differences would be applied to existing static pod manifests. See also: kubeadm upgrade apply --dry-run",
|
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) {
|
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))
|
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.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.controllerManagerManifestPath, "controller-manager-manifest", defaultControllerManagerManifestPath, "path to controller manifest")
|
||||||
cmd.Flags().StringVar(&flags.schedulerManifestPath, "scheduler-manifest", defaultSchedulerManifestPath, "path to scheduler 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 {
|
func runDiff(flags *diffFlags, args []string) error {
|
||||||
|
|
||||||
// If the version is specified in config file, pick up that value.
|
// If the version is specified in config file, pick up that value.
|
||||||
glog.V(1).Infof("fetching configuration from file", flags.parent.cfgPath)
|
glog.V(1).Infof("fetching configuration from file", flags.cfgPath)
|
||||||
cfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(flags.parent.cfgPath, &kubeadmv1alpha2.MasterConfiguration{})
|
cfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(flags.cfgPath, &kubeadmv1alpha2.MasterConfiguration{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -136,7 +141,7 @@ func runDiff(flags *diffFlags, args []string) error {
|
|||||||
Context: flags.contextLines,
|
Context: flags.contextLines,
|
||||||
}
|
}
|
||||||
|
|
||||||
difflib.WriteUnifiedDiff(flags.parent.out, diff)
|
difflib.WriteUnifiedDiff(flags.out, diff)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -27,13 +27,10 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestRunDiff(t *testing.T) {
|
func TestRunDiff(t *testing.T) {
|
||||||
parentFlags := &cmdUpgradeFlags{
|
flags := &diffFlags{
|
||||||
cfgPath: "",
|
cfgPath: "",
|
||||||
out: ioutil.Discard,
|
out: ioutil.Discard,
|
||||||
}
|
}
|
||||||
flags := &diffFlags{
|
|
||||||
parent: parentFlags,
|
|
||||||
}
|
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
@ -79,7 +76,7 @@ func TestRunDiff(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
parentFlags.cfgPath = tc.cfgPath
|
flags.cfgPath = tc.cfgPath
|
||||||
if tc.setManifestPath {
|
if tc.setManifestPath {
|
||||||
flags.apiServerManifestPath = tc.manifestPath
|
flags.apiServerManifestPath = tc.manifestPath
|
||||||
flags.controllerManagerManifestPath = tc.manifestPath
|
flags.controllerManagerManifestPath = tc.manifestPath
|
||||||
|
@ -51,28 +51,29 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type nodeUpgradeFlags struct {
|
type nodeUpgradeFlags struct {
|
||||||
parent *cmdUpgradeFlags
|
kubeConfigPath string
|
||||||
kubeletVersionStr string
|
kubeletVersionStr string
|
||||||
dryRun bool
|
dryRun bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCmdNode returns the cobra command for `kubeadm upgrade node`
|
// NewCmdNode returns the cobra command for `kubeadm upgrade node`
|
||||||
func NewCmdNode(parentFlags *cmdUpgradeFlags) *cobra.Command {
|
func NewCmdNode() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "node",
|
Use: "node",
|
||||||
Short: "Upgrade commands for a node in the cluster. Currently only supports upgrading the configuration, not the kubelet itself.",
|
Short: "Upgrade commands for a node in the cluster. Currently only supports upgrading the configuration, not the kubelet itself.",
|
||||||
RunE: cmdutil.SubCmdRunE("node"),
|
RunE: cmdutil.SubCmdRunE("node"),
|
||||||
}
|
}
|
||||||
cmd.AddCommand(NewCmdUpgradeNodeConfig(parentFlags))
|
cmd.AddCommand(NewCmdUpgradeNodeConfig())
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCmdUpgradeNodeConfig returns the cobra.Command for downloading the new/upgrading the kubelet configuration from the kubelet-config-1.X
|
// NewCmdUpgradeNodeConfig returns the cobra.Command for downloading the new/upgrading the kubelet configuration from the kubelet-config-1.X
|
||||||
// ConfigMap in the cluster
|
// ConfigMap in the cluster
|
||||||
func NewCmdUpgradeNodeConfig(parentFlags *cmdUpgradeFlags) *cobra.Command {
|
func NewCmdUpgradeNodeConfig() *cobra.Command {
|
||||||
flags := &nodeUpgradeFlags{
|
flags := &nodeUpgradeFlags{
|
||||||
parent: parentFlags,
|
kubeConfigPath: constants.GetKubeletKubeConfigPath(),
|
||||||
kubeletVersionStr: "",
|
kubeletVersionStr: "",
|
||||||
|
dryRun: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
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().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.")
|
cmd.Flags().StringVar(&flags.kubeletVersionStr, "kubelet-version", flags.kubeletVersionStr, "The *desired* version for the kubelet after the upgrade.")
|
||||||
return cmd
|
return cmd
|
||||||
@ -104,15 +106,9 @@ func RunUpgradeNodeConfig(flags *nodeUpgradeFlags) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the default for the kubeconfig path if the user didn't override with the flags
|
client, err := getClient(flags.kubeConfigPath, flags.dryRun)
|
||||||
// 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)
|
|
||||||
if err != nil {
|
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
|
// Parse the desired kubelet version
|
||||||
|
@ -36,14 +36,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type planFlags struct {
|
type planFlags struct {
|
||||||
|
*applyPlanFlags
|
||||||
|
|
||||||
newK8sVersionStr string
|
newK8sVersionStr string
|
||||||
parent *cmdUpgradeFlags
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCmdPlan returns the cobra command for `kubeadm upgrade plan`
|
// NewCmdPlan returns the cobra command for `kubeadm upgrade plan`
|
||||||
func NewCmdPlan(parentFlags *cmdUpgradeFlags) *cobra.Command {
|
func NewCmdPlan(apf *applyPlanFlags) *cobra.Command {
|
||||||
flags := &planFlags{
|
flags := &planFlags{
|
||||||
parent: parentFlags,
|
applyPlanFlags: apf,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
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.",
|
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) {
|
Run: func(_ *cobra.Command, args []string) {
|
||||||
var err error
|
var err error
|
||||||
parentFlags.ignorePreflightErrorsSet, err = validation.ValidateIgnorePreflightErrors(parentFlags.ignorePreflightErrors, parentFlags.skipPreFlight)
|
flags.ignorePreflightErrorsSet, err = validation.ValidateIgnorePreflightErrors(flags.ignorePreflightErrors, flags.skipPreFlight)
|
||||||
kubeadmutil.CheckErr(err)
|
kubeadmutil.CheckErr(err)
|
||||||
// Ensure the user is root
|
// Ensure the user is root
|
||||||
err = runPreflightChecks(parentFlags.ignorePreflightErrorsSet)
|
err = runPreflightChecks(flags.ignorePreflightErrorsSet)
|
||||||
kubeadmutil.CheckErr(err)
|
kubeadmutil.CheckErr(err)
|
||||||
|
|
||||||
// If the version is specified in config file, pick up that value.
|
// If the version is specified in config file, pick up that value.
|
||||||
if parentFlags.cfgPath != "" {
|
if flags.cfgPath != "" {
|
||||||
glog.V(1).Infof("fetching configuration from file", parentFlags.cfgPath)
|
glog.V(1).Infof("fetching configuration from file", flags.cfgPath)
|
||||||
cfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(parentFlags.cfgPath, &kubeadmapiv1alpha2.MasterConfiguration{})
|
cfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(flags.cfgPath, &kubeadmapiv1alpha2.MasterConfiguration{})
|
||||||
kubeadmutil.CheckErr(err)
|
kubeadmutil.CheckErr(err)
|
||||||
|
|
||||||
if cfg.KubernetesVersion != "" {
|
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
|
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.
|
// 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] verifying health of cluster")
|
||||||
glog.V(1).Infof("[upgrade/plan] retrieving configuration from 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -119,7 +122,7 @@ func RunPlan(flags *planFlags) error {
|
|||||||
|
|
||||||
// Compute which upgrade possibilities there are
|
// Compute which upgrade possibilities there are
|
||||||
glog.V(1).Infof("[upgrade/plan] computing upgrade possibilities")
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("[upgrade/versions] FATAL: %v", err)
|
return fmt.Errorf("[upgrade/versions] FATAL: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -21,13 +21,15 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
|
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
||||||
)
|
)
|
||||||
|
|
||||||
// cmdUpgradeFlags holds the values for the common flags in `kubeadm upgrade`
|
// applyPlanFlags holds the values for the common flags in `kubeadm upgrade apply` and `kubeadm upgrade plan`
|
||||||
type cmdUpgradeFlags struct {
|
type applyPlanFlags struct {
|
||||||
kubeConfigPath string
|
kubeConfigPath string
|
||||||
cfgPath string
|
cfgPath string
|
||||||
featureGatesString string
|
featureGatesString string
|
||||||
@ -42,7 +44,7 @@ type cmdUpgradeFlags struct {
|
|||||||
|
|
||||||
// NewCmdUpgrade returns the cobra command for `kubeadm upgrade`
|
// NewCmdUpgrade returns the cobra command for `kubeadm upgrade`
|
||||||
func NewCmdUpgrade(out io.Writer) *cobra.Command {
|
func NewCmdUpgrade(out io.Writer) *cobra.Command {
|
||||||
flags := &cmdUpgradeFlags{
|
flags := &applyPlanFlags{
|
||||||
kubeConfigPath: "/etc/kubernetes/admin.conf",
|
kubeConfigPath: "/etc/kubernetes/admin.conf",
|
||||||
cfgPath: "",
|
cfgPath: "",
|
||||||
featureGatesString: "",
|
featureGatesString: "",
|
||||||
@ -60,21 +62,24 @@ func NewCmdUpgrade(out io.Writer) *cobra.Command {
|
|||||||
RunE: cmdutil.SubCmdRunE("upgrade"),
|
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(NewCmdApply(flags))
|
||||||
cmd.AddCommand(NewCmdPlan(flags))
|
cmd.AddCommand(NewCmdPlan(flags))
|
||||||
cmd.AddCommand(NewCmdDiff(flags))
|
cmd.AddCommand(NewCmdDiff(out))
|
||||||
cmd.AddCommand(NewCmdNode(flags))
|
cmd.AddCommand(NewCmdNode())
|
||||||
|
|
||||||
return cmd
|
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"))
|
||||||
|
}
|
||||||
|
@ -29,14 +29,21 @@ import (
|
|||||||
|
|
||||||
// Run creates and executes new kubeadm command
|
// Run creates and executes new kubeadm command
|
||||||
func Run() error {
|
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.SetNormalizeFunc(utilflag.WordSepNormalizeFunc)
|
||||||
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
|
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
|
||||||
|
|
||||||
pflag.Set("logtostderr", "true")
|
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)
|
cmd := cmd.NewKubeadmCommand(os.Stdin, os.Stdout, os.Stderr)
|
||||||
return cmd.Execute()
|
return cmd.Execute()
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
rbac "k8s.io/api/rbac/v1"
|
rbac "k8s.io/api/rbac/v1"
|
||||||
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
@ -130,6 +131,11 @@ func DownloadConfig(client clientset.Interface, kubeletVersion *version.Version,
|
|||||||
configMapName, metav1.NamespaceSystem)
|
configMapName, metav1.NamespaceSystem)
|
||||||
|
|
||||||
kubeletCfg, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(configMapName, metav1.GetOptions{})
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package upgrade
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
@ -37,6 +38,7 @@ import (
|
|||||||
nodebootstraptoken "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node"
|
nodebootstraptoken "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node"
|
||||||
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
||||||
kubeletphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet"
|
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/selfhosting"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig"
|
"k8s.io/kubernetes/cmd/kubeadm/app/phases/uploadconfig"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||||
@ -58,6 +60,34 @@ func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.MasterC
|
|||||||
errs = append(errs, err)
|
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
|
// Create/update RBAC rules that makes the bootstrap tokens able to post CSRs
|
||||||
if err := nodebootstraptoken.AllowBootstrapTokensToPostCSRs(client); err != nil {
|
if err := nodebootstraptoken.AllowBootstrapTokensToPostCSRs(client); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
@ -94,6 +124,7 @@ func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.MasterC
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("[postupgrade] WARNING: failed to determine to backup kube-apiserver cert and key: %v", err)
|
fmt.Printf("[postupgrade] WARNING: failed to determine to backup kube-apiserver cert and key: %v", err)
|
||||||
} else if shouldBackup {
|
} 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.
|
// Don't fail the upgrade phase if failing to backup kube-apiserver cert and key.
|
||||||
if err := backupAPIServerCertAndKey(certAndKeyDir); err != nil {
|
if err := backupAPIServerCertAndKey(certAndKeyDir); err != nil {
|
||||||
fmt.Printf("[postupgrade] WARNING: failed to backup kube-apiserver cert and key: %v", err)
|
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
|
// Upgrade kube-dns/CoreDNS and kube-proxy
|
||||||
if err := dns.EnsureDNSAddon(cfg, client); err != nil {
|
if err := dns.EnsureDNSAddon(cfg, client); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
// Remove the old DNS deployment if a new DNS service is now used (kube-dns to CoreDNS or vice versa)
|
// 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 {
|
if err := removeOldDNSDeploymentIfAnotherDNSIsUsed(cfg, client); err != nil {
|
||||||
errs = append(errs, err)
|
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)
|
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.
|
// backupAPIServerCertAndKey backups the old cert and key of kube-apiserver to a specified directory.
|
||||||
func backupAPIServerCertAndKey(certAndKeyDir string) error {
|
func backupAPIServerCertAndKey(certAndKeyDir string) error {
|
||||||
subDir := filepath.Join(certAndKeyDir, "expired")
|
subDir := filepath.Join(certAndKeyDir, "expired")
|
||||||
|
@ -210,10 +210,7 @@ func (spm *fakeStaticPodPathManager) CleanupDirs() error {
|
|||||||
if err := os.RemoveAll(spm.BackupManifestDir()); err != nil {
|
if err := os.RemoveAll(spm.BackupManifestDir()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := os.RemoveAll(spm.BackupEtcdDir()); err != nil {
|
return os.RemoveAll(spm.BackupEtcdDir())
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type fakeTLSEtcdClient struct{ TLS bool }
|
type fakeTLSEtcdClient struct{ TLS bool }
|
||||||
|
@ -72,6 +72,10 @@ func TestUploadConfiguration(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
NodeRegistration: kubeadmapi.NodeRegistrationOptions{
|
||||||
|
Name: "node-foo",
|
||||||
|
CRISocket: "/var/run/custom-cri.sock",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
client := clientsetfake.NewSimpleClientset()
|
client := clientsetfake.NewSimpleClientset()
|
||||||
if tt.errOnCreate != nil {
|
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)
|
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" {
|
if decodedExtCfg.Kind != "MasterConfiguration" {
|
||||||
t.Errorf("Expected kind MasterConfiguration, got %v", decodedExtCfg.Kind)
|
t.Errorf("Expected kind MasterConfiguration, got %v", decodedExtCfg.Kind)
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@ package preflight
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -26,28 +28,23 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"crypto/tls"
|
|
||||||
"crypto/x509"
|
|
||||||
|
|
||||||
"github.com/PuerkitoBio/purell"
|
"github.com/PuerkitoBio/purell"
|
||||||
"github.com/blang/semver"
|
"github.com/blang/semver"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
netutil "k8s.io/apimachinery/pkg/util/net"
|
netutil "k8s.io/apimachinery/pkg/util/net"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
kubeadmdefaults "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
|
kubeadmdefaults "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
|
||||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/images"
|
"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/registry/core/service/ipallocator"
|
||||||
"k8s.io/kubernetes/pkg/util/initsystem"
|
"k8s.io/kubernetes/pkg/util/initsystem"
|
||||||
ipvsutil "k8s.io/kubernetes/pkg/util/ipvs"
|
ipvsutil "k8s.io/kubernetes/pkg/util/ipvs"
|
||||||
@ -411,12 +408,9 @@ func (HostnameCheck) Name() string {
|
|||||||
|
|
||||||
// Check validates if hostname match dns sub domain regex.
|
// Check validates if hostname match dns sub domain regex.
|
||||||
func (hc HostnameCheck) Check() (warnings, errors []error) {
|
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{}
|
errors = []error{}
|
||||||
warnings = []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)
|
addr, err := net.LookupHost(hc.nodeName)
|
||||||
if addr == nil {
|
if addr == nil {
|
||||||
warnings = append(warnings, fmt.Errorf("hostname \"%s\" could not be reached", hc.nodeName))
|
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: bridgenf, Content: []byte{'1'}},
|
||||||
FileContentCheck{Path: ipv4Forward, Content: []byte{'1'}},
|
FileContentCheck{Path: ipv4Forward, Content: []byte{'1'}},
|
||||||
SwapCheck{},
|
SwapCheck{},
|
||||||
|
InPathCheck{executable: "crictl", mandatory: true, exec: execer},
|
||||||
InPathCheck{executable: "ip", mandatory: true, exec: execer},
|
InPathCheck{executable: "ip", mandatory: true, exec: execer},
|
||||||
InPathCheck{executable: "iptables", mandatory: true, exec: execer},
|
InPathCheck{executable: "iptables", mandatory: true, exec: execer},
|
||||||
InPathCheck{executable: "mount", 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
|
// 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) {
|
func TryStartKubelet(ignorePreflightErrors sets.String) {
|
||||||
if setHasItemOrAll(ignorePreflightErrors, "StartKubelet") {
|
if setHasItemOrAll(ignorePreflightErrors, "StartKubelet") {
|
||||||
return
|
return
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/client-go/dynamic"
|
"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
|
// HandleGetAction handles GET actions to the dryrun clientset this interface supports
|
||||||
func (clg *ClientBackedDryRunGetter) HandleGetAction(action core.GetAction) (bool, runtime.Object, error) {
|
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{})
|
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 {
|
if err != nil {
|
||||||
return true, nil, err
|
return true, nil, err
|
||||||
}
|
}
|
||||||
@ -120,3 +123,9 @@ func decodeUnstructuredIntoAPIObject(action core.Action, unstructuredObj runtime
|
|||||||
}
|
}
|
||||||
return newObj, nil
|
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.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -61,7 +61,6 @@ func (idr *InitDryRunGetter) HandleGetAction(action core.GetAction) (bool, runti
|
|||||||
idr.handleGetNode,
|
idr.handleGetNode,
|
||||||
idr.handleSystemNodesClusterRoleBinding,
|
idr.handleSystemNodesClusterRoleBinding,
|
||||||
idr.handleGetBootstrapToken,
|
idr.handleGetBootstrapToken,
|
||||||
idr.handleGetKubeDNSConfigMap,
|
|
||||||
}
|
}
|
||||||
for _, f := range funcs {
|
for _, f := range funcs {
|
||||||
handled, obj, err := f(action)
|
handled, obj, err := f(action)
|
||||||
@ -133,6 +132,7 @@ func (idr *InitDryRunGetter) handleGetNode(action core.GetAction) (bool, runtime
|
|||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"kubernetes.io/hostname": idr.masterName,
|
"kubernetes.io/hostname": idr.masterName,
|
||||||
},
|
},
|
||||||
|
Annotations: map[string]string{},
|
||||||
},
|
},
|
||||||
}, nil
|
}, 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
|
// 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")
|
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
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user