mirror of https://github.com/k3s-io/k3s
kubeadm: Fix a couple of small-ish bugs for v1.11
parent
7f00fe4c3b
commit
5d96a719fb
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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.",
|
||||
)
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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: ""
|
||||
`),
|
||||
},
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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"))
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue