Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions microservices/gatewayApi/clients/ocp_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,12 @@ def get_route_overrides(root_path, override_tag):
def eval_services(host_list, override_tag, data):
if data is not None and 'services' in data:
for service in data['services']:
service_has_tag = 'tags' in service and override_tag in service['tags']

if 'routes' in service:
for route in service['routes']:
if 'hosts' in route:
if override_tag in route['tags']:
if service_has_tag or ('tags' in route and override_tag in route['tags']):
if 'hosts' in route:
for host in route['hosts']:
if host not in host_list:
host_list.append(host)
63 changes: 61 additions & 2 deletions microservices/gatewayApi/tests/clients/test_ocp_routes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from clients.ocp_routes import eval_services

def test_eval_services():
def test_eval_services_route_tags():

data = {
"services": [
Expand Down Expand Up @@ -35,4 +35,63 @@ def test_eval_services():
host_list = []
eval_services(host_list, 'override-tag', data)
assert len(host_list) == 1
assert host_list[0] == 'host1'
assert host_list[0] == 'host1'

def test_eval_services_service_tags():

data = {
"services": [
{},
{
"routes": [
]
},
{
"routes": [
{
"hosts": [],
"tags": []
}
]
},
{
"routes": [
{
"hosts": [
"host1"
],
"tags": [
"tag1",
"override-tag"
]
}
]
},
{
"routes": [
{
"hosts": [
"host2"
],
"tags": []
},
{
"hosts": [
"host3"
],
"tags": []
}
],
"tags": [
"tag2",
"override-tag"
]
}
]
}
host_list = []
eval_services(host_list, 'override-tag', data)
assert len(host_list) == 3
assert host_list[0] == 'host1'
assert host_list[1] == 'host2'
assert host_list[2] == 'host3'
33 changes: 31 additions & 2 deletions microservices/gatewayApi/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ def json():
}
return Response
elif (path == 'http://kong/certificates?tags=gwa.ns.mytest' or
path == 'http://kong/certificates?tags=gwa.ns.sescookie'):
path == 'http://kong/certificates?tags=gwa.ns.sescookie' or
path == 'http://kong/certificates?tags=gwa.ns.dclass'):
class Response:
def json():
return {
Expand Down Expand Up @@ -150,11 +151,33 @@ class Response:
'hosts': ['myapi.api.gov.bc.ca'],
'ns_attributes': {'perm-domains': ['.api.gov.bc.ca', '.cluster.local']},
'overrides': {
'aps.route.session.cookie.enabled': ['myapi.api.gov.bc.ca']
'aps.route.session.cookie.enabled': ['myapi.api.gov.bc.ca'],
"aps.route.dataclass.low": [],
"aps.route.dataclass.medium": [],
"aps.route.dataclass.high": [],
"aps.route.dataclass.public": []
},
'select_tag': 'ns.sescookie.dev'
}

assert json.dumps(kwargs['json'], sort_keys=True) == json.dumps(matched, sort_keys=True)
return Response
elif (url == 'http://kube-api/namespaces/dclass/routes'):
class Response:
status_code = 201
matched = {
'hosts': ['myapi.api.gov.bc.ca'],
'ns_attributes': {'perm-domains': ['.api.gov.bc.ca', '.cluster.local']},
'overrides': {
'aps.route.session.cookie.enabled': [],
"aps.route.dataclass.low": [],
"aps.route.dataclass.medium": [],
"aps.route.dataclass.high": ['myapi.api.gov.bc.ca'],
"aps.route.dataclass.public": []
},
'select_tag': 'ns.dclass.dev'
}

assert json.dumps(kwargs['json'], sort_keys=True) == json.dumps(matched, sort_keys=True)
return Response
elif (url == 'http://kube-api/namespaces/ns1/routes'):
Expand All @@ -179,6 +202,12 @@ class Response:
def json():
return {}
return Response
elif (url == 'http://kube-api/namespaces/dclass/local_tls'):
class Response:
status_code = 200
def json():
return {}
return Response
else:
raise Exception(url)

Expand Down
22 changes: 22 additions & 0 deletions microservices/gatewayApi/tests/routes/v2/test_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,28 @@ def test_happy_with_session_cookie_gateway_call(client):
assert response.status_code == 200
assert json.dumps(response.json) == '{"message": "Sync successful.", "results": "Deck reported no changes"}'

