From 489411d4688b91749c465f39fc5947e8909c55d5 Mon Sep 17 00:00:00 2001 From: phantomjinx Date: Fri, 12 Jan 2024 19:11:25 +0000 Subject: [PATCH] feat: Adds notional support for extracting the url into the hawtio.Status * While the extraction of the route url is quite straightforward, the use of ingress path rules and no hosts makes the return of a single string quite difficult. This may well need work in the future to improve the value returned --- pkg/controller/hawtio/hawtio_controller.go | 3 + pkg/resources/kubernetes/ingress.go | 71 +++++++++++++++++++++ pkg/resources/kubernetes/ingress_test.go | 73 ++++++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 pkg/resources/kubernetes/ingress_test.go diff --git a/pkg/controller/hawtio/hawtio_controller.go b/pkg/controller/hawtio/hawtio_controller.go index efdd91f345..dd750c97cb 100644 --- a/pkg/controller/hawtio/hawtio_controller.go +++ b/pkg/controller/hawtio/hawtio_controller.go @@ -541,6 +541,9 @@ func (r *ReconcileHawtio) Reconcile(request reconcile.Request) (reconcile.Result // And requeue to create a new route in the next reconcile loop return reconcile.Result{Requeue: true}, nil } + } else { + ingressRouteURL = kresources.GetIngressURL(ingress) + hawtioCopy.Status.URL = ingressRouteURL } // Reconcile console link in OpenShift console diff --git a/pkg/resources/kubernetes/ingress.go b/pkg/resources/kubernetes/ingress.go index a29b248a4b..c5b5913fb7 100644 --- a/pkg/resources/kubernetes/ingress.go +++ b/pkg/resources/kubernetes/ingress.go @@ -1,6 +1,8 @@ package kubernetes import ( + "strconv" + hawtiov1 "github.com/hawtio/hawtio-operator/pkg/apis/hawtio/v1" corev1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" @@ -67,3 +69,72 @@ func NewIngress(hawtio *hawtiov1.Hawtio, servingSecret *corev1.Secret) *networki return ingress } + +// GetIngressURL determines the full URL of the given ingress +func GetIngressURL(ingress *networkingv1.Ingress) string { + var scheme string + if len(ingress.Spec.TLS) > 0 { + scheme = "https" + } else { + scheme = "http" + } + + host, port := getIngressHostAndPort(ingress) + path := getIngressPath(ingress) + + url := scheme + "://" + host + if len(port) > 0 { + url = url + ":" + port + } + + return url + path +} + +func getIngressHostAndPort(ingress *networkingv1.Ingress) (string, string) { + ingressStatuses := ingress.Status.LoadBalancer.Ingress + if len(ingressStatuses) == 0 { + for _, ingressRule := range ingress.Spec.Rules { + if len(ingressRule.Host) > 0 { + return ingressRule.Host, "" + } + } + + return "*", "" // host must be a wildcard + } + + // get host or ip of the first ingress status available + var host string + port := "" + for _, ingressStatus := range ingress.Status.LoadBalancer.Ingress { + if len(ingressStatus.Hostname) > 0 { + host = ingressStatus.Hostname + } else if len(ingressStatus.IP) > 0 { + host = ingressStatus.IP + } + + if len(host) > 0 { + for _, statusPort := range ingressStatus.Ports { + port = strconv.FormatInt(int64(statusPort.Port), 10) + continue // get the first port + } + } + } + + if len(host) == 0 { + return "*", port + } + + return host, port +} + +func getIngressPath(ingress *networkingv1.Ingress) string { + for _, ingressRule := range ingress.Spec.Rules { + if ingressRule.IngressRuleValue.HTTP != nil { + for _, httpPath := range ingressRule.IngressRuleValue.HTTP.Paths { + return httpPath.Path + } + } + } + + return "/" +} diff --git a/pkg/resources/kubernetes/ingress_test.go b/pkg/resources/kubernetes/ingress_test.go new file mode 100644 index 0000000000..c57c490532 --- /dev/null +++ b/pkg/resources/kubernetes/ingress_test.go @@ -0,0 +1,73 @@ +package kubernetes + +import ( + "testing" + + corev1 "k8s.io/api/core/v1" + networkingv1 "k8s.io/api/networking/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/hawtio/hawtio-operator/pkg/resources" + + "github.com/stretchr/testify/assert" +) + +func TestGetIngressURL(t *testing.T) { + annotations := map[string]string{} + annotations["nginx.ingress.kubernetes.io/backend-protocol"] = "HTTPS" + annotations["nginx.ingress.kubernetes.io/force-ssl-redirect"] = "true" + annotations["nginx.ingress.kubernetes.io/rewrite-target"] = "/$1" + + labels := map[string]string{ + resources.LabelAppKey: "hawtio", + } + pathPrefix := networkingv1.PathTypePrefix + name := "hawtio-online" + + ingress := &networkingv1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: annotations, + Labels: labels, + Name: name, + }, + Spec: networkingv1.IngressSpec{ + TLS: []networkingv1.IngressTLS{ + { + SecretName: "some-tls-secret", + }, + }, + Rules: []networkingv1.IngressRule{ + { + IngressRuleValue: networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{{ + Path: "/(.*)", + PathType: &pathPrefix, + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: name, + Port: networkingv1.ServiceBackendPort{ + Number: 443, + }, + }, + }, + }}, + }, + }, + }, + }, + }, + Status: networkingv1.IngressStatus{ + LoadBalancer: corev1.LoadBalancerStatus{ + Ingress: []corev1.LoadBalancerIngress{ + { + IP: "192.168.99.9", + }, + }, + }, + }, + } + + url := GetIngressURL(ingress) + assert.Equal(t, "https://192.168.99.9/(.*)", url) +}