istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/config/analysis/analyzers/virtualservice/gateways.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package virtualservice 16 17 import ( 18 "fmt" 19 "strings" 20 21 "istio.io/api/networking/v1alpha3" 22 "istio.io/istio/pkg/config" 23 "istio.io/istio/pkg/config/analysis" 24 "istio.io/istio/pkg/config/analysis/analyzers/util" 25 "istio.io/istio/pkg/config/analysis/msg" 26 kubeconfig "istio.io/istio/pkg/config/gateway/kube" 27 "istio.io/istio/pkg/config/host" 28 "istio.io/istio/pkg/config/resource" 29 "istio.io/istio/pkg/config/schema/gvk" 30 ) 31 32 // GatewayAnalyzer checks the gateways associated with each virtual service 33 type GatewayAnalyzer struct{} 34 35 var _ analysis.Analyzer = &GatewayAnalyzer{} 36 37 // Metadata implements Analyzer 38 func (s *GatewayAnalyzer) Metadata() analysis.Metadata { 39 return analysis.Metadata{ 40 Name: "virtualservice.GatewayAnalyzer", 41 Description: "Checks the gateways associated with each virtual service", 42 Inputs: []config.GroupVersionKind{ 43 gvk.Gateway, 44 gvk.VirtualService, 45 }, 46 } 47 } 48 49 // Analyze implements Analyzer 50 func (s *GatewayAnalyzer) Analyze(c analysis.Context) { 51 c.ForEach(gvk.VirtualService, func(r *resource.Instance) bool { 52 s.analyzeVirtualService(r, c) 53 return true 54 }) 55 } 56 57 func (s *GatewayAnalyzer) analyzeVirtualService(r *resource.Instance, c analysis.Context) { 58 vs := r.Message.(*v1alpha3.VirtualService) 59 vsNs := r.Metadata.FullName.Namespace 60 vsName := r.Metadata.FullName 61 62 for i, gwName := range vs.Gateways { 63 // This is a special-case accepted value 64 if gwName == util.MeshGateway { 65 continue 66 } 67 68 if kubeconfig.IsInternalGatewayReference(gwName) { 69 m := msg.NewReferencedInternalGateway(r, vsName.String(), gwName) 70 71 if line, ok := util.ErrorLine(r, fmt.Sprintf(util.VSGateway, i)); ok { 72 m.Line = line 73 } 74 75 c.Report(gvk.VirtualService, m) 76 continue 77 } 78 79 gwFullName := resource.NewShortOrFullName(vsNs, gwName) 80 81 if !c.Exists(gvk.Gateway, gwFullName) { 82 m := msg.NewReferencedResourceNotFound(r, "gateway", gwName) 83 84 if line, ok := util.ErrorLine(r, fmt.Sprintf(util.VSGateway, i)); ok { 85 m.Line = line 86 } 87 88 c.Report(gvk.VirtualService, m) 89 } 90 91 if !vsHostInGateway(c, gwFullName, vs.Hosts, vsNs.String()) { 92 m := msg.NewVirtualServiceHostNotFoundInGateway(r, vs.Hosts, vsName.String(), gwFullName.String()) 93 94 if line, ok := util.ErrorLine(r, fmt.Sprintf(util.VSGateway, i)); ok { 95 m.Line = line 96 } 97 98 c.Report(gvk.VirtualService, m) 99 } 100 } 101 } 102 103 func vsHostInGateway(c analysis.Context, gateway resource.FullName, vsHosts []string, vsNamespace string) bool { 104 var gatewayHosts []string 105 var gatewayNs string 106 107 c.ForEach(gvk.Gateway, func(r *resource.Instance) bool { 108 if r.Metadata.FullName == gateway { 109 s := r.Message.(*v1alpha3.Gateway) 110 gatewayNs = r.Metadata.FullName.Namespace.String() 111 for _, v := range s.Servers { 112 sanitizeServerHostNamespace(v, gatewayNs) 113 gatewayHosts = append(gatewayHosts, v.Hosts...) 114 } 115 } 116 117 return true 118 }) 119 120 gatewayHostNames := host.NamesForNamespace(gatewayHosts, vsNamespace) 121 for _, gh := range gatewayHostNames { 122 for _, vsh := range vsHosts { 123 gatewayHost := gh 124 vsHost := host.Name(vsh) 125 126 if gatewayHost.Matches(vsHost) { 127 return true 128 } 129 } 130 } 131 132 return false 133 } 134 135 // convert ./host to currentNamespace/Host 136 // */host to just host 137 // */* to just * 138 func sanitizeServerHostNamespace(server *v1alpha3.Server, namespace string) { 139 for i, h := range server.Hosts { 140 if strings.Contains(h, "/") { 141 parts := strings.Split(h, "/") 142 if parts[0] == "." { 143 server.Hosts[i] = fmt.Sprintf("%s/%s", namespace, parts[1]) 144 } else if parts[0] == "*" { 145 if parts[1] == "*" { 146 server.Hosts = []string{"*"} 147 return 148 } 149 server.Hosts[i] = parts[1] 150 } 151 } 152 } 153 }