def test_happy_with_data_class_gateway_call(client):
configFile = '''
services:
- name: my-service
host: myupstream.local
tags: ["ns.dclass.dev", "aps.route.dataclass.high"]
routes:
- name: route-1
hosts: [ myapi.api.gov.bc.ca ]
tags: ["ns.dclass.dev"]
plugins:
- name: acl-auth
tags: ["ns.dclass.dev"]
'''

data={
"configFile": configFile,
"dryRun": False
}
response = client.put('/v2/namespaces/dclass/gateway', json=data)
assert response.status_code == 200
assert json.dumps(response.json) == '{"message": "Sync successful.", "results": "Deck reported no changes"}'

def test_success_mtls_reference(client):
configFile = '''
Expand Down
7 changes: 6 additions & 1 deletion microservices/gatewayApi/v2/routes/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,11 @@ def write_config(namespace: str) -> object:
"select_tag": selectTag,
"ns_attributes": ns_attributes.getAttrs(),
"overrides": {
"aps.route.session.cookie.enabled": get_route_overrides(tempFolder, "aps.route.session.cookie.enabled")
"aps.route.session.cookie.enabled": get_route_overrides(tempFolder, "aps.route.session.cookie.enabled"),
"aps.route.dataclass.low": get_route_overrides(tempFolder, "aps.route.dataclass.low"),
"aps.route.dataclass.medium": get_route_overrides(tempFolder, "aps.route.dataclass.medium"),
"aps.route.dataclass.high": get_route_overrides(tempFolder, "aps.route.dataclass.high"),
"aps.route.dataclass.public": get_route_overrides(tempFolder, "aps.route.dataclass.public"),
}
}
log.debug("[%s] - Initiating request to kube API %s" % (dp, route_payload))
Expand Down Expand Up @@ -622,6 +626,7 @@ def traverse_tags_transform(yaml, namespace, required_tag):
object_count = object_count + traverse_tags_transform(item, namespace, required_tag)
return object_count


def traverse_has_ns_qualifier(yaml, required_tag):
log = app.logger
traversables = ['services', 'routes', 'plugins', 'upstreams', 'consumers', 'certificates', 'ca_certificates']
Expand Down
8 changes: 8 additions & 0 deletions microservices/gatewayJobScheduler/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,21 @@ def transform_data_by_ns(data):

# check if namespace has data plane attribute and needs to be synced
if ns_attr_dict[namespace].get('perm-data-plane', [''])[0] == os.getenv('DATA_PLANE'):
# extract override values
session_cookie_enabled = False
if 'aps.route.session.cookie.enabled' in route_obj['tags']:
session_cookie_enabled = True
data_class = None
for tag in route_obj['tags']:
if tag.startswith('aps.route.dataclass'):
data_class = tag.split(".")[-1]
break

for host in route_obj['hosts']:
name = 'wild-%s-%s' % (select_tag.replace(".", "-"), host)
ns_dict[namespace].append({"name": name, "selectTag": select_tag, "host": host,
"sessionCookieEnabled": session_cookie_enabled,
"dataClass": data_class,
"dataPlane": os.getenv('DATA_PLANE')})
return ns_dict
except Exception as err:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ def test_happy_transform_data_by_ns():
]
}
]
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"}]}'
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"}]}'

def test_happy_transform_data_by_ns_with_override():
def test_happy_transform_data_by_ns_with_override_session_cookie():
with mock.patch('clients.namespace.admin_api') as mock_admin_api:
set_mock_admin_api_response(mock_admin_api)

Expand All @@ -30,8 +30,22 @@ def test_happy_transform_data_by_ns_with_override():
]
}
]
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"}]}'
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"}]}'

def test_happy_transform_data_by_ns_with_override_data_plane():
with mock.patch('clients.namespace.admin_api') as mock_admin_api:
set_mock_admin_api_response(mock_admin_api)

data = [
{
"name": "route-1",
"tags": [ "ns.ns1", "aps.route.dataclass.high"],
"hosts": [
"host-1"
]
}
]
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"}]}'

def set_mock_admin_api_response(dt):
class mock_admin_api:
Expand Down
24 changes: 20 additions & 4 deletions microservices/kubeApi/clients/ocp_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@
}
}

data_class_mapping = {
'aps.route.dataclass.low': 'low',
'aps.route.dataclass.medium': 'medium',
'aps.route.dataclass.high': 'high',
'aps.route.dataclass.public': 'public'
}

def read_and_indent(full_path, indent):
pad = " "
stream = open(full_path, 'r')
Expand Down Expand Up @@ -150,12 +157,21 @@ def prepare_apply_routes(ns, select_tag, hosts, root_path, data_plane, ns_templa
with open(out_filename, 'w') as out_file:
index = 1
for host in hosts:
data_class_annotation = ''
templ_version = ns_template_version
if overrides and 'aps.route.session.cookie.enabled' in overrides and host in overrides['aps.route.session.cookie.enabled']:
templ_version = 'v1'
if overrides:
if 'aps.route.session.cookie.enabled' in overrides and host in overrides['aps.route.session.cookie.enabled']:
templ_version = 'v1'
logger.debug("[%s] %s Template version override applied %s", select_tag, host, templ_version)

for tag, value in data_class_mapping.items():
if overrides.get(tag) and host in overrides[tag]:
data_class = value
data_class_annotation = f' aviinfrasetting.ako.vmware.com/name: "dataclass-{value}"'
logger.debug("[%s] %s Dataclass override applied %s -> %s", select_tag, host, tag, data_class)
else:
logger.debug("[%s] %s No override applied %s", select_tag, hosts, str(overrides))

route_template = ROUTES[templ_version]["ROUTE"]

# If host transformation is disabled, then select the appropriate
Expand All @@ -179,7 +195,7 @@ def prepare_apply_routes(ns, select_tag, hosts, root_path, data_plane, ns_templa
(select_tag, index, select_tag.replace('.', '-'), host, resource_version))
out_file.write(route_template.substitute(name=name, ns=ns, select_tag=select_tag, resource_version=resource_version, host=host, path='/',
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,
template_version=templ_version))
data_class_annotation=data_class_annotation, template_version=templ_version))
out_file.write('\n---\n')
index = index + 1
out_file.close()
Expand Down
10 changes: 8 additions & 2 deletions microservices/kubeApi/routers/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class BulkSyncRequest(BaseModel):
host: str
# Indicator of whether session cookies should be enabled by the Kube-API
sessionCookieEnabled: bool
# Data class for Emerald Cluster routes
dataClass: str


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

Expand Down Expand Up @@ -199,6 +202,9 @@ async def verify_and_create_routes(namespace: str, request: Request):
overrides = {}
if 'sessionCookieEnabled' in route and route['sessionCookieEnabled']:
overrides['aps.route.session.cookie.enabled'] = [route['host']]

if 'dataClass' in route and route['dataClass']:
overrides[f'aps.route.dataclass.{route["dataClass"]}'] = [route['host']]

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

def build_ref(v):
return "%s%s%s%s%s" % (v['name'], v['selectTag'], v['host'], v['dataPlane'], v['sessionCookieEnabled'])
return "%s%s%s%s%s%s" % (v['name'], v['selectTag'], v['host'], v['dataPlane'], v['sessionCookieEnabled'], v['dataClass'])

def in_list_by_name(match, list):
for item in list:
Expand Down
1 change: 1 addition & 0 deletions microservices/kubeApi/templates/v1/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
resourceVersion: "${resource_version}"
annotations:
haproxy.router.openshift.io/timeout: 30m
${data_class_annotation}
labels:
aps-generated-by: "gwa-cli"
aps-published-on: "${fmt_time}"
Expand Down
1 change: 1 addition & 0 deletions microservices/kubeApi/templates/v2/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
haproxy.router.openshift.io/balance: random
haproxy.router.openshift.io/disable_cookies: 'true'
haproxy.router.openshift.io/timeout: 30m
${data_class_annotation}
labels:
aps-generated-by: "gwa-cli"
aps-published-on: "${fmt_time}"
Expand Down
3 changes: 2 additions & 1 deletion microservices/kubeApi/tests/routers/test_add_route.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
haproxy.router.openshift.io/balance: random
haproxy.router.openshift.io/disable_cookies: 'true'
haproxy.router.openshift.io/timeout: 30m

labels:
aps-generated-by: "gwa-cli"
aps-published-on: "2024.05-May.08"
Expand Down Expand Up @@ -50,7 +51,7 @@ def mock_apply_routes (rootPath):
with open("%s/routes-current.yaml" % rootPath) as f:
assert routes_current_yaml == f.read()

def test_add_route_override(client):
def test_add_route(client):
with mock.patch('clients.ocp_routes.time_secs') as dt:
dt.return_value = 1715153983

Expand Down
Loading
Loading