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  }