github.com/kiali/kiali@v1.84.0/business/checkers/virtualservices/subset_presence_checker.go (about)

     1  package virtualservices
     2  
     3  import (
     4  	"fmt"
     5  
     6  	networking_v1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
     7  
     8  	"github.com/kiali/kiali/kubernetes"
     9  	"github.com/kiali/kiali/models"
    10  )
    11  
    12  type SubsetPresenceChecker struct {
    13  	Namespaces       []string
    14  	DestinationRules []*networking_v1beta1.DestinationRule
    15  	VirtualService   *networking_v1beta1.VirtualService
    16  }
    17  
    18  func (checker SubsetPresenceChecker) Check() ([]*models.IstioCheck, bool) {
    19  	valid := true
    20  	validations := make([]*models.IstioCheck, 0)
    21  
    22  	for routeIdx, httpRoute := range checker.VirtualService.Spec.Http {
    23  		if httpRoute == nil {
    24  			continue
    25  		}
    26  		for destWeightIdx, destinationWeight := range httpRoute.Route {
    27  			if destinationWeight == nil && destinationWeight.Destination == nil {
    28  				continue
    29  			}
    30  			host := destinationWeight.Destination.Host
    31  			if host == "" {
    32  				continue
    33  			}
    34  			subset := destinationWeight.Destination.Subset
    35  			if subset == "" {
    36  				continue
    37  			}
    38  			if !checker.subsetPresent(host, subset) {
    39  				path := fmt.Sprintf("spec/http[%d]/route[%d]/destination", routeIdx, destWeightIdx)
    40  				validation := models.Build("virtualservices.subsetpresent.subsetnotfound", path)
    41  				validations = append(validations, &validation)
    42  			}
    43  		}
    44  	}
    45  
    46  	for routeIdx, tcpRoute := range checker.VirtualService.Spec.Tcp {
    47  		if tcpRoute == nil {
    48  			continue
    49  		}
    50  		for destWeightIdx, destinationWeight := range tcpRoute.Route {
    51  			if destinationWeight == nil && destinationWeight.Destination == nil {
    52  				continue
    53  			}
    54  			host := destinationWeight.Destination.Host
    55  			if host == "" {
    56  				continue
    57  			}
    58  			subset := destinationWeight.Destination.Subset
    59  			if subset == "" {
    60  				continue
    61  			}
    62  			if !checker.subsetPresent(host, subset) {
    63  				path := fmt.Sprintf("spec/tcp[%d]/route[%d]/destination", routeIdx, destWeightIdx)
    64  				validation := models.Build("virtualservices.subsetpresent.subsetnotfound", path)
    65  				validations = append(validations, &validation)
    66  			}
    67  		}
    68  
    69  	}
    70  
    71  	for routeIdx, tlsRoute := range checker.VirtualService.Spec.Tls {
    72  		if tlsRoute == nil {
    73  			continue
    74  		}
    75  		for destWeightIdx, destinationWeight := range tlsRoute.Route {
    76  			if destinationWeight == nil && destinationWeight.Destination == nil {
    77  				continue
    78  			}
    79  			host := destinationWeight.Destination.Host
    80  			if host == "" {
    81  				continue
    82  			}
    83  			subset := destinationWeight.Destination.Subset
    84  			if subset == "" {
    85  				continue
    86  			}
    87  			if !checker.subsetPresent(host, subset) {
    88  				path := fmt.Sprintf("spec/tls[%d]/route[%d]/destination", routeIdx, destWeightIdx)
    89  				validation := models.Build("virtualservices.subsetpresent.subsetnotfound", path)
    90  				validations = append(validations, &validation)
    91  			}
    92  		}
    93  	}
    94  	return validations, valid
    95  }
    96  
    97  func (checker SubsetPresenceChecker) subsetPresent(host string, subset string) bool {
    98  	destinationRules, ok := checker.getDestinationRules(host)
    99  	if !ok || destinationRules == nil || len(destinationRules) == 0 {
   100  		return false
   101  	}
   102  
   103  	for _, dr := range destinationRules {
   104  		if hasSubsetDefined(dr, subset) {
   105  			return true
   106  		}
   107  	}
   108  	return false
   109  }
   110  
   111  func (checker SubsetPresenceChecker) getDestinationRules(virtualServiceHost string) ([]*networking_v1beta1.DestinationRule, bool) {
   112  	drs := make([]*networking_v1beta1.DestinationRule, 0, len(checker.DestinationRules))
   113  
   114  	for _, destinationRule := range checker.DestinationRules {
   115  		host := destinationRule.Spec.Host
   116  
   117  		drHost := kubernetes.GetHost(host, destinationRule.Namespace, checker.Namespaces)
   118  		vsHost := kubernetes.GetHost(virtualServiceHost, checker.VirtualService.Namespace, checker.Namespaces)
   119  
   120  		// TODO Host could be in another namespace (FQDN)
   121  		if kubernetes.FilterByHost(vsHost.String(), vsHost.Namespace, drHost.Service, drHost.Namespace) {
   122  			drs = append(drs, destinationRule)
   123  		}
   124  	}
   125  
   126  	return drs, len(drs) > 0
   127  }
   128  
   129  func hasSubsetDefined(destinationRule *networking_v1beta1.DestinationRule, subsetTarget string) bool {
   130  	for _, subset := range destinationRule.Spec.Subsets {
   131  		if subset == nil {
   132  			continue
   133  		}
   134  		if subset.Name == subsetTarget {
   135  			return true
   136  		}
   137  	}
   138  	return false
   139  }