github.com/kiali/kiali@v1.84.0/business/checkers/services/port_mapping_checker.go (about) 1 package services 2 3 import ( 4 "fmt" 5 "strings" 6 7 apps_v1 "k8s.io/api/apps/v1" 8 core_v1 "k8s.io/api/core/v1" 9 v1 "k8s.io/api/core/v1" 10 "k8s.io/apimachinery/pkg/labels" 11 "k8s.io/apimachinery/pkg/util/intstr" 12 13 "github.com/kiali/kiali/config" 14 "github.com/kiali/kiali/kubernetes" 15 "github.com/kiali/kiali/log" 16 "github.com/kiali/kiali/models" 17 ) 18 19 type PortMappingChecker struct { 20 Service v1.Service 21 Deployments []apps_v1.Deployment 22 Pods []core_v1.Pod 23 } 24 25 func (p PortMappingChecker) Check() ([]*models.IstioCheck, bool) { 26 validations := make([]*models.IstioCheck, 0) 27 28 // Check Port naming for services in the service mesh 29 if p.hasMatchingPodsWithSidecar(p.Service) { 30 for portIndex, sp := range p.Service.Spec.Ports { 31 if _, ok := p.Service.Labels["kiali_wizard"]; ok || strings.ToLower(string(sp.Protocol)) == "udp" { 32 continue 33 } else if sp.AppProtocol != nil { 34 if !kubernetes.MatchPortAppProtocolWithValidProtocols(sp.AppProtocol) { 35 validation := models.Build("port.appprotocol.mismatch", fmt.Sprintf("spec/ports[%d]", portIndex)) 36 validations = append(validations, &validation) 37 } 38 } else if !kubernetes.MatchPortNameWithValidProtocols(sp.Name) { 39 validation := models.Build("port.name.mismatch", fmt.Sprintf("spec/ports[%d]", portIndex)) 40 validations = append(validations, &validation) 41 } 42 } 43 } 44 45 // Ignoring istio-system Services as some ports are used for debug purposes and not exposed in deployments 46 if config.IsIstioNamespace(p.Service.Namespace) { 47 log.Tracef("Skipping Port matching check for Service %s from Istio Namespace %s", p.Service.Name, p.Service.Namespace) 48 return validations, len(validations) == 0 49 } 50 if deployment := p.findMatchingDeployment(p.Service.Spec.Selector); deployment != nil { 51 p.matchPorts(&p.Service, deployment, &validations) 52 } 53 54 return validations, len(validations) == 0 55 } 56 57 func (p PortMappingChecker) hasMatchingPodsWithSidecar(service v1.Service) bool { 58 sPods := models.Pods{} 59 sPods.Parse(kubernetes.FilterPodsByService(&service, p.Pods)) 60 return sPods.HasIstioSidecar() 61 } 62 63 func (p PortMappingChecker) findMatchingDeployment(selectors map[string]string) *apps_v1.Deployment { 64 if len(selectors) == 0 { 65 return nil 66 } 67 68 selector := labels.SelectorFromSet(labels.Set(selectors)) 69 70 for _, d := range p.Deployments { 71 labelSet := labels.Set(d.Labels) 72 73 if selector.Matches(labelSet) { 74 return &d 75 } 76 } 77 return nil 78 } 79 80 func (p PortMappingChecker) matchPorts(service *v1.Service, deployment *apps_v1.Deployment, validations *[]*models.IstioCheck) { 81 Service: 82 for portIndex, sp := range service.Spec.Ports { 83 if sp.TargetPort.Type == intstr.String && sp.TargetPort.StrVal != "" { 84 // Check port name in this case 85 for _, c := range deployment.Spec.Template.Spec.Containers { 86 for _, cp := range c.Ports { 87 if cp.Name == sp.TargetPort.StrVal { 88 continue Service 89 } 90 } 91 } 92 } else { 93 portNumber := sp.Port 94 if sp.TargetPort.Type == intstr.Int && sp.TargetPort.IntVal > 0 { 95 // Check port number from here 96 portNumber = sp.TargetPort.IntVal 97 } 98 for _, c := range deployment.Spec.Template.Spec.Containers { 99 for _, cp := range c.Ports { 100 if cp.ContainerPort == portNumber { 101 continue Service 102 } 103 } 104 } 105 } 106 validation := models.Build("service.deployment.port.mismatch", fmt.Sprintf("spec/ports[%d]", portIndex)) 107 *validations = append(*validations, &validation) 108 } 109 }