github.com/polarismesh/polaris@v1.17.8/apiserver/xdsserverv3/resource/help.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 resource
    19  
    20  import (
    21  	"encoding/hex"
    22  	"fmt"
    23  	"math"
    24  	"strconv"
    25  	"strings"
    26  	"time"
    27  
    28  	accesslog "github.com/envoyproxy/go-control-plane/envoy/config/accesslog/v3"
    29  	cluster "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
    30  	core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
    31  	corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
    32  	listenerv3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
    33  	ratelimitconfv3 "github.com/envoyproxy/go-control-plane/envoy/config/ratelimit/v3"
    34  	route "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
    35  	filev3 "github.com/envoyproxy/go-control-plane/envoy/extensions/access_loggers/file/v3"
    36  	envoy_extensions_common_ratelimit_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/common/ratelimit/v3"
    37  	ratelimitv32 "github.com/envoyproxy/go-control-plane/envoy/extensions/common/ratelimit/v3"
    38  	lrl "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/local_ratelimit/v3"
    39  	ratelimitfilter "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/ratelimit/v3"
    40  	routerv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/router/v3"
    41  	hcm "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
    42  	tcp "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/tcp_proxy/v3"
    43  	v32 "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3"
    44  	envoy_type_v3 "github.com/envoyproxy/go-control-plane/envoy/type/v3"
    45  	typev3 "github.com/envoyproxy/go-control-plane/envoy/type/v3"
    46  	resourcev3 "github.com/envoyproxy/go-control-plane/pkg/resource/v3"
    47  	"github.com/envoyproxy/go-control-plane/pkg/wellknown"
    48  	"github.com/golang/protobuf/ptypes"
    49  	_struct "github.com/golang/protobuf/ptypes/struct"
    50  	"github.com/golang/protobuf/ptypes/wrappers"
    51  	apifault "github.com/polarismesh/specification/source/go/api/v1/fault_tolerance"
    52  	apimodel "github.com/polarismesh/specification/source/go/api/v1/model"
    53  	apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage"
    54  	"github.com/polarismesh/specification/source/go/api/v1/traffic_manage"
    55  	apitraffic "github.com/polarismesh/specification/source/go/api/v1/traffic_manage"
    56  	"google.golang.org/protobuf/proto"
    57  	"google.golang.org/protobuf/types/known/anypb"
    58  	"google.golang.org/protobuf/types/known/durationpb"
    59  	"google.golang.org/protobuf/types/known/wrapperspb"
    60  
    61  	types "github.com/polarismesh/polaris/cache/api"
    62  	"github.com/polarismesh/polaris/common/model"
    63  	"github.com/polarismesh/polaris/common/utils"
    64  )
    65  
    66  const (
    67  	PassthroughClusterName  = "PassthroughCluster"
    68  	RouteConfigName         = "polaris-router"
    69  	OutBoundRouteConfigName = "polaris-outbound-router"
    70  	InBoundRouteConfigName  = "polaris-inbound-cluster"
    71  )
    72  
    73  const (
    74  	// LocalRateLimitStage envoy local ratelimit stage
    75  	LocalRateLimitStage = 0
    76  	// DistributedRateLimitStage envoy remote ratelimit stage
    77  	DistributedRateLimitStage = 1
    78  )
    79  
    80  var (
    81  	TrafficBoundRoute = map[corev3.TrafficDirection]string{
    82  		corev3.TrafficDirection_INBOUND:  InBoundRouteConfigName,
    83  		corev3.TrafficDirection_OUTBOUND: OutBoundRouteConfigName,
    84  	}
    85  )
    86  
    87  func MakeServiceGatewayDomains() []string {
    88  	return []string{"*"}
    89  }
    90  
    91  func FilterInboundRouterRule(svc *ServiceInfo) []*traffic_manage.SubRuleRouting {
    92  	ret := make([]*traffic_manage.SubRuleRouting, 0, 16)
    93  	for _, rule := range svc.Routing.GetRules() {
    94  		if rule.GetRoutingPolicy() != traffic_manage.RoutingPolicy_RulePolicy {
    95  			continue
    96  		}
    97  		routerRule := &traffic_manage.RuleRoutingConfig{}
    98  		if err := ptypes.UnmarshalAny(rule.RoutingConfig, routerRule); err != nil {
    99  			continue
   100  		}
   101  
   102  		for i, subRule := range routerRule.Rules {
   103  			var match bool
   104  			for _, dest := range subRule.GetDestinations() {
   105  				if svc.MatchService(dest.GetNamespace(), dest.GetService()) {
   106  					match = true
   107  					break
   108  				}
   109  			}
   110  			if match {
   111  				ret = append(ret, routerRule.Rules[i])
   112  			}
   113  		}
   114  	}
   115  	return ret
   116  }
   117  
   118  func BuildSidecarRouteMatch(routeMatch *route.RouteMatch, source *traffic_manage.SourceService) {
   119  	for i := range source.GetArguments() {
   120  		argument := source.GetArguments()[i]
   121  		if argument.Type == traffic_manage.SourceMatch_PATH {
   122  			if argument.Value.Type == apimodel.MatchString_EXACT {
   123  				routeMatch.PathSpecifier = &route.RouteMatch_Path{
   124  					Path: argument.GetValue().GetValue().GetValue()}
   125  			} else if argument.Value.Type == apimodel.MatchString_REGEX {
   126  				routeMatch.PathSpecifier = &route.RouteMatch_SafeRegex{SafeRegex: &v32.RegexMatcher{
   127  					Regex: argument.GetValue().GetValue().GetValue()}}
   128  			}
   129  		}
   130  	}
   131  	BuildCommonRouteMatch(routeMatch, source)
   132  }
   133  
   134  func BuildCommonRouteMatch(routeMatch *route.RouteMatch, source *traffic_manage.SourceService) {
   135  	for i := range source.GetArguments() {
   136  		argument := source.GetArguments()[i]
   137  		switch argument.Type {
   138  		case traffic_manage.SourceMatch_HEADER:
   139  			headerSubName := argument.Key
   140  			var headerMatch *route.HeaderMatcher
   141  			if argument.Value.Type == apimodel.MatchString_EXACT {
   142  				headerMatch = &route.HeaderMatcher{
   143  					Name: headerSubName,
   144  					HeaderMatchSpecifier: &route.HeaderMatcher_StringMatch{
   145  						StringMatch: &v32.StringMatcher{
   146  							MatchPattern: &v32.StringMatcher_Exact{
   147  								Exact: argument.GetValue().GetValue().GetValue()}},
   148  					},
   149  				}
   150  			}
   151  			if argument.Value.Type == apimodel.MatchString_NOT_EQUALS {
   152  				headerMatch = &route.HeaderMatcher{
   153  					Name: headerSubName,
   154  					HeaderMatchSpecifier: &route.HeaderMatcher_StringMatch{
   155  						StringMatch: &v32.StringMatcher{
   156  							MatchPattern: &v32.StringMatcher_Exact{
   157  								Exact: argument.GetValue().GetValue().GetValue()}},
   158  					},
   159  					InvertMatch: true,
   160  				}
   161  			}
   162  			if argument.Value.Type == apimodel.MatchString_REGEX {
   163  				headerMatch = &route.HeaderMatcher{
   164  					Name: headerSubName,
   165  					HeaderMatchSpecifier: &route.HeaderMatcher_StringMatch{
   166  						StringMatch: &v32.StringMatcher{MatchPattern: &v32.StringMatcher_SafeRegex{
   167  							SafeRegex: &v32.RegexMatcher{
   168  								EngineType: &v32.RegexMatcher_GoogleRe2{
   169  									GoogleRe2: &v32.RegexMatcher_GoogleRE2{}},
   170  								Regex: argument.GetValue().GetValue().GetValue()}}},
   171  					},
   172  				}
   173  			}
   174  			if headerMatch != nil {
   175  				routeMatch.Headers = append(routeMatch.Headers, headerMatch)
   176  			}
   177  		case traffic_manage.SourceMatch_QUERY:
   178  			querySubName := argument.Key
   179  			var queryMatcher *route.QueryParameterMatcher
   180  			if argument.Value.Type == apimodel.MatchString_EXACT {
   181  				queryMatcher = &route.QueryParameterMatcher{
   182  					Name: querySubName,
   183  					QueryParameterMatchSpecifier: &route.QueryParameterMatcher_StringMatch{
   184  						StringMatch: &v32.StringMatcher{
   185  							MatchPattern: &v32.StringMatcher_Exact{
   186  								Exact: argument.GetValue().GetValue().GetValue()}},
   187  					},
   188  				}
   189  			}
   190  			if argument.Value.Type == apimodel.MatchString_REGEX {
   191  				queryMatcher = &route.QueryParameterMatcher{
   192  					Name: querySubName,
   193  					QueryParameterMatchSpecifier: &route.QueryParameterMatcher_StringMatch{
   194  						StringMatch: &v32.StringMatcher{
   195  							MatchPattern: &v32.StringMatcher_SafeRegex{SafeRegex: &v32.RegexMatcher{
   196  								EngineType: &v32.RegexMatcher_GoogleRe2{
   197  									GoogleRe2: &v32.RegexMatcher_GoogleRE2{}},
   198  								Regex: argument.GetValue().GetValue().GetValue(),
   199  							}}},
   200  					},
   201  				}
   202  			}
   203  			if queryMatcher != nil {
   204  				routeMatch.QueryParameters = append(routeMatch.QueryParameters, queryMatcher)
   205  			}
   206  		}
   207  	}
   208  }
   209  
   210  func BuildWeightClustersV2(trafficDirection corev3.TrafficDirection,
   211  	destinations []*traffic_manage.DestinationGroup) *route.WeightedCluster {
   212  	var (
   213  		weightedClusters []*route.WeightedCluster_ClusterWeight
   214  		totalWeight      uint32
   215  	)
   216  
   217  	// 使用 destinations 生成 weightedClusters。makeClusters() 也使用这个字段生成对应的 subset
   218  	for _, destination := range destinations {
   219  		if destination.GetWeight() == 0 {
   220  			continue
   221  		}
   222  		fields := make(map[string]*_struct.Value)
   223  		for k, v := range destination.GetLabels() {
   224  			if k == utils.MatchAll && v.GetValue().GetValue() == utils.MatchAll {
   225  				// 重置 cluster 的匹配规则
   226  				fields = make(map[string]*_struct.Value)
   227  				break
   228  			}
   229  			fields[k] = &_struct.Value{
   230  				Kind: &_struct.Value_StringValue{
   231  					StringValue: v.Value.Value,
   232  				},
   233  			}
   234  		}
   235  		weightCluster := &route.WeightedCluster_ClusterWeight{
   236  			Name: MakeServiceName(model.ServiceKey{
   237  				Namespace: destination.Namespace,
   238  				Name:      destination.Service,
   239  			}, trafficDirection),
   240  			Weight: utils.NewUInt32Value(destination.GetWeight()),
   241  			MetadataMatch: &core.Metadata{
   242  				FilterMetadata: map[string]*_struct.Struct{
   243  					"envoy.lb": {
   244  						Fields: fields,
   245  					},
   246  				},
   247  			},
   248  		}
   249  		if len(fields) == 0 {
   250  			weightCluster.MetadataMatch = nil
   251  		}
   252  		weightedClusters = append(weightedClusters, weightCluster)
   253  		totalWeight += destination.Weight
   254  	}
   255  
   256  	return &route.WeightedCluster{
   257  		TotalWeight: &wrappers.UInt32Value{Value: totalWeight},
   258  		Clusters:    weightedClusters,
   259  	}
   260  }
   261  
   262  func BuildRateLimitConf(prefix string) *lrl.LocalRateLimit {
   263  	rateLimitConf := &lrl.LocalRateLimit{
   264  		StatPrefix: prefix,
   265  		// 默认全局限流没限制,由于 envoy 这里必须设置一个 TokenBucket,因此这里只能设置一个认为不可能达到的一个 TPS 进行实现不限流
   266  		// TPS = 4294967295/s
   267  		TokenBucket: &typev3.TokenBucket{
   268  			MaxTokens:     math.MaxUint32,
   269  			TokensPerFill: wrapperspb.UInt32(math.MaxUint32),
   270  			FillInterval:  durationpb.New(time.Second),
   271  		},
   272  		FilterEnabled: &core.RuntimeFractionalPercent{
   273  			RuntimeKey: prefix + "_local_rate_limit_enabled",
   274  			DefaultValue: &envoy_type_v3.FractionalPercent{
   275  				Numerator:   uint32(100),
   276  				Denominator: envoy_type_v3.FractionalPercent_HUNDRED,
   277  			},
   278  		},
   279  		FilterEnforced: &core.RuntimeFractionalPercent{
   280  			RuntimeKey: prefix + "_local_rate_limit_enforced",
   281  			DefaultValue: &envoy_type_v3.FractionalPercent{
   282  				Numerator:   uint32(100),
   283  				Denominator: envoy_type_v3.FractionalPercent_HUNDRED,
   284  			},
   285  		},
   286  		ResponseHeadersToAdd: []*core.HeaderValueOption{
   287  			{
   288  				Header: &core.HeaderValue{
   289  					Key:   "x-local-rate-limit",
   290  					Value: "true",
   291  				},
   292  				Append: wrapperspb.Bool(false),
   293  			},
   294  		},
   295  		// the token bucket must shared across all worker threads
   296  		LocalRateLimitPerDownstreamConnection: false,
   297  	}
   298  	return rateLimitConf
   299  }
   300  
   301  func BuildRateLimitDescriptors(rule *traffic_manage.Rule) ([]*route.RateLimit_Action,
   302  	[]*ratelimitv32.LocalRateLimitDescriptor) {
   303  	actions := make([]*route.RateLimit_Action, 0, 8)
   304  	descriptors := make([]*ratelimitv32.LocalRateLimitDescriptor, 0, 8)
   305  
   306  	entries := make([]*envoy_extensions_common_ratelimit_v3.RateLimitDescriptor_Entry, 0, len(rule.Labels))
   307  
   308  	methodMatchType := rule.GetMethod().GetType()
   309  	methodName := rule.GetMethod().GetValue().GetValue()
   310  	if methodName == "" {
   311  		methodName = "/"
   312  		methodMatchType = MatchString_Prefix
   313  	}
   314  	actions = append(actions, &route.RateLimit_Action{
   315  		ActionSpecifier: &route.RateLimit_Action_HeaderValueMatch_{
   316  			HeaderValueMatch: BuildRateLimitActionHeaderValueMatch(":path", &apitraffic.MatchArgument{
   317  				Key: ":path",
   318  				Value: &apimodel.MatchString{
   319  					Type:      methodMatchType,
   320  					Value:     wrapperspb.String(methodName),
   321  					ValueType: apimodel.MatchString_TEXT,
   322  				},
   323  			}),
   324  		},
   325  	})
   326  	entries = append(entries, &ratelimitv32.RateLimitDescriptor_Entry{
   327  		Key:   ":path",
   328  		Value: methodName,
   329  	})
   330  	arguments := rule.GetArguments()
   331  
   332  	for i := range arguments {
   333  		arg := arguments[i]
   334  		descriptorKey := strings.ToLower(arg.GetType().String()) + "." + arg.Key
   335  		switch arg.Type {
   336  		case apitraffic.MatchArgument_HEADER:
   337  			headerValueMatch := BuildRateLimitActionHeaderValueMatch(descriptorKey, arg)
   338  			actions = append(actions, &route.RateLimit_Action{
   339  				ActionSpecifier: &route.RateLimit_Action_HeaderValueMatch_{
   340  					HeaderValueMatch: headerValueMatch,
   341  				},
   342  			})
   343  			entries = append(entries, &ratelimitv32.RateLimitDescriptor_Entry{
   344  				Key:   descriptorKey,
   345  				Value: arg.GetValue().GetValue().GetValue(),
   346  			})
   347  		case apitraffic.MatchArgument_QUERY:
   348  			queryParameterValueMatch := BuildRateLimitActionQueryParameterValueMatch(descriptorKey, arg.Value)
   349  			actions = append(actions, &route.RateLimit_Action{
   350  				ActionSpecifier: &route.RateLimit_Action_QueryParameterValueMatch_{
   351  					QueryParameterValueMatch: queryParameterValueMatch,
   352  				},
   353  			})
   354  			entries = append(entries, &ratelimitv32.RateLimitDescriptor_Entry{
   355  				Key:   descriptorKey,
   356  				Value: arg.GetValue().GetValue().GetValue(),
   357  			})
   358  		case apitraffic.MatchArgument_METHOD:
   359  			actions = append(actions, &route.RateLimit_Action{
   360  				ActionSpecifier: &route.RateLimit_Action_RequestHeaders_{
   361  					RequestHeaders: &route.RateLimit_Action_RequestHeaders{
   362  						HeaderName:    ":method",
   363  						DescriptorKey: descriptorKey,
   364  					},
   365  				},
   366  			})
   367  			entries = append(entries, &envoy_extensions_common_ratelimit_v3.RateLimitDescriptor_Entry{
   368  				Key:   descriptorKey,
   369  				Value: arg.GetValue().GetValue().GetValue(),
   370  			})
   371  		case apitraffic.MatchArgument_CALLER_IP:
   372  			actions = append(actions, &route.RateLimit_Action{
   373  				ActionSpecifier: &route.RateLimit_Action_RemoteAddress_{
   374  					RemoteAddress: &route.RateLimit_Action_RemoteAddress{},
   375  				},
   376  			})
   377  		}
   378  	}
   379  
   380  	for _, amount := range rule.Amounts {
   381  		descriptor := &envoy_extensions_common_ratelimit_v3.LocalRateLimitDescriptor{
   382  			TokenBucket: &envoy_type_v3.TokenBucket{
   383  				MaxTokens:     amount.GetMaxAmount().GetValue(),
   384  				TokensPerFill: wrapperspb.UInt32(amount.GetMaxAmount().GetValue()),
   385  				FillInterval:  amount.GetValidDuration(),
   386  			},
   387  		}
   388  		descriptor.Entries = entries
   389  		descriptors = append(descriptors, descriptor)
   390  	}
   391  	return actions, descriptors
   392  }
   393  
   394  func BuildRateLimitActionQueryParameterValueMatch(key string,
   395  	value *apimodel.MatchString) *route.RateLimit_Action_QueryParameterValueMatch {
   396  	queryParameterValueMatch := &route.RateLimit_Action_QueryParameterValueMatch{
   397  		DescriptorKey:   key,
   398  		DescriptorValue: value.GetValue().GetValue(),
   399  		ExpectMatch:     wrapperspb.Bool(true),
   400  		QueryParameters: []*route.QueryParameterMatcher{},
   401  	}
   402  	switch value.GetType() {
   403  	case apimodel.MatchString_EXACT:
   404  		queryParameterValueMatch.QueryParameters = []*route.QueryParameterMatcher{
   405  			{
   406  				Name: key,
   407  				QueryParameterMatchSpecifier: &route.QueryParameterMatcher_StringMatch{
   408  					StringMatch: &v32.StringMatcher{
   409  						MatchPattern: &v32.StringMatcher_Exact{
   410  							Exact: value.GetValue().GetValue(),
   411  						},
   412  					},
   413  				},
   414  			},
   415  		}
   416  	case apimodel.MatchString_REGEX:
   417  		queryParameterValueMatch.QueryParameters = []*route.QueryParameterMatcher{
   418  			{
   419  				Name: key,
   420  				QueryParameterMatchSpecifier: &route.QueryParameterMatcher_StringMatch{
   421  					StringMatch: &v32.StringMatcher{
   422  						MatchPattern: &v32.StringMatcher_SafeRegex{
   423  							SafeRegex: &v32.RegexMatcher{
   424  								EngineType: &v32.RegexMatcher_GoogleRe2{},
   425  								Regex:      value.GetValue().GetValue(),
   426  							},
   427  						},
   428  					},
   429  				},
   430  			},
   431  		}
   432  	}
   433  
   434  	return queryParameterValueMatch
   435  }
   436  
   437  func BuildRateLimitActionHeaderValueMatch(key string, argument *apitraffic.MatchArgument) *route.RateLimit_Action_HeaderValueMatch {
   438  	headerValueMatch := &route.RateLimit_Action_HeaderValueMatch{
   439  		DescriptorKey:   key,
   440  		DescriptorValue: argument.GetValue().GetValue().GetValue(),
   441  		Headers:         []*route.HeaderMatcher{},
   442  	}
   443  	switch argument.GetValue().GetType() {
   444  	case apimodel.MatchString_EXACT, apimodel.MatchString_NOT_EQUALS:
   445  		headerValueMatch.Headers = []*route.HeaderMatcher{
   446  			{
   447  				Name:        argument.GetKey(),
   448  				InvertMatch: argument.GetValue().GetType() == apimodel.MatchString_NOT_EQUALS,
   449  				HeaderMatchSpecifier: &route.HeaderMatcher_StringMatch{
   450  					StringMatch: &v32.StringMatcher{
   451  						MatchPattern: &v32.StringMatcher_Exact{
   452  							Exact: argument.GetValue().GetValue().GetValue(),
   453  						},
   454  					},
   455  				},
   456  			},
   457  		}
   458  	case apimodel.MatchString_REGEX:
   459  		headerValueMatch.Headers = []*route.HeaderMatcher{
   460  			{
   461  				Name: argument.GetKey(),
   462  				HeaderMatchSpecifier: &route.HeaderMatcher_SafeRegexMatch{
   463  					SafeRegexMatch: &v32.RegexMatcher{
   464  						EngineType: &v32.RegexMatcher_GoogleRe2{},
   465  						Regex:      argument.GetValue().GetValue().GetValue(),
   466  					},
   467  				},
   468  			},
   469  		}
   470  	case MatchString_Prefix:
   471  		// 专门用于 prefix
   472  		headerValueMatch.Headers = []*route.HeaderMatcher{
   473  			{
   474  				Name: argument.GetKey(),
   475  				HeaderMatchSpecifier: &route.HeaderMatcher_StringMatch{
   476  					StringMatch: &v32.StringMatcher{
   477  						MatchPattern: &v32.StringMatcher_Prefix{
   478  							Prefix: argument.GetValue().GetValue().GetValue(),
   479  						},
   480  					},
   481  				},
   482  			},
   483  		}
   484  	}
   485  	return headerValueMatch
   486  }
   487  
   488  // 默认路由
   489  func MakeDefaultRoute(trafficDirection corev3.TrafficDirection, svcKey model.ServiceKey) *route.Route {
   490  	return &route.Route{
   491  		Match: &route.RouteMatch{
   492  			PathSpecifier: &route.RouteMatch_Prefix{
   493  				Prefix: "/",
   494  			},
   495  		},
   496  		Action: &route.Route_Route{
   497  			Route: &route.RouteAction{
   498  				ClusterSpecifier: &route.RouteAction_Cluster{
   499  					Cluster: MakeServiceName(svcKey, trafficDirection),
   500  				},
   501  			},
   502  		},
   503  	}
   504  }
   505  
   506  func GenerateServiceDomains(serviceInfo *ServiceInfo) []string {
   507  	// k8s dns 可解析的服务名
   508  	domain := serviceInfo.Name + "." + serviceInfo.Namespace
   509  	domains := []string{serviceInfo.Name, domain,
   510  		domain + K8sDnsResolveSuffixSvc,
   511  		domain + K8sDnsResolveSuffixSvcCluster,
   512  		domain + K8sDnsResolveSuffixSvcClusterLocal}
   513  
   514  	resDomains := domains
   515  	// 上面各种服务名加服务端口
   516  	ports := serviceInfo.Ports
   517  	for _, port := range ports {
   518  		// 如果是数字,则为每个域名产生一个带端口的域名
   519  		for _, s := range domains {
   520  			resDomains = append(resDomains, s+":"+strconv.FormatUint(uint64(port.Port), 10))
   521  		}
   522  	}
   523  	return resDomains
   524  }
   525  
   526  func BuildAllowAnyVHost() *route.VirtualHost {
   527  	return &route.VirtualHost{
   528  		Name:    "allow_any",
   529  		Domains: []string{"*"},
   530  		Routes: []*route.Route{
   531  			{
   532  				Match: &route.RouteMatch{
   533  					PathSpecifier: &route.RouteMatch_Prefix{
   534  						Prefix: "/",
   535  					},
   536  				},
   537  				Action: &route.Route_Route{
   538  					Route: &route.RouteAction{
   539  						ClusterSpecifier: &route.RouteAction_Cluster{
   540  							Cluster: PassthroughClusterName,
   541  						},
   542  					},
   543  				},
   544  			},
   545  		},
   546  	}
   547  }
   548  
   549  func MakeGatewayRoute(trafficDirection corev3.TrafficDirection, routeMatch *route.RouteMatch,
   550  	destinations []*traffic_manage.DestinationGroup) *route.Route {
   551  	sidecarRoute := &route.Route{
   552  		Match: routeMatch,
   553  		Action: &route.Route_Route{
   554  			Route: &route.RouteAction{
   555  				ClusterSpecifier: &route.RouteAction_WeightedClusters{
   556  					WeightedClusters: BuildWeightClustersV2(trafficDirection, destinations),
   557  				},
   558  			},
   559  		},
   560  	}
   561  	return sidecarRoute
   562  }
   563  
   564  func MakeSidecarRoute(trafficDirection corev3.TrafficDirection, routeMatch *route.RouteMatch,
   565  	svcInfo *ServiceInfo, destinations []*traffic_manage.DestinationGroup) *route.Route {
   566  	weightClusters := BuildWeightClustersV2(trafficDirection, destinations)
   567  	for i := range weightClusters.Clusters {
   568  		weightClusters.Clusters[i].Name = MakeServiceName(svcInfo.ServiceKey, trafficDirection)
   569  	}
   570  	currentRoute := &route.Route{
   571  		Match: routeMatch,
   572  		Action: &route.Route_Route{
   573  			Route: &route.RouteAction{
   574  				ClusterSpecifier: &route.RouteAction_WeightedClusters{
   575  					WeightedClusters: weightClusters,
   576  				},
   577  			},
   578  		},
   579  	}
   580  	return currentRoute
   581  }
   582  
   583  var PassthroughCluster = &cluster.Cluster{
   584  	Name:                 PassthroughClusterName,
   585  	ConnectTimeout:       durationpb.New(5 * time.Second),
   586  	ClusterDiscoveryType: &cluster.Cluster_Type{Type: cluster.Cluster_ORIGINAL_DST},
   587  	LbPolicy:             cluster.Cluster_CLUSTER_PROVIDED,
   588  	CircuitBreakers: &cluster.CircuitBreakers{
   589  		Thresholds: []*cluster.CircuitBreakers_Thresholds{
   590  			{
   591  				MaxConnections:     &wrappers.UInt32Value{Value: math.MaxUint32},
   592  				MaxPendingRequests: &wrappers.UInt32Value{Value: math.MaxUint32},
   593  				MaxRequests:        &wrappers.UInt32Value{Value: math.MaxUint32},
   594  				MaxRetries:         &wrappers.UInt32Value{Value: math.MaxUint32},
   595  			},
   596  		},
   597  	},
   598  }
   599  
   600  func MakeServiceName(svcKey model.ServiceKey, trafficDirection corev3.TrafficDirection) string {
   601  	return fmt.Sprintf("%s|%s|%s", corev3.TrafficDirection_name[int32(trafficDirection)],
   602  		svcKey.Namespace, svcKey.Name)
   603  }
   604  
   605  func MakeDefaultFilterChain() *listenerv3.FilterChain {
   606  	return &listenerv3.FilterChain{
   607  		Name: "PassthroughFilterChain",
   608  		Filters: []*listenerv3.Filter{
   609  			{
   610  				Name: wellknown.TCPProxy,
   611  				ConfigType: &listenerv3.Filter_TypedConfig{
   612  					TypedConfig: MustNewAny(&tcp.TcpProxy{
   613  						StatPrefix: PassthroughClusterName,
   614  						ClusterSpecifier: &tcp.TcpProxy_Cluster{
   615  							Cluster: PassthroughClusterName,
   616  						},
   617  					}),
   618  				},
   619  			},
   620  		},
   621  	}
   622  }
   623  
   624  func MakeSidecarBoundHCM(svcKey model.ServiceKey,
   625  	trafficDirection corev3.TrafficDirection) *hcm.HttpConnectionManager {
   626  	routerFilter := &hcm.HttpFilter{
   627  		Name: wellknown.Router,
   628  		ConfigType: &hcm.HttpFilter_TypedConfig{
   629  			TypedConfig: MustNewAny(&routerv3.Router{}),
   630  		},
   631  	}
   632  
   633  	hcmFilters := []*hcm.HttpFilter{routerFilter}
   634  	if trafficDirection == corev3.TrafficDirection_INBOUND {
   635  		hcmFilters = append([]*hcm.HttpFilter{
   636  			{
   637  				Name: "envoy.filters.http.local_ratelimit",
   638  				ConfigType: &hcm.HttpFilter_TypedConfig{
   639  					TypedConfig: MustNewAny(&lrl.LocalRateLimit{
   640  						StatPrefix: "http_local_rate_limiter",
   641  						Stage:      LocalRateLimitStage,
   642  					}),
   643  				},
   644  			},
   645  			{
   646  				Name: "envoy.filters.http.ratelimit",
   647  				ConfigType: &hcm.HttpFilter_TypedConfig{
   648  					TypedConfig: MustNewAny(&ratelimitfilter.RateLimit{
   649  						Domain:      fmt.Sprintf("%s.%s", svcKey.Name, svcKey.Namespace),
   650  						Stage:       DistributedRateLimitStage,
   651  						RequestType: "external",
   652  						Timeout:     durationpb.New(2 * time.Second),
   653  						RateLimitService: &ratelimitconfv3.RateLimitServiceConfig{
   654  							GrpcService: &corev3.GrpcService{
   655  								TargetSpecifier: &corev3.GrpcService_EnvoyGrpc_{
   656  									EnvoyGrpc: &corev3.GrpcService_EnvoyGrpc{
   657  										ClusterName: "polaris_ratelimit",
   658  									},
   659  								},
   660  								Timeout: durationpb.New(time.Second),
   661  							},
   662  							TransportApiVersion: core.ApiVersion_V3,
   663  						},
   664  					}),
   665  				},
   666  			},
   667  		}, hcmFilters...)
   668  	}
   669  
   670  	trafficDirectionName := corev3.TrafficDirection_name[int32(trafficDirection)]
   671  	manager := &hcm.HttpConnectionManager{
   672  		CodecType:           hcm.HttpConnectionManager_AUTO,
   673  		StatPrefix:          trafficDirectionName + "_HTTP",
   674  		RouteSpecifier:      routeSpecifier(trafficDirection),
   675  		AccessLog:           accessLog(),
   676  		HttpFilters:         hcmFilters,
   677  		HttpProtocolOptions: &core.Http1ProtocolOptions{AcceptHttp_10: true},
   678  	}
   679  	return manager
   680  }
   681  
   682  func MakeGatewayBoundHCM() *hcm.HttpConnectionManager {
   683  	hcmFilters := []*hcm.HttpFilter{
   684  		{
   685  			Name: "envoy.filters.http.local_ratelimit",
   686  			ConfigType: &hcm.HttpFilter_TypedConfig{
   687  				TypedConfig: MustNewAny(&lrl.LocalRateLimit{
   688  					StatPrefix: "http_local_rate_limiter",
   689  				}),
   690  			},
   691  		},
   692  		{
   693  			Name: wellknown.Router,
   694  			ConfigType: &hcm.HttpFilter_TypedConfig{
   695  				TypedConfig: MustNewAny(&routerv3.Router{}),
   696  			},
   697  		},
   698  	}
   699  	trafficDirectionName := corev3.TrafficDirection_name[int32(corev3.TrafficDirection_INBOUND)]
   700  	manager := &hcm.HttpConnectionManager{
   701  		CodecType:           hcm.HttpConnectionManager_AUTO,
   702  		StatPrefix:          trafficDirectionName + "_HTTP",
   703  		RouteSpecifier:      routeSpecifier(corev3.TrafficDirection_OUTBOUND),
   704  		AccessLog:           accessLog(),
   705  		HttpFilters:         hcmFilters,
   706  		HttpProtocolOptions: &core.Http1ProtocolOptions{AcceptHttp_10: true},
   707  	}
   708  	return manager
   709  }
   710  
   711  func routeSpecifier(trafficDirection corev3.TrafficDirection) *hcm.HttpConnectionManager_Rds {
   712  	return &hcm.HttpConnectionManager_Rds{
   713  		Rds: &hcm.Rds{
   714  			ConfigSource: &core.ConfigSource{
   715  				ResourceApiVersion: resourcev3.DefaultAPIVersion,
   716  				ConfigSourceSpecifier: &core.ConfigSource_Ads{
   717  					Ads: &core.AggregatedConfigSource{},
   718  				},
   719  			},
   720  			RouteConfigName: TrafficBoundRoute[trafficDirection],
   721  		},
   722  	}
   723  }
   724  
   725  func accessLog() []*accesslog.AccessLog {
   726  	return []*accesslog.AccessLog{
   727  		{
   728  			Name: wellknown.FileAccessLog,
   729  			ConfigType: &accesslog.AccessLog_TypedConfig{
   730  				TypedConfig: MustNewAny(&filev3.FileAccessLog{
   731  					Path: "/dev/stdout",
   732  				}),
   733  			},
   734  		},
   735  	}
   736  }
   737  
   738  func MustNewAny(src proto.Message) *anypb.Any {
   739  	a, _ := anypb.New(src)
   740  	return a
   741  }
   742  
   743  func MakeGatewayLocalRateLimit(rateLimitCache types.RateLimitCache, pathSpecifier string,
   744  	svcKey model.ServiceKey) ([]*route.RateLimit, map[string]*anypb.Any, error) {
   745  	conf, _ := rateLimitCache.GetRateLimitRules(svcKey)
   746  	if conf == nil {
   747  		return nil, nil, nil
   748  	}
   749  	confKey := fmt.Sprintf("INBOUND|GATEWAY|%s|%s|%s", svcKey.Namespace, svcKey.Name, pathSpecifier)
   750  	rateLimitConf := BuildRateLimitConf(confKey)
   751  	filters := make(map[string]*anypb.Any)
   752  	ratelimits := make([]*route.RateLimit, 0, len(conf))
   753  	for _, c := range conf {
   754  		rule := c.Proto
   755  		if rule == nil {
   756  			continue
   757  		}
   758  		if rule.GetDisable().GetValue() {
   759  			continue
   760  		}
   761  		if rule.GetMethod().GetValue().GetValue() != pathSpecifier {
   762  			continue
   763  		}
   764  		actions, descriptors := BuildRateLimitDescriptors(rule)
   765  		rateLimitConf.Descriptors = descriptors
   766  		ratelimitRule := &route.RateLimit{Actions: actions}
   767  		switch rule.GetType() {
   768  		case apitraffic.Rule_LOCAL:
   769  			ratelimitRule.Stage = wrapperspb.UInt32(LocalRateLimitStage)
   770  		case apitraffic.Rule_GLOBAL:
   771  			ratelimitRule.Stage = wrapperspb.UInt32(DistributedRateLimitStage)
   772  		}
   773  		ratelimits = append(ratelimits, ratelimitRule)
   774  	}
   775  	if len(ratelimits) == 0 {
   776  		return nil, nil, nil
   777  	}
   778  	filters["envoy.filters.http.local_ratelimit"] = MustNewAny(rateLimitConf)
   779  	return ratelimits, filters, nil
   780  }
   781  
   782  func MakeSidecarLocalRateLimit(rateLimitCache types.RateLimitCache,
   783  	svcKey model.ServiceKey) ([]*route.RateLimit, map[string]*anypb.Any, error) {
   784  	conf, _ := rateLimitCache.GetRateLimitRules(svcKey)
   785  	if conf == nil {
   786  		return nil, nil, nil
   787  	}
   788  	confKey := fmt.Sprintf("INBOUND|SIDECAR|%s|%s", svcKey.Namespace, svcKey.Name)
   789  	rateLimitConf := BuildRateLimitConf(confKey)
   790  	filters := make(map[string]*anypb.Any)
   791  	ratelimits := make([]*route.RateLimit, 0, len(conf))
   792  	for _, c := range conf {
   793  		rule := c.Proto
   794  		if rule == nil {
   795  			continue
   796  		}
   797  		if rule.GetDisable().GetValue() {
   798  			continue
   799  		}
   800  		actions, descriptors := BuildRateLimitDescriptors(rule)
   801  		rateLimitConf.Descriptors = descriptors
   802  		ratelimitRule := &route.RateLimit{Actions: actions}
   803  		switch rule.GetType() {
   804  		case apitraffic.Rule_LOCAL:
   805  			ratelimitRule.Stage = wrapperspb.UInt32(LocalRateLimitStage)
   806  		case apitraffic.Rule_GLOBAL:
   807  			ratelimitRule.Stage = wrapperspb.UInt32(DistributedRateLimitStage)
   808  		}
   809  		ratelimits = append(ratelimits, ratelimitRule)
   810  	}
   811  	filters["envoy.filters.http.local_ratelimit"] = MustNewAny(rateLimitConf)
   812  	return ratelimits, filters, nil
   813  }
   814  
   815  // Translate the circuit breaker configuration of Polaris into OutlierDetection
   816  func MakeOutlierDetection(serviceInfo *ServiceInfo) *cluster.OutlierDetection {
   817  	log.Infof("XDS][Sidecar] makeOutlierDetection service: %v enter", serviceInfo.Name)
   818  	circuitBreaker := serviceInfo.CircuitBreaker
   819  	if circuitBreaker == nil || len(circuitBreaker.Rules) == 0 {
   820  		return nil
   821  	}
   822  	var rule *apifault.CircuitBreakerRule
   823  	for _, item := range circuitBreaker.Rules {
   824  		log.Infof("[XDS][Sidecar] makeOutlierDetection rule: %+v", item)
   825  		if item.Level == apifault.Level_INSTANCE {
   826  			rule = item
   827  			break
   828  		}
   829  	}
   830  	// not config or close circuit breaker
   831  	if rule == nil || len(rule.TriggerCondition) == 0 || !rule.Enable {
   832  		return nil
   833  	}
   834  	triggerCondtion := rule.TriggerCondition[0]
   835  	outlierDetection := &cluster.OutlierDetection{}
   836  	outlierDetection.Interval = durationpb.New(time.Duration(triggerCondtion.GetInterval()) * time.Second)
   837  	outlierDetection.Consecutive_5Xx = &wrappers.UInt32Value{
   838  		Value: triggerCondtion.GetErrorCount()}
   839  	outlierDetection.FailurePercentageThreshold = &wrappers.UInt32Value{
   840  		Value: triggerCondtion.GetErrorPercent()}
   841  	outlierDetection.FailurePercentageRequestVolume = &wrappers.UInt32Value{
   842  		Value: triggerCondtion.GetMinimumRequest()}
   843  	if rule.RecoverCondition != nil {
   844  		outlierDetection.BaseEjectionTime =
   845  			durationpb.New(time.Duration(rule.GetRecoverCondition().GetSleepWindow()) * time.Second)
   846  	}
   847  
   848  	return outlierDetection
   849  }
   850  
   851  // Translate the FaultDetector configuration of Polaris into HealthCheck
   852  func MakeHealthCheck(serviceInfo *ServiceInfo) []*core.HealthCheck {
   853  	log.Infof("XDS][Sidecar] makeHealthCheck service: %v enter", serviceInfo.Name)
   854  	if serviceInfo.FaultDetect == nil || len(serviceInfo.FaultDetect.Rules) == 0 {
   855  		return nil
   856  	}
   857  	var healthChecks []*core.HealthCheck
   858  	for _, rule := range serviceInfo.FaultDetect.Rules {
   859  		log.Infof("[XDS][Sidecar] makeHealthCheck name: %v,  rule: %+v", rule.Name, rule)
   860  		healthCheck := &core.HealthCheck{
   861  			Timeout:            durationpb.New(time.Duration(rule.GetTimeout()) * time.Second),
   862  			Interval:           durationpb.New(time.Duration(rule.GetInterval()) * time.Second),
   863  			UnhealthyThreshold: &wrappers.UInt32Value{Value: 3},
   864  			HealthyThreshold:   &wrappers.UInt32Value{Value: 1},
   865  		}
   866  		if rule.GetProtocol() == apifault.FaultDetectRule_HTTP {
   867  			config := rule.GetHttpConfig()
   868  			if config == nil {
   869  				continue
   870  			}
   871  			var headers []*core.HeaderValueOption
   872  			for _, item := range config.GetHeaders() {
   873  				header := core.HeaderValueOption{
   874  					Header: &core.HeaderValue{
   875  						Key:   item.Key,
   876  						Value: item.Value,
   877  					},
   878  				}
   879  				headers = append(headers, &header)
   880  			}
   881  
   882  			httpHealthCheck := &core.HealthCheck_HttpHealthCheck{
   883  				Path:                config.Url,
   884  				Method:              core.RequestMethod(core.RequestMethod_value[config.Method]),
   885  				RequestHeadersToAdd: headers,
   886  			}
   887  			healthCheck.HealthChecker = &core.HealthCheck_HttpHealthCheck_{HttpHealthCheck: httpHealthCheck}
   888  			healthChecks = append(healthChecks, healthCheck)
   889  		} else if rule.GetProtocol() == apifault.FaultDetectRule_TCP {
   890  			config := rule.GetTcpConfig()
   891  			if config == nil {
   892  				continue
   893  			}
   894  			var receives []*core.HealthCheck_Payload
   895  			for _, item := range config.GetReceive() {
   896  				receives = append(receives, &core.HealthCheck_Payload{
   897  					Payload: &core.HealthCheck_Payload_Text{Text: hex.EncodeToString([]byte(item))},
   898  				})
   899  			}
   900  			tcpHealthCheck := &core.HealthCheck_TcpHealthCheck{
   901  				Send: &core.HealthCheck_Payload{
   902  					Payload: &core.HealthCheck_Payload_Text{Text: hex.EncodeToString([]byte(config.Send))},
   903  				},
   904  				Receive: receives,
   905  			}
   906  			healthCheck.HealthChecker = &core.HealthCheck_TcpHealthCheck_{TcpHealthCheck: tcpHealthCheck}
   907  			healthChecks = append(healthChecks, healthCheck)
   908  		}
   909  	}
   910  	return healthChecks
   911  }
   912  
   913  func MakeLbSubsetConfig(serviceInfo *ServiceInfo) *cluster.Cluster_LbSubsetConfig {
   914  	rules := FilterInboundRouterRule(serviceInfo)
   915  	if len(rules) == 0 {
   916  		return nil
   917  	}
   918  
   919  	lbSubsetConfig := &cluster.Cluster_LbSubsetConfig{}
   920  	var subsetSelectors []*cluster.Cluster_LbSubsetConfig_LbSubsetSelector
   921  	lbSubsetConfig.FallbackPolicy = cluster.Cluster_LbSubsetConfig_ANY_ENDPOINT
   922  
   923  	for _, rule := range rules {
   924  		// 对每一个 destination 产生一个 subset
   925  		for _, destination := range rule.GetDestinations() {
   926  			var keys []string
   927  			for s := range destination.GetLabels() {
   928  				keys = append(keys, s)
   929  			}
   930  			subsetSelectors = append(subsetSelectors, &cluster.Cluster_LbSubsetConfig_LbSubsetSelector{
   931  				Keys:           keys,
   932  				FallbackPolicy: cluster.Cluster_LbSubsetConfig_LbSubsetSelector_NO_FALLBACK,
   933  			})
   934  		}
   935  	}
   936  
   937  	lbSubsetConfig.SubsetSelectors = subsetSelectors
   938  	return lbSubsetConfig
   939  }
   940  
   941  func GenEndpointMetaFromPolarisIns(ins *apiservice.Instance) *core.Metadata {
   942  	meta := &core.Metadata{}
   943  	fields := make(map[string]*_struct.Value)
   944  	for k, v := range ins.Metadata {
   945  		fields[k] = &_struct.Value{
   946  			Kind: &_struct.Value_StringValue{
   947  				StringValue: v,
   948  			},
   949  		}
   950  	}
   951  
   952  	meta.FilterMetadata = make(map[string]*_struct.Struct)
   953  	meta.FilterMetadata["envoy.lb"] = &_struct.Struct{
   954  		Fields: fields,
   955  	}
   956  	if ins.Metadata != nil && ins.Metadata[TLSModeTag] != "" {
   957  		meta.FilterMetadata["envoy.transport_socket_match"] = MTLSTransportSocketMatch
   958  	}
   959  	return meta
   960  }
   961  
   962  func IsNormalEndpoint(ins *apiservice.Instance) bool {
   963  	if ins.GetIsolate().GetValue() {
   964  		return false
   965  	}
   966  	if ins.GetWeight().GetValue() == 0 {
   967  		return false
   968  	}
   969  	return true
   970  }
   971  
   972  func FormatEndpointHealth(ins *apiservice.Instance) core.HealthStatus {
   973  	if ins.GetHealthy().GetValue() {
   974  		return core.HealthStatus_HEALTHY
   975  	}
   976  	return core.HealthStatus_UNHEALTHY
   977  }