Skip to content

Commit

Permalink
Merge pull request #347 from pehala/unite_exposers
Browse files Browse the repository at this point in the history
Unify exposers
  • Loading branch information
pehala authored Apr 16, 2024
2 parents 4481a40 + 922967d commit 6bb0e8b
Show file tree
Hide file tree
Showing 14 changed files with 154 additions and 92 deletions.
2 changes: 2 additions & 0 deletions config/settings.local.yaml.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@
# auth_url: "" # authorization URL for already deployed Authorino
# oidc_url: "" # oidc URL for already deployed Authorino
# metrics_service_name: "" # controller metrics service name for already deployed Authorino
# default_exposer: "openshift" # Exposer type that should be used, options: 'openshift'
# control_plane:
# managedzone: aws-mz # Name of the ManagedZone resource residing on hub cluster
# hub: # Hub cluster
# project: "multi-cluster-gateways" # Optional: namespace where MGC resources are created and where the hub gateway will be created
# api_url: "https://api.openshift.com" # Optional: OpenShift API URL, if None it will OpenShift that you are logged in
Expand Down
3 changes: 3 additions & 0 deletions config/settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ default:
hyperfoil:
generate_reports: True
reports_dir: "reports"
default_exposer: "openshift"
control_plane:
managedzone: "aws-mz"
12 changes: 10 additions & 2 deletions testsuite/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,18 @@ def __init__(self, name, default, **kwargs) -> None:
"tracing.collector_url", default=fetch_service("jaeger-collector", protocol="rpc", port=4317)
),
DefaultValueValidator("tracing.query_url", default=fetch_route("jaeger-query", force_http=True)),
Validator(
"default_exposer",
# If exposer was successfully converted, it will no longer be a string"""
condition=lambda exposer: not isinstance(exposer, str),
must_exist=True,
messages={"condition": "{value} is not valid exposer"},
),
Validator("control_plane.managedzone", must_exist=True, ne=None),
DefaultValueValidator("rhsso.url", default=fetch_route("no-ssl-sso")),
DefaultValueValidator("rhsso.password", default=fetch_secret("credential-sso", "ADMIN_PASSWORD")),
DefaultValueValidator("mockserver.url", default=fetch_route("mockserver", force_http=True)),
],
validate_only=["authorino", "kuadrant"],
loaders=["dynaconf.loaders.env_loader", "testsuite.config.openshift_loader"],
validate_only=["authorino", "kuadrant", "default_exposer", "control_plane"],
loaders=["dynaconf.loaders.env_loader", "testsuite.config.openshift_loader", "testsuite.config.exposer"],
)
14 changes: 14 additions & 0 deletions testsuite/config/exposer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""Translates string to an Exposer class that can initialized"""

from testsuite.gateway.exposers import OpenShiftExposer

EXPOSERS = {"openshift": OpenShiftExposer}


# pylint: disable=unused-argument
def load(obj, env=None, silent=True, key=None, filename=None):
"""Selects proper Exposes class"""
try:
obj["default_exposer"] = EXPOSERS[obj["default_exposer"]]
except KeyError:
return
13 changes: 12 additions & 1 deletion testsuite/gateway/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,12 +188,23 @@ def hostname(self) -> str:
"""Returns full hostname in string form associated with this object"""


class Exposer:
class Exposer(LifecycleObject):
"""Exposes hostnames to be accessible from outside"""

def __init__(self, openshift):
super().__init__()
self.openshift = openshift
self.passthrough = False
self.verify = None

@abstractmethod
def expose_hostname(self, name, gateway: Gateway) -> Hostname:
"""
Exposes hostname, so it is accessible from outside
Actual hostname is generated from "name" and is returned in a form of a Hostname object
"""

@property
@abstractmethod
def base_domain(self) -> str:
"""Returns base domains for all hostnames created by this exposer"""
38 changes: 38 additions & 0 deletions testsuite/gateway/exposers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""General exposers, not tied to Envoy or Gateway API"""

from testsuite.gateway import Exposer, Gateway, Hostname
from testsuite.openshift.route import OpenshiftRoute


class OpenShiftExposer(Exposer):
"""Exposes hostnames through OpenShift Route objects"""

def __init__(self, openshift) -> None:
super().__init__(openshift)
self.routes: list[OpenshiftRoute] = []

@property
def base_domain(self) -> str:
return self.openshift.apps_url

def expose_hostname(self, name, gateway: Gateway) -> Hostname:
tls = False
termination = "edge"
if self.passthrough:
tls = True
termination = "passthrough"
route = OpenshiftRoute.create_instance(
gateway.openshift, name, gateway.service_name, "api", tls=tls, termination=termination
)
route.verify = self.verify
self.routes.append(route)
route.commit()
return route

def commit(self):
return

def delete(self):
for route in self.routes:
route.delete()
self.routes = []
54 changes: 17 additions & 37 deletions testsuite/gateway/gateway_api/hostname.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,15 @@
"""Module containing implementation for Hostname related classes of Gateway API"""

