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  }