Merge pull request #131036 from neolit123/1.33-fix-anonymous-auth-wait-all-cp-comp

kubeadm: fix WaitForAllControlPlaneComponents with anonymous auth
This commit is contained in:
Kubernetes Prow Robot 2025-03-25 07:54:34 -07:00 committed by GitHub
commit 49b85354fe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 64 additions and 47 deletions

View File

@ -67,7 +67,12 @@ func runWaitControlPlanePhase(c workflow.RunData) error {
return nil 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 { if err != nil {
return errors.Wrap(err, "error creating waiter") return errors.Wrap(err, "error creating waiter")
} }

View File

@ -117,8 +117,9 @@ func NewKubeWaiter(client clientset.Interface, timeout time.Duration, writer io.
// controlPlaneComponent holds a component name and an URL // controlPlaneComponent holds a component name and an URL
// on which to perform health checks. // on which to perform health checks.
type controlPlaneComponent struct { type controlPlaneComponent struct {
name string name string
url string addressPort string
endpoint string
} }
// getControlPlaneComponentAddressAndPort parses the command in a static Pod // getControlPlaneComponentAddressAndPort parses the command in a static Pod
@ -181,7 +182,6 @@ func getControlPlaneComponents(podMap map[string]*v1.Pod, addressAPIServer strin
type componentConfig struct { type componentConfig struct {
name string name string
podKey string
args []string args []string
defaultAddr string defaultAddr string
defaultPort string defaultPort string
@ -190,24 +190,21 @@ func getControlPlaneComponents(podMap map[string]*v1.Pod, addressAPIServer strin
components := []componentConfig{ components := []componentConfig{
{ {
name: "kube-apiserver", name: constants.KubeAPIServer,
podKey: constants.KubeAPIServer,
args: []string{argAdvertiseAddress, argPort}, args: []string{argAdvertiseAddress, argPort},
defaultAddr: addressAPIServer, defaultAddr: addressAPIServer,
defaultPort: portAPIServer, defaultPort: portAPIServer,
endpoint: endpointLivez, endpoint: endpointLivez,
}, },
{ {
name: "kube-controller-manager", name: constants.KubeControllerManager,
podKey: constants.KubeControllerManager,
args: []string{argBindAddress, argPort}, args: []string{argBindAddress, argPort},
defaultAddr: addressKCM, defaultAddr: addressKCM,
defaultPort: portKCM, defaultPort: portKCM,
endpoint: endpointHealthz, endpoint: endpointHealthz,
}, },
{ {
name: "kube-scheduler", name: constants.KubeScheduler,
podKey: constants.KubeScheduler,
args: []string{argBindAddress, argPort}, args: []string{argBindAddress, argPort},
defaultAddr: addressScheduler, defaultAddr: addressScheduler,
defaultPort: portScheduler, defaultPort: portScheduler,
@ -219,8 +216,8 @@ func getControlPlaneComponents(podMap map[string]*v1.Pod, addressAPIServer strin
address, port := component.defaultAddr, component.defaultPort address, port := component.defaultAddr, component.defaultPort
values, err := getControlPlaneComponentAddressAndPort( values, err := getControlPlaneComponentAddressAndPort(
podMap[component.podKey], podMap[component.name],
component.podKey, component.name,
component.args, component.args,
) )
if err != nil { if err != nil {
@ -235,8 +232,9 @@ func getControlPlaneComponents(podMap map[string]*v1.Pod, addressAPIServer strin
} }
result = append(result, controlPlaneComponent{ result = append(result, controlPlaneComponent{
name: component.name, name: component.name,
url: fmt.Sprintf("https://%s/%s", net.JoinHostPort(address, port), component.endpoint), addressPort: net.JoinHostPort(address, port),
endpoint: component.endpoint,
}) })
} }
@ -248,7 +246,7 @@ func getControlPlaneComponents(podMap map[string]*v1.Pod, addressAPIServer strin
// WaitForControlPlaneComponents waits for all control plane components to report "ok". // WaitForControlPlaneComponents waits for all control plane components to report "ok".
func (w *KubeWaiter) WaitForControlPlaneComponents(podMap map[string]*v1.Pod, apiSeverAddress string) error { func (w *KubeWaiter) WaitForControlPlaneComponents(podMap map[string]*v1.Pod, apiSeverAddress string) error {
fmt.Printf("[control-plane-check] Waiting for healthy control plane components."+ _, _ = fmt.Fprintf(w.writer, "[control-plane-check] Waiting for healthy control plane components."+
" This can take up to %v\n", w.timeout) " This can take up to %v\n", w.timeout)
components, err := getControlPlaneComponents(podMap, apiSeverAddress) components, err := getControlPlaneComponents(podMap, apiSeverAddress)
@ -260,7 +258,8 @@ func (w *KubeWaiter) WaitForControlPlaneComponents(podMap map[string]*v1.Pod, ap
errChan := make(chan error, len(components)) errChan := make(chan error, len(components))
for _, comp := range 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.Fprintf(w.writer, "[control-plane-check] Checking %s at %s\n", comp.name, url)
go func(comp controlPlaneComponent) { go func(comp controlPlaneComponent) {
tr := &http.Transport{ tr := &http.Transport{
@ -268,6 +267,7 @@ func (w *KubeWaiter) WaitForControlPlaneComponents(podMap map[string]*v1.Pod, ap
} }
client := &http.Client{Transport: tr} client := &http.Client{Transport: tr}
start := time.Now() start := time.Now()
statusCode := 0
var lastError error var lastError error
err := wait.PollUntilContextTimeout( err := wait.PollUntilContextTimeout(
@ -275,29 +275,41 @@ func (w *KubeWaiter) WaitForControlPlaneComponents(podMap map[string]*v1.Pod, ap
constants.KubernetesAPICallRetryInterval, constants.KubernetesAPICallRetryInterval,
w.timeout, w.timeout,
true, func(ctx context.Context) (bool, error) { true, func(ctx context.Context) (bool, error) {
resp, err := client.Get(comp.url) // The kube-apiserver check should use the client defined in the waiter
if err != nil { // or otherwise the regular http client can fail when anonymous auth is enabled.
lastError = errors.WithMessagef(err, "%s check failed at %s", comp.name, comp.url) if comp.name == constants.KubeAPIServer {
return false, nil 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() { if statusCode != http.StatusOK {
_ = resp.Body.Close()
}()
if resp.StatusCode != http.StatusOK {
lastError = errors.Errorf("%s check failed at %s with status: %d", lastError = errors.Errorf("%s check failed at %s with status: %d",
comp.name, comp.url, resp.StatusCode) comp.name, url, statusCode)
return false, nil return false, nil
} }
return true, nil return true, nil
}) })
if err != nil { if err != nil {
fmt.Printf("[control-plane-check] %s is not healthy after %v\n", comp.name, time.Since(start)) _, _ = fmt.Fprintf(w.writer, "[control-plane-check] %s is not healthy after %v\n", comp.name, time.Since(start))
errChan <- lastError errChan <- lastError
return return
} }
fmt.Printf("[control-plane-check] %s is healthy after %v\n", comp.name, time.Since(start)) _, _ = fmt.Fprintf(w.writer, "[control-plane-check] %s is healthy after %v\n", comp.name, time.Since(start))
errChan <- nil errChan <- nil
}(comp) }(comp)
} }
@ -312,7 +324,7 @@ func (w *KubeWaiter) WaitForControlPlaneComponents(podMap map[string]*v1.Pod, ap
// WaitForAPI waits for the API Server's /healthz endpoint to report "ok" // WaitForAPI waits for the API Server's /healthz endpoint to report "ok"
func (w *KubeWaiter) WaitForAPI() error { func (w *KubeWaiter) WaitForAPI() error {
fmt.Printf("[api-check] Waiting for a healthy API server. This can take up to %v\n", w.timeout) _, _ = fmt.Fprintf(w.writer, "[api-check] Waiting for a healthy API server. This can take up to %v\n", w.timeout)
start := time.Now() start := time.Now()
err := wait.PollUntilContextTimeout( err := wait.PollUntilContextTimeout(
@ -328,11 +340,11 @@ func (w *KubeWaiter) WaitForAPI() error {
return true, nil return true, nil
}) })
if err != nil { if err != nil {
fmt.Printf("[api-check] The API server is not healthy after %v\n", time.Since(start)) _, _ = fmt.Fprintf(w.writer, "[api-check] The API server is not healthy after %v\n", time.Since(start))
return err return err
} }
fmt.Printf("[api-check] The API server is healthy after %v\n", time.Since(start)) _, _ = fmt.Fprintf(w.writer, "[api-check] The API server is healthy after %v\n", time.Since(start))
return nil return nil
} }
@ -347,12 +359,12 @@ func (w *KubeWaiter) WaitForPodsWithLabel(kvLabel string) error {
listOpts := metav1.ListOptions{LabelSelector: kvLabel} listOpts := metav1.ListOptions{LabelSelector: kvLabel}
pods, err := w.client.CoreV1().Pods(metav1.NamespaceSystem).List(context.TODO(), listOpts) pods, err := w.client.CoreV1().Pods(metav1.NamespaceSystem).List(context.TODO(), listOpts)
if err != nil { if err != nil {
fmt.Fprintf(w.writer, "[apiclient] Error getting Pods with label selector %q [%v]\n", kvLabel, err) _, _ = fmt.Fprintf(w.writer, "[apiclient] Error getting Pods with label selector %q [%v]\n", kvLabel, err)
return false, nil return false, nil
} }
if lastKnownPodNumber != len(pods.Items) { if lastKnownPodNumber != len(pods.Items) {
fmt.Fprintf(w.writer, "[apiclient] Found %d Pods for label selector %s\n", len(pods.Items), kvLabel) _, _ = fmt.Fprintf(w.writer, "[apiclient] Found %d Pods for label selector %s\n", len(pods.Items), kvLabel)
lastKnownPodNumber = len(pods.Items) lastKnownPodNumber = len(pods.Items)
} }
@ -379,10 +391,10 @@ func (w *KubeWaiter) WaitForKubelet(healthzAddress string, healthzPort int32) er
) )
if healthzPort == 0 { if healthzPort == 0 {
fmt.Println("[kubelet-check] Skipping the kubelet health check because the healthz port is set to 0") _, _ = fmt.Fprintln(w.writer, "[kubelet-check] Skipping the kubelet health check because the healthz port is set to 0")
return nil return nil
} }
fmt.Printf("[kubelet-check] Waiting for a healthy kubelet at %s. This can take up to %v\n", _, _ = fmt.Fprintf(w.writer, "[kubelet-check] Waiting for a healthy kubelet at %s. This can take up to %v\n",
healthzEndpoint, w.timeout) healthzEndpoint, w.timeout)
formatError := func(cause string) error { formatError := func(cause string) error {
@ -417,11 +429,11 @@ func (w *KubeWaiter) WaitForKubelet(healthzAddress string, healthzPort int32) er
return true, nil return true, nil
}) })
if err != nil { if err != nil {
fmt.Printf("[kubelet-check] The kubelet is not healthy after %v\n", time.Since(start)) _, _ = fmt.Fprintf(w.writer, "[kubelet-check] The kubelet is not healthy after %v\n", time.Since(start))
return lastError return lastError
} }
fmt.Printf("[kubelet-check] The kubelet is healthy after %v\n", time.Since(start)) _, _ = fmt.Fprintf(w.writer, "[kubelet-check] The kubelet is healthy after %v\n", time.Since(start))
return nil return nil
} }
@ -528,10 +540,10 @@ func PrintControlPlaneErrorHelpScreen(outputWriter io.Writer, criSocket string)
Socket: criSocket, Socket: criSocket,
} }
_ = controlPlaneFailTempl.Execute(outputWriter, context) _ = controlPlaneFailTempl.Execute(outputWriter, context)
fmt.Println("") _, _ = fmt.Fprintln(outputWriter, "")
} }
// PrintKubeletErrorHelpScreen prints help text on kubelet errors. // PrintKubeletErrorHelpScreen prints help text on kubelet errors.
func PrintKubeletErrorHelpScreen(outputWriter io.Writer) { func PrintKubeletErrorHelpScreen(outputWriter io.Writer) {
fmt.Fprintln(outputWriter, kubeletFailMsg) _, _ = fmt.Fprintln(outputWriter, kubeletFailMsg)
} }

View File

@ -73,9 +73,9 @@ func TestGetControlPlaneComponents(t *testing.T) {
return podMap return podMap
}, },
expected: []controlPlaneComponent{ expected: []controlPlaneComponent{
{name: "kube-apiserver", url: fmt.Sprintf("https://[fd00:1::]:1111/%s", endpointLivez)}, {name: "kube-apiserver", addressPort: "[fd00:1::]:1111", endpoint: endpointLivez},
{name: "kube-controller-manager", url: fmt.Sprintf("https://127.0.0.1:2222/%s", endpointHealthz)}, {name: "kube-controller-manager", addressPort: "127.0.0.1:2222", endpoint: endpointHealthz},
{name: "kube-scheduler", url: fmt.Sprintf("https://127.0.0.1:3333/%s", endpointLivez)}, {name: "kube-scheduler", addressPort: "127.0.0.1:3333", endpoint: endpointLivez},
}, },
}, },
{ {
@ -106,9 +106,9 @@ func TestGetControlPlaneComponents(t *testing.T) {
return podMap return podMap
}, },
expected: []controlPlaneComponent{ expected: []controlPlaneComponent{
{name: "kube-apiserver", url: fmt.Sprintf("https://[fd00:1::]:1111/%s", endpointLivez)}, {name: "kube-apiserver", addressPort: "[fd00:1::]:1111", endpoint: endpointLivez},
{name: "kube-controller-manager", url: fmt.Sprintf("https://127.0.0.1:2222/%s", endpointHealthz)}, {name: "kube-controller-manager", addressPort: "127.0.0.1:2222", endpoint: endpointHealthz},
{name: "kube-scheduler", url: fmt.Sprintf("https://127.0.0.1:3333/%s", endpointLivez)}, {name: "kube-scheduler", addressPort: "127.0.0.1:3333", endpoint: endpointLivez},
}, },
}, },
{ {
@ -133,9 +133,9 @@ func TestGetControlPlaneComponents(t *testing.T) {
return podMap return podMap
}, },
expected: []controlPlaneComponent{ expected: []controlPlaneComponent{
{name: "kube-apiserver", url: fmt.Sprintf("https://192.168.0.1:6443/%s", endpointLivez)}, {name: "kube-apiserver", addressPort: "192.168.0.1:6443", endpoint: endpointLivez},
{name: "kube-controller-manager", url: fmt.Sprintf("https://127.0.0.1:10257/%s", endpointHealthz)}, {name: "kube-controller-manager", addressPort: "127.0.0.1:10257", endpoint: endpointHealthz},
{name: "kube-scheduler", url: fmt.Sprintf("https://127.0.0.1:10259/%s", endpointLivez)}, {name: "kube-scheduler", addressPort: "127.0.0.1:10259", endpoint: endpointLivez},
}, },
}, },
{ {