git: ba58e8ad7263 - main - nuageinit: implement manage_etc_hosts support

From: Baptiste Daroussin <bapt_at_FreeBSD.org>
Date: Fri, 05 Jun 2026 06:40:30 UTC
The branch main has been updated by bapt:

URL: https://cgit.FreeBSD.org/src/commit/?id=ba58e8ad726318ed59b6cc5934435dbddbe23dac

commit ba58e8ad726318ed59b6cc5934435dbddbe23dac
Author:     Baptiste Daroussin <bapt@FreeBSD.org>
AuthorDate: 2026-06-05 05:49:16 +0000
Commit:     Baptiste Daroussin <bapt@FreeBSD.org>
CommitDate: 2026-06-05 05:49:16 +0000

    nuageinit: implement manage_etc_hosts support
    
    Add support for adding the instance hostname to /etc/hosts on the
    127.0.0.1 and ::1 localhost lines, matching cloud-init's default
    behaviour (manage_etc_hosts: true).
    
    create a revolve_hostname helper to avoid code duplucation.
---
 libexec/nuageinit/nuage.lua   | 62 +++++++++++++++++++++++++++++++++++++++++++
 libexec/nuageinit/nuageinit   | 30 ++++++++++++++++-----
 libexec/nuageinit/nuageinit.7 | 13 +++++++++
 3 files changed, 99 insertions(+), 6 deletions(-)

diff --git a/libexec/nuageinit/nuage.lua b/libexec/nuageinit/nuage.lua
index 7cce4c9bece1..45e14ef0ce21 100644
--- a/libexec/nuageinit/nuage.lua
+++ b/libexec/nuageinit/nuage.lua
@@ -162,6 +162,67 @@ local function sethostname(hostname)
 	f:close()
 end
 
+local function update_etc_hosts(root, hostname)
+	if hostname == nil or hostname == "" then
+		return
+	end
+	local hosts_path = root .. "/etc/hosts"
+	local lines = {}
+	local already_present = false
+
+	local f = io.open(hosts_path, "r")
+	if not f then
+		-- File doesn't exist, create a minimal one
+		local nf = io.open(hosts_path, "w")
+		if not nf then
+			warnmsg("unable to create " .. hosts_path)
+			return
+		end
+		nf:write("::1\t\tlocalhost " .. hostname .. "\n")
+		nf:write("127.0.0.1\t\tlocalhost " .. hostname .. "\n")
+		nf:close()
+		return
+	end
+
+	for line in f:lines() do
+		if line:find(hostname, 1, true) then
+			already_present = true
+		end
+		table.insert(lines, line)
+	end
+	f:close()
+
+	if already_present then
+		return
+	end
+
+	-- Not present, append to localhost lines
+	local new_lines = {}
+	local found_localhost = false
+	for _, line in ipairs(lines) do
+		if (line:match("^127%.0%.0%.1%s") or line:match("^::1%s")) and line:find("localhost", 1, true) then
+			table.insert(new_lines, line .. " " .. hostname)
+			found_localhost = true
+		else
+			table.insert(new_lines, line)
+		end
+	end
+
+	if not found_localhost then
+		table.insert(new_lines, "127.0.0.1\t\tlocalhost " .. hostname)
+	end
+
+	f = io.open(hosts_path, "w")
+	if not f then
+		warnmsg("unable to open " .. hosts_path .. " for writing")
+		return
+	end
+	for _, line in ipairs(new_lines) do
+		f:write(line .. "\n")
+	end
+	f:close()
+end
+
 local function splitlist(list)
 	local ret = {}
 	if type(list) == "string" then
@@ -775,6 +836,7 @@ local n = {
 	addsshkey = addsshkey,
 	update_sshd_config = update_sshd_config,
 	delete_ssh_host_keys = delete_ssh_host_keys,
+	update_etc_hosts = update_etc_hosts,
 	chpasswd = chpasswd,
 	pkg_bootstrap = pkg_bootstrap,
 	install_package = install_package,
diff --git a/libexec/nuageinit/nuageinit b/libexec/nuageinit/nuageinit
index bfe5f893756e..9d2f3c6024c4 100755
--- a/libexec/nuageinit/nuageinit
+++ b/libexec/nuageinit/nuageinit
@@ -99,16 +99,23 @@ local function get_ifaces_by_mac()
 	return myifaces
 end
 
-local function sethostname(obj, metadata)
-	-- always prefer fqdn if specified over hostname
+local function resolve_hostname(obj, metadata)
 	if obj and obj.fqdn then
-		nuage.sethostname(obj.fqdn)
+		return obj.fqdn
 	elseif obj and obj.hostname then
-		nuage.sethostname(obj.hostname)
+		return obj.hostname
 	elseif metadata["local-hostname"] then
-		nuage.sethostname(metadata["local-hostname"])
+		return metadata["local-hostname"]
 	elseif metadata["hostname"] then
-		nuage.sethostname(metadata["hostname"])
+		return metadata["hostname"]
+	end
+	return nil
+end
+
+local function sethostname(obj, metadata)
+	local hostname = resolve_hostname(obj, metadata)
+	if hostname then
+		nuage.sethostname(hostname)
 	end
 end
 
@@ -541,6 +548,16 @@ local function bootcmd(obj)
 	end
 end
 
+local function manage_etc_hosts(obj, metadata)
+	if obj.manage_etc_hosts == false then
+		return
+	end
+	local hostname = resolve_hostname(obj, metadata)
+	if hostname then
+		nuage.update_etc_hosts(root, hostname)
+	end
+end
+
 local function runcmd(obj)
 	if obj.runcmd == nil then return end
 	local f = nil
@@ -813,6 +830,7 @@ elseif line == "#cloud-config" then
 	local pre_network_calls = {
 		bootcmd,
 		sethostname,
+		manage_etc_hosts,
 		settimezone,
 		groups,
 		create_default_user,
diff --git a/libexec/nuageinit/nuageinit.7 b/libexec/nuageinit/nuageinit.7
index 3cc0eceeb2ae..66a72324f414 100644
--- a/libexec/nuageinit/nuageinit.7
+++ b/libexec/nuageinit/nuageinit.7
@@ -146,6 +146,19 @@ Specify a fully qualified domain name for the instance.
 Specify the hostname of the instance if
 .Qq Ic fqdn
 is not set.
+.It Ic manage_etc_hosts
+Boolean which determines whether the hostname should be added to
+.Pa /etc/hosts
+on the
+.Qq 127.0.0.1
+and
+.Qq ::1
+localhost lines.
+Defaults to
+.Ar true .
+Set to
+.Ar false
+to skip this behaviour.
 .It Ic timezone
 Sets the system timezone based on the value provided.
 .Pp