1 package entrypoint_test
2
3 import (
4 "fmt"
5 "os"
6 "sort"
7 "strings"
8 "testing"
9
10 "github.com/stretchr/testify/assert"
11 "github.com/stretchr/testify/require"
12
13 "github.com/datawire/dlib/dlog"
14 "github.com/emissary-ingress/emissary/v3/cmd/entrypoint"
15 "github.com/emissary-ingress/emissary/v3/pkg/ambex"
16 v3bootstrap "github.com/emissary-ingress/emissary/v3/pkg/api/envoy/config/bootstrap/v3"
17 v3cluster "github.com/emissary-ingress/emissary/v3/pkg/api/envoy/config/cluster/v3"
18 "github.com/emissary-ingress/emissary/v3/pkg/kates"
19 "github.com/emissary-ingress/emissary/v3/pkg/snapshot/v1"
20 )
21
22
23
24 type FakeFeatures struct {
25 Invalid map[string]int `json:"invalid_counts"`
26 }
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 func TestFakeHello(t *testing.T) {
46
47
48
49 os.Setenv("AMBASSADOR_FORCE_SECRET_VALIDATION", "true")
50
51
52
53
54
55
56
57 f := entrypoint.RunFake(t, entrypoint.FakeConfig{EnvoyConfig: true}, nil)
58
59
60
61
62
63
64 assert.NoError(t, f.UpsertFile("testdata/FakeHello.yaml"))
65
66
67
68
69 assert.NoError(t, f.UpsertFile("testdata/BrokenSecret.yaml"))
70
71
72
73
74
75
76
77
78
79
80 f.Flush()
81
82
83
84
85
86
87
88
89
90
91 snap, err := f.GetSnapshot(func(snap *snapshot.Snapshot) bool {
92 hasMappings := len(snap.Kubernetes.Mappings) > 0
93 hasSecrets := len(snap.Kubernetes.Secrets) > 0
94 hasInvalid := len(snap.Invalid) > 0
95
96 return hasMappings && hasSecrets && hasInvalid
97 })
98 require.NoError(t, err)
99
100
101 assert.Equal(t, "hello", snap.Kubernetes.Mappings[0].Name)
102
103
104 assert.Equal(t, 1, len(snap.Kubernetes.Secrets))
105 assert.Equal(t, "tls-cert", snap.Kubernetes.Secrets[0].Name)
106
107
108 assert.Equal(t, 1, len(snap.Invalid))
109 assert.Equal(t, "tls-broken-cert", snap.Invalid[0].GetName())
110
111
112 var features FakeFeatures
113 err = f.GetFeatures(dlog.NewTestContext(t, false), &features)
114 require.NoError(t, err)
115
116 assert.Equal(t, 1, features.Invalid["Secret"])
117 }
118
119
120
121
122 func TestFakeHelloNoSecretValidation(t *testing.T) {
123
124
125
126
127
128 os.Setenv("AMBASSADOR_FORCE_SECRET_VALIDATION", "false")
129
130
131 f := entrypoint.RunFake(t, entrypoint.FakeConfig{EnvoyConfig: true}, nil)
132
133
134
135 assert.NoError(t, f.UpsertFile("testdata/FakeHello.yaml"))
136 assert.NoError(t, f.UpsertFile("testdata/BrokenSecret.yaml"))
137 f.Flush()
138
139
140
141 snap, err := f.GetSnapshot(func(snap *snapshot.Snapshot) bool {
142 hasMappings := len(snap.Kubernetes.Mappings) > 0
143 hasSecrets := len(snap.Kubernetes.Secrets) > 0
144 hasInvalid := len(snap.Invalid) > 0
145
146 return hasMappings && hasSecrets && hasInvalid
147 })
148 require.NoError(t, err)
149
150
151 assert.Equal(t, "hello", snap.Kubernetes.Mappings[0].Name)
152
153
154 assert.Equal(t, 2, len(snap.Kubernetes.Secrets))
155 secretNames := []string{snap.Kubernetes.Secrets[0].Name, snap.Kubernetes.Secrets[1].Name}
156 assert.Contains(t, secretNames, "tls-broken-cert")
157 assert.Contains(t, secretNames, "tls-cert")
158
159
160
161 assert.Equal(t, 1, len(snap.Invalid))
162 assert.Equal(t, "tls-broken-cert", snap.Invalid[0].GetName())
163
164
165 var features FakeFeatures
166 err = f.GetFeatures(dlog.NewTestContext(t, false), &features)
167 require.NoError(t, err)
168
169 assert.Equal(t, 1, features.Invalid["Secret"])
170 }
171
172
173
174 func TestFakeHelloEC(t *testing.T) {
175
176
177
178
179 os.Setenv("AMBASSADOR_FORCE_SECRET_VALIDATION", "true")
180
181
182 f := entrypoint.RunFake(t, entrypoint.FakeConfig{EnvoyConfig: true}, nil)
183
184
185 f.AutoFlush(true)
186
187
188 assert.NoError(t, f.UpsertFile("testdata/FakeHelloEC.yaml"))
189
190
191
192 snap, err := f.GetSnapshot(func(snap *snapshot.Snapshot) bool {
193 hasMappings := len(snap.Kubernetes.Mappings) > 0
194 hasSecrets := len(snap.Kubernetes.Secrets) > 0
195 hasInvalid := len(snap.Invalid) > 0
196
197 return hasMappings && hasSecrets && hasInvalid
198 })
199 require.NoError(t, err)
200
201
202 assert.Equal(t, "hello-elliptic-curve", snap.Kubernetes.Mappings[0].Name)
203
204
205 assert.Equal(t, 2, len(snap.Kubernetes.Secrets))
206 secretNames := []string{snap.Kubernetes.Secrets[0].Name, snap.Kubernetes.Secrets[1].Name}
207 assert.Contains(t, secretNames, "hello-elliptic-curve-client")
208 assert.Contains(t, secretNames, "tls-cert")
209
210
211
212 assert.Equal(t, 1, len(snap.Invalid))
213 assert.Equal(t, "hello-elliptic-curve-broken-server", snap.Invalid[0].GetName())
214
215 var features FakeFeatures
216 err = f.GetFeatures(dlog.NewTestContext(t, false), &features)
217 require.NoError(t, err)
218
219 assert.Equal(t, 1, features.Invalid["Secret"])
220 }
221
222
223 func TestFakeHelloWithEnvoyConfig(t *testing.T) {
224
225
226 f := entrypoint.RunFake(t, entrypoint.FakeConfig{EnvoyConfig: true}, nil)
227
228
229 assert.NoError(t, f.UpsertFile("testdata/FakeHello.yaml"))
230
231
232 f.Flush()
233
234
235
236 snap, err := f.GetSnapshot(func(snap *snapshot.Snapshot) bool {
237 return len(snap.Kubernetes.Mappings) > 0
238 })
239 require.NoError(t, err)
240
241
242 assert.Equal(t, "hello", snap.Kubernetes.Mappings[0].Name)
243
244
245
246
247 isHelloCluster := func(c *v3cluster.Cluster) bool {
248 return strings.Contains(c.Name, "hello")
249 }
250
251
252 envoyConfig, err := f.GetEnvoyConfig(func(envoy *v3bootstrap.Bootstrap) bool {
253 return FindCluster(envoy, isHelloCluster) != nil
254 })
255 require.NoError(t, err)
256
257
258
259
260
261
262
263
264
265 cluster := FindCluster(envoyConfig, isHelloCluster)
266 endpoints := cluster.LoadAssignment.Endpoints
267 require.NotEmpty(t, endpoints)
268 lbEndpoints := endpoints[0].LbEndpoints
269 require.NotEmpty(t, lbEndpoints)
270 endpoint := lbEndpoints[0].GetEndpoint()
271 address := endpoint.Address.GetSocketAddress().Address
272 assert.Equal(t, "hello", address)
273
274
275 var features FakeFeatures
276 err = f.GetFeatures(dlog.NewTestContext(t, false), &features)
277 require.NoError(t, err)
278
279 assert.Equal(t, 0, features.Invalid["Secret"])
280 }
281
282 func FindCluster(envoyConfig *v3bootstrap.Bootstrap, predicate func(*v3cluster.Cluster) bool) *v3cluster.Cluster {
283 for _, cluster := range envoyConfig.StaticResources.Clusters {
284 if predicate(cluster) {
285 return cluster
286 }
287 }
288
289 return nil
290 }
291
292 func deltaSummary(t *testing.T, snaps ...*snapshot.Snapshot) []string {
293 summary := []string{}
294
295 var typestr string
296
297 for _, snap := range snaps {
298 for _, delta := range snap.Deltas {
299 switch delta.DeltaType {
300 case kates.ObjectAdd:
301 typestr = "add"
302 case kates.ObjectUpdate:
303 typestr = "update"
304 case kates.ObjectDelete:
305 typestr = "delete"
306 default:
307
308 t.Fatalf("missing case for DeltaType enum: %#v", delta)
309 }
310
311 summary = append(summary, fmt.Sprintf("%s %s %s", typestr, delta.Kind, delta.Name))
312 }
313 }
314
315 sort.Strings(summary)
316
317 return summary
318 }
319
320
321
322
323
324 func getSnapshots(f *entrypoint.Fake, predicate func(*snapshot.Snapshot) bool) ([]*snapshot.Snapshot, error) {
325 var ret []*snapshot.Snapshot
326 for {
327 snap, err := f.GetSnapshot(func(_ *snapshot.Snapshot) bool {
328 return true
329 })
330 if err != nil {
331 return nil, err
332 }
333 ret = append(ret, snap)
334 if predicate(snap) {
335 break
336 }
337 }
338 return ret, nil
339 }
340
341
342
343
344 func TestFakeHelloConsul(t *testing.T) {
345 os.Setenv("CONSULPORT", "8500")
346 os.Setenv("CONSULHOST", "consul-1")
347
348
349 f := entrypoint.RunFake(t, entrypoint.FakeConfig{EnvoyConfig: true}, nil)
350
351
352
353 assert.NoError(t, f.UpsertFile("testdata/FakeHelloConsul.yaml"))
354
355
356
357
358 f.Flush()
359
360
361
362
363
364
365
366
367
368
369 entry, err := f.GetSnapshotEntry(func(entry entrypoint.SnapshotEntry) bool {
370 return entry.Disposition == entrypoint.SnapshotIncomplete && len(entry.Snapshot.Kubernetes.Mappings) > 0
371 })
372 require.NoError(t, err)
373
374 assert.Equal(t, "hello", entry.Snapshot.Kubernetes.Mappings[0].Name)
375
376 assert.Equal(t, "hello-tcp", entry.Snapshot.Kubernetes.TCPMappings[0].Name)
377
378
379 f.ConsulEndpoint("dc1", "hello", "1.2.3.4", 8080)
380
381 f.ConsulEndpoint("dc1", "hello-tcp", "5.6.7.8", 3099)
382 f.Flush()
383
384
385
386 endpoints, err := f.GetEndpoints(func(endpoints *ambex.Endpoints) bool {
387 _, ok := endpoints.Entries["consul/dc1/hello"]
388 if ok {
389 _, okTcp := endpoints.Entries["consul/dc1/hello-tcp"]
390 return okTcp
391 }
392 return false
393 })
394 require.NoError(t, err)
395 assert.Len(t, endpoints.Entries, 2)
396 assert.Equal(t, "1.2.3.4", endpoints.Entries["consul/dc1/hello"][0].Ip)
397
398
399
400
401 snap, err := f.GetSnapshot(func(snap *snapshot.Snapshot) bool {
402 return (len(snap.Kubernetes.Mappings) > 0) && (len(snap.Kubernetes.TCPMappings) > 0) && (len(snap.Kubernetes.ConsulResolvers) > 0)
403 })
404 require.NoError(t, err)
405
406
407 assert.Equal(t, "hello", snap.Kubernetes.Mappings[0].Name)
408 assert.Equal(t, "hello-tcp", snap.Kubernetes.TCPMappings[0].Name)
409
410
411
412 assert.Equal(t, "consul-server.default:8500", snap.Kubernetes.ConsulResolvers[0].Spec.Address)
413
414
415 assert.Equal(t, []string{"add ConsulResolver consul-dc1", "add Mapping hello", "add TCPMapping hello-tcp"}, deltaSummary(t, snap))
416
417
418
419
420 isHelloTCPCluster := func(c *v3cluster.Cluster) bool {
421 return strings.Contains(c.Name, "hello_tcp")
422 }
423 isHelloCluster := func(c *v3cluster.Cluster) bool {
424 return strings.Contains(c.Name, "hello") && !isHelloTCPCluster(c)
425 }
426
427
428 envoyConfig, err := f.GetEnvoyConfig(func(envoy *v3bootstrap.Bootstrap) bool {
429 return FindCluster(envoy, isHelloCluster) != nil
430 })
431 require.NoError(t, err)
432
433
434
435 cluster := FindCluster(envoyConfig, isHelloCluster)
436 assert.NotNil(t, cluster)
437
438 assert.Nil(t, cluster.LoadAssignment)
439
440 edsConfig := cluster.GetEdsClusterConfig()
441 require.NotNil(t, edsConfig)
442
443 eps := endpoints.Entries[edsConfig.ServiceName]
444 require.Len(t, eps, 1)
445
446 assert.Equal(t, "1.2.3.4", eps[0].Ip)
447
448
449 cluster = FindCluster(envoyConfig, isHelloTCPCluster)
450 assert.NotNil(t, cluster)
451
452 assert.Nil(t, cluster.LoadAssignment)
453
454 edsConfig = cluster.GetEdsClusterConfig()
455 require.NotNil(t, edsConfig)
456
457 eps = endpoints.Entries[edsConfig.ServiceName]
458 require.Len(t, eps, 1)
459
460 assert.Equal(t, "5.6.7.8", eps[0].Ip)
461
462
463 assert.NoError(t, f.UpsertYAML(`
464 ---
465 apiVersion: getambassador.io/v3alpha1
466 kind: ConsulResolver
467 metadata:
468 name: consul-dc1
469 spec:
470 address: $CONSULHOST:$CONSULPORT
471 datacenter: dc1
472 `))
473 f.Flush()
474
475
476 snap, err = f.GetSnapshot(func(snap *snapshot.Snapshot) bool {
477 return (len(snap.Kubernetes.Mappings) > 0) && (len(snap.Kubernetes.TCPMappings) > 0) && (len(snap.Kubernetes.ConsulResolvers) > 0)
478 })
479 require.NoError(t, err)
480
481
482 assert.Equal(t, []string{"update ConsulResolver consul-dc1"}, deltaSummary(t, snap))
483
484
485 assert.Equal(t, "hello", snap.Kubernetes.Mappings[0].Name)
486 assert.Equal(t, "hello-tcp", snap.Kubernetes.TCPMappings[0].Name)
487
488
489 assert.Equal(t, "consul-1:8500", snap.Kubernetes.ConsulResolvers[0].Spec.Address)
490
491
492
493
494 assert.NoError(t, f.Delete("ConsulResolver", "default", "consul-dc1"))
495 f.Flush()
496
497 assert.NoError(t, f.UpsertYAML(`
498 ---
499 apiVersion: getambassador.io/v3alpha1
500 kind: ConsulResolver
501 metadata:
502 name: consul-dc1
503 spec:
504 address: $CONSULHOST:9999
505 datacenter: dc1
506 `))
507 f.Flush()
508
509
510 snaps, err := getSnapshots(f, func(snap *snapshot.Snapshot) bool {
511 return (len(snap.Kubernetes.Mappings) > 0) && (len(snap.Kubernetes.TCPMappings) > 0) && (len(snap.Kubernetes.ConsulResolvers) > 0)
512 })
513 require.NoError(t, err)
514 require.Greater(t, len(snaps), 0)
515 snap = snaps[len(snaps)-1]
516
517
518
519 assert.Equal(t, []string{"add ConsulResolver consul-dc1", "delete ConsulResolver consul-dc1"}, deltaSummary(t, snaps...))
520
521
522 assert.Equal(t, "hello", snap.Kubernetes.Mappings[0].Name)
523 assert.Equal(t, "hello-tcp", snap.Kubernetes.TCPMappings[0].Name)
524
525
526 assert.Equal(t, "consul-1:9999", snap.Kubernetes.ConsulResolvers[0].Spec.Address)
527 }
528
View as plain text