1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package resource
18
19 import (
20 "fmt"
21 "time"
22
23 pstruct "github.com/golang/protobuf/ptypes/struct"
24
25 "github.com/golang/protobuf/ptypes"
26
27 alf "github.com/datawire/ambassador/v2/pkg/api/envoy/config/accesslog/v3"
28 cluster "github.com/datawire/ambassador/v2/pkg/api/envoy/config/cluster/v3"
29 core "github.com/datawire/ambassador/v2/pkg/api/envoy/config/core/v3"
30 endpoint "github.com/datawire/ambassador/v2/pkg/api/envoy/config/endpoint/v3"
31 endpointv2 "github.com/datawire/ambassador/v2/pkg/api/envoy/config/endpoint/v3"
32 listener "github.com/datawire/ambassador/v2/pkg/api/envoy/config/listener/v3"
33 listenerv2 "github.com/datawire/ambassador/v2/pkg/api/envoy/config/listener/v3"
34 route "github.com/datawire/ambassador/v2/pkg/api/envoy/config/route/v3"
35 routev2 "github.com/datawire/ambassador/v2/pkg/api/envoy/config/route/v3"
36 als "github.com/datawire/ambassador/v2/pkg/api/envoy/extensions/access_loggers/grpc/v3"
37 hcm "github.com/datawire/ambassador/v2/pkg/api/envoy/extensions/filters/network/http_connection_manager/v3"
38 tcp "github.com/datawire/ambassador/v2/pkg/api/envoy/extensions/filters/network/tcp_proxy/v3"
39 auth "github.com/datawire/ambassador/v2/pkg/api/envoy/extensions/transport_sockets/tls/v3"
40 runtime "github.com/datawire/ambassador/v2/pkg/api/envoy/service/runtime/v3"
41 "github.com/datawire/ambassador/v2/pkg/envoy-control-plane/cache/types"
42 "github.com/datawire/ambassador/v2/pkg/envoy-control-plane/cache/v3"
43 "github.com/datawire/ambassador/v2/pkg/envoy-control-plane/resource/v3"
44 "github.com/datawire/ambassador/v2/pkg/envoy-control-plane/wellknown"
45 )
46
47 const (
48 localhost = "127.0.0.1"
49
50
51 XdsCluster = "xds_cluster"
52
53
54 Ads = "ads"
55
56
57 Xds = "xds"
58
59
60 Rest = "rest"
61 )
62
63 var (
64
65 RefreshDelay = 500 * time.Millisecond
66 )
67
68
69 func MakeEndpoint(clusterName string, port uint32) *endpoint.ClusterLoadAssignment {
70 return &endpoint.ClusterLoadAssignment{
71 ClusterName: clusterName,
72 Endpoints: []*endpointv2.LocalityLbEndpoints{{
73 LbEndpoints: []*endpointv2.LbEndpoint{{
74 HostIdentifier: &endpointv2.LbEndpoint_Endpoint{
75 Endpoint: &endpointv2.Endpoint{
76 Address: &core.Address{
77 Address: &core.Address_SocketAddress{
78 SocketAddress: &core.SocketAddress{
79 Protocol: core.SocketAddress_TCP,
80 Address: localhost,
81 PortSpecifier: &core.SocketAddress_PortValue{
82 PortValue: port,
83 },
84 },
85 },
86 },
87 },
88 },
89 }},
90 }},
91 }
92 }
93
94
95 func MakeCluster(mode string, clusterName string) *cluster.Cluster {
96 edsSource := configSource(mode)
97
98 connectTimeout := 5 * time.Second
99 return &cluster.Cluster{
100 Name: clusterName,
101 ConnectTimeout: ptypes.DurationProto(connectTimeout),
102 ClusterDiscoveryType: &cluster.Cluster_Type{Type: cluster.Cluster_EDS},
103 EdsClusterConfig: &cluster.Cluster_EdsClusterConfig{
104 EdsConfig: edsSource,
105 },
106 }
107 }
108
109
110 func MakeRoute(routeName, clusterName string) *route.RouteConfiguration {
111 return &route.RouteConfiguration{
112 Name: routeName,
113 VirtualHosts: []*routev2.VirtualHost{{
114 Name: routeName,
115 Domains: []string{"*"},
116 Routes: []*routev2.Route{{
117 Match: &routev2.RouteMatch{
118 PathSpecifier: &routev2.RouteMatch_Prefix{
119 Prefix: "/",
120 },
121 },
122 Action: &routev2.Route_Route{
123 Route: &routev2.RouteAction{
124 ClusterSpecifier: &routev2.RouteAction_Cluster{
125 Cluster: clusterName,
126 },
127 },
128 },
129 }},
130 }},
131 }
132 }
133
134
135 func configSource(mode string) *core.ConfigSource {
136 source := &core.ConfigSource{}
137 source.ResourceApiVersion = resource.DefaultAPIVersion
138 switch mode {
139 case Ads:
140 source.ConfigSourceSpecifier = &core.ConfigSource_Ads{
141 Ads: &core.AggregatedConfigSource{},
142 }
143 case Xds:
144 source.ConfigSourceSpecifier = &core.ConfigSource_ApiConfigSource{
145 ApiConfigSource: &core.ApiConfigSource{
146 TransportApiVersion: resource.DefaultAPIVersion,
147 ApiType: core.ApiConfigSource_GRPC,
148 SetNodeOnFirstMessageOnly: true,
149 GrpcServices: []*core.GrpcService{{
150 TargetSpecifier: &core.GrpcService_EnvoyGrpc_{
151 EnvoyGrpc: &core.GrpcService_EnvoyGrpc{ClusterName: XdsCluster},
152 },
153 }},
154 },
155 }
156 case Rest:
157 source.ConfigSourceSpecifier = &core.ConfigSource_ApiConfigSource{
158 ApiConfigSource: &core.ApiConfigSource{
159 ApiType: core.ApiConfigSource_REST,
160 TransportApiVersion: resource.DefaultAPIVersion,
161 ClusterNames: []string{XdsCluster},
162 RefreshDelay: ptypes.DurationProto(RefreshDelay),
163 },
164 }
165 }
166 return source
167 }
168
169
170 func MakeHTTPListener(mode string, listenerName string, port uint32, route string) *listener.Listener {
171 rdsSource := configSource(mode)
172
173
174 alsConfig := &als.HttpGrpcAccessLogConfig{
175 CommonConfig: &als.CommonGrpcAccessLogConfig{
176 LogName: "echo",
177 GrpcService: &core.GrpcService{
178 TargetSpecifier: &core.GrpcService_EnvoyGrpc_{
179 EnvoyGrpc: &core.GrpcService_EnvoyGrpc{
180 ClusterName: XdsCluster,
181 },
182 },
183 },
184 },
185 }
186 alsConfigPbst, err := ptypes.MarshalAny(alsConfig)
187 if err != nil {
188 panic(err)
189 }
190
191
192 manager := &hcm.HttpConnectionManager{
193 CodecType: hcm.HttpConnectionManager_AUTO,
194 StatPrefix: "http",
195 RouteSpecifier: &hcm.HttpConnectionManager_Rds{
196 Rds: &hcm.Rds{
197 ConfigSource: rdsSource,
198 RouteConfigName: route,
199 },
200 },
201 HttpFilters: []*hcm.HttpFilter{{
202 Name: wellknown.Router,
203 }},
204 AccessLog: []*alf.AccessLog{{
205 Name: wellknown.HTTPGRPCAccessLog,
206 ConfigType: &alf.AccessLog_TypedConfig{
207 TypedConfig: alsConfigPbst,
208 },
209 }},
210 }
211 pbst, err := ptypes.MarshalAny(manager)
212 if err != nil {
213 panic(err)
214 }
215
216 return &listener.Listener{
217 Name: listenerName,
218 Address: &core.Address{
219 Address: &core.Address_SocketAddress{
220 SocketAddress: &core.SocketAddress{
221 Protocol: core.SocketAddress_TCP,
222 Address: localhost,
223 PortSpecifier: &core.SocketAddress_PortValue{
224 PortValue: port,
225 },
226 },
227 },
228 },
229 FilterChains: []*listenerv2.FilterChain{{
230 Filters: []*listenerv2.Filter{{
231 Name: wellknown.HTTPConnectionManager,
232 ConfigType: &listenerv2.Filter_TypedConfig{
233 TypedConfig: pbst,
234 },
235 }},
236 }},
237 }
238 }
239
240
241 func MakeTCPListener(listenerName string, port uint32, clusterName string) *listener.Listener {
242
243 config := &tcp.TcpProxy{
244 StatPrefix: "tcp",
245 ClusterSpecifier: &tcp.TcpProxy_Cluster{
246 Cluster: clusterName,
247 },
248 }
249 pbst, err := ptypes.MarshalAny(config)
250 if err != nil {
251 panic(err)
252 }
253 return &listener.Listener{
254 Name: listenerName,
255 Address: &core.Address{
256 Address: &core.Address_SocketAddress{
257 SocketAddress: &core.SocketAddress{
258 Protocol: core.SocketAddress_TCP,
259 Address: localhost,
260 PortSpecifier: &core.SocketAddress_PortValue{
261 PortValue: port,
262 },
263 },
264 },
265 },
266 FilterChains: []*listenerv2.FilterChain{{
267 Filters: []*listenerv2.Filter{{
268 Name: wellknown.TCPProxy,
269 ConfigType: &listenerv2.Filter_TypedConfig{
270 TypedConfig: pbst,
271 },
272 }},
273 }},
274 }
275 }
276
277
278 func MakeRuntime(runtimeName string) *runtime.Runtime {
279 return &runtime.Runtime{
280 Name: runtimeName,
281 Layer: &pstruct.Struct{
282 Fields: map[string]*pstruct.Value{
283 "field-0": {
284 Kind: &pstruct.Value_NumberValue{NumberValue: 100},
285 },
286 "field-1": {
287 Kind: &pstruct.Value_StringValue{StringValue: "foobar"},
288 },
289 },
290 },
291 }
292 }
293
294
295 type TestSnapshot struct {
296
297 Xds string
298
299 Version string
300
301 UpstreamPort uint32
302
303 BasePort uint32
304
305 NumClusters int
306
307 NumHTTPListeners int
308
309
310 NumTCPListeners int
311
312 NumRuntimes int
313
314 TLS bool
315 }
316
317
318 func (ts TestSnapshot) Generate() cache.Snapshot {
319 clusters := make([]types.Resource, ts.NumClusters)
320 endpoints := make([]types.Resource, ts.NumClusters)
321 for i := 0; i < ts.NumClusters; i++ {
322 name := fmt.Sprintf("cluster-%s-%d", ts.Version, i)
323 clusters[i] = MakeCluster(ts.Xds, name)
324 endpoints[i] = MakeEndpoint(name, ts.UpstreamPort)
325 }
326
327 routes := make([]types.Resource, ts.NumHTTPListeners)
328 for i := 0; i < ts.NumHTTPListeners; i++ {
329 name := fmt.Sprintf("route-%s-%d", ts.Version, i)
330 routes[i] = MakeRoute(name, cache.GetResourceName(clusters[i%ts.NumClusters]))
331 }
332
333 total := ts.NumHTTPListeners + ts.NumTCPListeners
334 listeners := make([]types.Resource, total)
335 for i := 0; i < total; i++ {
336 port := ts.BasePort + uint32(i)
337
338 name := fmt.Sprintf("listener-%d", port)
339 var listener *listener.Listener
340 if i < ts.NumHTTPListeners {
341 listener = MakeHTTPListener(ts.Xds, name, port, cache.GetResourceName(routes[i]))
342 } else {
343 listener = MakeTCPListener(name, port, cache.GetResourceName(clusters[i%ts.NumClusters]))
344 }
345
346 if ts.TLS {
347 for i, chain := range listener.FilterChains {
348 tlsc := &auth.DownstreamTlsContext{
349 CommonTlsContext: &auth.CommonTlsContext{
350 TlsCertificateSdsSecretConfigs: []*auth.SdsSecretConfig{{
351 Name: tlsName,
352 SdsConfig: configSource(ts.Xds),
353 }},
354 ValidationContextType: &auth.CommonTlsContext_ValidationContextSdsSecretConfig{
355 ValidationContextSdsSecretConfig: &auth.SdsSecretConfig{
356 Name: rootName,
357 SdsConfig: configSource(ts.Xds),
358 },
359 },
360 },
361 }
362 mt, _ := ptypes.MarshalAny(tlsc)
363 chain.TransportSocket = &core.TransportSocket{
364 Name: "envoy.transport_sockets.tls",
365 ConfigType: &core.TransportSocket_TypedConfig{
366 TypedConfig: mt,
367 },
368 }
369 listener.FilterChains[i] = chain
370 }
371 }
372
373 listeners[i] = listener
374 }
375
376 runtimes := make([]types.Resource, ts.NumRuntimes)
377 for i := 0; i < ts.NumRuntimes; i++ {
378 name := fmt.Sprintf("runtime-%d", i)
379 runtimes[i] = MakeRuntime(name)
380 }
381
382 var secrets []types.Resource
383 if ts.TLS {
384 for _, s := range MakeSecrets(tlsName, rootName) {
385 secrets = append(secrets, s)
386 }
387 }
388
389 out := cache.NewSnapshot(
390 ts.Version,
391 endpoints,
392 clusters,
393 routes,
394 listeners,
395 runtimes,
396 secrets,
397 )
398
399 return out
400 }
401
View as plain text