2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-07-31 18:19:40 +00:00

fix(ddns): retry transient DNS-update rejections and fail on persistent ones

ddns.pm's DNS-update send has a 3-try retry loop, but it only retried on
NOTAUTH and -- on the final attempt -- the `next` fell out of the loop without
reporting failure. makedns then printed "Completed updating DNS records." and
"DNS setup is completed" even when the update was never accepted.

Two problems this causes:
- SERVFAIL was never retried. named routinely replies SERVFAIL transiently
  right after a zone (re)load, before the zone is ready to accept dynamic
  updates; the update succeeds a second or two later. This reliably breaks real
  flat-cluster provisioning on el9/el10, where the test case's makedns -n runs
  right after named reloads the zone with the new compute node.
- A persistent NOTAUTH/SERVFAIL (retries exhausted) was silently swallowed and
  reported as success, so a genuinely failed DNS update looked like it worked.

Extract the batch send into send_ddns_update(), which retries NOTAUTH and
SERVFAIL (pausing on SERVFAIL), returns 0 only on NOERROR, and otherwise emits
the error and returns 1. Both batch-send sites now `return 1 if
send_ddns_update(...)`, so a real failure aborts add_or_delete_records instead
of falsely reporting success.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
This commit is contained in:
Daniel Hilst
2026-07-23 09:33:31 -03:00
parent cf44f51463
commit 9dd025bf05
+31 -36
View File
@@ -1576,6 +1576,34 @@ sub update_namedconf {
}
}
# Send a signed dynamic DNS update, retrying transient rejections. Right after a zone (re)load named
# can reply NOTAUTH, or SERVFAIL before the zone is ready to accept dynamic updates; both are
# recoverable, so retry a few times (pausing on SERVFAIL). Returns 0 only when the update was
# accepted (NOERROR) and 1 on a real or persistent failure -- so callers must NOT report success when
# this returns non-zero. (The previous inline loop fell through to success after exhausting its
# retries on NOTAUTH/SERVFAIL, so makedns claimed success even when the update was never accepted.)
sub send_ddns_update {
my ($ctx, $resolver, $update, $zone, $entry) = @_;
for my $attempt (1 .. 3) {
ddns_sign_update($ctx, $update);
my $reply = $resolver->send($update);
if (!$reply) {
xCAT::SvrUtils::sendmsg([ 1, "No reply received when sending DNS update to zone $zone" ], $callback);
return 1;
}
my $rcode = $reply->header->rcode;
return 0 if $rcode eq 'NOERROR';
if (($rcode eq 'NOTAUTH' || $rcode eq 'SERVFAIL') && $attempt < 3) {
sleep 2 if $rcode eq 'SERVFAIL';
next;
}
xCAT::SvrUtils::sendmsg([ 1, "Failure encountered updating $zone with entry '$entry', error was $rcode. See more details in system log." ], $callback);
return 1;
}
return 1;
}
sub add_or_delete_records {
my $ctx = shift;
@@ -1681,46 +1709,13 @@ sub add_or_delete_records {
}
$numreqs -= 1;
if ($numreqs == 0) {
# sometimes even the key is correct, but named still replies NOTAUTH, so retry
for (1 .. 3) {
ddns_sign_update($ctx, $update);
$numreqs = 300;
my $reply = $resolver->send($update);
if ($reply) {
if ($reply->header->rcode eq 'NOTAUTH') {
next;
}
if ($reply->header->rcode ne 'NOERROR') {
xCAT::SvrUtils::sendmsg([ 1, "Failure encountered updating $zone with entry '$entry', error was " . $reply->header->rcode . ". See more details in system log." ], $callback);
}
}
else {
xCAT::SvrUtils::sendmsg([ 1, "No reply received when sending DNS update to zone $zone" ], $callback);
}
last;
}
$numreqs = 300;
return 1 if send_ddns_update($ctx, $resolver, $update, $zone, $entry);
$update = Net::DNS::Update->new($zone); #new empty request
}
}
if ($numreqs != 300) { #either no entries at all to begin with or a perfect multiple of 300
# sometimes even the key is correct, but named still replies NOTAUTH, so retry
for (1 .. 3) {
ddns_sign_update($ctx, $update);
my $reply = $resolver->send($update);
if ($reply) {
if ($reply->header->rcode eq 'NOTAUTH') {
next;
}
if ($reply->header->rcode ne 'NOERROR') {
xCAT::SvrUtils::sendmsg([ 1, "Failure encountered updating $zone with entry '$entry', error was " . $reply->header->rcode . ". See more details in system log." ], $callback);
}
}
else {
xCAT::SvrUtils::sendmsg([ 1, "No reply received when sending DNS update to zone $zone" ], $callback);
}
last;
}
return 1 if send_ddns_update($ctx, $resolver, $update, $zone, $entry);
# sometimes resolver does not work if the update zone request sent so quick
sleep 1;