Skip to content

Commit

Permalink
check kas loadbalancer health
Browse files Browse the repository at this point in the history
  • Loading branch information
muraee committed Mar 8, 2023
1 parent 5baf27a commit 02efd3b
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 7 deletions.
2 changes: 2 additions & 0 deletions api/v1beta1/hostedcluster_conditions.go
Expand Up @@ -174,6 +174,8 @@ const (

ExternalDNSHostNotReachableReason = "ExternalDNSHostNotReachable"

ExternalKASEndpointNotReachableReason = "ExternalKASEndpointNotReachable"

ReconciliationPausedConditionReason = "ReconciliationPaused"
ReconciliationInvalidPausedUntilConditionReason = "InvalidPausedUntilValue"
)
Expand Down
Expand Up @@ -3,9 +3,11 @@ package hostedcontrolplane
import (
"context"
crand "crypto/rand"
"crypto/tls"
"errors"
"fmt"
"math/big"
"net/http"
"os"
"sort"
"strings"
Expand Down Expand Up @@ -79,6 +81,7 @@ import (
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/workqueue"
"k8s.io/utils/pointer"
Expand Down Expand Up @@ -575,6 +578,7 @@ func (r *HostedControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R
kubeConfigAvailable := hostedControlPlane.Status.KubeConfig != nil
etcdCondition := meta.FindStatusCondition(hostedControlPlane.Status.Conditions, string(hyperv1.EtcdAvailable))
kubeAPIServerCondition := meta.FindStatusCondition(hostedControlPlane.Status.Conditions, string(hyperv1.KubeAPIServerAvailable))
healthCheckErr := r.healthCheckKASExternalEndpoint(ctx, hostedControlPlane)

status := metav1.ConditionFalse
var reason, message string
Expand All @@ -594,6 +598,9 @@ func (r *HostedControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R
case kubeAPIServerCondition != nil && kubeAPIServerCondition.Status == metav1.ConditionFalse:
reason = kubeAPIServerCondition.Reason
message = kubeAPIServerCondition.Message
case healthCheckErr != nil:
reason = hyperv1.ExternalKASEndpointNotReachableReason
message = healthCheckErr.Error()
default:
reason = hyperv1.AsExpectedReason
message = ""
Expand Down Expand Up @@ -660,6 +667,73 @@ func (r *HostedControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R
return result, nil
}

func (r *HostedControlPlaneReconciler) healthCheckKASExternalEndpoint(ctx context.Context, hcp *hyperv1.HostedControlPlane) error {
serviceStrategy := util.ServicePublishingStrategyByTypeForHCP(hcp, hyperv1.APIServer)
if serviceStrategy == nil {
return fmt.Errorf("APIServer service strategy not specified")
}

if util.IsPublicHCP(hcp) {
var svc *corev1.Service
if serviceStrategy.Type == hyperv1.Route {
svc = manifests.RouterPublicService(hcp.Namespace)
} else {
svc = manifests.KubeAPIServerService(hcp.Namespace)
}
if err := r.Get(ctx, client.ObjectKeyFromObject(svc), svc); err != nil {
return fmt.Errorf("failed to get kube apiserver service: %w", err)
}

if len(svc.Status.LoadBalancer.Ingress) == 0 || svc.Status.LoadBalancer.Ingress[0].Hostname == "" {
return fmt.Errorf("APIServer load balancer is not provisioned")
}

hostName := svc.Status.LoadBalancer.Ingress[0].Hostname
port := util.InternalAPIPortWithDefault(hcp, config.DefaultAPIServerPort)
healthEndpoint := fmt.Sprintf("https://%s:%d/healthz", hostName, port)

httpClient := http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
},
}

resp, err := httpClient.Get(healthEndpoint)
if err != nil {
return err
}

// req, err := http.NewRequest(http.MethodGet, healthEndpoint, nil)
// if err != nil {
// return err
// }

// guestConfig, err := r.GetGuestClusterConfig(ctx, hcp)
// if err != nil {
// return err
// }

// transport, err := rest.TransportFor(guestConfig)
// if err != nil {
// return err
// }

// resp, err := transport.RoundTrip(req)
// if err != nil {
// return err
// }

if resp.StatusCode != http.StatusOK {
return fmt.Errorf("APIServer external endpoint %s is not healthy", healthEndpoint)
}
}

// private cluster, what to do?
return nil
}

func (r *HostedControlPlaneReconciler) validateConfigAndClusterCapabilities(hc *hyperv1.HostedControlPlane) error {
for _, svc := range hc.Spec.Services {
if svc.Type == hyperv1.Route && !r.ManagementClusterCapabilities.Has(capabilities.CapabilityRoute) {
Expand Down Expand Up @@ -3903,22 +3977,21 @@ func (r *HostedControlPlaneReconciler) validateAWSKMSConfig(ctx context.Context,
meta.SetStatusCondition(&hcp.Status.Conditions, condition)
}

func (r *HostedControlPlaneReconciler) GetGuestClusterClient(ctx context.Context, hcp *hyperv1.HostedControlPlane) (*kubernetes.Clientset, error) {
func (r *HostedControlPlaneReconciler) GetGuestClusterConfig(ctx context.Context, hcp *hyperv1.HostedControlPlane) (*rest.Config, error) {
kubeconfigSecret := manifests.KASExternalKubeconfigSecret(hcp.Namespace, hcp.Spec.KubeConfig)
if err := r.Get(ctx, client.ObjectKeyFromObject(kubeconfigSecret), kubeconfigSecret); err != nil {
return nil, err
}

kubeconfig := kubeconfigSecret.Data[DefaultAdminKubeconfigKey]
restConfig, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig)
if err != nil {
return nil, err
}
return clientcmd.RESTConfigFromKubeConfig(kubeconfig)
}

clientset, err := kubernetes.NewForConfig(restConfig)
func (r *HostedControlPlaneReconciler) GetGuestClusterClient(ctx context.Context, hcp *hyperv1.HostedControlPlane) (*kubernetes.Clientset, error) {
restConfig, err := r.GetGuestClusterConfig(ctx, hcp)
if err != nil {
return nil, err
}

return clientset, nil
return kubernetes.NewForConfig(restConfig)
}

0 comments on commit 02efd3b

Please sign in to comment.