Skip to content

Commit 89985a9

Browse files
authored
Merge pull request #128 from bcgov/dev
Feature/dataclass annotation (#127)
2 parents db633c3 + 67a55ba commit 89985a9

File tree

17 files changed

+596
-112
lines changed

17 files changed

+596
-112
lines changed

microservices/gatewayApi/clients/ocp_routes.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,12 @@ def get_route_overrides(root_path, override_tag):
263263
def eval_services(host_list, override_tag, data):
264264
if data is not None and 'services' in data:
265265
for service in data['services']:
266+
service_has_tag = 'tags' in service and override_tag in service['tags']
267+
266268
if 'routes' in service:
267269
for route in service['routes']:
268-
if 'hosts' in route:
269-
if override_tag in route['tags']:
270+
if service_has_tag or ('tags' in route and override_tag in route['tags']):
271+
if 'hosts' in route:
270272
for host in route['hosts']:
271273
if host not in host_list:
272274
host_list.append(host)

microservices/gatewayApi/tests/clients/test_ocp_routes.py

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from clients.ocp_routes import eval_services
22

3-
def test_eval_services():
3+
def test_eval_services_route_tags():
44

55
data = {
66
"services": [
@@ -35,4 +35,63 @@ def test_eval_services():
3535
host_list = []
3636
eval_services(host_list, 'override-tag', data)
3737
assert len(host_list) == 1
38-
assert host_list[0] == 'host1'
38+
assert host_list[0] == 'host1'
39+
40+
def test_eval_services_service_tags():
41+
42+
data = {
43+
"services": [
44+
{},
45+
{
46+
"routes": [
47+
]
48+
},
49+
{
50+
"routes": [
51+
{
52+
"hosts": [],
53+
"tags": []
54+
}
55+
]
56+
},
57+
{
58+
"routes": [
59+
{
60+
"hosts": [
61+
"host1"
62+
],
63+
"tags": [
64+
"tag1",
65+
"override-tag"
66+
]
67+
}
68+
]
69+
},
70+
{
71+
"routes": [
72+
{
73+
"hosts": [
74+
"host2"
75+
],
76+
"tags": []
77+
},
78+
{
79+
"hosts": [
80+
"host3"
81+
],
82+
"tags": []
83+
}
84+
],
85+
"tags": [
86+
"tag2",
87+
"override-tag"
88+
]
89+
}
90+
]
91+
}
92+
host_list = []
93+
eval_services(host_list, 'override-tag', data)
94+
assert len(host_list) == 3
95+
assert host_list[0] == 'host1'
96+
assert host_list[1] == 'host2'
97+
assert host_list[2] == 'host3'

microservices/gatewayApi/tests/conftest.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ def json():
9191
}
9292
return Response
9393
elif (path == 'http://kong/certificates?tags=gwa.ns.mytest' or
94-
path == 'http://kong/certificates?tags=gwa.ns.sescookie'):
94+
path == 'http://kong/certificates?tags=gwa.ns.sescookie' or
95+
path == 'http://kong/certificates?tags=gwa.ns.dclass'):
9596
class Response:
9697
def json():
9798
return {
@@ -150,11 +151,33 @@ class Response:
150151
'hosts': ['myapi.api.gov.bc.ca'],
151152
'ns_attributes': {'perm-domains': ['.api.gov.bc.ca', '.cluster.local']},
152153
'overrides': {
153-
'aps.route.session.cookie.enabled': ['myapi.api.gov.bc.ca']
154+
'aps.route.session.cookie.enabled': ['myapi.api.gov.bc.ca'],
155+
"aps.route.dataclass.low": [],
156+
"aps.route.dataclass.medium": [],
157+
"aps.route.dataclass.high": [],
158+
"aps.route.dataclass.public": []
154159
},
155160
'select_tag': 'ns.sescookie.dev'
156161
}
157162

163+
assert json.dumps(kwargs['json'], sort_keys=True) == json.dumps(matched, sort_keys=True)
164+
return Response
165+
elif (url == 'http://kube-api/namespaces/dclass/routes'):
166+
class Response:
167+
status_code = 201
168+
matched = {
169+
'hosts': ['myapi.api.gov.bc.ca'],
170+
'ns_attributes': {'perm-domains': ['.api.gov.bc.ca', '.cluster.local']},
171+
'overrides': {
172+
'aps.route.session.cookie.enabled': [],
173+
"aps.route.dataclass.low": [],
174+
"aps.route.dataclass.medium": [],
175+
"aps.route.dataclass.high": ['myapi.api.gov.bc.ca'],
176+
"aps.route.dataclass.public": []
177+
},
178+
'select_tag': 'ns.dclass.dev'
179+
}
180+
158181
assert json.dumps(kwargs['json'], sort_keys=True) == json.dumps(matched, sort_keys=True)
159182
return Response
160183
elif (url == 'http://kube-api/namespaces/ns1/routes'):
@@ -179,6 +202,12 @@ class Response:
179202
def json():
180203
return {}
181204
return Response
205+
elif (url == 'http://kube-api/namespaces/dclass/local_tls'):
206+
class Response:
207+
status_code = 200
208+
def json():
209+
return {}
210+
return Response
182211
else:
183212
raise Exception(url)
184213

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,28 @@ def test_happy_with_session_cookie_gateway_call(client):
9898
assert response.status_code == 200
9999
assert json.dumps(response.json) == '{"message": "Sync successful.", "results": "Deck reported no changes"}'
100100

101+
def test_happy_with_data_class_gateway_call(client):
102+
configFile = '''
103+
services:
104+
- name: my-service
105+
host: myupstream.local
106+
tags: ["ns.dclass.dev", "aps.route.dataclass.high"]
107+
routes:
108+
- name: route-1
109+
hosts: [ myapi.api.gov.bc.ca ]
110+
tags: ["ns.dclass.dev"]
111+
plugins:
112+
- name: acl-auth
113+
tags: ["ns.dclass.dev"]
114+
'''
115+
116+
data={
117+
"configFile": configFile,
118+
"dryRun": False
119+
}
120+
response = client.put('/v2/namespaces/dclass/gateway', json=data)
121+
assert response.status_code == 200
122+
assert json.dumps(response.json) == '{"message": "Sync successful.", "results": "Deck reported no changes"}'
101123

102124
def test_success_mtls_reference(client):
103125
configFile = '''

microservices/gatewayApi/v2/routes/gateway.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,11 @@ def write_config(namespace: str) -> object:
339339
"select_tag": selectTag,
340340
"ns_attributes": ns_attributes.getAttrs(),
341341
"overrides": {
342-
"aps.route.session.cookie.enabled": get_route_overrides(tempFolder, "aps.route.session.cookie.enabled")
342+
"aps.route.session.cookie.enabled": get_route_overrides(tempFolder, "aps.route.session.cookie.enabled"),
343+
"aps.route.dataclass.low": get_route_overrides(tempFolder, "aps.route.dataclass.low"),
344+
"aps.route.dataclass.medium": get_route_overrides(tempFolder, "aps.route.dataclass.medium"),
345+
"aps.route.dataclass.high": get_route_overrides(tempFolder, "aps.route.dataclass.high"),
346+
"aps.route.dataclass.public": get_route_overrides(tempFolder, "aps.route.dataclass.public"),
343347
}
344348
}
345349
log.debug("[%s] - Initiating request to kube API %s" % (dp, route_payload))
@@ -622,6 +626,7 @@ def traverse_tags_transform(yaml, namespace, required_tag):
622626
object_count = object_count + traverse_tags_transform(item, namespace, required_tag)
623627
return object_count
624628

629+
625630
def traverse_has_ns_qualifier(yaml, required_tag):
626631
log = app.logger
627632
traversables = ['services', 'routes', 'plugins', 'upstreams', 'consumers', 'certificates', 'ca_certificates']

microservices/gatewayJobScheduler/app.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,21 @@ def transform_data_by_ns(data):
2323

2424
# check if namespace has data plane attribute and needs to be synced
2525
if ns_attr_dict[namespace].get('perm-data-plane', [''])[0] == os.getenv('DATA_PLANE'):
26+
# extract override values
2627
session_cookie_enabled = False
2728
if 'aps.route.session.cookie.enabled' in route_obj['tags']:
2829
session_cookie_enabled = True
30+
data_class = None
31+
for tag in route_obj['tags']:
32+
if tag.startswith('aps.route.dataclass'):
33+
data_class = tag.split(".")[-1]
34+
break
35+
2936
for host in route_obj['hosts']:
3037
name = 'wild-%s-%s' % (select_tag.replace(".", "-"), host)
3138
ns_dict[namespace].append({"name": name, "selectTag": select_tag, "host": host,
3239
"sessionCookieEnabled": session_cookie_enabled,
40+
"dataClass": data_class,
3341
"dataPlane": os.getenv('DATA_PLANE')})
3442
return ns_dict
3543
except Exception as err:

microservices/gatewayJobScheduler/tests/test_transform_data_by_ns.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ def test_happy_transform_data_by_ns():
1515
]
1616
}
1717
]
18-
assert json.dumps(transform_data_by_ns(data)) == '{"ns1": [{"name": "wild-ns-ns1-host-1", "selectTag": "ns.ns1", "host": "host-1", "sessionCookieEnabled": false, "dataPlane": "test-dp"}]}'
18+
assert json.dumps(transform_data_by_ns(data)) == '{"ns1": [{"name": "wild-ns-ns1-host-1", "selectTag": "ns.ns1", "host": "host-1", "sessionCookieEnabled": false, "dataClass": null, "dataPlane": "test-dp"}]}'
1919

20-
def test_happy_transform_data_by_ns_with_override():
20+
def test_happy_transform_data_by_ns_with_override_session_cookie():
2121
with mock.patch('clients.namespace.admin_api') as mock_admin_api:
2222
set_mock_admin_api_response(mock_admin_api)
2323

@@ -30,8 +30,22 @@ def test_happy_transform_data_by_ns_with_override():
3030
]
3131
}
3232
]
33-
assert json.dumps(transform_data_by_ns(data)) == '{"ns1": [{"name": "wild-ns-ns1-host-1", "selectTag": "ns.ns1", "host": "host-1", "sessionCookieEnabled": true, "dataPlane": "test-dp"}]}'
33+
assert json.dumps(transform_data_by_ns(data)) == '{"ns1": [{"name": "wild-ns-ns1-host-1", "selectTag": "ns.ns1", "host": "host-1", "sessionCookieEnabled": true, "dataClass": null, "dataPlane": "test-dp"}]}'
3434

35+
def test_happy_transform_data_by_ns_with_override_data_plane():
36+
with mock.patch('clients.namespace.admin_api') as mock_admin_api:
37+
set_mock_admin_api_response(mock_admin_api)
38+
39+
data = [
40+
{
41+
"name": "route-1",
42+
"tags": [ "ns.ns1", "aps.route.dataclass.high"],
43+
"hosts": [
44+
"host-1"
45+
]
46+
}
47+
]
48+
assert json.dumps(transform_data_by_ns(data)) == '{"ns1": [{"name": "wild-ns-ns1-host-1", "selectTag": "ns.ns1", "host": "host-1", "sessionCookieEnabled": false, "dataClass": "high", "dataPlane": "test-dp"}]}'
3549

3650
def set_mock_admin_api_response(dt):
3751
class mock_admin_api:

microservices/kubeApi/clients/ocp_routes.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@
2828
}
2929
}
3030

31+
data_class_mapping = {
32+
'aps.route.dataclass.low': 'low',
33+
'aps.route.dataclass.medium': 'medium',
34+
'aps.route.dataclass.high': 'high',
35+
'aps.route.dataclass.public': 'public'
36+
}
37+
3138
def read_and_indent(full_path, indent):
3239
pad = " "
3340
stream = open(full_path, 'r')
@@ -150,12 +157,21 @@ def prepare_apply_routes(ns, select_tag, hosts, root_path, data_plane, ns_templa
150157
with open(out_filename, 'w') as out_file:
151158
index = 1
152159
for host in hosts:
160+
data_class_annotation = ''
153161
templ_version = ns_template_version
154-
if overrides and 'aps.route.session.cookie.enabled' in overrides and host in overrides['aps.route.session.cookie.enabled']:
155-
templ_version = 'v1'
162+
if overrides:
163+
if 'aps.route.session.cookie.enabled' in overrides and host in overrides['aps.route.session.cookie.enabled']:
164+
templ_version = 'v1'
165+
logger.debug("[%s] %s Template version override applied %s", select_tag, host, templ_version)
166+
167+
for tag, value in data_class_mapping.items():
168+
if overrides.get(tag) and host in overrides[tag]:
169+
data_class = value
170+
data_class_annotation = f' aviinfrasetting.ako.vmware.com/name: "dataclass-{value}"'
171+
logger.debug("[%s] %s Dataclass override applied %s -> %s", select_tag, host, tag, data_class)
156172
else:
157173
logger.debug("[%s] %s No override applied %s", select_tag, hosts, str(overrides))
158-
174+
159175
route_template = ROUTES[templ_version]["ROUTE"]
160176

161177
# If host transformation is disabled, then select the appropriate
@@ -179,7 +195,7 @@ def prepare_apply_routes(ns, select_tag, hosts, root_path, data_plane, ns_templa
179195
(select_tag, index, select_tag.replace('.', '-'), host, resource_version))
180196
out_file.write(route_template.substitute(name=name, ns=ns, select_tag=select_tag, resource_version=resource_version, host=host, path='/',
181197
ssl_ref=ssl_ref, ssl_key=ssl_key, ssl_crt=ssl_crt, service_name=data_plane, timestamp=ts, fmt_time=fmt_time, data_plane=data_plane,
182-
template_version=templ_version))
198+
data_class_annotation=data_class_annotation, template_version=templ_version))
183199
out_file.write('\n---\n')
184200
index = index + 1
185201
out_file.close()

microservices/kubeApi/routers/routes.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ class BulkSyncRequest(BaseModel):
4141
host: str
4242
# Indicator of whether session cookies should be enabled by the Kube-API
4343
sessionCookieEnabled: bool
44+
# Data class for Emerald Cluster routes
45+
dataClass: str
4446

4547

4648
@router.put("/namespaces/{namespace}/routes", status_code=201, dependencies=[Depends(verify_credentials)])
@@ -170,7 +172,8 @@ async def verify_and_create_routes(namespace: str, request: Request):
170172
"selectTag": route["metadata"]["labels"]["aps-select-tag"],
171173
"host": route["spec"]["host"],
172174
"dataPlane": route["spec"]["to"]["name"],
173-
"sessionCookieEnabled": True if route["metadata"]["labels"].get("aps-template-version") == "v1" else False
175+
"sessionCookieEnabled": True if route["metadata"]["labels"].get("aps-template-version") == "v1" else False,
176+
"dataClass": route["metadata"]["annotations"].get("aviinfrasetting.ako.vmware.com/name").split("-")[-1] if route["metadata"]["annotations"].get("aviinfrasetting.ako.vmware.com/name") else None
174177
}
175178
)
176179

@@ -199,6 +202,9 @@ async def verify_and_create_routes(namespace: str, request: Request):
199202
overrides = {}
200203
if 'sessionCookieEnabled' in route and route['sessionCookieEnabled']:
201204
overrides['aps.route.session.cookie.enabled'] = [route['host']]
205+
206+
if 'dataClass' in route and route['dataClass']:
207+
overrides[f'aps.route.dataclass.{route["dataClass"]}'] = [route['host']]
202208

203209
route_count = prepare_apply_routes(namespace, route['selectTag'], [
204210
route['host']], source_folder, route["dataPlane"], ns_template_version, overrides)
@@ -258,7 +264,7 @@ def in_list(match, list):
258264
return False
259265

260266
def build_ref(v):
261-
return "%s%s%s%s%s" % (v['name'], v['selectTag'], v['host'], v['dataPlane'], v['sessionCookieEnabled'])
267+
return "%s%s%s%s%s%s" % (v['name'], v['selectTag'], v['host'], v['dataPlane'], v['sessionCookieEnabled'], v['dataClass'])
262268

263269
def in_list_by_name(match, list):
264270
for item in list:

microservices/kubeApi/templates/v1/routes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
resourceVersion: "${resource_version}"
99
annotations:
1010
haproxy.router.openshift.io/timeout: 30m
11+
${data_class_annotation}
1112
labels:
1213
aps-generated-by: "gwa-cli"
1314
aps-published-on: "${fmt_time}"

0 commit comments

Comments
 (0)