Skip to content

Commit 71b9976

Browse files
committed
manage more than one TXT record so that the phala node can resolve routing of appid
1 parent 9087442 commit 71b9976

4 files changed

Lines changed: 92 additions & 1 deletion

File tree

custom-domain/dstack-ingress/scripts/dns_providers/base.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,16 @@ def set_txt_record(self, name: str, content: str, ttl: int = 60) -> bool:
247247
)
248248
return self.create_dns_record(new_record)
249249

250+
def append_txt_record(self, name: str, content: str, ttl: int = 60) -> bool:
251+
"""Append a TXT value to an existing RRset without removing other values.
252+
253+
Used for shared alias domains where multiple instances each need their
254+
APP_ID registered. Default falls back to replace behavior for providers
255+
that don't support multi-value RRsets.
256+
"""
257+
print("Note: provider does not support multi-value TXT; replacing")
258+
return self.set_txt_record(name, content, ttl)
259+
250260
def set_weighted_cname_record(
251261
self,
252262
name: str,

custom-domain/dstack-ingress/scripts/dns_providers/route53.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,65 @@ def set_weighted_cname_record(
305305
)
306306
return self.create_dns_record(new_record)
307307

308+
def append_txt_record(self, name: str, content: str, ttl: int = 60) -> bool:
309+
"""Append to a TXT RRset — fetches all existing values and UPSERTs the full set."""
310+
hosted_zone_id = self._ensure_hosted_zone_id(name)
311+
if not hosted_zone_id:
312+
return False
313+
314+
normalized_name = self._normalize_record_name(name)
315+
quoted_content = f'"{content}"'
316+
317+
# Fetch existing TXT RRset directly — get_dns_records only returns the first value
318+
paginator = self.client.get_paginator("list_resource_record_sets")
319+
existing_rrset = None
320+
try:
321+
for page in paginator.paginate(HostedZoneId=hosted_zone_id):
322+
for record_set in page["ResourceRecordSets"]:
323+
if record_set["Name"] == normalized_name and record_set["Type"] == "TXT":
324+
existing_rrset = record_set
325+
break
326+
if existing_rrset:
327+
break
328+
except Exception as e:
329+
print(f"Error fetching existing TXT records: {e}", file=sys.stderr)
330+
return False
331+
332+
existing_values = []
333+
if existing_rrset:
334+
existing_values = [rr["Value"] for rr in existing_rrset.get("ResourceRecords", [])]
335+
ttl = existing_rrset.get("TTL", ttl)
336+
337+
if quoted_content in existing_values:
338+
print(f"TXT record already contains {content}")
339+
return True
340+
341+
all_values = existing_values + [quoted_content]
342+
print(f"Appending TXT value for {name}: {len(all_values)} total entries")
343+
344+
change_batch = {
345+
"Changes": [
346+
{
347+
"Action": "UPSERT",
348+
"ResourceRecordSet": {
349+
"Name": normalized_name,
350+
"Type": "TXT",
351+
"TTL": ttl,
352+
"ResourceRecords": [{"Value": v} for v in all_values],
353+
},
354+
}
355+
]
356+
}
357+
358+
try:
359+
response = self.client.change_resource_record_sets(
360+
HostedZoneId=hosted_zone_id, ChangeBatch=change_batch
361+
)
362+
return response.get("ChangeInfo", {}).get("Status") in ["PENDING", "INSYNC"]
363+
except Exception as e:
364+
print(f"Error appending TXT record: {e}", file=sys.stderr)
365+
return False
366+
308367
def create_dns_record(self, record: DNSRecord) -> bool:
309368
"""
310369
Create a DNS record.

custom-domain/dstack-ingress/scripts/dnsman.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def main():
1414
)
1515
parser.add_argument(
1616
"action",
17-
choices=["set_cname", "set_alias", "set_txt", "set_caa", "set_weighted_cname"],
17+
choices=["set_cname", "set_alias", "set_txt", "set_txt_append", "set_caa", "set_weighted_cname"],
1818
help="Action to perform",
1919
)
2020
parser.add_argument("--domain", required=True, help="Domain name")
@@ -74,6 +74,17 @@ def main():
7474
sys.exit(1)
7575
print(f"Successfully set TXT record for {args.domain}")
7676

77+
elif args.action == "set_txt_append":
78+
if not args.content:
79+
print("Error: --content is required for TXT records", file=sys.stderr)
80+
sys.exit(1)
81+
82+
success = provider.append_txt_record(args.domain, args.content)
83+
if not success:
84+
print(f"Failed to append TXT record for {args.domain}", file=sys.stderr)
85+
sys.exit(1)
86+
print(f"Successfully appended TXT record for {args.domain}")
87+
7788
elif args.action == "set_weighted_cname":
7889
if not args.content:
7990
print(

custom-domain/dstack-ingress/scripts/entrypoint.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,17 @@ set_txt_record() {
247247
echo "Error: Failed to set TXT record for $domain"
248248
exit 1
249249
fi
250+
251+
# Also register APP_ID for alias domain (append-mode to support multiple instances)
252+
if [ -n "$ALIAS_DOMAIN" ]; then
253+
dnsman.py set_txt_append \
254+
--domain "${TXT_PREFIX}.${ALIAS_DOMAIN}" \
255+
--content "$APP_ID:$PORT"
256+
if [ $? -ne 0 ]; then
257+
echo "Warning: Failed to append TXT record for alias domain $ALIAS_DOMAIN"
258+
# Non-fatal: node routing still works; alias routing may be degraded
259+
fi
260+
fi
250261
}
251262

252263
set_alias_domain_cname() {

0 commit comments

Comments
 (0)