Skip to content

Commit

Permalink
Introduce mirrored reads [RHELDST-28332]
Browse files Browse the repository at this point in the history
This commit modifies exodus-cdn's lookup behavior to enable mirrored
reads. This means, that when exodus-cdn looks up content to be served
for a path with a $releasever alias in effect, exodus-cdn attempts to
look up content on both sides of the alias. (Previously, exodus-cdn
only performed a content lookup on the destination side.)

The mirrored reads are enabled by default, but they can be disabled
by setting the new config option "disable_mirrored_reads" to true
(1, '1', or 'True', where 'True' is not case sensitive.)
  • Loading branch information
crungehottman committed Feb 5, 2025
1 parent 1403d5c commit f81bc93
Show file tree
Hide file tree
Showing 7 changed files with 449 additions and 5 deletions.
1 change: 1 addition & 0 deletions configuration/lambda_config.template
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"headers": {
"max_age": $EXODUS_HEADERS_MAX_AGE
},
"disable_mirrored_reads": "$EXODUS_LAMBDA_DISABLE_MIRRORED_READS",
"lambda_version": "$EXODUS_LAMBDA_VERSION",
"index_filename": "$EXODUS_INDEX_FILENAME",
"logging": {
Expand Down
6 changes: 6 additions & 0 deletions exodus_lambda/functions/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ def lambda_version(self):
def index(self):
return self.conf["index_filename"]

@property
def disable_mirrored_reads(self):
if str(self.conf.get("disable_mirrored_reads", "false")).lower() in ('1', 'true'):
return True
return False

def set_lambda_version(self, response):
response.setdefault("headers", {})["x-exodus-version"] = [
{"key": "X-Exodus-Version", "value": self.lambda_version}
Expand Down
31 changes: 26 additions & 5 deletions exodus_lambda/functions/origin_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,14 @@ def uri_alias(self, uri, aliases, ignore_exclusions=False):

return uri

def resolve_aliases(self, uri, ignore_exclusions=False):
def resolve_aliases(
self, uri, ignore_exclusions=False, ignore_releasever=False
):
# aliases relating to origin, e.g. content/origin <=> origin

uri = self.uri_alias(
uri, self.definitions.get("origin_alias"), ignore_exclusions
)

# aliases relating to rhui; listing files are a special exemption
# because they must be allowed to differ for rhui vs non-rhui.
if not uri.endswith("/listing"):
Expand All @@ -140,9 +142,12 @@ def resolve_aliases(self, uri, ignore_exclusions=False):
)

# aliases relating to releasever; e.g. /content/dist/rhel8/8 <=> /content/dist/rhel8/8.5
uri = self.uri_alias(
uri, self.definitions.get("releasever_alias"), ignore_exclusions
)
if not ignore_releasever:
uri = self.uri_alias(
uri,
self.definitions.get("releasever_alias"),
ignore_exclusions,
)

self.logger.debug("Resolved request URI: %s", uri)

Expand Down Expand Up @@ -393,6 +398,22 @@ def handler(self, event, context):
if preferred_uri != fallback_uri:
uris.append(fallback_uri)

# When exodus-cdn is looking up content to be served for a path having a
# $releasever alias in effect, it should attempt to look up content on
# both sides of the alias.
if not self.disable_mirrored_reads:
# Attempt to look up the original path.
# Note: Only the releasever alias is left unresolved. Other alias types
# (rhui and origin aliases) are resolved.
for ignore_exclusions in (False, True):
mirrored_uri = self.resolve_aliases(
request["uri"],
ignore_exclusions=ignore_exclusions,
ignore_releasever=True,
)
if mirrored_uri not in uris:
uris.append(mirrored_uri)

for uri in uris:
if listing_response := self.handle_listing_request(uri):
self.set_cache_control(uri, listing_response)
Expand Down
1 change: 1 addition & 0 deletions scripts/mk-config
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export ENV_TYPE=${ENV_TYPE:-dev}
export EXODUS_TABLE=${EXODUS_TABLE:-$PROJECT-cdn-$ENV_TYPE}
export EXODUS_CONFIG_TABLE=${EXODUS_CONFIG_TABLE:-$PROJECT-config-$ENV_TYPE}
export EXODUS_INDEX_FILENAME=${EXODUS_INDEX_FILENAME:-.__exodus_autoindex}
export EXODUS_DISABLE_MIRRORED_READS=${EXODUS_DISABLE_MIRRORED_READS:-false}

REVISION="${CODEBUILD_RESOLVED_SOURCE_VERSION:-$(git rev-parse HEAD)}"
export EXODUS_LAMBDA_VERSION="${EXODUS_LAMBDA_VERSION:-$(date -u --iso=s) ${REVISION}}"
Expand Down
1 change: 1 addition & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def mock_conf_file():
test_env["ORIGIN_REQUEST_LOGGER_LEVEL"] = "DEBUG"
test_env["EXODUS_LAMBDA_VERSION"] = "fake version"
test_env["EXODUS_INDEX_FILENAME"] = ".__exodus_autoindex"
test_env["EXODUS_DISABLE_MIRRORED_READS"] = "false"

subprocess.run(
["envsubst"],
Expand Down
27 changes: 27 additions & 0 deletions tests/functions/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,30 @@ def test_json_logger_configurable_datefmt(caplog):
"response": None,
},
]


@pytest.mark.parametrize(
"config_value,disabled",
[
("True", True),
("true", True),
(1, True),
("1", True),
("", False),
("false", False),
],
ids=[
"mixed case true",
"lowercase true",
"int 1",
"string 1",
"empty string",
"false string",
],
)
def test_disable_reads(config_value, disabled):
"""Verify that the disable_mirrored_reads config value produces the expected
disable_mirrored_reads property."""
conf = copy.deepcopy(TEST_CONF)
conf["disable_mirrored_reads"] = config_value
assert LambdaBase(conf_file=conf).disable_mirrored_reads == disabled
Loading

0 comments on commit f81bc93

Please sign in to comment.