aboutsummaryrefslogtreecommitdiff
path: root/libexec/nuageinit
diff options
context:
space:
mode:
Diffstat (limited to 'libexec/nuageinit')
-rw-r--r--libexec/nuageinit/nuage.lua87
-rwxr-xr-xlibexec/nuageinit/nuageinit273
-rw-r--r--libexec/nuageinit/nuageinit.7123
-rw-r--r--libexec/nuageinit/tests/Makefile1
-rw-r--r--libexec/nuageinit/tests/nuage.sh10
-rw-r--r--libexec/nuageinit/tests/nuageinit.sh17
-rw-r--r--libexec/nuageinit/tests/settimezone.lua5
-rw-r--r--libexec/nuageinit/tests/utils.sh1
8 files changed, 473 insertions, 44 deletions
diff --git a/libexec/nuageinit/nuage.lua b/libexec/nuageinit/nuage.lua
index 493ae11d6ca7..ef3cfd994fe1 100644
--- a/libexec/nuageinit/nuage.lua
+++ b/libexec/nuageinit/nuage.lua
@@ -2,11 +2,23 @@
-- SPDX-License-Identifier: BSD-2-Clause
--
-- Copyright(c) 2022-2025 Baptiste Daroussin <bapt@FreeBSD.org>
+-- Copyright(c) 2025 Jesús Daniel Colmenares Oviedo <dtxdf@FreeBSD.org>
local unistd = require("posix.unistd")
local sys_stat = require("posix.sys.stat")
local lfs = require("lfs")
+local function getlocalbase()
+ local f = io.popen("sysctl -in user.localbase 2> /dev/null")
+ local localbase = f:read("*l")
+ f:close()
+ if localbase == nil or localbase:len() == 0 then
+ -- fallback
+ localbase = "/usr/local"
+ end
+ return localbase
+end
+
local function decode_base64(input)
local b = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
input = string.gsub(input, '[^'..b..'=]', '')
@@ -276,11 +288,59 @@ local function addsshkey(homedir, key)
end
end
+local function adddoas(pwd)
+ local chmodetcdir = false
+ local chmoddoasconf = false
+ local root = os.getenv("NUAGE_FAKE_ROOTDIR")
+ local localbase = getlocalbase()
+ local etcdir = localbase .. "/etc"
+ if root then
+ etcdir= root .. etcdir
+ end
+ local doasconf = etcdir .. "/doas.conf"
+ local doasconf_attr = lfs.attributes(doasconf)
+ if doasconf_attr == nil then
+ chmoddoasconf = true
+ local dirattrs = lfs.attributes(etcdir)
+ if dirattrs == nil then
+ local r, err = mkdir_p(etcdir)
+ if not r then
+ return nil, err .. " (creating " .. etcdir .. ")"
+ end
+ chmodetcdir = true
+ end
+ end
+ local f = io.open(doasconf, "a")
+ if not f then
+ warnmsg("impossible to open " .. doasconf)
+ return
+ end
+ if type(pwd.doas) == "string" then
+ local rule = pwd.doas
+ rule = rule:gsub("%%u", pwd.name)
+ f:write(rule .. "\n")
+ elseif type(pwd.doas) == "table" then
+ for _, str in ipairs(pwd.doas) do
+ local rule = str
+ rule = rule:gsub("%%u", pwd.name)
+ f:write(rule .. "\n")
+ end
+ end
+ f:close()
+ if chmoddoasconf then
+ chmod(doasconf, "0640")
+ end
+ if chmodetcdir then
+ chmod(etcdir, "0755")
+ end
+end
+
local function addsudo(pwd)
local chmodsudoersd = false
local chmodsudoers = false
local root = os.getenv("NUAGE_FAKE_ROOTDIR")
- local sudoers_dir = "/usr/local/etc/sudoers.d"
+ local localbase = getlocalbase()
+ local sudoers_dir = localbase .. "/etc/sudoers.d"
if root then
sudoers_dir= root .. sudoers_dir
end
@@ -311,10 +371,10 @@ local function addsudo(pwd)
end
f:close()
if chmodsudoers then
- chmod(sudoers, "0640")
+ chmod(sudoers, "0440")
end
if chmodsudoersd then
- chmod(sudoers, "0740")
+ chmod(sudoers_dir, "0750")
end
end
@@ -451,6 +511,23 @@ local function chpasswd(obj)
end
end
+local function settimezone(timezone)
+ if timezone == nil then
+ return
+ end
+ local root = os.getenv("NUAGE_FAKE_ROOTDIR")
+ if not root then
+ root = "/"
+ end
+
+ f, _, rc = os.execute("tzsetup -s -C " .. root .. " " .. timezone)
+
+ if not f then
+ warnmsg("Impossible to configure time zone ( rc = " .. rc .. " )")
+ return
+ end
+end
+
local function pkg_bootstrap()
if os.getenv("NUAGE_RUN_TESTS") then
return true
@@ -480,7 +557,7 @@ local function install_package(package)
end
local function run_pkg_cmd(subcmd)
- local cmd = "pkg " .. subcmd .. " -y"
+ local cmd = "env ASSUME_ALWAYS_YES=yes pkg " .. subcmd
if os.getenv("NUAGE_RUN_TESTS") then
print(cmd)
return true
@@ -556,6 +633,7 @@ local n = {
dirname = dirname,
mkdir_p = mkdir_p,
sethostname = sethostname,
+ settimezone = settimezone,
adduser = adduser,
addgroup = addgroup,
addsshkey = addsshkey,
@@ -566,6 +644,7 @@ local n = {
update_packages = update_packages,
upgrade_packages = upgrade_packages,
addsudo = addsudo,
+ adddoas = adddoas,
addfile = addfile
}
diff --git a/libexec/nuageinit/nuageinit b/libexec/nuageinit/nuageinit
index 0fcdc7274db3..29340a3d91ea 100755
--- a/libexec/nuageinit/nuageinit
+++ b/libexec/nuageinit/nuageinit
@@ -3,6 +3,7 @@
-- SPDX-License-Identifier: BSD-2-Clause-FreeBSD
--
-- Copyright(c) 2022-2025 Baptiste Daroussin <bapt@FreeBSD.org>
+-- Copyright(c) 2025 Jesús Daniel Colmenares Oviedo <dtxdf@FreeBSD.org>
local nuage = require("nuage")
local ucl = require("ucl")
@@ -46,7 +47,15 @@ local function open_config(name)
return openat("/etc/rc.conf.d", name)
end
-local function get_ifaces()
+local function open_resolv_conf()
+ return openat("/etc", "resolv.conf")
+end
+
+local function open_resolvconf_conf()
+ return openat("/etc", "resolvconf.conf")
+end
+
+local function get_ifaces_by_mac()
local parser = ucl.parser()
-- grab ifaces
local ns = io.popen("netstat -i --libxo json")
@@ -77,6 +86,10 @@ local function sethostname(obj)
end
end
+local function settimezone(obj)
+ nuage.settimezone(obj.timezone)
+end
+
local function groups(obj)
if obj.groups == nil then return end
@@ -127,6 +140,9 @@ local function users(obj)
if u.sudo then
nuage.addsudo(u)
end
+ if u.doas then
+ nuage.adddoas(u)
+ end
else
nuage.warn("invalid type : " .. type(u) .. " for users entry number " .. n)
end
@@ -171,6 +187,59 @@ local function ssh_authorized_keys(obj)
end
end
+local function nameservers(interface, obj)
+ local resolvconf_conf_handler = open_resolvconf_conf()
+
+ if obj.search then
+ local with_space = false
+
+ resolvconf_conf_handler:write('search_domains="')
+
+ for _, d in ipairs(obj.search) do
+ if with_space then
+ resolvconf_conf_handler:write(" " .. d)
+ else
+ resolvconf_conf_handler:write(d)
+ with_space = true
+ end
+ end
+
+ resolvconf_conf_handler:write('"\n')
+ end
+
+ if obj.addresses then
+ local with_space = false
+
+ resolvconf_conf_handler:write('name_servers="')
+
+ for _, a in ipairs(obj.addresses) do
+ if with_space then
+ resolvconf_conf_handler:write(" " .. a)
+ else
+ resolvconf_conf_handler:write(a)
+ with_space = true
+ end
+ end
+
+ resolvconf_conf_handler:write('"\n')
+ end
+
+ resolvconf_conf_handler:close()
+
+ local resolv_conf = root .. "/etc/resolv.conf"
+
+ resolv_conf_attr = lfs.attributes(resolv_conf)
+
+ if resolv_conf_attr == nil then
+ resolv_conf_handler = open_resolv_conf()
+ resolv_conf_handler:close()
+ end
+
+ if not os.execute("resolvconf -a " .. interface .. " < " .. resolv_conf) then
+ nuage.warn("Failed to execute resolvconf(8)")
+ end
+end
+
local function install_packages(packages)
if not nuage.pkg_bootstrap() then
nuage.warn("Failed to bootstrap pkg, skip installing packages")
@@ -187,6 +256,85 @@ local function install_packages(packages)
end
end
+local function list_ifaces()
+ local proc = io.popen("ifconfig -l")
+ local raw_ifaces = proc:read("*a")
+ proc:close()
+ local ifaces = {}
+ for i in raw_ifaces:gmatch("[^%s]+") do
+ table.insert(ifaces, i)
+ end
+ return ifaces
+end
+
+local function get_ifaces_by_driver()
+ local proc = io.popen("ifconfig -D")
+ local drivers = {}
+ local last_interface = nil
+ for line in proc:lines() do
+ local interface = line:match("^([%S]+): ")
+
+ if interface then
+ last_interface = interface
+ end
+
+ local driver = line:match("^[%s]+drivername: ([%S]+)$")
+
+ if driver then
+ drivers[driver] = last_interface
+ end
+ end
+ proc:close()
+
+ return drivers
+end
+
+local function match_rules(rules)
+ -- To comply with the cloud-init specification, all rules must match and a table
+ -- with the matching interfaces must be returned. This changes the way we initially
+ -- thought about our implementation, since at first we only needed one interface,
+ -- but cloud-init performs actions on a group of matching interfaces.
+ local interfaces = {}
+ if rules.macaddress then
+ local ifaces = get_ifaces_by_mac()
+ local interface = ifaces[rules.macaddress]
+ if not interface then
+ nuage.warn("not interface matching by MAC address: " .. rules.macaddress)
+ return
+ end
+ interfaces[interface] = 1
+ end
+ if rules.name then
+ local match = false
+ for _, i in pairs(list_ifaces()) do
+ if i:match(rules.name) then
+ match = true
+ interfaces[i] = 1
+ end
+ end
+ if not match then
+ nuage.warn("not interface matching by name: " .. rules.name)
+ return
+ end
+ end
+ if rules.driver then
+ local match = false
+ local drivers = get_ifaces_by_driver()
+ for d in pairs(drivers) do
+ if d:match(rules.driver) then
+ match = true
+ interface = drivers[d]
+ interfaces[interface] = 1
+ end
+ end
+ if not match then
+ nuage.warn("not interface matching by driver: " .. rules.driver)
+ return
+ end
+ end
+ return interfaces
+end
+
local function write_files(files, defer)
if not files then
return
@@ -210,41 +358,76 @@ end
local function network_config(obj)
if obj.network == nil then return end
- local ifaces = get_ifaces()
local network = open_config("network")
local routing = open_config("routing")
local ipv6 = {}
- for _, v in pairs(obj.network.ethernets) do
- if not v.match then
- goto next
+ local set_defaultrouter = true
+ local set_defaultrouter6 = true
+ local set_nameservers = true
+ for i, v in pairs(obj.network.ethernets) do
+ local interfaces = {}
+ if v.match then
+ interfaces = match_rules(v.match)
+
+ if next(interfaces) == nil then
+ goto next
+ end
+ else
+ interfaces[i] = 1
end
- if not v.match.macaddress then
- goto next
+ local extra_opts = ""
+ if v.wakeonlan then
+ extra_opts = extra_opts .. " wol"
end
- if not ifaces[v.match.macaddress] then
- nuage.warn("not interface matching: " .. v.match.macaddress)
- goto next
+ if v.mtu then
+ if type(v.mtu) == "number" then
+ mtu = tostring(v.mtu)
+ else
+ mtu = v.mtu
+ end
+ if mtu:match("%d") then
+ extra_opts = extra_opts .. " mtu " .. mtu
+ else
+ nuage.warn("MTU is not set because the specified value is invalid: " .. mtu)
+ end
end
- local interface = ifaces[v.match.macaddress]
- if v.dhcp4 then
- network:write("ifconfig_" .. interface .. '="DHCP"\n')
- elseif v.addresses then
- for _, a in pairs(v.addresses) do
- if a:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)") then
- network:write("ifconfig_" .. interface .. '="inet ' .. a .. '"\n')
- else
- network:write("ifconfig_" .. interface .. '_ipv6="inet6 ' .. a .. '"\n')
- ipv6[#ipv6 + 1] = interface
+ for interface in pairs(interfaces) do
+ if v.match and v.match.macaddress and v["set-name"] then
+ local ifaces = get_ifaces_by_mac()
+ local matched = ifaces[v.match.macaddress]
+ if matched and matched == interface then
+ network:write("ifconfig_" .. interface .. '_name=' .. v["set-name"] .. '\n')
+ interface = v["set-name"]
+ end
+ end
+ if v.dhcp4 then
+ network:write("ifconfig_" .. interface .. '="DHCP"' .. extra_opts .. '\n')
+ elseif v.addresses then
+ for _, a in pairs(v.addresses) do
+ if a:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)") then
+ network:write("ifconfig_" .. interface .. '="inet ' .. a .. extra_opts .. '"\n')
+ else
+ network:write("ifconfig_" .. interface .. '_ipv6="inet6 ' .. a .. extra_opts .. '"\n')
+ ipv6[#ipv6 + 1] = interface
+ end
+ end
+ if set_nameservers and v.nameservers then
+ set_nameservers = false
+ nameservers(interface, v.nameservers)
+ end
+ if set_defaultrouter and v.gateway4 then
+ set_defaultrouter = false
+ routing:write('defaultrouter="' .. v.gateway4 .. '"\n')
+ end
+ if v.gateway6 then
+ if set_defaultrouter6 then
+ set_defaultrouter6 = false
+ routing:write('ipv6_defaultrouter="' .. v.gateway6 .. '"\n')
+ end
+ routing:write("ipv6_route_" .. interface .. '="' .. v.gateway6)
+ routing:write(" -prefixlen 128 -interface " .. interface .. '"\n')
end
end
- end
- if v.gateway4 then
- routing:write('defaultrouter="' .. v.gateway4 .. '"\n')
- end
- if v.gateway6 then
- routing:write('ipv6_defaultrouter="' .. v.gateway6 .. '"\n')
- routing:write("ipv6_route_" .. interface .. '="' .. v.gateway6)
- routing:write(" -prefixlen 128 -interface " .. interface .. '"\n')
end
::next::
end
@@ -316,7 +499,7 @@ local function config2_network(p)
end
local obj = parser:get_object()
- local ifaces = get_ifaces()
+ local ifaces = get_ifaces_by_mac()
if not ifaces then
nuage.warn("no network interfaces found")
return
@@ -403,6 +586,26 @@ local function config2_network(p)
routing:close()
end
+local function parse_network_config()
+ local nc_file = ni_path .. "/network-config"
+ local nc_file_attr = lfs.attributes(nc_file)
+ if nc_file_attr == nil then
+ return
+ end
+ local f, err = io.open(nc_file)
+ if err then
+ nuage.err("error parsing nocloud network-config: " .. err)
+ end
+ local obj = yaml.load(f:read("*a"))
+ f:close()
+ if not obj then
+ nuage.err("error parsing nocloud network-config")
+ end
+ local netobj = {}
+ netobj["network"] = obj
+ return netobj
+end
+
if citype == "config-2" then
local parser = ucl.parser()
local res, err = parser:parse_file(ni_path .. "/meta_data.json")
@@ -468,6 +671,7 @@ f:close()
if line == "#cloud-config" then
local pre_network_calls = {
sethostname,
+ settimezone,
groups,
create_default_user,
ssh_keys,
@@ -498,7 +702,16 @@ if line == "#cloud-config" then
end
for i = 1, #calls_table do
- calls_table[i](obj)
+ if citype == "nocloud" and calls_table[i] == network_config then
+ netobj = parse_network_config()
+ if netobj == nil then
+ network_config(obj)
+ else
+ network_config(netobj)
+ end
+ else
+ calls_table[i](obj)
+ end
end
elseif line:sub(1, 2) == "#!" then
-- delay for execution at rc.local time --
diff --git a/libexec/nuageinit/nuageinit.7 b/libexec/nuageinit/nuageinit.7
index 327ce160e151..b527c984970c 100644
--- a/libexec/nuageinit/nuageinit.7
+++ b/libexec/nuageinit/nuageinit.7
@@ -1,6 +1,7 @@
.\" SPDX-License-Identifier: BSD-2-Clause
.\"
.\" Copyright (c) 2025 Baptiste Daroussin <bapt@FreeBSD.org>
+.\" Copyright (c) 2025 Jesús Daniel Colmenares Oviedo <dtxdf@FreeBSD.org>
.\"
.Dd June 26, 2025
.Dt NUAGEINIT 7
@@ -143,6 +144,11 @@ Specify a fully qualified domain name for the instance.
Specify the hostname of the instance if
.Qq Ic fqdn
is not set.
+.It Ic timezone
+Sets the system timezone based on the value provided.
+.Pp
+See also
+.Xr tzfile 3 Ns .
.It Ic groups
An array of strings or objects to be created:
.Bl -bullet
@@ -176,6 +182,96 @@ boolean which determines the value of the
configuration in
.Pa /etc/ssh/sshd_config
.It Ic network
+Network configuration parameters.
+.Pp
+Specifying the following parameters from a file named
+.Pa network-config
+takes precedence over their specification from the
+.Ic network
+parameter of
+.Pa user-data Ns .
+.Bl -tag -width "ethernets"
+.It Ic ethernets
+Mapping representing a generic configuration for existing network interfaces.
+.Pp
+Each key is an interface name that is only used when no
+.Sy match
+rule is specified.
+If
+.Sy match
+rules are specified, an arbitrary name can be used
+.Po e.g.: id0 Pc Ns .
+.Bl -tag -width "nameservers"
+.It Ic match
+This selects a subset of available physical devices by various hardware properties.
+The following configuration will then apply to all matching devices, as soon as
+they appear.
+All specified properties must match.
+The following properties for
+creating matches are supported:
+.Bl -tag -width "macaddress"
+.It Ic macaddress
+.No Device's MAC address in the form Sy xx:xx:xx:xx:xx:xx Ns .
+Letters should be lowercase.
+.It Ic name
+Current interface name.
+Lua pattern-matching expressions are supported.
+.It Ic driver
+Interface driver name and unit number of the interface.
+Lua pattern-natching expressions
+are supported.
+.El
+.It Ic set-name
+When matching on unique properties such as MAC, match rules can be written so that they
+match only one device.
+Then this property can be used to give that device a more
+specific/desirable/nicer name than the default.
+.Pp
+While multiple properties can be used in a match,
+.Sy macaddress
+is required for nuageinit to perform the rename.
+.It Ic mtu
+The MTU key represents a device's Maximum Transmission Unit, the largest size packet
+or frame.
+.It Ic wakeonlan
+Enable wake on LAN.
+Off by default.
+.It Ic dhcp4
+Configure the interface to use DHCP.
+.Pp
+This takes precedence over
+.Sy addresses
+when both are specified.
+.It Ic addresses
+List of strings representing IPv4 or IPv6 addresses.
+.It Ic gateway4
+Set default gateway for IPv4, for manual address configuration.
+This requires setting
+.Sy addresses
+too.
+.Pp
+Since only one default router can be configured at a time, this parameter is applied
+when processing the first entry, and any others are silently ignored.
+.It Ic gateway6
+Set default gateway for IPv6, for manual address configuration.
+This requires setting
+.Sy addresses
+too.
+.Pp
+Since only one default router can be configured at a time, this parameter is applied
+when processing the first entry, and any others are silently ignored.
+.It Ic nameservers
+Set DNS servers and search domains, for manual address configuration.
+.Pp
+There are two supported fields:
+.Bl -tag -width "addresses"
+.It Ic search
+Search list for host-name lookup.
+.It Ic addresses
+List of IPv4 or IPv6 name server addresses that the resolver should query.
+.El
+.El
+.El
.It Ic runcmd
An array of commands to be run at the end of the boot process
.It Ic packages
@@ -186,7 +282,7 @@ Update the remote package metadata.
Upgrade the packages installed to their latest version.
.It Ic users
Specify a list of users to be created:
-.Bl -tag -width "plain_text_passwd"
+.Bl -tag -width "ssh_authorized_keys"
.It Ic name
Name of the user.
.It Ic gecos
@@ -201,18 +297,25 @@ The list of other groups the user should belong to.
A boolean which determines if the home directory should be created or not.
.It Ic shell
The shell that should be used for the user.
+.It Ic ssh_authorized_keys
+List of SSH keys for the user.
.It Ic passwd
The encrypted password for the user.
.It Ic plain_text_passwd
The password in plain text for the user.
Ignored if an encrypted password is already provided.
-.It Ic groups
-The list of other groups the user should belong to.
.It Ic locked
Boolean to determine if the user account should be locked.
.It Ic sudo
-A string or an array of strings which which should be appended to
-.Pa /usr/local/etc/sudoers.d/90-nuageinit-users
+A string or an array of strings which should be appended to
+.Pa ${LOCALBASE}/etc/sudoers.d/90-nuageinit-users
+.It Ic doas
+A string or an array of strings which should be appended to
+.Pa ${LOCALBASE}/etc/doas.conf
+.Pp
+Instead of hardcoding the username, you can use
+.Sy %u Ns ,
+which will be replaced by the current username.
.El
.Pp
A special case exist: if the entry is a simple string with the value
@@ -251,7 +354,7 @@ It accepts the following keys for each objects:
The content to be written to the file.
If this key is not existing then an empty file will be created.
.It Ic encoding
-Specifiy the encoding used for content.
+Specify the encoding used for content.
If not specified, then plain text is considered.
Only
.Ar b64
@@ -287,7 +390,7 @@ users:
- name: user
gecos: Foo B. Bar
sudo: ALL=(ALL) NOPASSWD:ALL
- ssh-authorized-keys:
+ ssh_authorized_keys:
- ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAr...
packages:
- neovim
@@ -303,6 +406,12 @@ ssh_keys:
...
-----END OPENSSH PRIVATE KEY-----
ed25519_public: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK+MH4E8KO32N5CXRvXVqvyZVl0+6ue4DobdhU0FqFd+
+network:
+ ethernets:
+ vtnet0:
+ addresses:
+ - 192.168.8.2/24
+ gateway4: 192.168.8.1
.Ed
.Sh SEE ALSO
.Xr kenv 2 ,
diff --git a/libexec/nuageinit/tests/Makefile b/libexec/nuageinit/tests/Makefile
index c69bc28a4c86..dc8997717b59 100644
--- a/libexec/nuageinit/tests/Makefile
+++ b/libexec/nuageinit/tests/Makefile
@@ -15,6 +15,7 @@ ${PACKAGE}FILES+= adduser_passwd.lua
${PACKAGE}FILES+= dirname.lua
${PACKAGE}FILES+= err.lua
${PACKAGE}FILES+= sethostname.lua
+${PACKAGE}FILES+= settimezone.lua
${PACKAGE}FILES+= warn.lua
${PACKAGE}FILES+= addfile.lua
diff --git a/libexec/nuageinit/tests/nuage.sh b/libexec/nuageinit/tests/nuage.sh
index 56651c8c5bb7..57d83b62928a 100644
--- a/libexec/nuageinit/tests/nuage.sh
+++ b/libexec/nuageinit/tests/nuage.sh
@@ -1,5 +1,6 @@
#-
# Copyright (c) 2022-2025 Baptiste Daroussin <bapt@FreeBSD.org>
+# Copyright (c) 2025 Jesús Daniel Colmenares Oviedo <dtxdf@FreeBSD.org>
#
# SPDX-License-Identifier: BSD-2-Clause
#
@@ -7,12 +8,21 @@
export NUAGE_FAKE_ROOTDIR="$PWD"
atf_test_case sethostname
+atf_test_case settimezone
atf_test_case addsshkey
atf_test_case adduser
atf_test_case adduser_passwd
atf_test_case addgroup
atf_test_case addfile
+settimezone_body()
+{
+ atf_check /usr/libexec/flua $(atf_get_srcdir)/settimezone.lua
+ if [ ! -f etc/localtime ]; then
+ atf_fail "localtime not written"
+ fi
+}
+
sethostname_body()
{
atf_check /usr/libexec/flua $(atf_get_srcdir)/sethostname.lua
diff --git a/libexec/nuageinit/tests/nuageinit.sh b/libexec/nuageinit/tests/nuageinit.sh
index 849f1c258b62..2b7c5226c97a 100644
--- a/libexec/nuageinit/tests/nuageinit.sh
+++ b/libexec/nuageinit/tests/nuageinit.sh
@@ -1,5 +1,6 @@
#-
# Copyright (c) 2022-2025 Baptiste Daroussin <bapt@FreeBSD.org>
+# Copyright (c) 2025 Jesús Daniel Colmenares Oviedo <dtxdf@FreeBSD.org>
#
# SPDX-License-Identifier: BSD-2-Clause
#
@@ -119,12 +120,16 @@ users:
gecos: Foo B. Bar
primary_group: foobar
sudo: ALL=(ALL) NOPASSWD:ALL
+ doas: permit persist %u as root
groups: users
passwd: $6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/
- name: bla
sudo:
- "ALL=(ALL) NOPASSWD:/usr/sbin/pw"
- "ALL=(ALL) ALL"
+ doas:
+ - "deny %u as foobar"
+ - "permit persist %u as root cmd whoami"
EOF
atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit postnet
@@ -147,7 +152,13 @@ EOF
sed -i "" "s/freebsd:.*:1001/freebsd:freebsd:1001/" "${PWD}"/etc/master.passwd
atf_check -o file:expectedpasswd cat "${PWD}"/etc/master.passwd
atf_check -o file:expectedgroup cat "${PWD}"/etc/group
- atf_check -o inline:"foobar ALL=(ALL) NOPASSWD:ALL\nbla ALL=(ALL) NOPASSWD:/usr/sbin/pw\nbla ALL=(ALL) ALL\n" cat ${PWD}/usr/local/etc/sudoers.d/90-nuageinit-users
+ localbase=`sysctl -ni user.localbase 2> /dev/null`
+ if [ -z "${localbase}" ]; then
+ # fallback
+ localbase="/usr/local"
+ fi
+ atf_check -o inline:"foobar ALL=(ALL) NOPASSWD:ALL\nbla ALL=(ALL) NOPASSWD:/usr/sbin/pw\nbla ALL=(ALL) ALL\n" cat "${PWD}/${localbase}/etc/sudoers.d/90-nuageinit-users"
+ atf_check -o inline:"permit persist foobar as root\ndeny bla as foobar\npermit persist bla as root cmd whoami\n" cat "${PWD}/${localbase}/etc/doas.conf"
}
nocloud_network_head()
@@ -815,7 +826,7 @@ config2_userdata_update_packages_body()
package_update: true
EOF
chmod 755 "${PWD}"/media/nuageinit/user_data
- atf_check -o inline:"pkg update -y\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit postnet
+ atf_check -o inline:"env ASSUME_ALWAYS_YES=yes pkg update\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit postnet
}
config2_userdata_upgrade_packages_body()
@@ -829,7 +840,7 @@ config2_userdata_upgrade_packages_body()
package_upgrade: true
EOF
chmod 755 "${PWD}"/media/nuageinit/user_data
- atf_check -o inline:"pkg upgrade -y\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit postnet
+ atf_check -o inline:"env ASSUME_ALWAYS_YES=yes pkg upgrade\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit postnet
}
config2_userdata_shebang_body()
diff --git a/libexec/nuageinit/tests/settimezone.lua b/libexec/nuageinit/tests/settimezone.lua
new file mode 100644
index 000000000000..a8cacf09f4e7
--- /dev/null
+++ b/libexec/nuageinit/tests/settimezone.lua
@@ -0,0 +1,5 @@
+#!/usr/libexec/flua
+
+local n = require("nuage")
+
+n.settimezone("UTC")
diff --git a/libexec/nuageinit/tests/utils.sh b/libexec/nuageinit/tests/utils.sh
index 26f117d81d60..76cd7e045473 100644
--- a/libexec/nuageinit/tests/utils.sh
+++ b/libexec/nuageinit/tests/utils.sh
@@ -1,5 +1,6 @@
#-
# Copyright (c) 2022 Baptiste Daroussin <bapt@FreeBSD.org>
+# Copyright (c) 2025 Jesús Daniel Colmenares Oviedo <dtxdf@FreeBSD.org>
#
# SPDX-License-Identifier: BSD-2-Clause
#