Skip to content

Commit 131d15c

Browse files
committed
Update gatewayApi for different response + error messaging
1 parent 3ed3865 commit 131d15c

File tree

5 files changed

+80
-42
lines changed

5 files changed

+80
-42
lines changed

microservices/gatewayApi/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Run `pip install -r requirements.txt` to install dependencies and `python3 wsgi.
2222
Run `docker build . -t gwa_kong_api` to build the docker container and the following commands to run it
2323

2424
```sh
25-
hostip=$(ifconfig en0 | awk '$1 == "inet" {print $2}')
25+
hostip=$(hostname -I | awk '{print $1}')
2626

2727
docker run -ti --rm \
2828
-e CONFIG_PATH=/tmp/production.json -e ENVIRONMENT=production \
@@ -40,6 +40,7 @@ docker run -ti --rm \
4040
-e HOST_TRANSFORM_BASE_URL=api.cloud \
4141
-e PLUGINS_RATELIMITING_REDIS_PASSWORD="" \
4242
-e DATA_PLANES_CONFIG_PATH=/dp/data_planes_config.json \
43+
-e COMPATIBILITY_API_URL=https://compatibility-api.cloud \
4344
-v `pwd`/_tmp:/ssl \
4445
-v `pwd`/_tmp:/dp/ \
4546
-v ~/.kube/config:/root/.kube/config \
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import requests
22
from flask import current_app as app
33

4-
def check_kong3_compatibility(namespace: str, config: dict) -> tuple[bool, str, dict | None]:
4+
def check_kong3_compatibility(namespace: str, config: dict) -> tuple[bool, str, list[str], dict | None]:
55
"""
66
Check Kong 3.x compatibility of configuration using compatibility API
7-
Returns (is_compatible, warning_message, kong2_config)
7+
Returns (is_compatible, warning_message, failed_routes, kong2_config)
88
"""
99
log = app.logger
1010

