mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-31 13:03: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
|
# drop info from this interface
|
||||||
rm -f "$RESOLV_CONF"
|
rm -f "$RESOLV_CONF"
|
||||||
rm -f "$NTPFILE"
|
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
|
if [ -x /usr/sbin/avahi-autoipd ]; then
|
||||||
/usr/sbin/avahi-autoipd -c $interface && /usr/sbin/avahi-autoipd -k $interface
|
/usr/sbin/avahi-autoipd -c $interface && /usr/sbin/avahi-autoipd -k $interface
|
||||||
fi
|
fi
|
||||||
@@ -135,9 +139,10 @@ case "$ACTION" in
|
|||||||
|
|
||||||
# set hostname if given
|
# set hostname if given
|
||||||
if [ -n "$hostname" ]; then
|
if [ -n "$hostname" ]; then
|
||||||
log "setting new hostname: $hostname"
|
log "received DHCP hostname: $hostname"
|
||||||
hostname "$hostname"
|
mkdir -p /etc/hostname.d
|
||||||
sed -i -E "s/^(127\.0\.1\.1\s+).*/\1$hostname/" /etc/hosts
|
echo "$hostname" > "/etc/hostname.d/90-dhcp-${interface}"
|
||||||
|
/usr/libexec/infix/hostname dhcp
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# drop info from this interface
|
# drop info from this interface
|
||||||
|
|||||||
+22
-73
@@ -206,11 +206,6 @@ done:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sys_reload_services(void)
|
|
||||||
{
|
|
||||||
return systemf("initctl -nbq touch sysklogd");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define TIMEZONE_CONF "/etc/timezone"
|
#define TIMEZONE_CONF "/etc/timezone"
|
||||||
#define TIMEZONE_PREV TIMEZONE_CONF "-"
|
#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)
|
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 hostnm[65], domain[65];
|
||||||
char buf[256], *fmt;
|
int rc = SR_ERR_OK;
|
||||||
FILE *nfp, *fp;
|
char *fmt;
|
||||||
int err, fd;
|
FILE *fp;
|
||||||
|
|
||||||
if (event != SR_EV_DONE || !lydx_get_xpathf(diff, XPATH_HOSTNAME_))
|
if (event != SR_EV_DONE || !lydx_get_xpathf(diff, XPATH_HOSTNAME_))
|
||||||
return SR_ERR_OK;
|
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);
|
fmt = strdup(nm);
|
||||||
|
|
||||||
if (hostnamefmt(confd, fmt, hostnm, sizeof(hostnm), domain, sizeof(domain))) {
|
if (hostnamefmt(confd, fmt, hostnm, sizeof(hostnm), domain, sizeof(domain))) {
|
||||||
err = SR_ERR_SYS;
|
rc = SR_ERR_SYS;
|
||||||
goto err;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = sethostname(hostnm, strlen(hostnm));
|
/* Use hostname.d for deterministic hostname management */
|
||||||
if (err) {
|
systemf("mkdir -p /etc/hostname.d");
|
||||||
ERROR("failed setting hostname");
|
|
||||||
err = SR_ERR_SYS;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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))) {
|
if (domain[0] && setdomainname(domain, strlen(domain))) {
|
||||||
ERROR("failed setting domain name");
|
ERROR("failed setting domain name");
|
||||||
/* Not cause for failing this function */
|
/* Not cause for failing this function */
|
||||||
}
|
}
|
||||||
|
|
||||||
fp = fopen(_PATH_HOSTNAME, "w");
|
if (systemf("/usr/libexec/infix/hostname")) {
|
||||||
if (!fp) {
|
failed:
|
||||||
err = SR_ERR_INTERNAL;
|
ERROR("failed setting hostname");
|
||||||
goto err;
|
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)
|
if (fmt)
|
||||||
free(fmt);
|
free(fmt);
|
||||||
|
if (rc)
|
||||||
if (err) {
|
return rc;
|
||||||
ERROR("Failed activating changes.");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
if (sys_reload_services())
|
|
||||||
return SR_ERR_SYS;
|
|
||||||
|
|
||||||
return SR_ERR_OK;
|
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 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;
|
int rc = SR_ERR_OK;
|
||||||
|
|
||||||
if ((rc = change_auth(session, config, diff, event, confd)))
|
if ((rc = change_auth(session, config, diff, event, confd)))
|
||||||
return rc;
|
return rc;
|
||||||
if ((rc = change_ntp(session, config, diff, event, confd)))
|
if ((rc = change_ntp(session, config, diff, event, confd)))
|
||||||
|
|||||||
Reference in New Issue
Block a user