Skip to content
Open
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
27 changes: 20 additions & 7 deletions src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,13 +356,26 @@ def _make_env_config(self, domain="svc.cluster.local") -> dict | None:
svc_name = relation.data[relation.app].get("service-name")
svc_port = relation.data[relation.app].get("service-port")
backend_site_name = relation.data[relation.app].get("service-hostname")
clients = []
for peer in relation.units:
unit_name = peer.name.replace("/", "-")
service_url = f"{unit_name}.{svc_name}-endpoints.{self.model.name}.{domain}"
clients.append(f"http://{service_url}:{svc_port}")
# XXX: Will need to deal with multiple units at some point
backend = clients[0]
# In a Cross-Model Relation (CMR), remote unit names follow the pattern
# "remote-<uuid>/<n>" and cannot be used to build headless pod DNS entries
# (the unit name is a Juju-internal proxy token, not a real K8s pod name).
# Detect CMR by checking for the "remote-" prefix, and fall back to
# service-level DNS using the namespace provided in the relation data.
is_cmr = any(peer.name.startswith("remote-") for peer in relation.units)
if is_cmr:
svc_namespace = relation.data[relation.app].get(
"service-namespace", self.model.name
)
service_url = f"{svc_name}.{svc_namespace}.{domain}"
backend = f"http://{service_url}:{svc_port}"
else:
clients = []
for peer in relation.units:
unit_name = peer.name.replace("/", "-")
service_url = f"{unit_name}.{svc_name}-endpoints.{self.model.name}.{domain}"
clients.append(f"http://{service_url}:{svc_port}")
# XXX: Will need to deal with multiple units at some point
backend = clients[0]
elif relation:
return None
else:
Expand Down
55 changes: 55 additions & 0 deletions tests/unit/test_charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,61 @@ def test_make_env_config_with_proxy_relation(self):
new_site = new_env_config["CONTENT_CACHE_SITE"]
assert new_site == relations_data["service-hostname"]

def test_make_env_config_with_cmr_proxy_relation(self):
"""
arrange: set nginx-proxy relation with a CMR (Cross-Model Relation) remote unit
act: verify env config
assert: backend uses service-level DNS with service-namespace, not pod-level DNS
"""
config = self.config
harness = self.harness
harness.disable_hooks()
harness.update_config(config)
# CMR remote application names follow the "remote-<uuid>" pattern
cmr_app_name = "remote-9e5538f0707b46568cc9b04d9f39f708"
relation_id = harness.add_relation("nginx-proxy", cmr_app_name)
harness.add_relation_unit(relation_id, f"{cmr_app_name}/0")
relations_data = {
"service-name": "indico",
"service-hostname": "indico.example.com",
"service-port": "8080",
"service-namespace": "target-model",
}
harness.update_relation_data(relation_id, cmr_app_name, relations_data)
env_config = harness.charm._make_env_config()
# The backend must use service-level K8s DNS, not pod-level headless DNS
assert env_config["CONTENT_CACHE_BACKEND"] == (
"http://indico.target-model.svc.cluster.local:8080"
)
assert env_config["NGINX_BACKEND"] == "http://indico.target-model.svc.cluster.local:8080"
assert env_config["CONTENT_CACHE_SITE"] == "indico.example.com"

def test_make_env_config_with_cmr_proxy_relation_no_namespace(self):
"""
arrange: set nginx-proxy relation with a CMR remote unit but no service-namespace
act: verify env config
assert: backend falls back to service-level DNS using the local model name
"""
config = self.config
harness = self.harness
harness.disable_hooks()
harness.update_config(config)
cmr_app_name = "remote-9e5538f0707b46568cc9b04d9f39f708"
relation_id = harness.add_relation("nginx-proxy", cmr_app_name)
harness.add_relation_unit(relation_id, f"{cmr_app_name}/0")
relations_data = {
"service-name": "indico",
"service-hostname": "indico.example.com",
"service-port": "8080",
}
harness.update_relation_data(relation_id, cmr_app_name, relations_data)
env_config = harness.charm._make_env_config()
# Falls back to local model name when service-namespace is absent
local_model = harness.charm.model.name
assert env_config["CONTENT_CACHE_BACKEND"] == (
f"http://indico.{local_model}.svc.cluster.local:8080"
)

def test_make_pebble_config(self):
"""
arrange: define pebble config
Expand Down
Loading