gitee.com/zhaochuninhefei/gmgo@v0.0.31-0.20240209061119-069254a02979/go-control-plane/pkg/test/resource/v3/resource.go (about)

     1  // Copyright 2018 Envoyproxy 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 resource creates test xDS resources
    16  package resource
    17  
    18  import (
    19  	"fmt"
    20  	"google.golang.org/protobuf/types/known/anypb"
    21  	"google.golang.org/protobuf/types/known/durationpb"
    22  	"time"
    23  
    24  	pstruct "github.com/golang/protobuf/ptypes/struct"
    25  
    26  	alf "gitee.com/zhaochuninhefei/gmgo/go-control-plane/envoy/config/accesslog/v3"
    27  	cluster "gitee.com/zhaochuninhefei/gmgo/go-control-plane/envoy/config/cluster/v3"
    28  	core "gitee.com/zhaochuninhefei/gmgo/go-control-plane/envoy/config/core/v3"
    29  	endpoint "gitee.com/zhaochuninhefei/gmgo/go-control-plane/envoy/config/endpoint/v3"
    30  	listener "gitee.com/zhaochuninhefei/gmgo/go-control-plane/envoy/config/listener/v3"
    31  	route "gitee.com/zhaochuninhefei/gmgo/go-control-plane/envoy/config/route/v3"
    32  	als "gitee.com/zhaochuninhefei/gmgo/go-control-plane/envoy/extensions/access_loggers/grpc/v3"
    33  	hcm "gitee.com/zhaochuninhefei/gmgo/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
    34  	tcp "gitee.com/zhaochuninhefei/gmgo/go-control-plane/envoy/extensions/filters/network/tcp_proxy/v3"
    35  	auth "gitee.com/zhaochuninhefei/gmgo/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
    36  	runtime "gitee.com/zhaochuninhefei/gmgo/go-control-plane/envoy/service/runtime/v3"
    37  	"gitee.com/zhaochuninhefei/gmgo/go-control-plane/pkg/cache/types"
    38  	"gitee.com/zhaochuninhefei/gmgo/go-control-plane/pkg/cache/v3"
    39  	"gitee.com/zhaochuninhefei/gmgo/go-control-plane/pkg/resource/v3"
    40  	"gitee.com/zhaochuninhefei/gmgo/go-control-plane/pkg/wellknown"
    41  )
    42  
    43  const (
    44  	localhost = "127.0.0.1"
    45  
    46  	// XdsCluster is the cluster name for the control server (used by non-ADS set-up)
    47  	XdsCluster = "xds_cluster"
    48  
    49  	// Ads mode for resources: one aggregated xDS service
    50  	Ads = "ads"
    51  
    52  	// Xds mode for resources: individual xDS services
    53  	Xds = "xds"
    54  
    55  	// Rest mode for resources: polling using Fetch
    56  	Rest = "rest"
    57  
    58  	// Delta mode for resources: individual delta xDS services
    59  	Delta = "delta"
    60  
    61  	// DeltaAds Delta Ads mode for resource: one aggregated delta xDS service
    62  	DeltaAds = "delta-ads"
    63  )
    64  
    65  var (
    66  	// RefreshDelay for the polling config source
    67  	RefreshDelay = 500 * time.Millisecond
    68  )
    69  
    70  // MakeEndpoint creates a localhost endpoint on a given port.
    71  func MakeEndpoint(clusterName string, port uint32) *endpoint.ClusterLoadAssignment {
    72  	return &endpoint.ClusterLoadAssignment{
    73  		ClusterName: clusterName,
    74  		Endpoints: []*endpoint.LocalityLbEndpoints{{
    75  			LbEndpoints: []*endpoint.LbEndpoint{{
    76  				HostIdentifier: &endpoint.LbEndpoint_Endpoint{
    77  					Endpoint: &endpoint.Endpoint{
    78  						Address: &core.Address{
    79  							Address: &core.Address_SocketAddress{
    80  								SocketAddress: &core.SocketAddress{
    81  									Protocol: core.SocketAddress_TCP,
    82  									Address:  localhost,
    83  									PortSpecifier: &core.SocketAddress_PortValue{
    84  										PortValue: port,
    85  									},
    86  								},
    87  							},
    88  						},
    89  					},
    90  				},
    91  			}},
    92  		}},
    93  	}
    94  }
    95  
    96  // MakeCluster creates a cluster using either ADS or EDS.
    97  func MakeCluster(mode string, clusterName string) *cluster.Cluster {
    98  	edsSource := configSource(mode)
    99  
   100  	connectTimeout := 5 * time.Second
   101  	return &cluster.Cluster{
   102  		Name: clusterName,
   103  		// ptypes.DurationProto is deprecated: Call the durationpb.New function instead.
   104  		//ConnectTimeout:       ptypes.DurationProto(connectTimeout),
   105  		ConnectTimeout:       durationpb.New(connectTimeout),
   106  		ClusterDiscoveryType: &cluster.Cluster_Type{Type: cluster.Cluster_EDS},
   107  		EdsClusterConfig: &cluster.Cluster_EdsClusterConfig{
   108  			EdsConfig: edsSource,
   109  		},
   110  	}
   111  }
   112  
   113  // MakeRoute creates an HTTP route that routes to a given cluster.
   114  func MakeRoute(routeName, clusterName string) *route.RouteConfiguration {
   115  	return &route.RouteConfiguration{
   116  		Name: routeName,
   117  		VirtualHosts: []*route.VirtualHost{{
   118  			Name:    routeName,
   119  			Domains: []string{"*"},
   120  			Routes: []*route.Route{{
   121  				Match: &route.RouteMatch{
   122  					PathSpecifier: &route.RouteMatch_Prefix{
   123  						Prefix: "/",
   124  					},
   125  				},
   126  				Action: &route.Route_Route{
   127  					Route: &route.RouteAction{
   128  						ClusterSpecifier: &route.RouteAction_Cluster{
   129  							Cluster: clusterName,
   130  						},
   131  					},
   132  				},
   133  			}},
   134  		}},
   135  	}
   136  }
   137  
   138  // data source configuration
   139  func configSource(mode string) *core.ConfigSource {
   140  	source := &core.ConfigSource{}
   141  	source.ResourceApiVersion = resource.DefaultAPIVersion
   142  	switch mode {
   143  	case Ads:
   144  		source.ConfigSourceSpecifier = &core.ConfigSource_Ads{
   145  			Ads: &core.AggregatedConfigSource{},
   146  		}
   147  	case DeltaAds:
   148  		source.ConfigSourceSpecifier = &core.ConfigSource_Ads{
   149  			Ads: &core.AggregatedConfigSource{},
   150  		}
   151  	case Xds:
   152  		source.ConfigSourceSpecifier = &core.ConfigSource_ApiConfigSource{
   153  			ApiConfigSource: &core.ApiConfigSource{
   154  				TransportApiVersion:       resource.DefaultAPIVersion,
   155  				ApiType:                   core.ApiConfigSource_GRPC,
   156  				SetNodeOnFirstMessageOnly: true,
   157  				GrpcServices: []*core.GrpcService{{
   158  					TargetSpecifier: &core.GrpcService_EnvoyGrpc_{
   159  						EnvoyGrpc: &core.GrpcService_EnvoyGrpc{ClusterName: XdsCluster},
   160  					},
   161  				}},
   162  			},
   163  		}
   164  	case Rest:
   165  		source.ConfigSourceSpecifier = &core.ConfigSource_ApiConfigSource{
   166  			ApiConfigSource: &core.ApiConfigSource{
   167  				ApiType:             core.ApiConfigSource_REST,
   168  				TransportApiVersion: resource.DefaultAPIVersion,
   169  				ClusterNames:        []string{XdsCluster},
   170  				// ptypes.DurationProto is deprecated: Call the durationpb.New function instead.
   171  				//RefreshDelay:        ptypes.DurationProto(RefreshDelay),
   172  				RefreshDelay: durationpb.New(RefreshDelay),
   173  			},
   174  		}
   175  	case Delta:
   176  		source.ConfigSourceSpecifier = &core.ConfigSource_ApiConfigSource{
   177  			ApiConfigSource: &core.ApiConfigSource{
   178  				TransportApiVersion:       resource.DefaultAPIVersion,
   179  				ApiType:                   core.ApiConfigSource_DELTA_GRPC,
   180  				SetNodeOnFirstMessageOnly: true,
   181  				GrpcServices: []*core.GrpcService{{
   182  					TargetSpecifier: &core.GrpcService_EnvoyGrpc_{
   183  						EnvoyGrpc: &core.GrpcService_EnvoyGrpc{ClusterName: XdsCluster},
   184  					},
   185  				}},
   186  			},
   187  		}
   188  	}
   189  	return source
   190  }
   191  
   192  // MakeHTTPListener creates a listener using either ADS or RDS for the route.
   193  func MakeHTTPListener(mode string, listenerName string, port uint32, route string) *listener.Listener {
   194  	rdsSource := configSource(mode)
   195  
   196  	// access log service configuration
   197  	alsConfig := &als.HttpGrpcAccessLogConfig{
   198  		CommonConfig: &als.CommonGrpcAccessLogConfig{
   199  			LogName:             "echo",
   200  			TransportApiVersion: resource.DefaultAPIVersion,
   201  			GrpcService: &core.GrpcService{
   202  				TargetSpecifier: &core.GrpcService_EnvoyGrpc_{
   203  					EnvoyGrpc: &core.GrpcService_EnvoyGrpc{
   204  						ClusterName: XdsCluster,
   205  					},
   206  				},
   207  			},
   208  		},
   209  	}
   210  	// ptypes.MarshalAny is deprecated: Call the anypb.New function instead.
   211  	//alsConfigPbst, err := ptypes.MarshalAny(alsConfig)
   212  	alsConfigPbst, err := anypb.New(alsConfig)
   213  	if err != nil {
   214  		panic(err)
   215  	}
   216  
   217  	// HTTP filter configuration
   218  	manager := &hcm.HttpConnectionManager{
   219  		CodecType:  hcm.HttpConnectionManager_AUTO,
   220  		StatPrefix: "http",
   221  		RouteSpecifier: &hcm.HttpConnectionManager_Rds{
   222  			Rds: &hcm.Rds{
   223  				ConfigSource:    rdsSource,
   224  				RouteConfigName: route,
   225  			},
   226  		},
   227  		HttpFilters: []*hcm.HttpFilter{{
   228  			Name: wellknown.Router,
   229  		}},
   230  		AccessLog: []*alf.AccessLog{{
   231  			Name: wellknown.HTTPGRPCAccessLog,
   232  			ConfigType: &alf.AccessLog_TypedConfig{
   233  				TypedConfig: alsConfigPbst,
   234  			},
   235  		}},
   236  	}
   237  	// ptypes.MarshalAny is deprecated: Call the anypb.New function instead.
   238  	//pbst, err := ptypes.MarshalAny(manager)
   239  	pbst, err := anypb.New(manager)
   240  	if err != nil {
   241  		panic(err)
   242  	}
   243  
   244  	return &listener.Listener{
   245  		Name: listenerName,
   246  		Address: &core.Address{
   247  			Address: &core.Address_SocketAddress{
   248  				SocketAddress: &core.SocketAddress{
   249  					Protocol: core.SocketAddress_TCP,
   250  					Address:  localhost,
   251  					PortSpecifier: &core.SocketAddress_PortValue{
   252  						PortValue: port,
   253  					},
   254  				},
   255  			},
   256  		},
   257  		FilterChains: []*listener.FilterChain{{
   258  			Filters: []*listener.Filter{{
   259  				Name: wellknown.HTTPConnectionManager,
   260  				ConfigType: &listener.Filter_TypedConfig{
   261  					TypedConfig: pbst,
   262  				},
   263  			}},
   264  		}},
   265  	}
   266  }
   267  
   268  // MakeTCPListener creates a TCP listener for a cluster.
   269  func MakeTCPListener(listenerName string, port uint32, clusterName string) *listener.Listener {
   270  	// TCP filter configuration
   271  	config := &tcp.TcpProxy{
   272  		StatPrefix: "tcp",
   273  		ClusterSpecifier: &tcp.TcpProxy_Cluster{
   274  			Cluster: clusterName,
   275  		},
   276  	}
   277  	// ptypes.MarshalAny is deprecated: Call the anypb.New function instead.
   278  	//pbst, err := ptypes.MarshalAny(config)
   279  	pbst, err := anypb.New(config)
   280  	if err != nil {
   281  		panic(err)
   282  	}
   283  	return &listener.Listener{
   284  		Name: listenerName,
   285  		Address: &core.Address{
   286  			Address: &core.Address_SocketAddress{
   287  				SocketAddress: &core.SocketAddress{
   288  					Protocol: core.SocketAddress_TCP,
   289  					Address:  localhost,
   290  					PortSpecifier: &core.SocketAddress_PortValue{
   291  						PortValue: port,
   292  					},
   293  				},
   294  			},
   295  		},
   296  		FilterChains: []*listener.FilterChain{{
   297  			Filters: []*listener.Filter{{
   298  				Name: wellknown.TCPProxy,
   299  				ConfigType: &listener.Filter_TypedConfig{
   300  					TypedConfig: pbst,
   301  				},
   302  			}},
   303  		}},
   304  	}
   305  }
   306  
   307  // MakeRuntime creates an RTDS layer with some fields.
   308  func MakeRuntime(runtimeName string) *runtime.Runtime {
   309  	return &runtime.Runtime{
   310  		Name: runtimeName,
   311  		Layer: &pstruct.Struct{
   312  			Fields: map[string]*pstruct.Value{
   313  				"field-0": {
   314  					Kind: &pstruct.Value_NumberValue{NumberValue: 100},
   315  				},
   316  				"field-1": {
   317  					Kind: &pstruct.Value_StringValue{StringValue: "foobar"},
   318  				},
   319  			},
   320  		},
   321  	}
   322  }
   323  
   324  // MakeExtensionConfig creates a extension config for a cluster.
   325  func MakeExtensionConfig(mode string, extensionConfigName string, route string) *core.TypedExtensionConfig {
   326  	rdsSource := configSource(mode)
   327  
   328  	// HTTP filter configuration
   329  	manager := &hcm.HttpConnectionManager{
   330  		CodecType:  hcm.HttpConnectionManager_AUTO,
   331  		StatPrefix: "http",
   332  		RouteSpecifier: &hcm.HttpConnectionManager_Rds{
   333  			Rds: &hcm.Rds{
   334  				ConfigSource:    rdsSource,
   335  				RouteConfigName: route,
   336  			},
   337  		},
   338  		HttpFilters: []*hcm.HttpFilter{{
   339  			Name: wellknown.Router,
   340  		}},
   341  	}
   342  	// ptypes.MarshalAny is deprecated: Call the anypb.New function instead.
   343  	//pbst, err := ptypes.MarshalAny(manager)
   344  	pbst, err := anypb.New(manager)
   345  	if err != nil {
   346  		panic(err)
   347  	}
   348  
   349  	return &core.TypedExtensionConfig{
   350  		Name:        extensionConfigName,
   351  		TypedConfig: pbst,
   352  	}
   353  }
   354  
   355  // TestSnapshot holds parameters for a synthetic snapshot.
   356  type TestSnapshot struct {
   357  	// Xds indicates snapshot mode: ads, xds, rest, or delta
   358  	Xds string
   359  	// Version for the snapshot.
   360  	Version string
   361  	// UpstreamPort for the single endpoint on the localhost.
   362  	UpstreamPort uint32
   363  	// BasePort is the initial port for the listeners.
   364  	BasePort uint32
   365  	// NumClusters is the total number of clusters to generate.
   366  	NumClusters int
   367  	// NumHTTPListeners is the total number of HTTP listeners to generate.
   368  	NumHTTPListeners int
   369  	// NumTCPListeners is the total number of TCP listeners to generate.
   370  	// Listeners are assigned clusters in a round-robin fashion.
   371  	NumTCPListeners int
   372  	// NumRuntimes is the total number of RTDS layers to generate.
   373  	NumRuntimes int
   374  	// TLS enables SDS-enabled TLS mode on all listeners
   375  	TLS bool
   376  	// NumExtension is the total number of Extension Config
   377  	NumExtension int
   378  }
   379  
   380  // Generate produces a snapshot from the parameters.
   381  func (ts TestSnapshot) Generate() cache.Snapshot {
   382  	clusters := make([]types.Resource, ts.NumClusters)
   383  	endpoints := make([]types.Resource, ts.NumClusters)
   384  	for i := 0; i < ts.NumClusters; i++ {
   385  		name := fmt.Sprintf("cluster-%s-%d", ts.Version, i)
   386  		clusters[i] = MakeCluster(ts.Xds, name)
   387  		endpoints[i] = MakeEndpoint(name, ts.UpstreamPort)
   388  	}
   389  
   390  	routes := make([]types.Resource, ts.NumHTTPListeners)
   391  	for i := 0; i < ts.NumHTTPListeners; i++ {
   392  		name := fmt.Sprintf("route-%s-%d", ts.Version, i)
   393  		routes[i] = MakeRoute(name, cache.GetResourceName(clusters[i%ts.NumClusters]))
   394  	}
   395  
   396  	total := ts.NumHTTPListeners + ts.NumTCPListeners
   397  	listeners := make([]types.Resource, total)
   398  	for i := 0; i < total; i++ {
   399  		port := ts.BasePort + uint32(i)
   400  		// listener name must be same since ports are shared and previous listener is drained
   401  		name := fmt.Sprintf("listener-%d", port)
   402  		var listenerTmp *listener.Listener
   403  		if i < ts.NumHTTPListeners {
   404  			listenerTmp = MakeHTTPListener(ts.Xds, name, port, cache.GetResourceName(routes[i]))
   405  		} else {
   406  			listenerTmp = MakeTCPListener(name, port, cache.GetResourceName(clusters[i%ts.NumClusters]))
   407  		}
   408  
   409  		if ts.TLS {
   410  			for i, chain := range listenerTmp.FilterChains {
   411  				tlsc := &auth.DownstreamTlsContext{
   412  					CommonTlsContext: &auth.CommonTlsContext{
   413  						TlsCertificateSdsSecretConfigs: []*auth.SdsSecretConfig{{
   414  							Name:      tlsName,
   415  							SdsConfig: configSource(ts.Xds),
   416  						}},
   417  						ValidationContextType: &auth.CommonTlsContext_ValidationContextSdsSecretConfig{
   418  							ValidationContextSdsSecretConfig: &auth.SdsSecretConfig{
   419  								Name:      rootName,
   420  								SdsConfig: configSource(ts.Xds),
   421  							},
   422  						},
   423  					},
   424  				}
   425  				// ptypes.MarshalAny is deprecated: Call the anypb.New function instead.
   426  				//mt, _ := ptypes.MarshalAny(tlsc)
   427  				mt, _ := anypb.New(tlsc)
   428  				chain.TransportSocket = &core.TransportSocket{
   429  					Name: "envoy.transport_sockets.tls",
   430  					ConfigType: &core.TransportSocket_TypedConfig{
   431  						TypedConfig: mt,
   432  					},
   433  				}
   434  				listenerTmp.FilterChains[i] = chain
   435  			}
   436  		}
   437  
   438  		listeners[i] = listenerTmp
   439  	}
   440  
   441  	runtimes := make([]types.Resource, ts.NumRuntimes)
   442  	for i := 0; i < ts.NumRuntimes; i++ {
   443  		name := fmt.Sprintf("runtime-%d", i)
   444  		runtimes[i] = MakeRuntime(name)
   445  	}
   446  
   447  	var secrets []types.Resource
   448  	if ts.TLS {
   449  		for _, s := range MakeSecrets(tlsName, rootName) {
   450  			secrets = append(secrets, s)
   451  		}
   452  	}
   453  
   454  	extensions := make([]types.Resource, ts.NumExtension)
   455  	for i := 0; i < ts.NumExtension; i++ {
   456  		routeName := fmt.Sprintf("route-%s-%d", ts.Version, i)
   457  		extensionConfigName := fmt.Sprintf("extensionConfig-%d", i)
   458  		extensions[i] = MakeExtensionConfig(Ads, extensionConfigName, routeName)
   459  	}
   460  
   461  	out, _ := cache.NewSnapshot(ts.Version, map[resource.Type][]types.Resource{
   462  		resource.EndpointType:        endpoints,
   463  		resource.ClusterType:         clusters,
   464  		resource.RouteType:           routes,
   465  		resource.ListenerType:        listeners,
   466  		resource.RuntimeType:         runtimes,
   467  		resource.SecretType:          secrets,
   468  		resource.ExtensionConfigType: extensions,
   469  	})
   470  
   471  	return out
   472  }