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 }