1import logging
2from pathlib import Path
3from typing import TYPE_CHECKING, Optional
4
5import pytest
6
7from tests.selfsigned import TLSCerts
8from tests.utils import (
9 assert_valid_envoy_config,
10 econf_foreach_cluster,
11 module_and_mapping_manifests,
12)
13
14logging.basicConfig(
15 level=logging.INFO,
16 format="%(asctime)s test %(levelname)s: %(message)s",
17 datefmt="%Y-%m-%d %H:%M:%S",
18)
19
20logger = logging.getLogger("ambassador")
21
22from ambassador import IR, Config, EnvoyConfig
23from ambassador.fetch import ResourceFetcher
24from ambassador.utils import NullSecretHandler, SecretHandler, SecretInfo
25from tests.utils import default_listener_manifests
26
27if TYPE_CHECKING:
28 from ambassador.ir.irresource import IRResource # pragma: no cover
29
30
31class MockSecretHandler(SecretHandler):
32 def load_secret(
33 self, resource: "IRResource", secret_name: str, namespace: str
34 ) -> Optional[SecretInfo]:
35 return SecretInfo(
36 "fallback-self-signed-cert",
37 "ambassador",
38 "mocked-fallback-secret",
39 TLSCerts["acook"].pubcert,
40 TLSCerts["acook"].privkey,
41 decode_b64=False,
42 )
43
44
45def _get_envoy_config(yaml):
46
47 aconf = Config()
48 fetcher = ResourceFetcher(logger, aconf)
49 fetcher.parse_yaml(default_listener_manifests() + yaml, k8s=True)
50
51 aconf.load_all(fetcher.sorted())
52
53 secret_handler = NullSecretHandler(logger, None, None, "0")
54
55 ir = IR(aconf, file_checker=lambda path: True, secret_handler=secret_handler)
56
57 assert ir
58 return EnvoyConfig.generate(ir)
59
60
61@pytest.mark.compilertest
62def test_tracing_config_v3(tmp_path: Path):
63
64 aconf = Config()
65
66 yaml = (
67 module_and_mapping_manifests(None, [])
68 + "\n"
69 + """
70---
71apiVersion: getambassador.io/v3alpha1
72kind: TracingService
73metadata:
74 name: myts
75 namespace: default
76spec:
77 service: zipkin-test:9411
78 driver: zipkin
79 custom_tags:
80 - tag: ltag
81 literal:
82 value: avalue
83 - tag: etag
84 environment:
85 name: UNKNOWN_ENV_VAR
86 default_value: efallback
87 - tag: htag
88 request_header:
89 name: x-does-not-exist
90 default_value: hfallback
91"""
92 )
93
94 fetcher = ResourceFetcher(logger, aconf)
95 fetcher.parse_yaml(yaml, k8s=True)
96
97 aconf.load_all(fetcher.sorted())
98
99 secret_handler = MockSecretHandler(
100 logger, "mockery", str(tmp_path / "ambassador" / "snapshots"), "v1"
101 )
102 ir = IR(aconf, file_checker=lambda path: True, secret_handler=secret_handler)
103
104 assert ir
105
106 econf = EnvoyConfig.generate(ir)
107
108 # check if custom_tags are added
109 assert econf.as_dict()["static_resources"]["listeners"][0]["filter_chains"][0]["filters"][0][
110 "typed_config"
111 ]["tracing"] == {
112 "custom_tags": [
113 {"literal": {"value": "avalue"}, "tag": "ltag"},
114 {
115 "environment": {"default_value": "efallback", "name": "UNKNOWN_ENV_VAR"},
116 "tag": "etag",
117 },
118 {
119 "request_header": {"default_value": "hfallback", "name": "x-does-not-exist"},
120 "tag": "htag",
121 },
122 ]
123 }
124
125 bootstrap_config, ads_config, _ = econf.split_config()
126 assert "tracing" in bootstrap_config
127 assert bootstrap_config["tracing"] == {
128 "http": {
129 "name": "envoy.zipkin",
130 "typed_config": {
131 "@type": "type.googleapis.com/envoy.config.trace.v3.ZipkinConfig",
132 "collector_endpoint": "/api/v2/spans",
133 "collector_endpoint_version": "HTTP_JSON",
134 "trace_id_128bit": True,
135 "collector_cluster": "cluster_tracing_zipkin_test_9411_default",
136 },
137 }
138 }
139
140 ads_config.pop("@type", None)
141 assert_valid_envoy_config(ads_config, extra_dirs=[str(tmp_path / "ambassador" / "snapshots")])
142 assert_valid_envoy_config(
143 bootstrap_config, extra_dirs=[str(tmp_path / "ambassador" / "snapshots")]
144 )
145
146
147@pytest.mark.compilertest
148def test_tracing_zipkin_defaults():
149
150 yaml = """
151---
152apiVersion: getambassador.io/v3alpha1
153kind: TracingService
154metadata:
155 name: myts
156 namespace: default
157spec:
158 service: zipkin-test:9411
159 driver: zipkin
160"""
161
162 econf = _get_envoy_config(yaml)
163
164 bootstrap_config, _, _ = econf.split_config()
165 assert "tracing" in bootstrap_config
166
167 assert bootstrap_config["tracing"] == {
168 "http": {
169 "name": "envoy.zipkin",
170 "typed_config": {
171 "@type": "type.googleapis.com/envoy.config.trace.v3.ZipkinConfig",
172 "collector_endpoint": "/api/v2/spans",
173 "collector_endpoint_version": "HTTP_JSON",
174 "trace_id_128bit": True,
175 "collector_cluster": "cluster_tracing_zipkin_test_9411_default",
176 },
177 }
178 }
179
180
181@pytest.mark.compilertest
182def test_tracing_cluster_fields():
183
184 yaml = """
185---
186apiVersion: getambassador.io/v3alpha1
187kind: TracingService
188metadata:
189 name: myts
190 namespace: default
191spec:
192 service: zipkin-test:9411
193 driver: zipkin
194 stats_name: tracingservice
195"""
196
197 econf = _get_envoy_config(yaml)
198
199 bootstrap_config, _, _ = econf.split_config()
200 assert "tracing" in bootstrap_config
201
202 cluster_name = "cluster_tracing_zipkin_test_9411_default"
203 assert bootstrap_config["tracing"] == {
204 "http": {
205 "name": "envoy.zipkin",
206 "typed_config": {
207 "@type": "type.googleapis.com/envoy.config.trace.v3.ZipkinConfig",
208 "collector_endpoint": "/api/v2/spans",
209 "collector_endpoint_version": "HTTP_JSON",
210 "trace_id_128bit": True,
211 "collector_cluster": cluster_name,
212 },
213 }
214 }
215
216 def check_fields(cluster):
217 assert cluster["alt_stat_name"] == "tracingservice"
218
219 econf_foreach_cluster(econf.as_dict(), check_fields, name=cluster_name)
220
221
222@pytest.mark.compilertest
223def test_tracing_zipkin_invalid_collector_version():
224 """test to ensure that providing an improper value will result in an error and the tracer not included"""
225
226 yaml = """
227---
228apiVersion: getambassador.io/v3alpha1
229kind: TracingService
230metadata:
231 name: myts
232 namespace: default
233spec:
234 service: zipkin-test:9411
235 driver: zipkin
236 config:
237 collector_endpoint_version: "HTTP_JSON_V1"
238"""
239
240 econf = _get_envoy_config(yaml)
241
242 bootstrap_config, _, _ = econf.split_config()
243 assert "tracing" not in bootstrap_config
244
245
246@pytest.mark.compilertest
247def test_lightstep_not_supported(tmp_path: Path):
248
249 yaml = """
250---
251apiVersion: getambassador.io/v3alpha1
252kind: TracingService
253metadata:
254 name: tracing
255 namespace: ambassador
256spec:
257 service: lightstep:80
258 driver: lightstep
259 custom_tags:
260 - tag: ltag
261 literal:
262 value: avalue
263 - tag: etag
264 environment:
265 name: UNKNOWN_ENV_VAR
266 default_value: efallback
267 - tag: htag
268 request_header:
269 name: x-does-not-exist
270 default_value: hfallback
271 config:
272 access_token_file: /lightstep-credentials/access-token
273 propagation_modes: ["ENVOY", "TRACE_CONTEXT"]
274"""
275 econf = _get_envoy_config(yaml)
276 assert "ir.tracing" in econf.ir.aconf.errors
277
278 tracing_error = econf.ir.aconf.errors["ir.tracing"][0]["error"]
279 assert "'lightstep' driver is no longer supported" in tracing_error
280
281 bootstrap_config, _, _ = econf.split_config()
282 assert "tracing" not in bootstrap_config
View as plain text