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  }