Skip to content

Commit

Permalink
Add gateway listener editing support
Browse files Browse the repository at this point in the history
Signed-off-by: Alex Zgabur <[email protected]>
  • Loading branch information
azgabur committed Sep 25, 2024
1 parent 0196a63 commit 246353c
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 136 deletions.
38 changes: 38 additions & 0 deletions testsuite/gateway/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,44 @@ def remove_all_backend(self):
"""Sets match for a specific backend"""


@dataclass
class GatewayListener:
"""
Dataclass of Gateway listener object.
When used in `add_listener()` function you MUST specify a unique name!
"""

hostname: str
name: str = "api"
port: int = 80
protocol: str = "HTTP"
allowedRoutes = {"namespaces": {"from": "All"}}


@dataclass(kw_only=True)
class TLSGatewayListener(GatewayListener):
"""
Dataclass for Gateway listener with TLS support.
When used in `add_listener()` function you MUST specify a unique name!
"""

gateway_name: str
mode: str = "Terminate"
port: int = 443
protocol: str = "HTTPS"

def asdict(self):
"""Custom asdict to easily add tls certificateRefs"""
return {
"name": self.name,
"hostname": self.hostname,
"port": self.port,
"protocol": self.protocol,
"allowedRoutes": self.allowedRoutes,
"tls": {"mode": self.mode, "certificateRefs": [{"name": f"{self.gateway_name}-tls", "kind": "Secret"}]},
}


