Skip to content

Commit

Permalink
make possible to rewrite destination urls by domain mappings (#500)
Browse files Browse the repository at this point in the history
  • Loading branch information
ziollek authored Oct 11, 2023
1 parent bf8577b commit 6534c7a
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 30 deletions.
2 changes: 1 addition & 1 deletion vaas/vaas/metrics/prometheus.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def _split_dotted_name_to_short_name_and_labels(self, name: str) -> Tuple[str, D
"""
Splits dotted name for example "my_metric.label1.value1.label2.value2" into tuple containing:
- short_name -> "my_metric"
- labels -> {"label1": "value1", "label2": "value2"
- labels -> {"label1": "value1", "label2": "value2"}
"""
labels = self.labels.copy()
parts = name.split(".")
Expand Down
16 changes: 10 additions & 6 deletions vaas/vaas/router/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
import uuid
from typing import Dict
from typing import Dict, Tuple, List
from django.db import models
from django.conf import settings
from django.core.validators import MinValueValidator, MaxValueValidator
Expand Down Expand Up @@ -37,11 +37,15 @@ class ResponseStatusCode(models.IntegerChoices):
def get_hashed_assertions_pks(self) -> Dict[int, int]:
return {hash((a.given_url, a.expected_location)): a.pk for a in self.assertions.all()}

def get_redirect_destination(self, mapped_domain: str) -> str:
destination_url = urlsplit(self.destination)
if DomainMapping.objects.filter(domain=destination_url.netloc).exists():
return self.destination.replace(destination_url.netloc, mapped_domain)
return self.destination
def fetch_all_destinations_mappings(self, cluster: LogicalCluster) -> Tuple[str, List[str]]:
"""
Fetch tuple containing domain parsed from destination url and all found mappings for input cluster
"""
all_mappings = set()
destination_domain = urlsplit(self.destination).netloc
for domain_mapping in DomainMapping.objects.filter(domain=destination_domain):
all_mappings = all_mappings.union(set(domain_mapping.mapped_domains(cluster)))
return destination_domain, list(all_mappings)

@property
def final_condition(self):
Expand Down
14 changes: 10 additions & 4 deletions vaas/vaas/vcl/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,15 +158,15 @@ def is_active(self):


class VclRedirect:
def __init__(self, redirect: Redirect, mapped_domain: str):
def __init__(self, redirect: Redirect, mapped_domain: str, destination: str):
self.id = f"{redirect.pk}/{mapped_domain}"
self.redirect_id = redirect.pk
self.src_domain = redirect.src_domain
self.rewrite_groups = redirect.rewrite_groups
self.action = redirect.action
self.preserve_query_params = redirect.preserve_query_params
self.final_condition = redirect.final_condition
self.destination = redirect.get_redirect_destination(mapped_domain)
self.destination = destination


class VclTagBuilder:
Expand All @@ -191,12 +191,18 @@ def prepare_redirects(self) -> Dict[str, List[VclRedirect]]:
redirects = {}
related_domains = MappingProvider(DomainMapping.objects.all()).provide_related_domains(self.varnish.cluster)
for redirect in self.input.redirects:
destination_domain, destination_mappings = redirect.fetch_all_destinations_mappings(self.varnish.cluster)
if str(redirect.src_domain) in related_domains:
for mapped_domain in redirect.src_domain.mapped_domains(self.varnish.cluster):
destination = str(redirect.destination)
if destination_domain == redirect.src_domain.domain:
destination = destination.replace(destination_domain, mapped_domain)
elif all((destination_domain, len(destination_mappings) == 1)):
destination = destination.replace(destination_domain, destination_mappings[0])
if entries := redirects.get(mapped_domain, []):
entries.append(VclRedirect(redirect, mapped_domain))
entries.append(VclRedirect(redirect, mapped_domain, destination))
else:
redirects[mapped_domain] = [VclRedirect(redirect, mapped_domain)]
redirects[mapped_domain] = [VclRedirect(redirect, mapped_domain, destination)]
return redirects

@collect_processing
Expand Down
26 changes: 19 additions & 7 deletions vaas/vaas/vcl/tests/expected-vcl-4.0-canary.vcl
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ sub vcl_synth {
if (resp.status == 989) {
set resp.status = 200;
set resp.http.Content-Type = "application/json";
synthetic ( {"{ "vcl_version" : "ce716", "varnish_status": "disabled" }"} );
synthetic ( {"{ "vcl_version" : "70175", "varnish_status": "disabled" }"} );
return (deliver);
}
}
Expand Down Expand Up @@ -411,30 +411,42 @@ sub vcl_recv {
unset req.http.x-canary-random;

# Flexible REDIRECT
if (req.http.host == "example.prod.com") {
if (req.http.host == "example.prod.org") {
if (req.url ~ "/source") {
set req.http.x-redirect = "2";
set req.http.x-destination = "http://example.prod.com/new_destination";
set req.http.x-destination = "http://example.prod.org/new_destination";
set req.http.x-response-code = "301";
set req.http.x-action = "redirect";
}
else if (req.url ~ "/source") {
set req.http.x-redirect = "1";
set req.http.x-destination = "http://example.prod.com/destination";
set req.http.x-destination = "http://example.prod.org/destination";
set req.http.x-response-code = "301";
set req.http.x-action = "redirect";
}
else if (req.url ~ "/external") {
set req.http.x-redirect = "3";
set req.http.x-destination = "http://example-external.com/external_destination";
set req.http.x-response-code = "301";
set req.http.x-action = "redirect";
}
if (req.http.host == "example.prod.org") {
}
if (req.http.host == "example.prod.com") {
if (req.url ~ "/source") {
set req.http.x-redirect = "2";
set req.http.x-destination = "http://example.prod.org/new_destination";
set req.http.x-destination = "http://example.prod.com/new_destination";
set req.http.x-response-code = "301";
set req.http.x-action = "redirect";
}
else if (req.url ~ "/source") {
set req.http.x-redirect = "1";
set req.http.x-destination = "http://example.prod.org/destination";
set req.http.x-destination = "http://example.prod.com/destination";
set req.http.x-response-code = "301";
set req.http.x-action = "redirect";
}
else if (req.url ~ "/external") {
set req.http.x-redirect = "3";
set req.http.x-destination = "http://example-external.com/external_destination";
set req.http.x-response-code = "301";
set req.http.x-action = "redirect";
}
Expand Down
26 changes: 19 additions & 7 deletions vaas/vaas/vcl/tests/expected-vcl-4.0.vcl
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ sub vcl_synth {
if (resp.status == 989) {
set resp.status = 200;
set resp.http.Content-Type = "application/json";
synthetic ( {"{ "vcl_version" : "721d3", "varnish_status": "disabled" }"} );
synthetic ( {"{ "vcl_version" : "34535", "varnish_status": "disabled" }"} );
return (deliver);
}
}
Expand Down Expand Up @@ -438,30 +438,42 @@ sub vcl_recv {
unset req.http.x-canary-random;

# Flexible REDIRECT
if (req.http.host == "example.prod.com") {
if (req.http.host == "example.prod.org") {
if (req.url ~ "/source") {
set req.http.x-redirect = "2";
set req.http.x-destination = "http://example.prod.com/new_destination";
set req.http.x-destination = "http://example.prod.org/new_destination";
set req.http.x-response-code = "301";
set req.http.x-action = "redirect";
}
else if (req.url ~ "/source") {
set req.http.x-redirect = "1";
set req.http.x-destination = "http://example.prod.com/destination";
set req.http.x-destination = "http://example.prod.org/destination";
set req.http.x-response-code = "301";
set req.http.x-action = "redirect";
}
else if (req.url ~ "/external") {
set req.http.x-redirect = "3";
set req.http.x-destination = "http://example-external.com/external_destination";
set req.http.x-response-code = "301";
set req.http.x-action = "redirect";
}
if (req.http.host == "example.prod.org") {
}
if (req.http.host == "example.prod.com") {
if (req.url ~ "/source") {
set req.http.x-redirect = "2";
set req.http.x-destination = "http://example.prod.org/new_destination";
set req.http.x-destination = "http://example.prod.com/new_destination";
set req.http.x-response-code = "301";
set req.http.x-action = "redirect";
}
else if (req.url ~ "/source") {
set req.http.x-redirect = "1";
set req.http.x-destination = "http://example.prod.org/destination";
set req.http.x-destination = "http://example.prod.com/destination";
set req.http.x-response-code = "301";
set req.http.x-action = "redirect";
}
else if (req.url ~ "/external") {
set req.http.x-redirect = "3";
set req.http.x-destination = "http://example-external.com/external_destination";
set req.http.x-response-code = "301";
set req.http.x-action = "redirect";
}
Expand Down
27 changes: 22 additions & 5 deletions vaas/vaas/vcl/tests/test_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,14 @@ def setUp(self):
service_mesh_routing=True,
labels_list='["cluster4"]'
)
self.domainapping = DomainMapping.objects.create(
self.example_domain_mapping = DomainMapping.objects.create(
domain='example.com', mappings_list='["example.{env}.com", "example.{env}.org"]', type='dynamic'
)
self.domainapping.clusters.add(cluster1)
self.example_domain_mapping.clusters.add(cluster1)
self.external_domain_mapping = DomainMapping.objects.create(
domain='external.com', mappings_list='["example-external.com"]', type='static'
)
self.external_domain_mapping.clusters.add(cluster1)
time_profile = TimeProfile.objects.create(
name='generic', max_connections=1, connect_timeout=0.5, first_byte_timeout=0.1, between_bytes_timeout=1
)
Expand Down Expand Up @@ -256,7 +260,7 @@ def setUp(self):
route.clusters.add(cluster2)

Redirect.objects.create(
src_domain=self.domainapping,
src_domain=self.example_domain_mapping,
condition='req.url ~ "/source"',
destination='http://example.com/destination',
action=301,
Expand All @@ -266,7 +270,7 @@ def setUp(self):
)

Redirect.objects.create(
src_domain=self.domainapping,
src_domain=self.example_domain_mapping,
condition='req.url ~ "/source"',
destination='http://example.com/new_destination',
action=301,
Expand All @@ -275,6 +279,16 @@ def setUp(self):
required_custom_header=False
)

Redirect.objects.create(
src_domain=self.example_domain_mapping,
condition='req.url ~ "/external"',
destination='http://external.com/external_destination',
action=301,
priority=260,
preserve_query_params=False,
required_custom_header=False
)

self.varnish = VarnishServer.objects.create(ip='127.0.0.1', dc=self.dc2, template=template_v4_with_tag,
cluster=cluster1)
self.varnish_dc1 = VarnishServer.objects.create(ip='127.4.0.1', dc=self.dc1, template=template_v4_with_tag,
Expand Down Expand Up @@ -419,7 +433,7 @@ def test_should_decorate_set_backend_tag_with_fallback_service_in_dc1(self):

assert_list_equal(expected_datacenters, active_director_datacenters)

def test_should_decorate_flexible_router_tag_with_mapped_domain(self):
def test_should_decorate_flexible_router_tag_with_properly_mapped_destination_domain(self):
vcl_tag_builder = VclTagBuilder(self.varnish, VclRendererInput())
tag = vcl_tag_builder.get_expanded_tags('FLEXIBLE_ROUTER').pop()
assert_set_equal({'example.prod.com', 'example.prod.org'}, set(tag.parameters['redirects'].keys()))
Expand All @@ -429,13 +443,16 @@ def test_should_decorate_flexible_router_tag_with_mapped_domain(self):
tag.parameters['redirects']['example.prod.com'][1].destination)
assert_equals('http://example.prod.org/destination',
tag.parameters['redirects']['example.prod.org'][1].destination)
assert_equals('http://example-external.com/external_destination',
tag.parameters['redirects']['example.prod.com'][2].destination)

def test_should_sort_redirects_by_priority(self):
vcl_tag_builder = VclTagBuilder(self.varnish, VclRendererInput())
tag = vcl_tag_builder.get_expanded_tags('FLEXIBLE_ROUTER').pop()
assert_set_equal({'example.prod.com', 'example.prod.org'}, set(tag.parameters['redirects'].keys()))
assert_equals('2/example.prod.com', tag.parameters['redirects']['example.prod.com'][0].id)
assert_equals('1/example.prod.com', tag.parameters['redirects']['example.prod.com'][1].id)
assert_equals('3/example.prod.com', tag.parameters['redirects']['example.prod.com'][2].id)


class VclRendererInputTest(TestCase):
Expand Down

0 comments on commit 6534c7a

Please sign in to comment.