github.com/verrazzano/verrazzano@v1.7.1/tools/oam-converter/pkg/services/destination.go (about) 1 // Copyright (c) 2023, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package services 5 6 import ( 7 "fmt" 8 "github.com/verrazzano/verrazzano/tools/oam-converter/pkg/constants" 9 istio "istio.io/api/networking/v1beta1" 10 corev1 "k8s.io/api/core/v1" 11 "strings" 12 ) 13 14 // CreateDestinationFromService selects a Service and creates a virtual service destination for the selected service. 15 // If the selected service does not have a port, it is not included in the destination. If the selected service 16 // declares port(s), it selects the appropriate one and add it to the destination. 17 func CreateDestinationFromService(service *corev1.Service) (*istio.HTTPRouteDestination, error) { 18 19 dest := istio.HTTPRouteDestination{ 20 Destination: &istio.Destination{Host: service.Name}} 21 // If the selected service declares port(s), select the appropriate port and add it to the destination. 22 if len(service.Spec.Ports) > 0 { 23 selectedPort, err := selectPortForDestination(service) 24 if err != nil { 25 return nil, err 26 } 27 dest.Destination.Port = &istio.PortSelector{Number: uint32(selectedPort.Port)} 28 } 29 return &dest, nil 30 } 31 32 // selectPortForDestination selects a Service port to be used for virtual service destination port. 33 // The port is selected based on the following logic: 34 // - If there is one port, return that port. 35 // - If there are multiple ports, select the http/WebLogic port. 36 // - If there are multiple ports and more than one http/WebLogic port, return an error. 37 // - If there are multiple ports and none of then are http/WebLogic ports, return an error. 38 func selectPortForDestination(service *corev1.Service) (corev1.ServicePort, error) { 39 servicePorts := service.Spec.Ports 40 // If there is only one port, return that port 41 if len(servicePorts) == 1 { 42 return servicePorts[0], nil 43 } 44 allowedPorts := append(getHTTPPorts(service), getWebLogicPorts(service)...) 45 // If there are multiple ports and one http/WebLogic port, return that port 46 if len(servicePorts) > 1 && len(allowedPorts) == 1 { 47 return allowedPorts[0], nil 48 } 49 // If there are multiple ports and none of them are http/WebLogic ports, return an error 50 if len(servicePorts) > 1 && len(allowedPorts) < 1 { 51 return corev1.ServicePort{}, fmt.Errorf("unable to select the service port for destination. The service port " + 52 "should be named with prefix \"http\" if there are multiple ports OR the IngressTrait must specify the port") 53 } 54 // If there are multiple http/WebLogic ports, return an error 55 if len(allowedPorts) > 1 { 56 return corev1.ServicePort{}, fmt.Errorf("unable to select the service port for destination. Only one service " + 57 "port should be named with prefix \"http\" OR the IngressTrait must specify the port") 58 } 59 return corev1.ServicePort{}, fmt.Errorf("unable to select default port for destination") 60 } 61 62 // getHTTPPorts returns all the service ports having the prefix "http" in their names. 63 func getHTTPPorts(service *corev1.Service) []corev1.ServicePort { 64 var httpPorts []corev1.ServicePort 65 for _, servicePort := range service.Spec.Ports { 66 // Check if service port name has the http prefix 67 if strings.HasPrefix(servicePort.Name, "http") { 68 httpPorts = append(httpPorts, servicePort) 69 } 70 } 71 return httpPorts 72 } 73 74 // getWebLogicPorts returns WebLogic ports if any present for the service. A port is evaluated as a WebLogic port if 75 // the port name is from the known WebLogic non-http prefixed port names used by the WebLogic operator. 76 func getWebLogicPorts(service *corev1.Service) []corev1.ServicePort { 77 var webLogicPorts []corev1.ServicePort 78 selectorMap := service.Spec.Selector 79 value, ok := selectorMap["weblogic.createdByOperator"] 80 if !ok || value == "false" { 81 return webLogicPorts 82 } 83 for _, servicePort := range service.Spec.Ports { 84 // Check if service port name is one of the predefined WebLogic port names 85 for _, webLogicPortName := range constants.WeblogicPortNames { 86 if servicePort.Name == webLogicPortName { 87 webLogicPorts = append(webLogicPorts, servicePort) 88 } 89 } 90 } 91 return webLogicPorts 92 } 93 94 // CreateDestinationMatchRulePort fetches a Service matching the specified rule port and creates virtual service destination. 95 func CreateDestinationMatchRulePort(service *corev1.Service, rulePort uint32) (*istio.HTTPRouteDestination, error) { 96 97 dest := &istio.HTTPRouteDestination{ 98 Destination: &istio.Destination{Host: service.Name}} 99 // Set the port to rule destination port 100 dest.Destination.Port = &istio.PortSelector{Number: rulePort} 101 102 return nil, fmt.Errorf("unable to select service for specified destination port %d", rulePort) 103 }