class Hostname(ABC):
"""
Abstraction layer on top of externally exposed hostname
Expand Down
67 changes: 23 additions & 44 deletions testsuite/gateway/gateway_api/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,66 +5,45 @@
import openshift_client as oc

from testsuite.certificates import Certificate
from testsuite.gateway import Gateway
from testsuite.gateway import Gateway, GatewayListener
from testsuite.kubernetes.client import KubernetesClient
from testsuite.kubernetes import KubernetesObject
from testsuite.kubernetes import KubernetesObject, modify
from testsuite.kuadrant.policy import Policy
from testsuite.utils import check_condition
from testsuite.utils import check_condition, asdict


class KuadrantGateway(KubernetesObject, Gateway):
"""Gateway object for Kuadrant"""

@classmethod
def create_instance(cls, cluster: KubernetesClient, name, hostname, labels, tls=False):
def create_instance(cls, cluster: KubernetesClient, name, labels):
"""Creates new instance of Gateway"""

model: dict[Any, Any] = {
"apiVersion": "gateway.networking.k8s.io/v1beta1",
"kind": "Gateway",
"metadata": {"name": name, "labels": labels},
"spec": {
"gatewayClassName": "istio",
"listeners": [
{
"name": "api",
"port": 80,
"protocol": "HTTP",
"hostname": hostname,
"allowedRoutes": {"namespaces": {"from": "All"}},
}
],
},
"spec": {"gatewayClassName": "istio", "listeners": []},
}

if tls:
model["spec"]["listeners"] = [
{
"name": "api",
"port": 443,
"protocol": "HTTPS",
"hostname": hostname,
"allowedRoutes": {"namespaces": {"from": "All"}},
"tls": {
"mode": "Terminate",
"certificateRefs": [{"name": f"{name}-tls", "kind": "Secret"}],
},
}
]

return cls(model, context=cluster.context)

def add_listener(self, name: str, hostname: str):
"""Adds new listener to the Gateway"""
self.model.spec.listeners.append(
{
"name": name,
"port": 80,
"protocol": "HTTP",
"hostname": hostname,
"allowedRoutes": {"namespaces": {"from": "All"}},
}
gateway = cls(model, context=cluster.context)
return gateway

@modify
def add_listener(self, listener: GatewayListener):
"""Adds a listener to Gateway."""
self.model.spec.listeners.append(asdict(listener))

@modify
def remove_listener(self, listener_name: str):
"""Removes a listener from Gateway."""
self.model.spec.listeners = list(filter(lambda i: i["name"] != listener_name, self.model.spec.listeners))

def get_listener_dns_ttl(self, listener_name: str) -> int:
"""Returns TTL stored in DNSRecord CR under the specified Listener."""
dns_record = self.cluster.do_action(
"get", ["-o", "yaml", f"dnsrecords.kuadrant.io/{self.name()}-{listener_name}"], parse_output=True
)
return dns_record.model.spec.endpoints[0].recordTTL

@property
def service_name(self) -> str:
Expand Down
9 changes: 7 additions & 2 deletions testsuite/tests/multicluster/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from testsuite.backend.httpbin import Httpbin
from testsuite.certificates import Certificate
from testsuite.gateway import Exposer, CustomReference, Hostname
from testsuite.gateway import TLSGatewayListener
from testsuite.gateway.gateway_api.gateway import KuadrantGateway
from testsuite.gateway.gateway_api.hostname import DNSPolicyExposer
from testsuite.gateway.gateway_api.route import HTTPRoute
Expand Down Expand Up @@ -106,7 +107,9 @@ def routes(request, gateway, gateway2, blame, hostname, backends, module_label)
@pytest.fixture(scope="module")
def gateway(request, cluster, blame, label, wildcard_domain):
"""Deploys Gateway to first Kubernetes cluster"""
gw = KuadrantGateway.create_instance(cluster, blame("gw"), wildcard_domain, {"app": label}, tls=True)
name = blame("gw")
gw = KuadrantGateway.create_instance(cluster, name, {"app": label})
gw.add_listener(TLSGatewayListener(hostname=wildcard_domain, gateway_name=name))
request.addfinalizer(gw.delete)
gw.commit()
gw.wait_for_ready()
Expand All @@ -116,7 +119,9 @@ def gateway(request, cluster, blame, label, wildcard_domain):
@pytest.fixture(scope="module")
def gateway2(request, cluster2, blame, label, wildcard_domain):
"""Deploys Gateway to second Kubernetes cluster"""
gw = KuadrantGateway.create_instance(cluster2, blame("gw"), wildcard_domain, {"app": label}, tls=True)
name = blame("gw")
gw = KuadrantGateway.create_instance(cluster2, name, {"app": label})
gw.add_listener(TLSGatewayListener(hostname=wildcard_domain, gateway_name=name))
request.addfinalizer(gw.delete)
gw.commit()
gw.wait_for_ready()
Expand Down
5 changes: 3 additions & 2 deletions testsuite/tests/singlecluster/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from openshift_client import selector

from testsuite.backend.httpbin import Httpbin
from testsuite.gateway import GatewayRoute, Gateway, Hostname
from testsuite.gateway import GatewayRoute, Gateway, Hostname, GatewayListener
from testsuite.gateway.envoy import Envoy
from testsuite.gateway.envoy.route import EnvoyVirtualRoute
from testsuite.gateway.gateway_api.gateway import KuadrantGateway
Expand Down Expand Up @@ -130,7 +130,8 @@ def backend(request, cluster, blame, label, testconfig):
def gateway(request, kuadrant, cluster, blame, label, testconfig, wildcard_domain) -> Gateway:
"""Deploys Gateway that wires up the Backend behind the reverse-proxy and Authorino instance"""
if kuadrant:
gw = KuadrantGateway.create_instance(cluster, blame("gw"), wildcard_domain, {"app": label})
gw = KuadrantGateway.create_instance(cluster, blame("gw"), {"app": label})
gw.add_listener(GatewayListener(wildcard_domain))
else:
authorino = request.getfixturevalue("authorino")
gw = Envoy(
Expand Down
10 changes: 8 additions & 2 deletions testsuite/tests/singlecluster/gateway/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pytest

from testsuite.gateway import Exposer
from testsuite.gateway import Exposer, TLSGatewayListener
from testsuite.gateway.gateway_api.gateway import KuadrantGateway
from testsuite.gateway.gateway_api.hostname import DNSPolicyExposer
from testsuite.httpx.auth import HttpxOidcClientAuth
Expand All @@ -13,7 +13,13 @@
@pytest.fixture(scope="module")
def gateway(request, cluster, blame, wildcard_domain, module_label):
"""Returns ready gateway"""
gw = KuadrantGateway.create_instance(cluster, blame("gw"), wildcard_domain, {"app": module_label}, tls=True)
gateway_name = blame("gw")
gw = KuadrantGateway.create_instance(
cluster,
gateway_name,
{"app": module_label},
)
gw.add_listener(TLSGatewayListener(hostname=wildcard_domain, gateway_name=gateway_name))
request.addfinalizer(gw.delete)
gw.commit()
gw.wait_for_ready()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@

import pytest

from testsuite.gateway.gateway_api.gateway import KuadrantGateway
from testsuite.gateway.gateway_api.gateway import KuadrantGateway, GatewayListener

pytestmark = [pytest.mark.kuadrant_only, pytest.mark.dnspolicy]


@pytest.fixture(scope="module")
def gateway(request, cluster, blame, wildcard_domain, module_label):
"""Create gateway without TLS enabled"""
gw = KuadrantGateway.create_instance(cluster, blame("gw"), wildcard_domain, {"app": module_label}, tls=False)
gw = KuadrantGateway.create_instance(cluster, blame("gw"), {"app": module_label})
gw.add_listener(GatewayListener(wildcard_domain))
request.addfinalizer(gw.delete)
gw.commit()
gw.wait_for_ready()
Expand All @@ -38,8 +39,10 @@ def test_dnspolicy_removal(gateway, dns_policy, client):
response = client.get("/get")
assert response.status_code == 200

dns_ttl = gateway.get_listener_dns_ttl(GatewayListener.name)
dns_policy.delete()
sleep(60) # wait for records deletion/ttl expiration from the previous request
# wait for records deletion/ttl expiration from the previous request
sleep(dns_ttl)

assert not gateway.refresh().is_affected_by(dns_policy)
response = client.get("/get")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
from testsuite.kubernetes.secret import Secret
from testsuite.kuadrant.policy import has_condition
from testsuite.kuadrant.policy.dns import has_record_condition
from testsuite.gateway.gateway_api.gateway import KuadrantGateway
from testsuite.gateway.gateway_api.gateway import KuadrantGateway, GatewayListener

pytestmark = [pytest.mark.kuadrant_only, pytest.mark.dnspolicy]


@pytest.fixture(scope="module")
def gateway(request, cluster, blame, wildcard_domain, module_label):
"""Create gateway without TLS enabled"""
gw = KuadrantGateway.create_instance(cluster, blame("gw"), wildcard_domain, {"app": module_label}, tls=False)
gw = KuadrantGateway.create_instance(cluster, blame("gw"), {"app": module_label})
gw.add_listener(GatewayListener(wildcard_domain, name="api"))
request.addfinalizer(gw.delete)
gw.commit()
gw.wait_for_ready()
Expand Down

This file was deleted.

12 changes: 7 additions & 5 deletions testsuite/tests/singlecluster/gateway/test_scale_listeners.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from testsuite.httpx import KuadrantClient
from testsuite.gateway.gateway_api.route import HTTPRoute
from testsuite.gateway.gateway_api.gateway import KuadrantGateway
from testsuite.gateway.gateway_api.gateway import KuadrantGateway, GatewayListener
from testsuite.kuadrant.policy.dns import DNSPolicy

pytestmark = [pytest.mark.kuadrant_only, pytest.mark.dnspolicy]
Expand All @@ -15,9 +15,10 @@
@pytest.fixture(scope="module")
def gateway(request, cluster, blame, base_domain, module_label):
"""Create first gateway with 64 listeners"""
gw = KuadrantGateway.create_instance(cluster, blame("gw"), f"gw1-api.{base_domain}", {"app": module_label})
gw = KuadrantGateway.create_instance(cluster, blame("gw"), {"app": module_label})
gw.add_listener(GatewayListener(f"gw1-api.{base_domain}"))
for i in range(1, MAX_GATEWAY_LISTENERS):
gw.add_listener(f"api{i}", f"gw1-api{i}.{base_domain}")
gw.add_listener(GatewayListener(f"api{i}", f"gw1-api{i}.{base_domain}"))
request.addfinalizer(gw.delete)
gw.commit()
gw.wait_for_ready()
Expand All @@ -27,9 +28,10 @@ def gateway(request, cluster, blame, base_domain, module_label):
@pytest.fixture(scope="module")
def gateway2(request, cluster, blame, base_domain, module_label):
"""Create second gateway with 64 listeners"""
gw = KuadrantGateway.create_instance(cluster, blame("gw"), f"gw2-api.{base_domain}", {"app": module_label})
gw = KuadrantGateway.create_instance(cluster, blame("gw"), {"app": module_label})
gw.add_listener(GatewayListener(f"gw2-api.{base_domain}"))
for i in range(1, MAX_GATEWAY_LISTENERS):
gw.add_listener(f"api{i}", f"gw2-api{i}.{base_domain}")
gw.add_listener(GatewayListener(f"api{i}", f"gw2-api{i}.{base_domain}"))
request.addfinalizer(gw.delete)
gw.commit()
gw.wait_for_ready()
Expand Down

0 comments on commit 246353c

Please sign in to comment.