from functools import cached_property

from httpx import Client
from openshift_client import selector

from testsuite.certificates import Certificate
from testsuite.config import settings
from testsuite.httpx import KuadrantClient
from testsuite.lifecycle import LifecycleObject
from testsuite.gateway import Gateway, Hostname, Exposer
from testsuite.openshift.route import OpenshiftRoute


class OpenShiftExposer(Exposer, LifecycleObject):
"""Exposes hostnames through OpenShift Route objects"""

def __init__(self, passthrough=False) -> None:
super().__init__()
self.routes: list[OpenshiftRoute] = []
self.passthrough = passthrough

def expose_hostname(self, name, gateway: Gateway) -> Hostname:
tls = False
termination = "edge"
if self.passthrough:
tls = True
termination = "passthrough"
route = OpenshiftRoute.create_instance(
gateway.openshift, name, gateway.service_name, "api", tls=tls, termination=termination
)
self.routes.append(route)
route.commit()
return route

def commit(self):
return

def delete(self):
for route in self.routes:
route.delete()
self.routes = []
from testsuite.utils import generate_tail


class StaticHostname(Hostname):
Expand All @@ -62,12 +35,19 @@ def hostname(self):
class DNSPolicyExposer(Exposer):
"""Exposing is done as part of DNSPolicy, so no work needs to be done here"""

def __init__(self, base_domain, tls_cert: Certificate = None):
super().__init__()
self.base_domain = base_domain
self.tls_cert = tls_cert
@cached_property
def base_domain(self) -> str:
mz_name = settings["control_plane"]["managedzone"]
zone = selector(f"managedzone/{mz_name}", static_context=self.openshift.context).object()
return f'{generate_tail(5)}.{zone.model["spec"]["domainName"]}'

def expose_hostname(self, name, gateway: Gateway) -> Hostname:
return StaticHostname(
f"{name}.{self.base_domain}", gateway.get_tls_cert() if self.tls_cert is None else self.tls_cert
f"{name}.{self.base_domain}", gateway.get_tls_cert() if self.verify is None else self.verify
)

def commit(self):
pass

def delete(self):
pass
5 changes: 5 additions & 0 deletions testsuite/openshift/route.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
class OpenshiftRoute(OpenShiftObject, Hostname):
"""Openshift Route object"""

def __init__(self, dict_to_model=None, string_to_model=None, context=None):
super().__init__(dict_to_model, string_to_model, context)
self.verify = None

