github.com/polarismesh/polaris@v1.17.8/apiserver/xdsserverv3/generate.go (about) 1 /** 2 * Tencent is pleased to support the open source community by making Polaris available. 3 * 4 * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 5 * 6 * Licensed under the BSD 3-Clause License (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * https://opensource.org/licenses/BSD-3-Clause 11 * 12 * Unless required by applicable law or agreed to in writing, software distributed 13 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 14 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 15 * specific language governing permissions and limitations under the License. 16 */ 17 18 package xdsserverv3 19 20 import ( 21 "context" 22 "errors" 23 24 "github.com/envoyproxy/go-control-plane/pkg/cache/types" 25 cachev3 "github.com/envoyproxy/go-control-plane/pkg/cache/v3" 26 resourcev3 "github.com/envoyproxy/go-control-plane/pkg/resource/v3" 27 "go.uber.org/atomic" 28 "go.uber.org/zap" 29 30 "github.com/polarismesh/polaris/apiserver/xdsserverv3/resource" 31 "github.com/polarismesh/polaris/common/model" 32 "github.com/polarismesh/polaris/service" 33 ) 34 35 // XdsResourceGenerator is the xDS resource generator 36 type XdsResourceGenerator struct { 37 namingServer service.DiscoverServer 38 cache cachev3.SnapshotCache 39 versionNum *atomic.Uint64 40 xdsNodesMgr *resource.XDSNodeManager 41 } 42 43 func (x *XdsResourceGenerator) Generate(versionLocal string, 44 registryInfo map[string]map[model.ServiceKey]*resource.ServiceInfo) { 45 46 _ = x.buildSidecarXDSCache(versionLocal, registryInfo) 47 _ = x.buildGatewayXDSCache(versionLocal, registryInfo) 48 } 49 50 func (x *XdsResourceGenerator) buildSidecarXDSCache(versionLocal string, 51 registryInfo map[string]map[model.ServiceKey]*resource.ServiceInfo) error { 52 53 nodes := x.xdsNodesMgr.ListSidecarNodes() 54 if len(nodes) == 0 || len(registryInfo) == 0 { 55 // 如果没有任何一个 XDS Sidecar Node 客户端,不做任何操作 56 log.Info("[XDS][Sidecar][V2] xds nodes or registryInfo is empty", zap.Int("nodes", len(nodes)), 57 zap.Int("register", len(registryInfo))) 58 return nil 59 } 60 61 alreadyMakeCache := map[string]struct{}{} 62 for i := range nodes { 63 node := nodes[i] 64 if node.IsGateway() { 65 log.Error("[XDS][Sidecar][V2] run type not sidecar or info is invalid", 66 zap.String("node", node.Node.Id)) 67 continue 68 } 69 70 cacheKey := (resource.PolarisNodeHash{}).ID(node.Node) 71 if _, exist := alreadyMakeCache[cacheKey]; exist { 72 continue 73 } 74 alreadyMakeCache[cacheKey] = struct{}{} 75 76 selfNamespace := node.GetSelfNamespace() 77 services := registryInfo[selfNamespace] 78 if len(services) == 0 { 79 log.Info("[XDS][Sidecar][V2] service is empty, maybe not update", 80 zap.String("namespace", selfNamespace), zap.String("cacheKey", cacheKey)) 81 continue 82 } 83 if err := x.makeSidecarSnapshot(cacheKey, node, node.TLSMode, versionLocal, services); err != nil { 84 log.Error("[XDS][Sidecar][V2] make snapshot fail", zap.String("cacheKey", cacheKey), 85 zap.Error(err)) 86 } 87 } 88 return nil 89 } 90 91 // buildGatewayXDSCache 网关场景是允许跨命名空间直接进行访问 92 func (x *XdsResourceGenerator) buildGatewayXDSCache(versionLocal string, 93 registryInfo map[string]map[model.ServiceKey]*resource.ServiceInfo) error { 94 95 nodes := x.xdsNodesMgr.ListGatewayNodes() 96 if len(nodes) == 0 || len(registryInfo) == 0 { 97 // 如果没有任何一个 XDS Gateway Node 客户端,不做任何操作 98 log.Info("[XDS][Gateway][V2] xds nodes or registryInfo is empty", zap.Int("nodes", len(nodes)), 99 zap.Int("registr", len(registryInfo))) 100 return nil 101 } 102 103 alreadyMakeCache := map[string]struct{}{} 104 for i := range nodes { 105 node := nodes[i] 106 if !node.IsGateway() { 107 log.Error("[XDS][Gateway][V2] run type not gateway or info is invalid", 108 zap.String("node", node.Node.Id)) 109 continue 110 } 111 112 cacheKey := (resource.PolarisNodeHash{}).ID(node.Node) 113 if _, exist := alreadyMakeCache[cacheKey]; exist { 114 continue 115 } 116 alreadyMakeCache[cacheKey] = struct{}{} 117 if err := x.makeGatewaySnapshot(node, node.TLSMode, versionLocal, registryInfo); err != nil { 118 log.Error("[XDS][Gateway][V2] make snapshot fail", zap.String("cacheKey", cacheKey), 119 zap.Error(err)) 120 } 121 } 122 return nil 123 } 124 125 // makeSidecarSnapshot nodeId must be like sideacr~namespace or namespace 126 func (x *XdsResourceGenerator) makeSidecarSnapshot(cacheKey string, xdsNode *resource.XDSClient, 127 tlsMode resource.TLSMode, version string, services map[model.ServiceKey]*resource.ServiceInfo) error { 128 129 // 构建所有 XDS 的 Snapshot Resource 130 opt := &resource.BuildOption{ 131 Services: services, 132 TLSMode: tlsMode, 133 VersionLocal: version, 134 Namespace: xdsNode.GetSelfNamespace(), 135 } 136 // 构建 endpoints XDS 资源缓存数据 137 boundEndpoints, err := x.generateXDSResource(resource.EDS, xdsNode, opt) 138 if err != nil { 139 return err 140 } 141 // 构建 cluster XDS 资源缓存数据 142 boundClusters, err := x.generateXDSResource(resource.CDS, xdsNode, opt) 143 if err != nil { 144 return err 145 } 146 // 构建 route XDS 资源缓存 147 boundRouters, err := x.generateXDSResource(resource.RDS, xdsNode, opt) 148 if err != nil { 149 return err 150 } 151 // 构建 listener XDS 资源缓存 152 boundListeners, err := x.generateXDSResource(resource.LDS, xdsNode, opt) 153 if err != nil { 154 return err 155 } 156 157 resources := make(map[resourcev3.Type][]types.Resource) 158 resources[resourcev3.EndpointType] = boundEndpoints 159 resources[resourcev3.ClusterType] = boundClusters 160 resources[resourcev3.RouteType] = boundRouters 161 resources[resourcev3.ListenerType] = boundListeners 162 163 snapshot, err := cachev3.NewSnapshot(version, resources) 164 if err != nil { 165 log.Error("[XDS][Sidecar][V2] fail to create snapshot", zap.Any("envoy-node", xdsNode.Node.Id), 166 zap.String("cacheKey", cacheKey), zap.Error(err)) 167 return err 168 } 169 if err := snapshot.Consistent(); err != nil { 170 log.Error("[XDS][Sidecar][V2] verify snapshot consistent", zap.Any("envoy-node", xdsNode.Node.Id), 171 zap.String("cacheKey", cacheKey), zap.Any("snapshot", string(resource.DumpSnapShotJSON(snapshot))), 172 zap.Error(err)) 173 return err 174 } 175 176 // 为每个 nodeId 刷写 cache ,推送 xds 更新 177 if err := x.cache.SetSnapshot(context.Background(), cacheKey, snapshot); err != nil { 178 log.Error("[XDS][Sidecar][V2] upsert snapshot error", zap.Any("envoy-node", xdsNode.Node.Id), 179 zap.String("cacheKey", cacheKey), zap.Error(err)) 180 return err 181 } 182 log.Info("[XDS][Sidecar][V2] upsert snapshot success", zap.Any("envoy-node", xdsNode.Node.Id), 183 zap.String("cacheKey", cacheKey), zap.String("snapshot", string(resource.DumpSnapShotJSON(snapshot)))) 184 return nil 185 } 186 187 // makeGatewaySnapshot nodeId must be like gateway~namespace 188 func (x *XdsResourceGenerator) makeGatewaySnapshot(xdsNode *resource.XDSClient, tlsMode resource.TLSMode, 189 version string, registryInfo map[string]map[model.ServiceKey]*resource.ServiceInfo) error { 190 191 nodeId := xdsNode.Node.Id 192 193 opt := &resource.BuildOption{ 194 TLSMode: tlsMode, 195 VersionLocal: version, 196 } 197 var ( 198 allEndpoints []types.Resource 199 allClusters []types.Resource 200 allRouters []types.Resource 201 ) 202 for namespace, services := range registryInfo { 203 opt.Services = services 204 opt.Namespace = namespace 205 // 构建 endpoints XDS 资源缓存数据,这里不需要下发网关的自己的 206 endpoints, err := x.generateXDSResource(resource.EDS, xdsNode, opt) 207 if err != nil { 208 return err 209 } 210 allEndpoints = append(allEndpoints, endpoints...) 211 // 构建 cluster XDS 资源缓存数据 212 clusters, err := x.generateXDSResource(resource.CDS, xdsNode, opt) 213 if err != nil { 214 return err 215 } 216 allClusters = append(allClusters, clusters...) 217 // 构建 route XDS 资源缓存 218 routers, err := x.generateXDSResource(resource.RDS, xdsNode, opt) 219 if err != nil { 220 return err 221 } 222 allRouters = append(allRouters, routers...) 223 } 224 225 // 构建 listener XDS 资源缓存 226 listeners, err := x.generateXDSResource(resource.LDS, xdsNode, opt) 227 if err != nil { 228 return err 229 } 230 231 resources := make(map[resourcev3.Type][]types.Resource) 232 resources[resourcev3.EndpointType] = allEndpoints 233 resources[resourcev3.ClusterType] = allClusters 234 resources[resourcev3.RouteType] = allRouters 235 resources[resourcev3.ListenerType] = listeners 236 snapshot, err := cachev3.NewSnapshot(version, resources) 237 if err != nil { 238 log.Errorf("[XDS][Gateway][V2] fail to create snapshot for %s, err is %v", nodeId, err) 239 return err 240 } 241 if err := snapshot.Consistent(); err != nil { 242 return err 243 } 244 245 cacheKey := (resource.PolarisNodeHash{}).ID(xdsNode.Node) 246 // 为每个 nodeId 刷写 cache ,推送 xds 更新 247 if err := x.cache.SetSnapshot(context.Background(), cacheKey, snapshot); err != nil { 248 log.Error("[XDS][Gateway][V2] upsert snapshot error", 249 zap.String("cacheKey", cacheKey), zap.Error(err)) 250 return err 251 } 252 log.Info("[XDS][Gateway][V2] upsert snapshot success", zap.String("cacheKey", cacheKey), 253 zap.String("snapshot", string(resource.DumpSnapShotJSON(snapshot)))) 254 return nil 255 } 256 257 func (x *XdsResourceGenerator) generateXDSResource(xdsType resource.XDSType, xdsNode *resource.XDSClient, 258 opt *resource.BuildOption) ([]types.Resource, error) { 259 260 var xdsBuilder resource.XDSBuilder 261 switch xdsType { 262 case resource.CDS: 263 xdsBuilder = &CDSBuilder{} 264 case resource.EDS: 265 xdsBuilder = &EDSBuilder{} 266 case resource.LDS: 267 xdsBuilder = &LDSBuilder{} 268 case resource.RDS: 269 xdsBuilder = &RDSBuilder{} 270 default: 271 return nil, errors.New("unsupport xds build type") 272 } 273 274 // 构建 XDS 资源缓存数据 275 xdsBuilder.Init(xdsNode, x.namingServer) 276 resources, err := xdsBuilder.Generate(opt) 277 if err != nil { 278 return nil, err 279 } 280 return resources.([]types.Resource), nil 281 }