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