Skip to content

Commit 8b996c6

Browse files
committed
add host aliases for binding flows, refactor binding views and add details to the main page
Signed-off-by: Karol Szwaj <karol.szwaj@gmail.com> On-behalf-of: @SAP karol.szwaj@sap.com
1 parent c2e3a81 commit 8b996c6

9 files changed

Lines changed: 971 additions & 413 deletions

File tree

backend/http/handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ func (h *handler) handleKonnectorManifests(w http.ResponseWriter, r *http.Reques
220220
}
221221
konnectorImage := fmt.Sprintf("ghcr.io/kube-bind/konnector:%s", konnectorVersion)
222222

223-
manifests := kuberesources.NewKonnectorManifests(konnectorImage)
223+
manifests := kuberesources.NewKonnectorManifests(konnectorImage, nil)
224224

225225
// Serialize each object to YAML and join with document separators
226226
s := runtime.NewScheme()

backend/kubernetes/manager.go

Lines changed: 97 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ package kubernetes
1919
import (
2020
"context"
2121
"fmt"
22+
"net"
23+
"net/url"
2224
"strings"
2325
"time"
2426

@@ -475,6 +477,9 @@ func (m *Manager) ApplyToConsumer(
475477
if err := kubebindv1alpha2.AddToScheme(s); err != nil {
476478
return nil, fmt.Errorf("failed to add kube-bind scheme: %w", err)
477479
}
480+
if err := apiextensionsv1.AddToScheme(s); err != nil {
481+
return nil, fmt.Errorf("failed to add apiextensions scheme: %w", err)
482+
}
478483

479484
consumerClient, err := client.New(consumerConfig, client.Options{Scheme: s})
480485
if err != nil {
@@ -489,13 +494,26 @@ func (m *Manager) ApplyToConsumer(
489494
return nil, fmt.Errorf("failed to create kube-bind namespace: %w", err)
490495
}
491496

492-
// 2. Deploy konnector (idempotent)
493-
konnectorDeployed, err := m.ensureKonnector(ctx, consumerClient, konnectorImage)
497+
// 2. Resolve host aliases from the provider kubeconfig so the konnector
498+
// can reach the provider API server (needed in Kind/Docker environments
499+
// where the hostname resolves to localhost on the host but not in pods).
500+
hostAliases := m.resolveProviderHostAliases(ctx, providerKubeconfigData)
501+
502+
// 3. Deploy konnector (idempotent)
503+
konnectorDeployed, err := m.ensureKonnector(ctx, consumerClient, konnectorImage, hostAliases)
494504
if err != nil {
495505
return nil, fmt.Errorf("failed to deploy konnector: %w", err)
496506
}
497507

498-
// 3. Create kubeconfig secret for the provider
508+
// 3b. If konnector was newly deployed, wait for it to bootstrap CRDs
509+
if konnectorDeployed {
510+
logger.Info("Waiting for konnector to bootstrap CRDs on consumer cluster")
511+
if err := m.waitForCRD(ctx, consumerClient, "apiservicebindingbundles.kube-bind.io"); err != nil {
512+
return nil, fmt.Errorf("timed out waiting for konnector CRDs: %w", err)
513+
}
514+
}
515+
516+
// 4. Create kubeconfig secret for the provider
499517
secretName := fmt.Sprintf("kubeconfig-%s", bindingName)
500518
kubeconfigSecret := &corev1.Secret{
501519
ObjectMeta: metav1.ObjectMeta{
@@ -523,7 +541,7 @@ func (m *Manager) ApplyToConsumer(
523541
}
524542
}
525543

526-
// 4. Create APIServiceBindingBundle
544+
// 5. Create APIServiceBindingBundle
527545
bundle := &kubebindv1alpha2.APIServiceBindingBundle{
528546
ObjectMeta: metav1.ObjectMeta{
529547
Name: bindingName,
@@ -562,9 +580,61 @@ func (m *Manager) ApplyToConsumer(
562580
}, nil
563581
}
564582

583+
// resolveProviderHostAliases extracts the provider API server hostname from the
584+
// kubeconfig and resolves it to IP addresses. This allows the konnector pods on
585+
// the consumer cluster to reach the provider even when the hostname only resolves
586+
// correctly from the backend pod's network (e.g., Kind/Docker environments).
587+
func (m *Manager) resolveProviderHostAliases(_ context.Context, providerKubeconfigData []byte) []corev1.HostAlias {
588+
config, err := clientcmd.RESTConfigFromKubeConfig(providerKubeconfigData)
589+
if err != nil {
590+
return nil
591+
}
592+
593+
u, err := url.Parse(config.Host)
594+
if err != nil {
595+
return nil
596+
}
597+
598+
hostname := u.Hostname()
599+
if hostname == "" {
600+
return nil
601+
}
602+
603+
// Skip if the host is already an IP address
604+
if net.ParseIP(hostname) != nil {
605+
return nil
606+
}
607+
608+
// Resolve the hostname from the backend pod's perspective
609+
ips, err := net.LookupHost(hostname)
610+
if err != nil || len(ips) == 0 {
611+
return nil
612+
}
613+
614+
// Filter out loopback addresses — they won't work in consumer pods
615+
var validIPs []string
616+
for _, ip := range ips {
617+
parsed := net.ParseIP(ip)
618+
if parsed != nil && !parsed.IsLoopback() {
619+
validIPs = append(validIPs, ip)
620+
}
621+
}
622+
623+
if len(validIPs) == 0 {
624+
return nil
625+
}
626+
627+
return []corev1.HostAlias{
628+
{
629+
IP: validIPs[0],
630+
Hostnames: []string{hostname},
631+
},
632+
}
633+
}
634+
565635
// ensureKonnector deploys the konnector agent to the consumer cluster.
566636
// Returns true if the konnector was newly deployed, false if it already existed.
567-
func (m *Manager) ensureKonnector(ctx context.Context, c client.Client, konnectorImage string) (bool, error) {
637+
func (m *Manager) ensureKonnector(ctx context.Context, c client.Client, konnectorImage string, hostAliases []corev1.HostAlias) (bool, error) {
568638
// Check if konnector deployment already exists
569639
existing := &appsv1.Deployment{}
570640
err := c.Get(ctx, types.NamespacedName{Name: kuberesources.KonnectorDeploymentName, Namespace: kuberesources.KonnectorNamespace}, existing)
@@ -575,7 +645,7 @@ func (m *Manager) ensureKonnector(ctx context.Context, c client.Client, konnecto
575645
return false, fmt.Errorf("failed to check for existing konnector: %w", err)
576646
}
577647

578-
manifests := kuberesources.NewKonnectorManifests(konnectorImage)
648+
manifests := kuberesources.NewKonnectorManifests(konnectorImage, hostAliases)
579649

580650
if err := c.Create(ctx, manifests.ServiceAccount); err != nil && !errors.IsAlreadyExists(err) {
581651
return false, fmt.Errorf("failed to create konnector service account: %w", err)
@@ -593,6 +663,27 @@ func (m *Manager) ensureKonnector(ctx context.Context, c client.Client, konnecto
593663
return true, nil
594664
}
595665

666+
// waitForCRD polls until a CRD is registered on the target cluster.
667+
func (m *Manager) waitForCRD(ctx context.Context, c client.Client, crdName string) error {
668+
return wait.PollUntilContextTimeout(ctx, 2*time.Second, 120*time.Second, true, func(ctx context.Context) (bool, error) {
669+
crd := &apiextensionsv1.CustomResourceDefinition{}
670+
err := c.Get(ctx, types.NamespacedName{Name: crdName}, crd)
671+
if err != nil {
672+
if errors.IsNotFound(err) {
673+
return false, nil // keep polling
674+
}
675+
return false, nil // transient error, keep polling
676+
}
677+
// Check if the CRD is established
678+
for _, cond := range crd.Status.Conditions {
679+
if cond.Type == apiextensionsv1.Established && cond.Status == apiextensionsv1.ConditionTrue {
680+
return true, nil
681+
}
682+
}
683+
return false, nil
684+
})
685+
}
686+
596687
func (m *Manager) SeedDefaultCluster(ctx context.Context) error {
597688
logger := klog.FromContext(ctx)
598689

backend/kubernetes/resources/konnector.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ type KonnectorManifests struct {
4646

4747
// NewKonnectorManifests returns the full set of Kubernetes objects needed to deploy
4848
// the konnector agent to a consumer cluster.
49-
func NewKonnectorManifests(konnectorImage string) *KonnectorManifests {
49+
func NewKonnectorManifests(konnectorImage string, hostAliases []corev1.HostAlias) *KonnectorManifests {
5050
replicas := int32(KonnectorReplicas)
5151
httpPort := intstr.FromInt(KonnectorHealthzPort)
5252

@@ -111,6 +111,7 @@ func NewKonnectorManifests(konnectorImage string) *KonnectorManifests {
111111
Spec: corev1.PodSpec{
112112
RestartPolicy: corev1.RestartPolicyAlways,
113113
ServiceAccountName: KonnectorServiceAccountName,
114+
HostAliases: hostAliases,
114115
Containers: []corev1.Container{
115116
{
116117
Name: "konnector",

0 commit comments

Comments
 (0)