diff --git a/cmd/kubeadm/app/cmd/phases/join/waitcontrolplane.go b/cmd/kubeadm/app/cmd/phases/join/waitcontrolplane.go index e126aa6c8ff..53a546c3b0d 100644 --- a/cmd/kubeadm/app/cmd/phases/join/waitcontrolplane.go +++ b/cmd/kubeadm/app/cmd/phases/join/waitcontrolplane.go @@ -67,7 +67,12 @@ func runWaitControlPlanePhase(c workflow.RunData) error { return nil } - waiter, err := newControlPlaneWaiter(data.DryRun(), 0, nil, data.OutputWriter()) + client, err := data.Client() + if err != nil { + return err + } + + waiter, err := newControlPlaneWaiter(data.DryRun(), 0, client, data.OutputWriter()) if err != nil { return errors.Wrap(err, "error creating waiter") } diff --git a/cmd/kubeadm/app/util/apiclient/wait.go b/cmd/kubeadm/app/util/apiclient/wait.go index 3b312fc122a..5d716537766 100644 --- a/cmd/kubeadm/app/util/apiclient/wait.go +++ b/cmd/kubeadm/app/util/apiclient/wait.go @@ -117,8 +117,9 @@ func NewKubeWaiter(client clientset.Interface, timeout time.Duration, writer io. // controlPlaneComponent holds a component name and an URL // on which to perform health checks. type controlPlaneComponent struct { - name string - url string + name string + addressPort string + endpoint string } // getControlPlaneComponentAddressAndPort parses the command in a static Pod @@ -181,7 +182,6 @@ func getControlPlaneComponents(podMap map[string]*v1.Pod, addressAPIServer strin type componentConfig struct { name string - podKey string args []string defaultAddr string defaultPort string @@ -190,24 +190,21 @@ func getControlPlaneComponents(podMap map[string]*v1.Pod, addressAPIServer strin components := []componentConfig{ { - name: "kube-apiserver", - podKey: constants.KubeAPIServer, + name: constants.KubeAPIServer, args: []string{argAdvertiseAddress, argPort}, defaultAddr: addressAPIServer, defaultPort: portAPIServer, endpoint: endpointLivez, }, { - name: "kube-controller-manager", - podKey: constants.KubeControllerManager, + name: constants.KubeControllerManager, args: []string{argBindAddress, argPort}, defaultAddr: addressKCM, defaultPort: portKCM, endpoint: endpointHealthz, }, { - name: "kube-scheduler", - podKey: constants.KubeScheduler, + name: constants.KubeScheduler, args: []string{argBindAddress, argPort}, defaultAddr: addressScheduler, defaultPort: portScheduler, @@ -219,8 +216,8 @@ func getControlPlaneComponents(podMap map[string]*v1.Pod, addressAPIServer strin address, port := component.defaultAddr, component.defaultPort values, err := getControlPlaneComponentAddressAndPort( - podMap[component.podKey], - component.podKey, + podMap[component.name], + component.name, component.args, ) if err != nil { @@ -235,8 +232,9 @@ func getControlPlaneComponents(podMap map[string]*v1.Pod, addressAPIServer strin } result = append(result, controlPlaneComponent{ - name: component.name, - url: fmt.Sprintf("https://%s/%s", net.JoinHostPort(address, port), component.endpoint), + name: component.name, + addressPort: net.JoinHostPort(address, port), + endpoint: component.endpoint, }) } @@ -260,7 +258,8 @@ func (w *KubeWaiter) WaitForControlPlaneComponents(podMap map[string]*v1.Pod, ap errChan := make(chan error, len(components)) for _, comp := range components { - fmt.Printf("[control-plane-check] Checking %s at %s\n", comp.name, comp.url) + url := fmt.Sprintf("https://%s/%s", comp.addressPort, comp.endpoint) + fmt.Printf("[control-plane-check] Checking %s at %s\n", comp.name, url) go func(comp controlPlaneComponent) { tr := &http.Transport{ @@ -268,6 +267,7 @@ func (w *KubeWaiter) WaitForControlPlaneComponents(podMap map[string]*v1.Pod, ap } client := &http.Client{Transport: tr} start := time.Now() + statusCode := 0 var lastError error err := wait.PollUntilContextTimeout( @@ -275,18 +275,30 @@ func (w *KubeWaiter) WaitForControlPlaneComponents(podMap map[string]*v1.Pod, ap constants.KubernetesAPICallRetryInterval, w.timeout, true, func(ctx context.Context) (bool, error) { - resp, err := client.Get(comp.url) - if err != nil { - lastError = errors.WithMessagef(err, "%s check failed at %s", comp.name, comp.url) - return false, nil + // The kube-apiserver check should use the client defined in the waiter + // or otherwise the regular http client can fail when anonymous auth is enabled. + if comp.name == constants.KubeAPIServer { + result := w.client.Discovery().RESTClient(). + Get().AbsPath(comp.endpoint).Do(ctx).StatusCode(&statusCode) + if err := result.Error(); err != nil { + lastError = errors.WithMessagef(err, "%s check failed at %s", comp.name, url) + return false, nil + } + } else { + resp, err := client.Get(url) + if err != nil { + lastError = errors.WithMessagef(err, "%s check failed at %s", comp.name, url) + return false, nil + } + defer func() { + _ = resp.Body.Close() + }() + statusCode = resp.StatusCode } - defer func() { - _ = resp.Body.Close() - }() - if resp.StatusCode != http.StatusOK { + if statusCode != http.StatusOK { lastError = errors.Errorf("%s check failed at %s with status: %d", - comp.name, comp.url, resp.StatusCode) + comp.name, url, statusCode) return false, nil } diff --git a/cmd/kubeadm/app/util/apiclient/wait_test.go b/cmd/kubeadm/app/util/apiclient/wait_test.go index b2dd3da9cdb..3849cceeb0f 100644 --- a/cmd/kubeadm/app/util/apiclient/wait_test.go +++ b/cmd/kubeadm/app/util/apiclient/wait_test.go @@ -73,9 +73,9 @@ func TestGetControlPlaneComponents(t *testing.T) { return podMap }, expected: []controlPlaneComponent{ - {name: "kube-apiserver", url: fmt.Sprintf("https://[fd00:1::]:1111/%s", endpointLivez)}, - {name: "kube-controller-manager", url: fmt.Sprintf("https://127.0.0.1:2222/%s", endpointHealthz)}, - {name: "kube-scheduler", url: fmt.Sprintf("https://127.0.0.1:3333/%s", endpointLivez)}, + {name: "kube-apiserver", addressPort: "[fd00:1::]:1111", endpoint: endpointLivez}, + {name: "kube-controller-manager", addressPort: "127.0.0.1:2222", endpoint: endpointHealthz}, + {name: "kube-scheduler", addressPort: "127.0.0.1:3333", endpoint: endpointLivez}, }, }, { @@ -106,9 +106,9 @@ func TestGetControlPlaneComponents(t *testing.T) { return podMap }, expected: []controlPlaneComponent{ - {name: "kube-apiserver", url: fmt.Sprintf("https://[fd00:1::]:1111/%s", endpointLivez)}, - {name: "kube-controller-manager", url: fmt.Sprintf("https://127.0.0.1:2222/%s", endpointHealthz)}, - {name: "kube-scheduler", url: fmt.Sprintf("https://127.0.0.1:3333/%s", endpointLivez)}, + {name: "kube-apiserver", addressPort: "[fd00:1::]:1111", endpoint: endpointLivez}, + {name: "kube-controller-manager", addressPort: "127.0.0.1:2222", endpoint: endpointHealthz}, + {name: "kube-scheduler", addressPort: "127.0.0.1:3333", endpoint: endpointLivez}, }, }, { @@ -133,9 +133,9 @@ func TestGetControlPlaneComponents(t *testing.T) { return podMap }, expected: []controlPlaneComponent{ - {name: "kube-apiserver", url: fmt.Sprintf("https://192.168.0.1:6443/%s", endpointLivez)}, - {name: "kube-controller-manager", url: fmt.Sprintf("https://127.0.0.1:10257/%s", endpointHealthz)}, - {name: "kube-scheduler", url: fmt.Sprintf("https://127.0.0.1:10259/%s", endpointLivez)}, + {name: "kube-apiserver", addressPort: "192.168.0.1:6443", endpoint: endpointLivez}, + {name: "kube-controller-manager", addressPort: "127.0.0.1:10257", endpoint: endpointHealthz}, + {name: "kube-scheduler", addressPort: "127.0.0.1:10259", endpoint: endpointLivez}, }, }, {