@@ -16,11 +16,13 @@ def check_kong3_compatibility(namespace: str, config: dict) -> tuple[bool, str,
1616
res.raise_for_status()
1717

1818
data = res.json()
19+
log.debug("[%s] - Compatibility API result for Kong 3 compatibility check: %s" % (namespace, data["kong3_compatible"]))
1920
return (
2021
data["kong3_compatible"],
21-
data["conversion_output"] if not data["kong3_compatible"] else "",
22+
data["message"],
23+
data["failed_routes"],
2224
data["kong2_output"]
2325
)
2426
except Exception as e:
2527
log.error("[%s] - Compatibility API error: %s" % (namespace, str(e)))
26-
return (True, "", {}) # Fail open - assume compatible if service unavailable
28+
return (True, "", [], {}) # Fail open - assume compatible if service unavailable

microservices/gatewayApi/tests/conftest.py

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -297,33 +297,45 @@ def mock_requests_post(url, json=None, **kwargs):
297297
if url == 'http://compatibility-api/configs':
298298
log.debug(f"Mocking compatibility API: {url}")
299299
class Response:
300-
status_code = 200
301300
def json(self):
302-
# Default to compatible if no paths
303-
is_compatible = True
304-
has_paths = False
301+
# Check if any routes have regex without tilde
302+
has_incompatible = False
303+
failed_routes = []
304+
305+
if json and "services" in json:
306+
for service in json["services"]:
307+
if "routes" in service:
308+
for route in service["routes"]:
309+
if "paths" in route and "name" in route:
310+
for path in route["paths"]:
311+
if "*" in path and not path.startswith("~"):
312+
has_incompatible = True
313+
failed_routes.append(route["name"])
314+
315+
message = (
316+
"Gateway configuration is compatible with Kong 3."
317+
if not has_incompatible else
318+
"WARNING: Kong 3 incompatible routes found.\n\n"
319+
"APS will soon be updated to use Kong gateway version 3.\n"
320+
"Kong 3 requires that regular expressions in route paths start with a '~' character.\n\n"
321+
"For related information, please visit:\n"
322+
"https://docs.konghq.com/deck/latest/3.0-upgrade\n\n"
323+
"Please update the following routes:"
324+
)
305325

306-
if json and 'services' in json:
307-
for service in json['services']:
308-
if 'routes' in service:
309-
for route in service['routes']:
310-
if 'paths' in route:
311-
has_paths = True
312-
# If any path doesn't start with ~, mark as incompatible
313-
for path in route['paths']:
314-
if not path.startswith('~'):
315-
is_compatible = False
316-
break
317-
318326
return {
319-
"kong3_compatible": is_compatible,
320-
"conversion_output": "Warning: unsupported routes' paths format with Kong version 3.0" if not is_compatible else "",
327+
"kong3_compatible": not has_incompatible,
328+
"message": message,
329+
"failed_routes": failed_routes,
321330
"kong2_output": json
322331
}
323-
332+
324333
def raise_for_status(self):
325-
if self.status_code >= 400:
334+
if self.status_code != 200:
326335
raise Exception(f"HTTP {self.status_code}")
336+
337+
status_code = 200
338+
327339
return Response()
328340
raise Exception(f"Unexpected URL: {url}")
329341

microservices/gatewayApi/tests/routes/v2/test_gateway.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def test_success_mtls_reference(client):
169169
assert json.dumps(response.json) == '{"message": "Sync successful.", "results": "Deck reported no changes"}'
170170

171171
def test_kong3_compatibility_warning(client):
172-
"""Test that Kong 3 incompatible config generates warning but still succeeds"""
172+
"""Test that Kong 3 incompatible config generates warning"""
173173
configFile = '''
174174
services:
175175
- name: my-service
@@ -178,7 +178,11 @@ def test_kong3_compatibility_warning(client):
178178
routes:
179179
- name: route-1
180180
hosts: [ myapi.api.gov.bc.ca ]
181-
paths: [ "/example*" ]
181+
paths: [ "/path*" ]
182+
tags: ["ns.mytest", "another2"]
183+
- name: route-2
184+
hosts: [ myapi2.api.gov.bc.ca ]
185+
paths: [ "/other*" ]
182186
tags: ["ns.mytest", "another2"]
183187
'''
184188

@@ -190,4 +194,11 @@ def test_kong3_compatibility_warning(client):
190194
assert response.status_code == 200
191195
response_data = response.json
192196
assert response_data["message"] == "Sync successful."
193-
assert "Kong 3 Compatibility Warning" in response_data["results"]
197+
198+
# Verify warning message and failed routes are in results
199+
results = response_data["results"]
200+
assert "WARNING: Kong 3 incompatible routes found" in results
201+
assert "route-1" in results
202+
assert "route-2" in results
203+
# Routes should only be listed once even if multiple incompatible paths
204+
assert results.count("route-1") == 1

microservices/gatewayApi/v2/routes/gateway.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,10 @@ def write_config(namespace: str) -> object:
219219
orig_config = prep_submitted_config(clone_yaml_files(yaml_documents))
220220

221221
update_routes_flag = False
222+
223+
warning_message = ""
224+
all_failed_routes = []
225+
has_incompatible_routes = False
222226

223227
for index, gw_config in enumerate(yaml_documents):
224228
log.info("[%s] Parsing file %s" % (namespace, index))
@@ -240,19 +244,17 @@ def write_config(namespace: str) -> object:
240244
# Enrich the rate-limiting plugin with the appropriate Redis details
241245
plugins_transformations(namespace, gw_config)
242246

243-
# Check Kong 3.x compatibility
244-
is_compatible, warning, kong2_config = check_kong3_compatibility(namespace, gw_config)
245-
if is_compatible:
246-
log.info("[%s] Kong 3 compatibility check passed" % (namespace))
247-
# If Kong 3 compatibility check passed, use the downgraded Kong 2 config
248-
# This is a temporary measure and can be removed once Kong 3 is deployed
247+
# Check Kong 3 compatibility
248+
is_compatible, warning_message, failed_routes, kong2_config = check_kong3_compatibility(namespace, gw_config)
249+
250+
# Track incompatible routes
251+
if not is_compatible:
252+
has_incompatible_routes = True
253+
all_failed_routes.extend(failed_routes)
254+
255+
# Use kong2_config (which has compatibility tags) regardless of compatibility status
256+
if kong2_config:
249257
gw_config = kong2_config
250-
else:
251-
log.info("[%s] Kong 3 compatibility warning: %s" % (namespace, warning))
252-
# Add warning to the final results
253-
if 'warnings' not in locals():
254-
warnings = []
255-
warnings.append("Kong 3 Compatibility Warning: %s" % warning)
256258

257259
# After enrichments, dump config to file
258260
with open("%s/%s" % (tempFolder, 'config-%02d.yaml' % index), 'w') as file:
@@ -423,8 +425,18 @@ def write_config(namespace: str) -> object:
423425
record_gateway_event(event_id, 'published', 'completed', namespace, blob=orig_config)
424426

425427
results = mask(out.decode('utf-8'))
426-
if 'warnings' in locals() and warnings:
427-
results = results + "\n\n" + "\n".join(warnings)
428+
429+
# Add Kong 3 compatibility warning if needed
430+
if has_incompatible_routes:
431+
# Add unique failed routes
432+
unique_failed_routes = sorted(set(all_failed_routes))
433+
route_list = "\n".join(f" - {route}" for route in unique_failed_routes)
434+
warning_message = warning_message + "\n" + route_list
435+
436+
# Note: When all routes are compatible, no special response is given.
437+
# To add the success message (contained in warning_message), move this
438+
# line out of the if block above.
439+
results = results + warning_message
428440

429441
return make_response(jsonify(message=message, results=results))
430442

0 commit comments

Comments
 (0)