diff --git a/cmd/kubeadm/app/cmd/certs.go b/cmd/kubeadm/app/cmd/certs.go index f4e7d92454f..1e5115a558d 100644 --- a/cmd/kubeadm/app/cmd/certs.go +++ b/cmd/kubeadm/app/cmd/certs.go @@ -49,6 +49,7 @@ import ( "k8s.io/kubernetes/cmd/kubeadm/app/util/errors" kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" "k8s.io/kubernetes/cmd/kubeadm/app/util/output" + staticpodutil "k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod" ) var ( @@ -346,7 +347,10 @@ func getInternalCfg(cfgPath string, client kubernetes.Interface, cfg kubeadmapiv // In case the user is not providing a custom config, try to get current config from the cluster. // NB. this operation should not block, because we want to allow certificate renewal also in case of not-working clusters if cfgPath == "" && client != nil { - internalcfg, err := configutil.FetchInitConfigurationFromCluster(client, printer, logPrefix, false, false) + getNodeRegistration := true + getAPIEndpoint := staticpodutil.IsControlPlaneNode() + getComponentConfigs := true + internalcfg, err := configutil.FetchInitConfigurationFromCluster(client, printer, logPrefix, getNodeRegistration, getAPIEndpoint, getComponentConfigs) if err == nil { printer.Println() // add empty line to separate the FetchInitConfigurationFromCluster output from the command output // certificate renewal or expiration checking doesn't depend on a running cluster, which means the CertificatesDir diff --git a/cmd/kubeadm/app/cmd/join.go b/cmd/kubeadm/app/cmd/join.go index c43b1e903b7..7bcbe82f278 100644 --- a/cmd/kubeadm/app/cmd/join.go +++ b/cmd/kubeadm/app/cmd/join.go @@ -709,7 +709,10 @@ func fetchInitConfigurationFromJoinConfiguration(cfg *kubeadmapi.JoinConfigurati // fetchInitConfiguration reads the cluster configuration from the kubeadm-admin configMap func fetchInitConfiguration(client clientset.Interface) (*kubeadmapi.InitConfiguration, error) { - initConfiguration, err := configutil.FetchInitConfigurationFromCluster(client, nil, "preflight", true, false) + getNodeRegistration := false + getAPIEndpoint := false + getComponentConfigs := true + initConfiguration, err := configutil.FetchInitConfigurationFromCluster(client, nil, "preflight", getNodeRegistration, getAPIEndpoint, getComponentConfigs) if err != nil { return nil, errors.Wrap(err, "unable to fetch the kubeadm-config ConfigMap") } diff --git a/cmd/kubeadm/app/cmd/reset.go b/cmd/kubeadm/app/cmd/reset.go index 818b6eb2768..23f2bf62a1c 100644 --- a/cmd/kubeadm/app/cmd/reset.go +++ b/cmd/kubeadm/app/cmd/reset.go @@ -44,6 +44,7 @@ import ( "k8s.io/kubernetes/cmd/kubeadm/app/util/errors" kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" utilruntime "k8s.io/kubernetes/cmd/kubeadm/app/util/runtime" + staticpodutil "k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod" ) var ( @@ -132,7 +133,10 @@ func newResetData(cmd *cobra.Command, opts *resetOptions, in io.Reader, out io.W if err == nil { klog.V(1).Infof("[reset] Loaded client set from kubeconfig file: %s", opts.kubeconfigPath) - initCfg, err = configutil.FetchInitConfigurationFromCluster(client, nil, "reset", false, false) + getNodeRegistration := true + getAPIEndpoint := staticpodutil.IsControlPlaneNode() + getComponentConfigs := true + initCfg, err = configutil.FetchInitConfigurationFromCluster(client, nil, "reset", getNodeRegistration, getAPIEndpoint, getComponentConfigs) if err != nil { klog.Warningf("[reset] Unable to fetch the kubeadm-config ConfigMap from cluster: %v", err) } diff --git a/cmd/kubeadm/app/cmd/upgrade/apply.go b/cmd/kubeadm/app/cmd/upgrade/apply.go index a7bae51dd03..c6c61ed3ac6 100644 --- a/cmd/kubeadm/app/cmd/upgrade/apply.go +++ b/cmd/kubeadm/app/cmd/upgrade/apply.go @@ -229,7 +229,10 @@ func newApplyData(cmd *cobra.Command, args []string, applyFlags *applyFlags) (*a // Fetches the cluster configuration. klog.V(1).Infoln("[upgrade] retrieving configuration from cluster") - initCfg, err := configutil.FetchInitConfigurationFromCluster(client, nil, "upgrade", false, false) + getNodeRegistration := true + isControlPlaneNode := true + getComponentConfigs := true + initCfg, err := configutil.FetchInitConfigurationFromCluster(client, nil, "upgrade", getNodeRegistration, isControlPlaneNode, getComponentConfigs) if err != nil { if apierrors.IsNotFound(err) { _, _ = printer.Printf("[upgrade] In order to upgrade, a ConfigMap called %q in the %q namespace must exist.\n", constants.KubeadmConfigConfigMap, metav1.NamespaceSystem) diff --git a/cmd/kubeadm/app/cmd/upgrade/common.go b/cmd/kubeadm/app/cmd/upgrade/common.go index a3579e53254..0fee21e2ecb 100644 --- a/cmd/kubeadm/app/cmd/upgrade/common.go +++ b/cmd/kubeadm/app/cmd/upgrade/common.go @@ -45,6 +45,7 @@ import ( "k8s.io/kubernetes/cmd/kubeadm/app/util/errors" kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" "k8s.io/kubernetes/cmd/kubeadm/app/util/output" + staticpodutil "k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod" ) // enforceRequirements verifies that it's okay to upgrade and then returns the variables needed for the rest of the procedure @@ -92,7 +93,10 @@ func enforceRequirements(flagSet *pflag.FlagSet, flags *applyPlanFlags, args []s return nil, nil, nil, nil, err } - initCfg, err := configutil.FetchInitConfigurationFromCluster(client, printer, "upgrade/config", false, false) + getNodeRegistration := true + getAPIEndpoint := staticpodutil.IsControlPlaneNode() + getComponentConfigs := true + initCfg, err := configutil.FetchInitConfigurationFromCluster(client, printer, "upgrade/config", getNodeRegistration, getAPIEndpoint, getComponentConfigs) if err != nil { return nil, nil, nil, nil, errors.Wrap(err, "[upgrade/init config] FATAL") } diff --git a/cmd/kubeadm/app/cmd/upgrade/diff.go b/cmd/kubeadm/app/cmd/upgrade/diff.go index 947d763a57b..3d5bf468e9b 100644 --- a/cmd/kubeadm/app/cmd/upgrade/diff.go +++ b/cmd/kubeadm/app/cmd/upgrade/diff.go @@ -41,6 +41,7 @@ import ( "k8s.io/kubernetes/cmd/kubeadm/app/util/errors" kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" "k8s.io/kubernetes/cmd/kubeadm/app/util/output" + staticpodutil "k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod" ) type diffFlags struct { @@ -106,7 +107,7 @@ func validateManifestsPath(manifests ...string) (err error) { } // FetchInitConfigurationFunc defines the signature of the function which will fetch InitConfiguration from cluster. -type FetchInitConfigurationFunc func(client clientset.Interface, printer output.Printer, logPrefix string, newControlPlane, skipComponentConfigs bool) (*kubeadmapi.InitConfiguration, error) +type FetchInitConfigurationFunc func(client clientset.Interface, printer output.Printer, logPrefix string, getNodeRegistration, getAPIEndpoint, getComponentConfigs bool) (*kubeadmapi.InitConfiguration, error) func runDiff(fs *pflag.FlagSet, flags *diffFlags, args []string, fetchInitConfigurationFromCluster FetchInitConfigurationFunc) error { externalCfg := &v1beta4.UpgradeConfiguration{} @@ -119,7 +120,10 @@ func runDiff(fs *pflag.FlagSet, flags *diffFlags, args []string, fetchInitConfig if err != nil { return errors.Wrapf(err, "couldn't create a Kubernetes client from file %q", flags.kubeConfigPath) } - initCfg, err := fetchInitConfigurationFromCluster(client, &output.TextPrinter{}, "upgrade/diff", false, true) + getNodeRegistration := true + getAPIEndpoint := staticpodutil.IsControlPlaneNode() + getComponentConfigs := false + initCfg, err := fetchInitConfigurationFromCluster(client, &output.TextPrinter{}, "upgrade/diff", getNodeRegistration, getAPIEndpoint, getComponentConfigs) if err != nil { return err } diff --git a/cmd/kubeadm/app/cmd/upgrade/diff_test.go b/cmd/kubeadm/app/cmd/upgrade/diff_test.go index f2304128592..7e65ee1a18b 100644 --- a/cmd/kubeadm/app/cmd/upgrade/diff_test.go +++ b/cmd/kubeadm/app/cmd/upgrade/diff_test.go @@ -44,7 +44,7 @@ func createTestRunDiffFile(contents []byte) (string, error) { return file.Name(), nil } -func fakeFetchInitConfig(client clientset.Interface, printer output.Printer, logPrefix string, newControlPlane, skipComponentConfigs bool) (*kubeadmapi.InitConfiguration, error) { +func fakeFetchInitConfig(client clientset.Interface, printer output.Printer, logPrefix string, getNodeRegistration, getAPIEndpoint, getComponentConfigs bool) (*kubeadmapi.InitConfiguration, error) { return &kubeadmapi.InitConfiguration{ ClusterConfiguration: kubeadmapi.ClusterConfiguration{ KubernetesVersion: "v1.0.1", diff --git a/cmd/kubeadm/app/cmd/upgrade/node.go b/cmd/kubeadm/app/cmd/upgrade/node.go index b0f57d0b1e2..1e3cd71041e 100644 --- a/cmd/kubeadm/app/cmd/upgrade/node.go +++ b/cmd/kubeadm/app/cmd/upgrade/node.go @@ -19,14 +19,12 @@ package upgrade import ( "fmt" "io" - "os" "github.com/spf13/cobra" flag "github.com/spf13/pflag" "k8s.io/apimachinery/pkg/util/sets" clientset "k8s.io/client-go/kubernetes" - "k8s.io/klog/v2" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta4" @@ -40,6 +38,7 @@ import ( configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config" "k8s.io/kubernetes/cmd/kubeadm/app/util/errors" "k8s.io/kubernetes/cmd/kubeadm/app/util/output" + staticpodutil "k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod" ) // nodeOptions defines all the options exposed via flags by kubeadm upgrade node. @@ -164,13 +163,8 @@ func addUpgradeNodeFlags(flagSet *flag.FlagSet, nodeOptions *nodeOptions) { // This func takes care of validating nodeOptions passed to the command, and then it converts // options into the internal InitConfiguration type that is used as input all the phases in the kubeadm upgrade node workflow func newNodeData(cmd *cobra.Command, nodeOptions *nodeOptions, out io.Writer) (*nodeData, error) { - // Checks if a node is a control-plane node by looking up the kube-apiserver manifest file - isControlPlaneNode := true - filepath := constants.GetStaticPodFilepath(constants.KubeAPIServer, constants.GetStaticPodDirectory()) - if _, err := os.Stat(filepath); os.IsNotExist(err) { - klog.V(1).Infof("assuming this is not a control plane node because %q is missing", filepath) - isControlPlaneNode = false - } + isControlPlaneNode := staticpodutil.IsControlPlaneNode() + if len(nodeOptions.kubeConfigPath) == 0 { // Update the kubeconfig path depending on whether this is a control plane node or not. nodeOptions.kubeConfigPath = constants.GetKubeletKubeConfigPath() @@ -198,9 +192,10 @@ func newNodeData(cmd *cobra.Command, nodeOptions *nodeOptions, out io.Writer) (* } // Fetches the cluster configuration - // NB in case of control-plane node, we are reading all the info for the node; in case of NOT control-plane node - // (worker node), we are not reading local API address and the CRI socket from the node object - initCfg, err := configutil.FetchInitConfigurationFromCluster(client, nil, "upgrade", !isControlPlaneNode, false) + getNodeRegistration := true + getAPIEndpoint := isControlPlaneNode + getComponentConfigs := true + initCfg, err := configutil.FetchInitConfigurationFromCluster(client, nil, "upgrade", getNodeRegistration, getAPIEndpoint, getComponentConfigs) if err != nil { return nil, errors.Wrap(err, "unable to fetch the kubeadm-config ConfigMap") } diff --git a/cmd/kubeadm/app/util/config/cluster.go b/cmd/kubeadm/app/util/config/cluster.go index 724530f692a..40ba9b2dbd1 100644 --- a/cmd/kubeadm/app/util/config/cluster.go +++ b/cmd/kubeadm/app/util/config/cluster.go @@ -52,7 +52,7 @@ import ( ) // FetchInitConfigurationFromCluster fetches configuration from a ConfigMap in the cluster -func FetchInitConfigurationFromCluster(client clientset.Interface, printer output.Printer, logPrefix string, newControlPlane, skipComponentConfigs bool) (*kubeadmapi.InitConfiguration, error) { +func FetchInitConfigurationFromCluster(client clientset.Interface, printer output.Printer, logPrefix string, getNodeRegistration, getAPIEndpoint, getComponentConfigs bool) (*kubeadmapi.InitConfiguration, error) { if printer == nil { printer = &output.TextPrinter{} } @@ -61,7 +61,7 @@ func FetchInitConfigurationFromCluster(client clientset.Interface, printer outpu _, _ = printer.Printf("[%s] Use 'kubeadm init phase upload-config kubeadm --config your-config-file' to re-upload it.\n", logPrefix) // Fetch the actual config from cluster - cfg, err := getInitConfigurationFromCluster(constants.KubernetesDir, client, newControlPlane, skipComponentConfigs) + cfg, err := getInitConfigurationFromCluster(constants.KubernetesDir, client, getNodeRegistration, getAPIEndpoint, getComponentConfigs) if err != nil { return nil, err } @@ -76,7 +76,7 @@ func FetchInitConfigurationFromCluster(client clientset.Interface, printer outpu } // getInitConfigurationFromCluster is separate only for testing purposes, don't call it directly, use FetchInitConfigurationFromCluster instead -func getInitConfigurationFromCluster(kubeconfigDir string, client clientset.Interface, newControlPlane, skipComponentConfigs bool) (*kubeadmapi.InitConfiguration, error) { +func getInitConfigurationFromCluster(kubeconfigDir string, client clientset.Interface, getNodeRegistration, getAPIEndpoint, getComponentConfigs bool) (*kubeadmapi.InitConfiguration, error) { // Also, the config map really should be KubeadmConfigConfigMap... configMap, err := apiclient.GetConfigMapWithShortRetry(client, metav1.NamespaceSystem, constants.KubeadmConfigConfigMap) if err != nil { @@ -106,26 +106,28 @@ func getInitConfigurationFromCluster(kubeconfigDir string, client clientset.Inte return nil, errors.Wrap(err, "failed to decode cluster configuration data") } - if !skipComponentConfigs { + if getComponentConfigs { // get the component configs from the corresponding config maps if err := componentconfigs.FetchFromCluster(&initcfg.ClusterConfiguration, client); err != nil { return nil, errors.Wrap(err, "failed to get component configs") } } - // if this isn't a new controlplane instance (e.g. in case of kubeadm upgrades) - // get nodes specific information as well - if !newControlPlane { + if getNodeRegistration { // gets the nodeRegistration for the current from the node object kubeconfigFile := filepath.Join(kubeconfigDir, constants.KubeletKubeConfigFileName) if err := GetNodeRegistration(kubeconfigFile, client, &initcfg.NodeRegistration, &initcfg.ClusterConfiguration); err != nil { return nil, errors.Wrap(err, "failed to get node registration") } - // gets the APIEndpoint for the current node - if err := getAPIEndpoint(client, initcfg.NodeRegistration.Name, &initcfg.LocalAPIEndpoint); err != nil { + } + + if getAPIEndpoint { + // gets the APIEndpoint for the current control plane node + if err := GetAPIEndpoint(client, initcfg.NodeRegistration.Name, &initcfg.LocalAPIEndpoint); err != nil { return nil, errors.Wrap(err, "failed to getAPIEndpoint") } } + return initcfg, nil } @@ -258,7 +260,8 @@ func getNodeNameFromSSR(client clientset.Interface) (string, error) { return strings.TrimPrefix(user, constants.NodesUserPrefix), nil } -func getAPIEndpoint(client clientset.Interface, nodeName string, apiEndpoint *kubeadmapi.APIEndpoint) error { +// GetAPIEndpoint gets the API endpoint for a given node. +func GetAPIEndpoint(client clientset.Interface, nodeName string, apiEndpoint *kubeadmapi.APIEndpoint) error { return getAPIEndpointWithRetry(client, nodeName, apiEndpoint, constants.KubernetesAPICallRetryInterval, kubeadmapi.GetActiveTimeouts().KubernetesAPICall.Duration) } diff --git a/cmd/kubeadm/app/util/config/cluster_test.go b/cmd/kubeadm/app/util/config/cluster_test.go index 94aa9917c93..41329eee458 100644 --- a/cmd/kubeadm/app/util/config/cluster_test.go +++ b/cmd/kubeadm/app/util/config/cluster_test.go @@ -491,13 +491,14 @@ func TestGetInitConfigurationFromCluster(t *testing.T) { defer os.RemoveAll(tmpdir) var tests = []struct { - name string - fileContents []byte - node *v1.Node - staticPods []testresources.FakeStaticPod - configMaps []testresources.FakeConfigMap - newControlPlane bool - expectedError bool + name string + fileContents []byte + node *v1.Node + staticPods []testresources.FakeStaticPod + configMaps []testresources.FakeConfigMap + getNodeRegistration bool + getAPIEndpoint bool + expectedError bool }{ { name: "invalid - No kubeadm-config ConfigMap", @@ -556,6 +557,8 @@ func TestGetInitConfigurationFromCluster(t *testing.T) { Taints: []v1.Taint{kubeadmconstants.ControlPlaneTaint}, }, }, + getNodeRegistration: true, + getAPIEndpoint: true, }, { name: "valid v1beta3 - new control plane == true", // InitConfiguration composed with data from different places, without node specific information @@ -588,7 +591,8 @@ func TestGetInitConfigurationFromCluster(t *testing.T) { }, }, }, - newControlPlane: true, + getNodeRegistration: false, + getAPIEndpoint: false, }, } @@ -629,7 +633,8 @@ func TestGetInitConfigurationFromCluster(t *testing.T) { } } - cfg, err := getInitConfigurationFromCluster(tmpdir, client, rt.newControlPlane, false) + getComponentConfigs := true + cfg, err := getInitConfigurationFromCluster(tmpdir, client, rt.getNodeRegistration, rt.getAPIEndpoint, getComponentConfigs) if rt.expectedError != (err != nil) { t.Errorf("unexpected return err from getInitConfigurationFromCluster: %v", err) return @@ -649,13 +654,13 @@ func TestGetInitConfigurationFromCluster(t *testing.T) { if cfg.NodeRegistration.ImagePullPolicy != kubeadmapiv1.DefaultImagePullPolicy { t.Errorf("invalid cfg.NodeRegistration.ImagePullPolicy %v", cfg.NodeRegistration.ImagePullPolicy) } - if !rt.newControlPlane && (cfg.LocalAPIEndpoint.AdvertiseAddress != "1.2.3.4" || cfg.LocalAPIEndpoint.BindPort != 1234) { + if rt.getNodeRegistration && rt.getAPIEndpoint && (cfg.LocalAPIEndpoint.AdvertiseAddress != "1.2.3.4" || cfg.LocalAPIEndpoint.BindPort != 1234) { t.Errorf("invalid cfg.LocalAPIEndpoint: %v", cfg.LocalAPIEndpoint) } - if !rt.newControlPlane && (cfg.NodeRegistration.Name != nodeName || cfg.NodeRegistration.CRISocket != "myCRIsocket" || len(cfg.NodeRegistration.Taints) != 1) { + if rt.getNodeRegistration && (cfg.NodeRegistration.Name != nodeName || cfg.NodeRegistration.CRISocket != "myCRIsocket" || len(cfg.NodeRegistration.Taints) != 1) { t.Errorf("invalid cfg.NodeRegistration: %v", cfg.NodeRegistration) } - if rt.newControlPlane && len(cfg.NodeRegistration.CRISocket) > 0 { + if !rt.getNodeRegistration && len(cfg.NodeRegistration.CRISocket) > 0 { t.Errorf("invalid cfg.NodeRegistration.CRISocket: expected empty CRISocket, but got %v", cfg.NodeRegistration.CRISocket) } if _, ok := cfg.ComponentConfigs[componentconfigs.KubeletGroup]; !ok { diff --git a/cmd/kubeadm/app/util/staticpod/utils.go b/cmd/kubeadm/app/util/staticpod/utils.go index 5b70cb89c35..b49940d6c9d 100644 --- a/cmd/kubeadm/app/util/staticpod/utils.go +++ b/cmd/kubeadm/app/util/staticpod/utils.go @@ -436,3 +436,18 @@ func DeepHashObject(hasher hash.Hash, objectToWrite interface{}) { hasher.Reset() fmt.Fprintf(hasher, "%v", dump.ForHash(objectToWrite)) } + +// IsControlPlaneNode returns true if the kube-apiserver static pod manifest is present +// on the host. +func IsControlPlaneNode() bool { + isControlPlaneNode := true + + filepath := kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.KubeAPIServer, + kubeadmconstants.GetStaticPodDirectory()) + + if _, err := os.Stat(filepath); os.IsNotExist(err) { + isControlPlaneNode = false + } + + return isControlPlaneNode +}