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 }