mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-27 19:23:02 +02:00
confd: add deterministic hostname management via /etc/hostname.d/
Resolve race condition between DHCP and configured hostname by introducing priority-based hostname management using /etc/hostname.d/ directory pattern. Priority order (highest wins): 90-dhcp-<iface> - DHCP assigned hostname 50-configured - YANG /system/hostname config 10-default - Bootstrap/factory default The new /usr/libexec/infix/hostname helper reads all sources and applies the highest priority hostname. It exits early if hostname unchanged, preventing unnecessary service restarts. Fixes #1112 Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
+74
@@ -0,0 +1,74 @@
|
||||
#!/bin/sh
|
||||
# Deterministically set system hostname from /etc/hostname.d/
|
||||
#
|
||||
# Highest numbered file wins (lexicographic sort, 90-dhcp > 50-configured > 10-default)
|
||||
#
|
||||
# Priority scheme:
|
||||
# 10-default - Bootstrap/factory default (%h-%m format)
|
||||
# 50-configured - From confd /system/hostname
|
||||
# 90-dhcp-<iface> - From DHCP clietn on interface (highest priority)
|
||||
|
||||
HOSTNAME_D="/etc/hostname.d"
|
||||
|
||||
# Ensure directory exists
|
||||
mkdir -p "$HOSTNAME_D"
|
||||
|
||||
# Find the highest priority file (reverse sort, take first)
|
||||
hostname_file=$(ls -1 "$HOSTNAME_D" 2>/dev/null | sort -r | head -1)
|
||||
|
||||
if [ -z "$hostname_file" ]; then
|
||||
logger -it confd "No hostname sources found in $HOSTNAME_D"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Read hostname from the file (first line only, strip whitespace)
|
||||
new_hostname=$(cat "$HOSTNAME_D/$hostname_file" | head -1 | tr -d '\n\r\t ')
|
||||
if [ -z "$new_hostname" ]; then
|
||||
logger -it confd "Empty hostname in $hostname_file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ${#new_hostname} -gt 64 ]; then
|
||||
logger -it confd "Hostname too long (${#new_hostname} > 64) in $hostname_file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if hostname has actually changed
|
||||
current_hostname=$(hostname)
|
||||
if [ "$new_hostname" = "$current_hostname" ]; then
|
||||
# No change needed, exit silently
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Set the hostname
|
||||
logger -it confd "Setting hostname to '$new_hostname' from $hostname_file"
|
||||
hostname "$new_hostname"
|
||||
|
||||
# Update /etc/hostname (for persistence across reboots)
|
||||
echo "$new_hostname" > /etc/hostname
|
||||
|
||||
# Update /etc/hosts (127.0.1.1 entry for proper name resolution)
|
||||
if grep -q "^127\.0\.1\.1" /etc/hosts; then
|
||||
sed -i -E "s/^(127\.0\.1\.1\s+).*/\1$new_hostname/" /etc/hosts
|
||||
else
|
||||
# Add entry if it doesn't exist
|
||||
echo "127.0.1.1 $new_hostname" >> /etc/hosts
|
||||
fi
|
||||
|
||||
# Notify services of hostname change, skip while in bootstrap
|
||||
initctl -nbq touch sysklogd
|
||||
if ! runlevel >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
initctl -bq status lldpd && lldpcli configure system hostname "$new_hostname" 2>/dev/null
|
||||
initctl -bq status mdns && avahi-set-host-name "$new_hostname" 2>/dev/null
|
||||
initctl -bq touch netbrowse 2>/dev/null
|
||||
|
||||
# If called from dhcp script we need to reload to activate new name in syslogd
|
||||
# Otherwise we're called from confd, which does the reload when all is done.
|
||||
if [ -n "$1" ]; then
|
||||
initctl -b reload
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
# Initialize default hostname for hostname.d pattern
|
||||
# This runs very early in boot to set up the default hostname entry
|
||||
|
||||
HOSTNAME_D="/etc/hostname.d"
|
||||
|
||||
# Ensure directory exists
|
||||
mkdir -p "$HOSTNAME_D"
|
||||
|
||||
# If no default exists yet, create it from /etc/hostname (from squashfs)
|
||||
if [ ! -f "$HOSTNAME_D/10-default" ] && [ -f /etc/hostname ]; then
|
||||
cp /etc/hostname "$HOSTNAME_D/10-default"
|
||||
fi
|
||||
|
||||
# Apply hostname using the deterministic helper
|
||||
if [ -x /usr/libexec/infix/hostname ]; then
|
||||
/usr/libexec/infix/hostname
|
||||
fi
|
||||
@@ -108,6 +108,10 @@ case "$ACTION" in
|
||||
# drop info from this interface
|
||||
rm -f "$RESOLV_CONF"
|
||||
rm -f "$NTPFILE"
|
||||
if [ -f "/etc/hostname.d/90-dhcp-${interface}" ]; then
|
||||
rm -f "/etc/hostname.d/90-dhcp-${interface}"
|
||||
/usr/libexec/infix/hostname dhcp
|
||||
fi
|
||||
if [ -x /usr/sbin/avahi-autoipd ]; then
|
||||
/usr/sbin/avahi-autoipd -c $interface && /usr/sbin/avahi-autoipd -k $interface
|
||||
fi
|
||||
@@ -135,9 +139,10 @@ case "$ACTION" in
|
||||
|
||||
# set hostname if given
|
||||
if [ -n "$hostname" ]; then
|
||||
log "setting new hostname: $hostname"
|
||||
hostname "$hostname"
|
||||
sed -i -E "s/^(127\.0\.1\.1\s+).*/\1$hostname/" /etc/hosts
|
||||
log "received DHCP hostname: $hostname"
|
||||
mkdir -p /etc/hostname.d
|
||||
echo "$hostname" > "/etc/hostname.d/90-dhcp-${interface}"
|
||||
/usr/libexec/infix/hostname dhcp
|
||||
fi
|
||||
|
||||
# drop info from this interface
|
||||
|
||||
+22
-73
@@ -206,11 +206,6 @@ done:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int sys_reload_services(void)
|
||||
{
|
||||
return systemf("initctl -nbq touch sysklogd");
|
||||
}
|
||||
|
||||
|
||||
#define TIMEZONE_CONF "/etc/timezone"
|
||||
#define TIMEZONE_PREV TIMEZONE_CONF "-"
|
||||
@@ -1558,11 +1553,10 @@ int hostnamefmt(struct confd *confd, const char *fmt, char *hostnm, size_t hostl
|
||||
|
||||
static int change_hostname(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
|
||||
{
|
||||
const char *hostip = "127.0.1.1";
|
||||
char hostnm[65], domain[65];
|
||||
char buf[256], *fmt;
|
||||
FILE *nfp, *fp;
|
||||
int err, fd;
|
||||
int rc = SR_ERR_OK;
|
||||
char *fmt;
|
||||
FILE *fp;
|
||||
|
||||
if (event != SR_EV_DONE || !lydx_get_xpathf(diff, XPATH_HOSTNAME_))
|
||||
return SR_ERR_OK;
|
||||
@@ -1572,82 +1566,36 @@ static int change_hostname(sr_session_ctx_t *session, struct lyd_node *config, s
|
||||
fmt = strdup(nm);
|
||||
|
||||
if (hostnamefmt(confd, fmt, hostnm, sizeof(hostnm), domain, sizeof(domain))) {
|
||||
err = SR_ERR_SYS;
|
||||
goto err;
|
||||
rc = SR_ERR_SYS;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
err = sethostname(hostnm, strlen(hostnm));
|
||||
if (err) {
|
||||
ERROR("failed setting hostname");
|
||||
err = SR_ERR_SYS;
|
||||
goto err;
|
||||
}
|
||||
/* Use hostname.d for deterministic hostname management */
|
||||
systemf("mkdir -p /etc/hostname.d");
|
||||
|
||||
fp = fopen("/etc/hostname.d/50-configured", "w");
|
||||
if (!fp)
|
||||
goto failed;
|
||||
|
||||
fprintf(fp, "%s\n", hostnm);
|
||||
fclose(fp);
|
||||
|
||||
/* Handle domain name if present */
|
||||
if (domain[0] && setdomainname(domain, strlen(domain))) {
|
||||
ERROR("failed setting domain name");
|
||||
/* Not cause for failing this function */
|
||||
}
|
||||
|
||||
fp = fopen(_PATH_HOSTNAME, "w");
|
||||
if (!fp) {
|
||||
err = SR_ERR_INTERNAL;
|
||||
goto err;
|
||||
if (systemf("/usr/libexec/infix/hostname")) {
|
||||
failed:
|
||||
ERROR("failed setting hostname");
|
||||
rc = SR_ERR_SYS;
|
||||
}
|
||||
|
||||
fprintf(fp, "%s\n", hostnm);
|
||||
fclose(fp);
|
||||
|
||||
nfp = fopen(_PATH_HOSTS "+", "w");
|
||||
if (!nfp) {
|
||||
err = SR_ERR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
fd = fileno(nfp);
|
||||
if (fd == -1 || fchown(fd, 0, 0) || fchmod(fd, 0644)) {
|
||||
fclose(nfp);
|
||||
goto err;
|
||||
}
|
||||
|
||||
fp = fopen(_PATH_HOSTS, "r");
|
||||
if (!fp) {
|
||||
err = SR_ERR_INTERNAL;
|
||||
fclose(nfp);
|
||||
goto err;
|
||||
}
|
||||
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
if (!strncmp(buf, hostip, strlen(hostip))) {
|
||||
if (domain[0])
|
||||
snprintf(buf, sizeof(buf), "%s\t%s.%s %s\n", hostip, hostnm, domain, hostnm);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%s\t%s\n", hostip, hostnm);
|
||||
}
|
||||
fputs(buf, nfp);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fclose(nfp);
|
||||
if (rename(_PATH_HOSTS "+", _PATH_HOSTS))
|
||||
ERRNO("Failed activating changes to "_PATH_HOSTS);
|
||||
|
||||
/* skip in bootstrap, lldpd and avahi have not started yet */
|
||||
if (systemf("runlevel >/dev/null 2>&1"))
|
||||
goto err;
|
||||
|
||||
/* Inform any running lldpd and avahi of the change ... */
|
||||
systemf("initctl -bq status lldpd && lldpcli configure system hostname %s", hostnm);
|
||||
systemf("initctl -bq status mdns && avahi-set-host-name %s", hostnm);
|
||||
systemf("initctl -bq touch netbrowse");
|
||||
err:
|
||||
if (fmt)
|
||||
free(fmt);
|
||||
|
||||
if (err) {
|
||||
ERROR("Failed activating changes.");
|
||||
return err;
|
||||
}
|
||||
if (sys_reload_services())
|
||||
return SR_ERR_SYS;
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
@@ -1656,6 +1604,7 @@ err:
|
||||
int ietf_system_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
|
||||
{
|
||||
int rc = SR_ERR_OK;
|
||||
|
||||
if ((rc = change_auth(session, config, diff, event, confd)))
|
||||
return rc;
|
||||
if ((rc = change_ntp(session, config, diff, event, confd)))
|
||||
|
||||
Reference in New Issue
Block a user