github.com/stakater/IngressMonitorController@v1.0.103/pkg/kube/wrappers/routeWrapper.go (about) 1 package wrappers 2 3 import ( 4 "context" 5 "log" 6 "net/url" 7 "path" 8 9 routev1 "github.com/openshift/api/route/v1" 10 "github.com/stakater/IngressMonitorController/pkg/constants" 11 meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 12 "k8s.io/apimachinery/pkg/labels" 13 "k8s.io/client-go/kubernetes" 14 ) 15 16 type RouteWrapper struct { 17 Route *routev1.Route 18 Namespace string 19 KubeClient kubernetes.Interface 20 } 21 22 func (rw *RouteWrapper) supportsTLS() bool { 23 if rw.Route.Spec.TLS != nil { 24 return true 25 } 26 return false 27 } 28 29 func (rw *RouteWrapper) tryGetTLSHost() (string, bool) { 30 if rw.supportsTLS() { 31 return "https://" + rw.Route.Spec.Host, true 32 } 33 34 annotations := rw.Route.GetAnnotations() 35 if value, ok := annotations[constants.ForceHTTPSAnnotation]; ok { 36 if value == "true" { 37 // Annotation exists and is enabled 38 return "https://" + rw.Route.Spec.Host, true 39 } 40 } 41 42 return "", false 43 } 44 45 func (rw *RouteWrapper) getHost() string { 46 return "http://" + rw.Route.Spec.Host 47 } 48 49 func (rw *RouteWrapper) getRoutePort() string { 50 if rw.Route.Spec.Port != nil && rw.Route.Spec.Port.TargetPort.String() != "" { 51 return rw.Route.Spec.Port.TargetPort.String() 52 } 53 return "" 54 } 55 56 func (rw *RouteWrapper) getRouteSubPath() string { 57 return rw.Route.Spec.Path 58 } 59 60 func (rw *RouteWrapper) hasService() (string, bool) { 61 if rw.Route.Spec.To.Name != "" { 62 return rw.Route.Spec.To.Name, true 63 } 64 return "", false 65 } 66 67 func (rw *RouteWrapper) tryGetHealthEndpointFromRoute() (string, bool) { 68 69 serviceName, exists := rw.hasService() 70 71 if !exists { 72 return "", false 73 } 74 75 service, err := rw.KubeClient.CoreV1().Services(rw.Route.Namespace).Get(context.TODO(), serviceName, meta_v1.GetOptions{}) 76 if err != nil { 77 log.Printf("Get service from kubernetes cluster error:%v", err) 78 return "", false 79 } 80 81 set := labels.Set(service.Spec.Selector) 82 83 if pods, err := rw.KubeClient.CoreV1().Pods(rw.Route.Namespace).List(context.TODO(), meta_v1.ListOptions{LabelSelector: set.AsSelector().String()}); err != nil { 84 log.Printf("List Pods of service[%s] error:%v", service.GetName(), err) 85 } else if len(pods.Items) > 0 { 86 pod := pods.Items[0] 87 88 podContainers := pod.Spec.Containers 89 90 if len(podContainers) == 1 { 91 if podContainers[0].ReadinessProbe != nil && podContainers[0].ReadinessProbe.HTTPGet != nil { 92 return podContainers[0].ReadinessProbe.HTTPGet.Path, true 93 } 94 } else { 95 log.Printf("Pod has %d containers so skipping health endpoint", len(podContainers)) 96 } 97 } 98 99 return "", false 100 } 101 102 func (rw *RouteWrapper) GetURL() string { 103 var URL string 104 105 if host, exists := rw.tryGetTLSHost(); exists { // Get TLS Host if it exists 106 URL = host 107 } else { 108 URL = rw.getHost() // Fallback for normal Host 109 } 110 111 // Convert url to url object 112 u, err := url.Parse(URL) 113 114 if err != nil { 115 log.Printf("URL parsing error in getURL() :%v", err) 116 return "" 117 } 118 119 annotations := rw.Route.GetAnnotations() 120 121 if value, ok := annotations[constants.OverridePathAnnotation]; ok { 122 u.Path = value 123 } else { 124 // Append subpath 125 u.Path = path.Join(u.Path, rw.getRouteSubPath()) 126 127 // Find pod by backtracking route -> service -> pod 128 healthEndpoint, exists := rw.tryGetHealthEndpointFromRoute() 129 130 // Health endpoint from pod successful 131 if exists { 132 u.Path = path.Join(u.Path, healthEndpoint) 133 } else { // Try to get annotation and set 134 135 // Annotation for health Endpoint exists 136 if value, ok := annotations[constants.MonitorHealthAnnotation]; ok { 137 u.Path = path.Join(u.Path, value) 138 } 139 } 140 } 141 142 return u.String() 143 }