diff --git a/libexec/nuageinit/nuage.lua b/libexec/nuageinit/nuage.lua index addab5419193..0fe7400c2bbc 100644 --- a/libexec/nuageinit/nuage.lua +++ b/libexec/nuageinit/nuage.lua @@ -1,387 +1,407 @@ --- -- SPDX-License-Identifier: BSD-2-Clause -- -- Copyright(c) 2022-2025 Baptiste Daroussin local unistd = require("posix.unistd") local sys_stat = require("posix.sys.stat") local lfs = require("lfs") local function warnmsg(str, prepend) if not str then return end local tag = "" if prepend ~= false then tag = "nuageinit: " end io.stderr:write(tag .. str .. "\n") end local function errmsg(str, prepend) warnmsg(str, prepend) os.exit(1) end local function dirname(oldpath) if not oldpath then return nil end local path = oldpath:gsub("[^/]+/*$", "") if path == "" then return nil end return path end local function mkdir_p(path) if lfs.attributes(path, "mode") ~= nil then return true end local r, err = mkdir_p(dirname(path)) if not r then return nil, err .. " (creating " .. path .. ")" end return lfs.mkdir(path) end local function sethostname(hostname) if hostname == nil then return end local root = os.getenv("NUAGE_FAKE_ROOTDIR") if not root then root = "" end local hostnamepath = root .. "/etc/rc.conf.d/hostname" mkdir_p(dirname(hostnamepath)) local f, err = io.open(hostnamepath, "w") if not f then warnmsg("Impossible to open " .. hostnamepath .. ":" .. err) return end f:write('hostname="' .. hostname .. '"\n') f:close() end local function splitlist(list) local ret = {} if type(list) == "string" then for str in list:gmatch("([^, ]+)") do ret[#ret + 1] = str end elseif type(list) == "table" then ret = list else warnmsg("Invalid type " .. type(list) .. ", expecting table or string") end return ret end local function adduser(pwd) if (type(pwd) ~= "table") then warnmsg("Argument should be a table") return nil end local root = os.getenv("NUAGE_FAKE_ROOTDIR") local cmd = "pw " if root then cmd = cmd .. "-R " .. root .. " " end local f = io.popen(cmd .. " usershow " .. pwd.name .. " -7 2> /dev/null") local pwdstr = f:read("*a") f:close() if pwdstr:len() ~= 0 then return pwdstr:match("%a+:.+:%d+:%d+:.*:(.*):.*") end if not pwd.gecos then pwd.gecos = pwd.name .. " User" end if not pwd.homedir then pwd.homedir = "/home/" .. pwd.name end local extraargs = "" if pwd.groups then local list = splitlist(pwd.groups) extraargs = " -G " .. table.concat(list, ",") end -- pw will automatically create a group named after the username -- do not add a -g option in this case if pwd.primary_group and pwd.primary_group ~= pwd.name then extraargs = extraargs .. " -g " .. pwd.primary_group end if not pwd.no_create_home then extraargs = extraargs .. " -m " end if not pwd.shell then pwd.shell = "/bin/sh" end local precmd = "" local postcmd = "" local input = nil if pwd.passwd then input = pwd.passwd postcmd = " -H 0" elseif pwd.plain_text_passwd then input = pwd.plain_text_passwd postcmd = " -h 0" end cmd = precmd .. "pw " if root then cmd = cmd .. "-R " .. root .. " " end cmd = cmd .. "useradd -n " .. pwd.name .. " -M 0755 -w none " cmd = cmd .. extraargs .. " -c '" .. pwd.gecos cmd = cmd .. "' -d '" .. pwd.homedir .. "' -s " .. pwd.shell .. postcmd f = io.popen(cmd, "w") if input then f:write(input) end local r = f:close(cmd) if not r then warnmsg("fail to add user " .. pwd.name) warnmsg(cmd) return nil end if pwd.locked then cmd = "pw " if root then cmd = cmd .. "-R " .. root .. " " end cmd = cmd .. "lock " .. pwd.name os.execute(cmd) end return pwd.homedir end local function addgroup(grp) if (type(grp) ~= "table") then warnmsg("Argument should be a table") return false end local root = os.getenv("NUAGE_FAKE_ROOTDIR") local cmd = "pw " if root then cmd = cmd .. "-R " .. root .. " " end local f = io.popen(cmd .. " groupshow " .. grp.name .. " 2> /dev/null") local grpstr = f:read("*a") f:close() if grpstr:len() ~= 0 then return true end local extraargs = "" if grp.members then local list = splitlist(grp.members) extraargs = " -M " .. table.concat(list, ",") end cmd = "pw " if root then cmd = cmd .. "-R " .. root .. " " end cmd = cmd .. "groupadd -n " .. grp.name .. extraargs local r = os.execute(cmd) if not r then warnmsg("fail to add group " .. grp.name) warnmsg(cmd) return false end return true end local function addsshkey(homedir, key) local chownak = false local chowndotssh = false local root = os.getenv("NUAGE_FAKE_ROOTDIR") if root then homedir = root .. "/" .. homedir end local ak_path = homedir .. "/.ssh/authorized_keys" local dotssh_path = homedir .. "/.ssh" local dirattrs = lfs.attributes(ak_path) if dirattrs == nil then chownak = true dirattrs = lfs.attributes(dotssh_path) if dirattrs == nil then assert(lfs.mkdir(dotssh_path)) chowndotssh = true dirattrs = lfs.attributes(homedir) end end local f = io.open(ak_path, "a") if not f then warnmsg("impossible to open " .. ak_path) return end f:write(key .. "\n") f:close() if chownak then sys_stat.chmod(ak_path, 384) unistd.chown(ak_path, dirattrs.uid, dirattrs.gid) end if chowndotssh then sys_stat.chmod(dotssh_path, 448) unistd.chown(dotssh_path, dirattrs.uid, dirattrs.gid) end end local function update_sshd_config(key, value) local sshd_config = "/etc/ssh/sshd_config" local root = os.getenv("NUAGE_FAKE_ROOTDIR") if root then sshd_config = root .. sshd_config end local f = assert(io.open(sshd_config, "r+")) local tgt = assert(io.open(sshd_config .. ".nuageinit", "w")) local found = false local pattern = "^%s*"..key:lower().."%s+(%w+)%s*#?.*$" while true do local line = f:read() if line == nil then break end local _, _, val = line:lower():find(pattern) if val then found = true if val == value then assert(tgt:write(line .. "\n")) else assert(tgt:write(key .. " " .. value .. "\n")) end else assert(tgt:write(line .. "\n")) end end if not found then assert(tgt:write(key .. " " .. value .. "\n")) end assert(f:close()) assert(tgt:close()) os.rename(sshd_config .. ".nuageinit", sshd_config) end local function exec_change_password(user, password, type, expire) local root = os.getenv("NUAGE_FAKE_ROOTDIR") local cmd = "pw " if root then cmd = cmd .. "-R " .. root .. " " end local postcmd = " -H 0" local input = password if type ~= nil and type == "text" then postcmd = " -h 0" else if password == "RANDOM" then input = nil postcmd = " -w random" end end cmd = cmd .. "usermod " .. user .. postcmd if expire then cmd = cmd .. " -p 1" else cmd = cmd .. " -p 0" end local f = io.popen(cmd .. " >/dev/null", "w") if input then f:write(input) end -- ignore stdout to avoid printing the password in case of random password local r = f:close(cmd) if not r then warnmsg("fail to change user password ".. user) warnmsg(cmd) end end local function change_password_from_line(line, expire) local user, password = line:match("%s*(%w+):(%S+)%s*") local type = nil if user and password then if password == "R" then password = "RANDOM" end if not password:match("^%$%d+%$%w+%$") then if password ~= "RANDOM" then type = "text" end end exec_change_password(user, password, type, expire) end end local function chpasswd(obj) if type(obj) ~= "table" then warnmsg("Invalid chpasswd entry, expecting an object") return end local expire = false if obj.expire ~= nil then if type(obj.expire) == "boolean" then expire = obj.expire else warnmsg("Invalid type for chpasswd.expire, expecting a boolean, got a ".. type(obj.expire)) end end if obj.users ~= nil then if type(obj.users) ~= "table" then warnmsg("Invalid type for chpasswd.users, expecting a list, got a ".. type(obj.users)) goto list end for _, u in ipairs(obj.users) do if type(u) ~= "table" then warnmsg("Invalid chpasswd.users entry, expecting an object, got a " .. type(u)) goto next end if not u.name then warnmsg("Invalid entry for chpasswd.users: missing 'name'") goto next end if not u.password then warnmsg("Invalid entry for chpasswd.users: missing 'password'") goto next end exec_change_password(u.name, u.password, u.type, expire) ::next:: end end ::list:: if obj.list ~= nil then warnmsg("chpasswd.list is deprecated consider using chpasswd.users") if type(obj.list) == "string" then for line in obj.list:gmatch("[^\n]+") do change_password_from_line(line, expire) end elseif type(obj.list) == "table" then for _, u in ipairs(obj.list) do change_password_from_line(u, expire) end end end end local function pkg_bootstrap() + if os.getenv("NUAGE_RUN_TESTS") then + return true + end if os.execute("pkg -N 2>/dev/null") then return true end print("Bootstrapping pkg") return os.execute("env ASSUME_ALWAYS_YES=YES pkg bootstrap") end +local function install_package(package) + if package == nil then + return true + end + local install_cmd = "pkg install -y " .. package + local test_cmd = "pkg info -q " .. package + if os.getenv("NUAGE_RUN_TESTS") then + print(install_cmd) + print(test_cmd) + return true + end + if os.execute(test_cmd) then + return true + end + return os.execute(install_cmd) +end local n = { warn = warnmsg, err = errmsg, dirname = dirname, mkdir_p = mkdir_p, sethostname = sethostname, adduser = adduser, addgroup = addgroup, addsshkey = addsshkey, update_sshd_config = update_sshd_config, chpasswd = chpasswd, - pkg_bootstrap = pkg_bootstrap + pkg_bootstrap = pkg_bootstrap, + install_package = install_package } return n diff --git a/libexec/nuageinit/nuageinit b/libexec/nuageinit/nuageinit index ef215af00924..ef5726960978 100755 --- a/libexec/nuageinit/nuageinit +++ b/libexec/nuageinit/nuageinit @@ -1,378 +1,397 @@ #!/usr/libexec/flua --- -- SPDX-License-Identifier: BSD-2-Clause-FreeBSD -- -- Copyright(c) 2022-2025 Baptiste Daroussin local nuage = require("nuage") local ucl = require("ucl") local yaml = require("yaml") local sys_stat = require("posix.sys.stat") if #arg ~= 2 then nuage.err("Usage: " .. arg[0] .. " ( | )", false) end local path = arg[1] local citype = arg[2] local default_user = { name = "freebsd", homedir = "/home/freebsd", groups = "wheel", gecos = "FreeBSD User", shell = "/bin/sh", plain_text_passwd = "freebsd" } local root = os.getenv("NUAGE_FAKE_ROOTDIR") if not root then root = "" end local function openat(dir, name) local path_dir = root .. dir local path_name = path_dir .. "/" .. name nuage.mkdir_p(path_dir) local f, err = io.open(path_name, "w") if not f then nuage.err("unable to open " .. path_name .. ": " .. err) end return f, path_name end local function open_ssh_key(name) return openat("/etc/ssh", name) end local function open_config(name) return openat("/etc/rc.conf.d", name) end local function get_ifaces() local parser = ucl.parser() -- grab ifaces local ns = io.popen("netstat -i --libxo json") local netres = ns:read("*a") ns:close() local res, err = parser:parse_string(netres) if not res then nuage.warn("Error parsing netstat -i --libxo json outout: " .. err) return nil end local ifaces = parser:get_object() local myifaces = {} for _, iface in pairs(ifaces["statistics"]["interface"]) do if iface["network"]:match("") then local s = iface["address"] myifaces[s:lower()] = iface["name"] end end return myifaces end +local function install_packages(packages) + if not nuage.pkg_bootstrap() then + nuage.warn("Failed to bootstrap pkg, skip installing packages") + return + end + for n, p in pairs(packages) do + if type(p) == "string" then + if not nuage.install_package(p) then + nuage.warn("Failed to install : " .. p) + end + else + nuage.warn("Invalid type : " .. type(p) .. " for packages entry number " .. n) + end + end +end + local function config2_network(p) local parser = ucl.parser() local f = io.open(p .. "/network_data.json") if not f then -- silently return no network configuration is provided return end f:close() local res, err = parser:parse_file(p .. "/network_data.json") if not res then nuage.warn("error parsing network_data.json: " .. err) return end local obj = parser:get_object() local ifaces = get_ifaces() if not ifaces then nuage.warn("no network interfaces found") return end local mylinks = {} for _, v in pairs(obj["links"]) do local s = v["ethernet_mac_address"]:lower() mylinks[v["id"]] = ifaces[s] end local network = open_config("network") local routing = open_config("routing") local ipv6 = {} local ipv6_routes = {} local ipv4 = {} for _, v in pairs(obj["networks"]) do local interface = mylinks[v["link"]] if v["type"] == "ipv4_dhcp" then network:write("ifconfig_" .. interface .. '="DHCP"\n') end if v["type"] == "ipv4" then network:write( "ifconfig_" .. interface .. '="inet ' .. v["ip_address"] .. " netmask " .. v["netmask"] .. '"\n' ) if v["gateway"] then routing:write('defaultrouter="' .. v["gateway"] .. '"\n') end if v["routes"] then for i, r in ipairs(v["routes"]) do local rname = "cloudinit" .. i .. "_" .. interface if v["gateway"] and v["gateway"] == r["gateway"] then goto next end if r["network"] == "0.0.0.0" then routing:write('defaultrouter="' .. r["gateway"] .. '"\n') goto next end routing:write("route_" .. rname .. '="-net ' .. r["network"] .. " ") routing:write(r["gateway"] .. " " .. r["netmask"] .. '"\n') ipv4[#ipv4 + 1] = rname ::next:: end end end if v["type"] == "ipv6" then ipv6[#ipv6 + 1] = interface ipv6_routes[#ipv6_routes + 1] = interface network:write("ifconfig_" .. interface .. '_ipv6="inet6 ' .. v["ip_address"] .. '"\n') if v["gateway"] then routing:write('ipv6_defaultrouter="' .. v["gateway"] .. '"\n') routing:write("ipv6_route_" .. interface .. '="' .. v["gateway"]) routing:write(" -prefixlen 128 -interface " .. interface .. '"\n') end -- TODO compute the prefixlen for the routes --if v["routes"] then -- for i, r in ipairs(v["routes"]) do -- local rname = "cloudinit" .. i .. "_" .. mylinks[v["link"]] -- -- skip all the routes which are already covered by the default gateway, some provider -- -- still list plenty of them. -- if v["gateway"] == r["gateway"] then -- goto next -- end -- routing:write("ipv6_route_" .. rname .. '"\n') -- ipv6_routes[#ipv6_routes + 1] = rname -- ::next:: -- end --end end end if #ipv4 > 0 then routing:write('static_routes="') routing:write(table.concat(ipv4, " ") .. '"\n') end if #ipv6 > 0 then network:write('ipv6_network_interfaces="') network:write(table.concat(ipv6, " ") .. '"\n') network:write('ipv6_default_interface="' .. ipv6[1] .. '"\n') end if #ipv6_routes > 0 then routing:write('ipv6_static_routes="') routing:write(table.concat(ipv6, " ") .. '"\n') end network:close() routing:close() end if citype == "config-2" then local parser = ucl.parser() local res, err = parser:parse_file(path .. "/meta_data.json") if not res then nuage.err("error parsing config-2 meta_data.json: " .. err) end local obj = parser:get_object() if obj.public_keys then local homedir = nuage.adduser(default_user) for _,v in pairs(obj.public_keys) do nuage.addsshkey(homedir, v) end end nuage.sethostname(obj["hostname"]) -- network config2_network(path) elseif citype == "nocloud" then local f, err = io.open(path .. "/meta-data") if err then nuage.err("error parsing nocloud meta-data: " .. err) end local obj = yaml.eval(f:read("*a")) f:close() if not obj then nuage.err("error parsing nocloud meta-data") end local hostname = obj["local-hostname"] if not hostname then hostname = obj["hostname"] end if hostname then nuage.sethostname(hostname) end else nuage.err("Unknown cloud init type: " .. citype) end -- deal with user-data local ud = nil local f = nil userdatas = {"user-data", "user_data"} for _, v in pairs(userdatas) do f = io.open(path .. "/" .. v, "r") if f then ud = v break end end if not f then os.exit(0) end local line = f:read("*l") f:close() if line == "#cloud-config" then f = io.open(path .. "/" .. ud) local obj = yaml.eval(f:read("*a")) f:close() if not obj then nuage.err("error parsing cloud-config file: " .. ud) end if obj.groups then for n, g in pairs(obj.groups) do if (type(g) == "string") then local r = nuage.addgroup({name = g}) if not r then nuage.warn("failed to add group: " .. g) end elseif type(g) == "table" then for k, v in pairs(g) do nuage.addgroup({name = k, members = v}) end else nuage.warn("invalid type: " .. type(g) .. " for users entry number " .. n) end end end if obj.users then for n, u in pairs(obj.users) do if type(u) == "string" then if u == "default" then nuage.adduser(default_user) else nuage.adduser({name = u}) end elseif type(u) == "table" then -- ignore users without a username if u.name == nil then goto unext end local homedir = nuage.adduser(u) if u.ssh_authorized_keys then for _, v in ipairs(u.ssh_authorized_keys) do nuage.addsshkey(homedir, v) end end else nuage.warn("invalid type : " .. type(u) .. " for users entry number " .. n) end ::unext:: end else -- default user if none are defined nuage.adduser(default_user) end if obj.ssh_keys and type(obj.ssh_keys) == "table" then for key, val in pairs(obj.ssh_keys) do for keyname, keytype in key:gmatch("(%w+)_(%w+)") do local sshkn = nil if keytype == "public" then sshkn = "ssh_host_" .. keyname .. "_key.pub" elseif keytype == "private" then sshkn = "ssh_host_" .. keyname .. "_key" end if sshkn then local sshkey, path = open_ssh_key(sshkn) if sshkey then sshkey:write(val .. "\n") sshkey:close() end if keytype == "private" then sys_stat.chmod(path, 384) end end end end end if obj.ssh_authorized_keys then local homedir = nuage.adduser(default_user) for _, k in ipairs(obj.ssh_authorized_keys) do nuage.addsshkey(homedir, k) end end if obj.network then 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 end if not v.match.macaddress then goto next end if not ifaces[v.match.macaddress] then nuage.warn("not interface matching: " .. v.match.macaddress) goto next 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 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 if #ipv6 > 0 then network:write('ipv6_network_interfaces="') network:write(table.concat(ipv6, " ") .. '"\n') network:write('ipv6_default_interface="' .. ipv6[1] .. '"\n') end network:close() routing:close() end if obj.ssh_pwauth ~= nil then local value = "no" if obj.ssh_pwauth then value = "yes" end nuage.update_sshd_config("PasswordAuthentication", value) end if obj.chpasswd ~= nil then nuage.chpasswd(obj.chpasswd) end if obj.runcmd then for _, c in ipairs(obj.runcmd) do if not os.execute(c) then nuage.warn("Failed to execute '" .. c .. "'") -- execute the next command anyway -- end end end + if obj.packages then + install_packages(obj.packages) + end else local res, err = os.execute(path .. "/" .. ud) if not res then nuage.err("error executing user-data script: " .. err) end end diff --git a/libexec/nuageinit/tests/nuageinit.sh b/libexec/nuageinit/tests/nuageinit.sh index 06f4a12d7503..e8742be3ba51 100644 --- a/libexec/nuageinit/tests/nuageinit.sh +++ b/libexec/nuageinit/tests/nuageinit.sh @@ -1,759 +1,803 @@ #- # Copyright (c) 2022 Baptiste Daroussin # # SPDX-License-Identifier: BSD-2-Clause # export NUAGE_FAKE_ROOTDIR="$PWD" atf_test_case args atf_test_case nocloud atf_test_case nocloud_userdata_script atf_test_case nocloud_user_data_script atf_test_case nocloud_userdata_cloudconfig_users atf_test_case nocloud_network atf_test_case config2 atf_test_case config2_pubkeys atf_test_case config2_pubkeys_user_data atf_test_case config2_pubkeys_meta_data atf_test_case config2_network atf_test_case config2_network_static_v4 atf_test_case config2_ssh_keys atf_test_case nocloud_userdata_cloudconfig_ssh_pwauth atf_test_case nocloud_userdata_cloudconfig_chpasswd atf_test_case nocloud_userdata_cloudconfig_chpasswd_list_string atf_test_case nocloud_userdata_cloudconfig_chpasswd_list_list atf_test_case config2_userdata_runcmd +atf_test_case config2_userdata_packages setup_test_adduser() { here=$(pwd) export NUAGE_FAKE_ROOTDIR=$(pwd) mkdir -p etc/ssh cat > etc/master.passwd << EOF root:*:0:0::0:0:Charlie &:/root:/bin/csh sys:*:1:0::0:0:Sys:/home/sys:/bin/csh EOF pwd_mkdb -d etc ${here}/etc/master.passwd cat > etc/group << EOF wheel:*:0:root users:*:1: EOF } args_body() { atf_check -s exit:1 -e inline:"Usage: /usr/libexec/nuageinit ( | )\n" /usr/libexec/nuageinit atf_check -s exit:1 -e inline:"Usage: /usr/libexec/nuageinit ( | )\n" /usr/libexec/nuageinit bla atf_check -s exit:1 -e inline:"Usage: /usr/libexec/nuageinit ( | )\n" /usr/libexec/nuageinit bla meh plop atf_check -s exit:1 -e inline:"nuageinit: Unknown cloud init type: meh\n" /usr/libexec/nuageinit bla meh } nocloud_body() { mkdir -p media/nuageinit atf_check -s exit:1 -e match:"nuageinit: error parsing nocloud.*" /usr/libexec/nuageinit "${PWD}"/media/nuageinit/ nocloud printf "instance-id: iid-local01\nlocal-hostname: cloudimg\n" > "${PWD}"/media/nuageinit/meta-data atf_check -s exit:0 /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud atf_check -o inline:"hostname=\"cloudimg\"\n" cat etc/rc.conf.d/hostname cat > media/nuageinit/meta-data << EOF instance-id: iid-local01 hostname: myhost EOF atf_check -s exit:0 /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud atf_check -o inline:"hostname=\"myhost\"\n" cat etc/rc.conf.d/hostname } nocloud_userdata_script_body() { mkdir -p media/nuageinit printf "instance-id: iid-local01\n" > "${PWD}"/media/nuageinit/meta-data printf "#!/bin/sh\necho yeah\n" > "${PWD}"/media/nuageinit/user-data chmod 755 "${PWD}"/media/nuageinit/user-data atf_check -s exit:0 -o inline:"yeah\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud } nocloud_user_data_script_body() { mkdir -p media/nuageinit printf "instance-id: iid-local01\n" > "${PWD}"/media/nuageinit/meta-data printf "#!/bin/sh\necho yeah\n" > "${PWD}"/media/nuageinit/user_data chmod 755 "${PWD}"/media/nuageinit/user_data atf_check -s exit:0 -o inline:"yeah\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud } nocloud_userdata_cloudconfig_users_head() { atf_set "require.user" root } nocloud_userdata_cloudconfig_users_body() { mkdir -p media/nuageinit printf "instance-id: iid-local01\n" > "${PWD}"/media/nuageinit/meta-data mkdir -p etc cat > etc/master.passwd << EOF root:*:0:0::0:0:Charlie &:/root:/bin/sh sys:*:1:0::0:0:Sys:/home/sys:/bin/sh EOF pwd_mkdb -d etc "${PWD}"/etc/master.passwd cat > etc/group << EOF wheel:*:0:root users:*:1: EOF cat > media/nuageinit/user-data << 'EOF' #cloud-config groups: - admingroup: [root,sys] - cloud-users users: - default - name: foobar gecos: Foo B. Bar primary_group: foobar groups: users passwd: $6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/ EOF atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud cat > expectedgroup << EOF wheel:*:0:root,freebsd users:*:1:foobar admingroup:*:1001:root,sys cloud-users:*:1002: freebsd:*:1003: foobar:*:1004: EOF cat > expectedpasswd << 'EOF' root:*:0:0::0:0:Charlie &:/root:/bin/sh sys:*:1:0::0:0:Sys:/home/sys:/bin/sh freebsd:freebsd:1001:1003::0:0:FreeBSD User:/home/freebsd:/bin/sh foobar:$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/:1002:1004::0:0:Foo B. Bar:/home/foobar:/bin/sh 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 } nocloud_network_head() { atf_set "require.user" root } nocloud_network_body() { mkdir -p media/nuageinit mkdir -p etc cat > etc/master.passwd << EOF root:*:0:0::0:0:Charlie &:/root:/bin/sh sys:*:1:0::0:0:Sys:/home/sys:/bin/sh EOF pwd_mkdb -d etc "${PWD}"/etc/master.passwd cat > etc/group << EOF wheel:*:0:root users:*:1: EOF mynetworks=$(ifconfig -l ether) if [ -z "$mynetworks" ]; then atf_skip "a network interface is needed" fi set -- $mynetworks myiface=$1 myaddr=$(ifconfig $myiface ether | awk '/ether/ { print $2 }') printf "instance-id: iid-local01\n" > "${PWD}"/media/nuageinit/meta-data cat > media/nuageinit/user-data << EOF #cloud-config network: version: 2 ethernets: # opaque ID for physical interfaces, only referred to by other stanzas id0: match: macaddress: "$myaddr" addresses: - 192.0.2.2/24 - 2001:db8::2/64 gateway4: 192.0.2.1 gateway6: 2001:db8::1 EOF atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud cat > network << EOF ifconfig_${myiface}="inet 192.0.2.2/24" ifconfig_${myiface}_ipv6="inet6 2001:db8::2/64" ipv6_network_interfaces="${myiface}" ipv6_default_interface="${myiface}" EOF cat > routing << EOF defaultrouter="192.0.2.1" ipv6_defaultrouter="2001:db8::1" ipv6_route_${myiface}="2001:db8::1 -prefixlen 128 -interface ${myiface}" EOF atf_check -o file:network cat "${PWD}"/etc/rc.conf.d/network atf_check -o file:routing cat "${PWD}"/etc/rc.conf.d/routing } config2_body() { mkdir -p media/nuageinit atf_check -s exit:1 -e match:"nuageinit: error parsing config-2 meta_data.json:.*" /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 printf "{}" > media/nuageinit/meta_data.json atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 cat > media/nuageinit/meta_data.json << EOF { "hostname": "cloudimg" } EOF atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 atf_check -o inline:"hostname=\"cloudimg\"\n" cat etc/rc.conf.d/hostname } config2_pubkeys_head() { atf_set "require.user" root } config2_pubkeys_body() { mkdir -p media/nuageinit touch media/nuageinit/meta_data.json cat > media/nuageinit/user-data << EOF #cloud-config ssh_authorized_keys: - "ssh-rsa AAAAB3NzaC1y...== Generated by Nova" EOF mkdir -p etc cat > etc/master.passwd << EOF root:*:0:0::0:0:Charlie &:/root:/bin/sh sys:*:1:0::0:0:Sys:/home/sys:/bin/sh EOF pwd_mkdb -d etc "${PWD}"/etc/master.passwd cat > etc/group << EOF wheel:*:0:root users:*:1: EOF atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 atf_check -o inline:"ssh-rsa AAAAB3NzaC1y...== Generated by Nova\n" cat home/freebsd/.ssh/authorized_keys } config2_pubkeys_user_data_head() { atf_set "require.user" root } config2_pubkeys_user_data_body() { mkdir -p media/nuageinit touch media/nuageinit/meta_data.json cat > media/nuageinit/user_data << EOF #cloud-config ssh_authorized_keys: - "ssh-rsa AAAAB3NzaC1y...== Generated by Nova" EOF mkdir -p etc cat > etc/master.passwd << EOF root:*:0:0::0:0:Charlie &:/root:/bin/sh sys:*:1:0::0:0:Sys:/home/sys:/bin/sh EOF pwd_mkdb -d etc "${PWD}"/etc/master.passwd cat > etc/group << EOF wheel:*:0:root users:*:1: EOF atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 atf_check -o inline:"ssh-rsa AAAAB3NzaC1y...== Generated by Nova\n" cat home/freebsd/.ssh/authorized_keys } config2_pubkeys_meta_data_body() { here=$(pwd) export NUAGE_FAKE_ROOTDIR=$(pwd) if [ $(id -u) -ne 0 ]; then atf_skip "root required" fi mkdir -p media/nuageinit cat > media/nuageinit/meta_data.json << EOF { "uuid": "uuid_for_this_instance", "admin_pass": "a_generated_password", "public_keys": { "tdb": "ssh-ed25519 my_key_id tdb@host" }, "keys": [ { "name": "tdb", "type": "ssh", "data": "ssh-ed25519 my_key_id tdb@host" } ], "hostname": "freebsd-14-test.novalocal", "name": "freebsd-14-test", "launch_index": 0, "availability_zone": "nova", "random_seed": "long_random_seed", "project_id": "my_project_id", "devices": [], "dedicated_cpus": [] } EOF mkdir -p etc cat > etc/master.passwd << EOF root:*:0:0::0:0:Charlie &:/root:/bin/csh sys:*:1:0::0:0:Sys:/home/sys:/bin/csh EOF pwd_mkdb -d etc ${here}/etc/master.passwd cat > etc/group << EOF wheel:*:0:root users:*:1: EOF atf_check /usr/libexec/nuageinit ${here}/media/nuageinit config-2 atf_check -o inline:"ssh-ed25519 my_key_id tdb@host\n" cat home/freebsd/.ssh/authorized_keys } config2_network_body() { mkdir -p media/nuageinit printf "{}" > media/nuageinit/meta_data.json mynetworks=$(ifconfig -l ether) if [ -z "$mynetworks" ]; then atf_skip "a network interface is needed" fi set -- $mynetworks myiface=$1 myaddr=$(ifconfig $myiface ether | awk '/ether/ { print $2 }') cat > media/nuageinit/network_data.json << EOF { "links": [ { "ethernet_mac_address": "$myaddr", "id": "iface0", "mtu": null } ], "networks": [ { "id": "network0", "link": "iface0", "type": "ipv4_dhcp" }, { // IPv6 "id": "private-ipv4", "type": "ipv6", "link": "iface0", // supports condensed IPv6 with CIDR netmask "ip_address": "2001:db8::3257:9652/64", "gateway": "fd00::1", "routes": [ { "network": "::", "netmask": "::", "gateway": "fd00::1" }, { "network": "::", "netmask": "ffff:ffff:ffff::", "gateway": "fd00::1:1" } ], "network_id": "da5bb487-5193-4a65-a3df-4a0055a8c0d8" } ] } EOF atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 cat > network << EOF ifconfig_${myiface}="DHCP" ifconfig_${myiface}_ipv6="inet6 2001:db8::3257:9652/64" ipv6_network_interfaces="${myiface}" ipv6_default_interface="${myiface}" EOF cat > routing << EOF ipv6_defaultrouter="fd00::1" ipv6_route_${myiface}="fd00::1 -prefixlen 128 -interface ${myiface}" ipv6_static_routes="${myiface}" EOF atf_check -o file:network cat "${PWD}"/etc/rc.conf.d/network atf_check -o file:routing cat "${PWD}"/etc/rc.conf.d/routing } config2_network_static_v4_body() { mkdir -p media/nuageinit printf "{}" > media/nuageinit/meta_data.json mynetworks=$(ifconfig -l ether) if [ -z "$mynetworks" ]; then atf_skip "a network interface is needed" fi set -- $mynetworks myiface=$1 myaddr=$(ifconfig $myiface ether | awk '/ether/ { print $2 }') cat > media/nuageinit/network_data.json << EOF { "links": [ { "ethernet_mac_address": "$myaddr", "id": "iface0", "mtu": null } ], "networks": [ { "id": "network0", "link": "iface0", "type": "ipv4", "ip_address": "10.184.0.244", "netmask": "255.255.240.0", "routes": [ { "network": "10.0.0.0", "netmask": "255.0.0.0", "gateway": "11.0.0.1" }, { "network": "0.0.0.0", "netmask": "0.0.0.0", "gateway": "23.253.157.1" } ] } ] } EOF atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 cat > network << EOF ifconfig_${myiface}="inet 10.184.0.244 netmask 255.255.240.0" EOF cat > routing << EOF route_cloudinit1_${myiface}="-net 10.0.0.0 11.0.0.1 255.0.0.0" defaultrouter="23.253.157.1" static_routes="cloudinit1_${myiface}" EOF atf_check -o file:network cat "${PWD}"/etc/rc.conf.d/network atf_check -o file:routing cat "${PWD}"/etc/rc.conf.d/routing } config2_ssh_keys_head() { atf_set "require.user" root } config2_ssh_keys_body() { here=$(pwd) export NUAGE_FAKE_ROOTDIR=$(pwd) mkdir -p media/nuageinit touch media/nuageinit/meta_data.json cat > media/nuageinit/user-data << EOF #cloud-config ssh_keys: rsa_private: | -----BEGIN RSA PRIVATE KEY----- MIIBxwIBAAJhAKD0YSHy73nUgysO13XsJmd4fHiFyQ+00R7VVu2iV9Qco ... -----END RSA PRIVATE KEY----- rsa_public: ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEAoPRhIfLvedSDKw7Xd ... ed25519_private: | -----BEGIN OPENSSH PRIVATE KEY----- blabla ... -----END OPENSSH PRIVATE KEY----- ed25519_public: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK+MH4E8KO32N5CXRvXVqvyZVl0+6ue4DobdhU0FqFd+ EOF mkdir -p etc/ssh cat > etc/master.passwd << EOF root:*:0:0::0:0:Charlie &:/root:/bin/csh sys:*:1:0::0:0:Sys:/home/sys:/bin/csh EOF pwd_mkdb -d etc ${here}/etc/master.passwd cat > etc/group << EOF wheel:*:0:root users:*:1: EOF atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 _expected="-----BEGIN RSA PRIVATE KEY----- MIIBxwIBAAJhAKD0YSHy73nUgysO13XsJmd4fHiFyQ+00R7VVu2iV9Qco ... -----END RSA PRIVATE KEY----- " atf_check -o inline:"${_expected}" cat ${PWD}/etc/ssh/ssh_host_rsa_key _expected="ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEAoPRhIfLvedSDKw7Xd ...\n" atf_check -o inline:"${_expected}" cat ${PWD}/etc/ssh/ssh_host_rsa_key.pub _expected="-----BEGIN OPENSSH PRIVATE KEY----- blabla ... -----END OPENSSH PRIVATE KEY-----\n" atf_check -o inline:"${_expected}" cat ${PWD}/etc/ssh/ssh_host_ed25519_key _expected="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK+MH4E8KO32N5CXRvXVqvyZVl0+6ue4DobdhU0FqFd+\n" atf_check -o inline:"${_expected}" cat ${PWD}/etc/ssh/ssh_host_ed25519_key.pub } nocloud_userdata_cloudconfig_ssh_pwauth_head() { atf_set "require.user" root } nocloud_userdata_cloudconfig_ssh_pwauth_body() { mkdir -p etc cat > etc/master.passwd << EOF root:*:0:0::0:0:Charlie &:/root:/bin/sh sys:*:1:0::0:0:Sys:/home/sys:/bin/sh EOF pwd_mkdb -d etc "${PWD}"/etc/master.passwd cat > etc/group << EOF wheel:*:0:root users:*:1: EOF mkdir -p media/nuageinit printf "instance-id: iid-local01\n" > "${PWD}"/media/nuageinit/meta-data cat > media/nuageinit/user-data << 'EOF' #cloud-config ssh_pwauth: true EOF mkdir -p etc/ssh/ touch etc/ssh/sshd_config atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud atf_check -o inline:"PasswordAuthentication yes\n" cat etc/ssh/sshd_config # Same value we don't touch anything printf " PasswordAuthentication yes # I want password\n" > etc/ssh/sshd_config atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud atf_check -o inline:" PasswordAuthentication yes # I want password\n" cat etc/ssh/sshd_config printf " PasswordAuthentication no # Should change\n" > etc/ssh/sshd_config atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud atf_check -o inline:"PasswordAuthentication yes\n" cat etc/ssh/sshd_config cat > media/nuageinit/user-data << 'EOF' #cloud-config ssh_pwauth: false EOF printf " PasswordAuthentication no # no passwords\n" > etc/ssh/sshd_config atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud atf_check -o inline:" PasswordAuthentication no # no passwords\n" cat etc/ssh/sshd_config printf " PasswordAuthentication yes # Should change\n" > etc/ssh/sshd_config atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud atf_check -o inline:"PasswordAuthentication no\n" cat etc/ssh/sshd_config } nocloud_userdata_cloudconfig_chpasswd_head() { atf_set "require.user" root } nocloud_userdata_cloudconfig_chpasswd_body() { mkdir -p etc cat > etc/master.passwd << EOF root:*:0:0::0:0:Charlie &:/root:/bin/sh sys:*:1:0::0:0:Sys:/home/sys:/bin/sh user:*:1:0::0:0:Sys:/home/sys:/bin/sh EOF pwd_mkdb -d etc "${PWD}"/etc/master.passwd cat > etc/group << EOF wheel:*:0:root users:*:1: EOF mkdir -p media/nuageinit printf "instance-id: iid-local01\n" > "${PWD}"/media/nuageinit/meta-data cat > media/nuageinit/user-data << 'EOF' #cloud-config chpasswd: expire: true users: - { user: "sys", password: RANDOM } EOF atf_check -o empty -e inline:"nuageinit: Invalid entry for chpasswd.users: missing 'name'\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud # nothing modified atf_check -o inline:"sys:*:1:0::0:0:Sys:/home/sys:/bin/sh\n" pw -R $(pwd) usershow sys cat > media/nuageinit/user-data << 'EOF' #cloud-config chpasswd: expire: true users: - { name: "sys", pwd: RANDOM } EOF atf_check -o empty -e inline:"nuageinit: Invalid entry for chpasswd.users: missing 'password'\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud # nothing modified atf_check -o inline:"sys:*:1:0::0:0:Sys:/home/sys:/bin/sh\n" pw -R $(pwd) usershow sys cat > media/nuageinit/user-data << 'EOF' #cloud-config chpasswd: expire: false users: - { name: "sys", password: RANDOM } EOF # not empty because the password is printed to stdout atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud atf_check -o match:'sys:\$.*:1:0::0:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys cat > media/nuageinit/user-data << 'EOF' #cloud-config chpasswd: expire: true users: - { name: "sys", password: RANDOM } EOF # not empty because the password is printed to stdout atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud atf_check -o match:'sys:\$.*:1:0::1:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys cat > media/nuageinit/user-data << 'EOF' #cloud-config chpasswd: expire: true users: - { name: "user", password: "$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/" } EOF # not empty because the password is printed to stdout atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud atf_check -o inline:'user:$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/:1:0::1:0:Sys:/home/sys:/bin/sh\n' pw -R $(pwd) usershow user } nocloud_userdata_cloudconfig_chpasswd_list_string_head() { atf_set "require.user" root } nocloud_userdata_cloudconfig_chpasswd_list_string_body() { mkdir -p etc cat > etc/master.passwd << EOF root:*:0:0::0:0:Charlie &:/root:/bin/sh sys:*:1:0::0:0:Sys:/home/sys:/bin/sh user:*:1:0::0:0:Sys:/home/sys:/bin/sh EOF pwd_mkdb -d etc "${PWD}"/etc/master.passwd cat > etc/group << EOF wheel:*:0:root users:*:1: EOF mkdir -p media/nuageinit printf "instance-id: iid-local01\n" > "${PWD}"/media/nuageinit/meta-data cat > media/nuageinit/user-data << 'EOF' #cloud-config chpasswd: expire: true list: | sys:RANDOM EOF atf_check -o empty -e inline:"nuageinit: chpasswd.list is deprecated consider using chpasswd.users\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud atf_check -o match:'sys:\$.*:1:0::1:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys cat > media/nuageinit/user-data << 'EOF' #cloud-config chpasswd: expire: false list: | sys:plop user:$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/ root:R EOF atf_check -o empty -e ignore /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud atf_check -o match:'sys:\$.*:1:0::0:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys atf_check -o inline:'user:$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/:1:0::0:0:Sys:/home/sys:/bin/sh\n' pw -R $(pwd) usershow user atf_check -o match:'root:\$.*:0:0::0:0:Charlie &:/root:/bin/sh$' pw -R $(pwd) usershow root } nocloud_userdata_cloudconfig_chpasswd_list_list_head() { atf_set "require.user" root } nocloud_userdata_cloudconfig_chpasswd_list_list_body() { mkdir -p etc cat > etc/master.passwd << EOF root:*:0:0::0:0:Charlie &:/root:/bin/sh sys:*:1:0::0:0:Sys:/home/sys:/bin/sh user:*:1:0::0:0:Sys:/home/sys:/bin/sh EOF pwd_mkdb -d etc "${PWD}"/etc/master.passwd cat > etc/group << EOF wheel:*:0:root users:*:1: EOF mkdir -p media/nuageinit printf "instance-id: iid-local01\n" > "${PWD}"/media/nuageinit/meta-data cat > media/nuageinit/user-data << 'EOF' #cloud-config chpasswd: expire: true list: - sys:RANDOM EOF atf_check -o empty -e inline:"nuageinit: chpasswd.list is deprecated consider using chpasswd.users\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud atf_check -o match:'sys:\$.*:1:0::1:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys cat > media/nuageinit/user-data << 'EOF' #cloud-config chpasswd: expire: false list: - sys:plop - user:$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/ - root:R EOF atf_check -o empty -e ignore /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud atf_check -o match:'sys:\$.*:1:0::0:0:Sys:/home/sys:/bin/sh$' pw -R $(pwd) usershow sys atf_check -o inline:'user:$6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/:1:0::0:0:Sys:/home/sys:/bin/sh\n' pw -R $(pwd) usershow user atf_check -o match:'root:\$.*:0:0::0:0:Charlie &:/root:/bin/sh$' pw -R $(pwd) usershow root } config2_userdata_runcmd_head() { atf_set "require.user" root } config2_userdata_runcmd_body() { mkdir -p media/nuageinit setup_test_adduser printf "{}" > media/nuageinit/meta_data.json cat > media/nuageinit/user_data << 'EOF' #cloud-config runcmd: EOF chmod 755 "${PWD}"/media/nuageinit/user_data atf_check -s exit:1 -e match:"attempt to index a nil value" /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 cat > media/nuageinit/user_data << 'EOF' #cloud-config runcmd: - plop EOF chmod 755 "${PWD}"/media/nuageinit/user_data atf_check -s exit:0 -e inline:"sh: plop: not found\nnuageinit: Failed to execute 'plop'\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 cat > media/nuageinit/user_data << 'EOF' #cloud-config runcmd: - echo "yeah!" > "${PWD}"/media/nuageinit/runcmd_echo - uname -s > "${PWD}"/media/nuageinit/runcmd_uname EOF chmod 755 "${PWD}"/media/nuageinit/user_data atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 atf_check -s exit:0 -o inline:"yeah!\n" cat "${PWD}"/media/nuageinit/runcmd_echo atf_check -s exit:0 -o inline:"FreeBSD\n" cat "${PWD}"/media/nuageinit/runcmd_uname } +config2_userdata_packages_head() +{ + atf_set "require.user" root +} +config2_userdata_packages_body() +{ + mkdir -p media/nuageinit + setup_test_adduser + export NUAGE_RUN_TESTS=1 + printf "{}" > media/nuageinit/meta_data.json + cat > media/nuageinit/user_data << 'EOF' +#cloud-config +packages: +EOF + chmod 755 "${PWD}"/media/nuageinit/user_data + atf_check -s exit:1 -e match:"attempt to index a nil value" /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 + cat > media/nuageinit/user_data << 'EOF' +#cloud-config +packages: + - yeah/plop +EOF + chmod 755 "${PWD}"/media/nuageinit/user_data + atf_check -s exit:0 -o inline:"pkg install -y yeah/plop\npkg info -q yeah/plop\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 + + cat > media/nuageinit/user_data << 'EOF' +#cloud-config +packages: + - curl +EOF + chmod 755 "${PWD}"/media/nuageinit/user_data + atf_check -o inline:"pkg install -y curl\npkg info -q curl\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 + + cat > media/nuageinit/user_data << 'EOF' +#cloud-config +packages: + - curl + - meh: bla +EOF + chmod 755 "${PWD}"/media/nuageinit/user_data + atf_check -o inline:"pkg install -y curl\npkg info -q curl\n" -e inline:"nuageinit: Invalid type : table for packages entry number 2\n" /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 +} + atf_init_test_cases() { atf_add_test_case args atf_add_test_case nocloud atf_add_test_case nocloud_userdata_script atf_add_test_case nocloud_user_data_script atf_add_test_case nocloud_userdata_cloudconfig_users atf_add_test_case nocloud_network atf_add_test_case config2 atf_add_test_case config2_pubkeys atf_add_test_case config2_pubkeys_user_data atf_add_test_case config2_pubkeys_meta_data atf_add_test_case config2_network atf_add_test_case config2_network_static_v4 atf_add_test_case config2_ssh_keys atf_add_test_case nocloud_userdata_cloudconfig_ssh_pwauth atf_add_test_case nocloud_userdata_cloudconfig_chpasswd atf_add_test_case nocloud_userdata_cloudconfig_chpasswd_list_string atf_add_test_case nocloud_userdata_cloudconfig_chpasswd_list_list atf_add_test_case config2_userdata_runcmd + atf_add_test_case config2_userdata_packages }