@classmethod
def create_instance(
cls,
Expand Down Expand Up @@ -41,6 +45,7 @@ def client(self, **kwargs) -> Client:
protocol = "http"
if "tls" in self.model.spec:
protocol = "https"
kwargs.setdefault("verify", self.verify)
return KuadrantClient(base_url=f"{protocol}://{self.hostname}", **kwargs)

@cached_property
Expand Down
23 changes: 17 additions & 6 deletions testsuite/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from testsuite.gateway.envoy import Envoy
from testsuite.gateway.envoy.route import EnvoyVirtualRoute
from testsuite.gateway.gateway_api.gateway import KuadrantGateway
from testsuite.gateway.gateway_api.hostname import OpenShiftExposer
from testsuite.gateway.gateway_api.route import HTTPRoute
from testsuite.utils import randomize, _whoami

Expand Down Expand Up @@ -129,14 +128,20 @@ def testconfig():


@pytest.fixture(scope="session")
def openshift(testconfig):
def hub_openshift(testconfig):
"""OpenShift client for the primary namespace"""
client = testconfig["service_protection"]["project"]
if not client.connected:
pytest.fail("You are not logged into Openshift or the namespace doesn't exist")
return client


@pytest.fixture(scope="session")
def openshift(hub_openshift):
"""OpenShift client for the primary namespace"""
return hub_openshift


@pytest.fixture(scope="session")
def openshift2(testconfig, skip_or_fail):
"""OpenShift client for the secondary namespace located on the same cluster as primary Openshift"""
Expand Down Expand Up @@ -319,9 +324,9 @@ def route(request, kuadrant, gateway, blame, hostname, backend, module_label) ->


@pytest.fixture(scope="session")
def exposer(request) -> Exposer:
def exposer(request, testconfig, hub_openshift) -> Exposer:
"""Exposer object instance"""
exposer = OpenShiftExposer()
exposer = testconfig["default_exposer"](hub_openshift)
request.addfinalizer(exposer.delete)
exposer.commit()
return exposer
Expand All @@ -335,11 +340,17 @@ def hostname(gateway, exposer, blame) -> Hostname:


@pytest.fixture(scope="session")
def wildcard_domain(openshift):
def base_domain(exposer):
"""Returns preconfigured base domain"""
return exposer.base_domain


@pytest.fixture(scope="session")
def wildcard_domain(base_domain):
"""
Wildcard domain of openshift cluster
"""
return f"*.{openshift.apps_url}"
return f"*.{base_domain}"


@pytest.fixture(scope="module")
Expand Down
11 changes: 6 additions & 5 deletions testsuite/tests/kuadrant/authorino/operator/tls/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from testsuite.openshift import Selector
from testsuite.gateway import Exposer
from testsuite.gateway.envoy.tls import TLSEnvoy
from testsuite.gateway.gateway_api.hostname import OpenShiftExposer
from testsuite.gateway.exposers import OpenShiftExposer
from testsuite.openshift.secret import TLSSecret
from testsuite.utils import cert_builder

Expand Down Expand Up @@ -78,7 +78,7 @@ def _create_secret(certificate: Certificate, name: str, labels: Optional[Dict[st
@pytest.fixture(scope="module")
def authorino_domain(openshift):
"""
Hostname of the upstream certificate sent to be validated by APIcast
Hostname of the upstream certificate sent to be validated by Envoy
May be overwritten to configure different test cases
"""
return f"*.{openshift.project}.svc.cluster.local"
Expand Down Expand Up @@ -180,10 +180,11 @@ def gateway(
return envoy


@pytest.fixture(scope="module")
def exposer(request) -> Exposer:
@pytest.fixture(scope="session")
def exposer(request, hub_openshift) -> Exposer:
"""Exposer object instance with TLS passthrough"""
exposer = OpenShiftExposer(passthrough=True)
exposer = OpenShiftExposer(hub_openshift)
exposer.passthrough = True
request.addfinalizer(exposer.delete)
exposer.commit()
return exposer
Expand Down
41 changes: 25 additions & 16 deletions testsuite/tests/mgc/conftest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Conftest for MGC tests"""

import pytest
from openshift_client import selector
from weakget import weakget

from testsuite.backend.httpbin import Httpbin
Expand All @@ -11,7 +10,6 @@
from testsuite.gateway.gateway_api.hostname import DNSPolicyExposer
from testsuite.gateway.gateway_api.route import HTTPRoute
from testsuite.policy.tls_policy import TLSPolicy
from testsuite.utils import generate_tail


@pytest.fixture(scope="session")
Expand All @@ -32,13 +30,13 @@ def hub_openshift(testconfig):


@pytest.fixture(scope="module")
def hub_gateway(request, hub_openshift, blame, base_domain, module_label) -> MGCGateway:
def hub_gateway(request, hub_openshift, blame, wildcard_domain, module_label) -> MGCGateway:
"""Creates and returns configured and ready Hub Gateway"""
hub_gateway = MGCGateway.create_instance(
openshift=hub_openshift,
name=blame("mgc-gateway"),
gateway_class="kuadrant-multi-cluster-gateway-instance-per-cluster",
hostname=f"*.{base_domain}",
hostname=wildcard_domain,
tls=True,
placement="http-gateway",
labels={"app": module_label},
Expand Down Expand Up @@ -74,17 +72,23 @@ def route(request, gateway, blame, hostname, backend, module_label) -> GatewayRo


@pytest.fixture(scope="module")
def exposer(base_domain, hub_gateway) -> Exposer:
def exposer(request, hub_openshift) -> Exposer:
"""DNSPolicyExposer setup with expected TLS certificate"""
return DNSPolicyExposer(base_domain, tls_cert=hub_gateway.get_tls_cert())
exposer = DNSPolicyExposer(hub_openshift)
request.addfinalizer(exposer.delete)
exposer.commit()
return exposer


# pylint: disable=unused-argument
@pytest.fixture(scope="module")
def gateway(hub_gateway, spokes, hub_policies_commit):
def gateway(exposer, hub_gateway, spokes, hub_policies_commit):
"""Downstream gateway, e.g. gateway on a spoke cluster"""
# wait for upstream gateway here to be able to get spoke gateways
hub_gateway.wait_for_ready()
# Only here is Hub Gateway ready, which means only here we can assign verify
exposer.verify = hub_gateway.get_tls_cert()

gw = hub_gateway.get_spoke_gateway(spokes)
gw.wait_for_ready()
return gw
Expand All @@ -96,15 +100,6 @@ def openshift(gateway):
return gateway.openshift


@pytest.fixture(scope="module", params=["aws-mz", "gcp-mz"])
def base_domain(request, hub_openshift):
"""Returns preconfigured base domain"""
mz_name = request.param

zone = selector(f"managedzone/{mz_name}", static_context=hub_openshift.context).object()
return f"{generate_tail()}.{zone.model['spec']['domainName']}"


@pytest.fixture(scope="module")
def dns_policy(blame, hub_gateway, module_label):
"""DNSPolicy fixture"""
Expand Down Expand Up @@ -144,3 +139,17 @@ def backend(request, openshift, blame, label):
request.addfinalizer(httpbin.delete)
httpbin.commit()
return httpbin


@pytest.fixture(scope="module")
def base_domain(exposer):
"""Returns preconfigured base domain"""
return exposer.base_domain


@pytest.fixture(scope="module")
def wildcard_domain(base_domain):
"""
Wildcard domain of openshift cluster
"""
return f"*.{base_domain}"
Loading

0 comments on commit 6bb0e8b

Please sign in to comment.