The branch main has been updated by bapt: URL: https://cgit.FreeBSD.org/src/commit/?id=58653bf4d0fb8ccd5de146d671ec101a1df0ede0
commit 58653bf4d0fb8ccd5de146d671ec101a1df0ede0 Author: Baptiste Daroussin <[email protected]> AuthorDate: 2026-06-05 21:28:25 +0000 Commit: Baptiste Daroussin <[email protected]> CommitDate: 2026-06-05 21:28:25 +0000 nuageinit: implement phone_home support Posts instance data (hostname, instance_id, public keys) to a URL using fetch(1). Supports: - url: target URL - post: list of data items to send, or 'all' - tries: number of retry attempts (default 1) --- libexec/nuageinit/nuageinit | 91 +++++++++++++++++++++++++++++++++++- libexec/nuageinit/tests/nuageinit.sh | 33 +++++++++++++ 2 files changed, 122 insertions(+), 2 deletions(-) diff --git a/libexec/nuageinit/nuageinit b/libexec/nuageinit/nuageinit index 1391aff13bd6..8e207cae0a15 100755 --- a/libexec/nuageinit/nuageinit +++ b/libexec/nuageinit/nuageinit @@ -808,6 +808,79 @@ local function final_message(obj) nuage.warn(msg, false) end +local function phone_home(obj, metadata) + if obj.phone_home == nil then return end + local ph = obj.phone_home + if type(ph) ~= "table" then + nuage.warn("phone_home must be an object") + return + end + if not ph.url then + nuage.warn("phone_home.url is required") + return + end + local url = ph.url + local tries = ph.tries or 1 + if type(tries) ~= "number" or tries < 1 then + tries = 1 + end + + -- Collect data to post + local data = {} + local post = ph.post + if post == "all" then + post = {"pub_key_rsa", "pub_key_ecdsa", "pub_key_ed25519", + "instance_id", "hostname", "fqdn"} + end + if type(post) == "table" then + for _, key in ipairs(post) do + if key == "hostname" then + if metadata.hostname then + table.insert(data, "hostname=" .. metadata.hostname) + end + elseif key == "fqdn" then + if metadata.hostname then + table.insert(data, "fqdn=" .. metadata.hostname) + end + elseif key == "instance_id" then + if metadata.uuid then + table.insert(data, "instance_id=" .. metadata.uuid) + end + elseif key:match("^pub_key_") then + local algo = key:match("^pub_key_(.+)$") + if metadata.public_keys then + for _, k in ipairs(metadata.public_keys) do + if algo == "rsa" and k:match("^ssh%-rsa ") then + table.insert(data, key .. "=" .. nuage.encode_base64(k)) + elseif algo == "ecdsa" and k:match("^ecdsa%-") then + table.insert(data, key .. "=" .. nuage.encode_base64(k)) + elseif algo == "ed25519" and k:match("^ssh%-ed25519 ") then + table.insert(data, key .. "=" .. nuage.encode_base64(k)) + end + end + end + end + end + end + local post_data = table.concat(data, "&") + local cmd = "fetch -q -o /dev/null --post-data " .. nuage.shell_escape(post_data) + cmd = cmd .. " " .. nuage.shell_escape(url) + + if os.getenv("NUAGE_RUN_TESTS") then + print(cmd) + return + end + for i = 1, tries do + if os.execute(cmd) then + break + end + if i < tries then + -- wait 1 second before retrying + os.execute("sleep 1") + end + end +end + local function chpasswd(obj) if obj.chpasswd == nil then return end nuage.chpasswd(obj.chpasswd) @@ -973,10 +1046,23 @@ local function load_metadata(citype) nuage.err("error parsing nocloud meta-data") end return obj - elseif citype ~= "postnet" then + elseif citype == "postnet" then + -- reload metadata: try config-2 format first, then nocloud + local parser = ucl.parser() + local res, err = parser:parse_file(ni_path .. "/meta_data.json") + if res then + return parser:get_object() + end + local f = io.open(ni_path .. "/meta-data") + if f then + local obj = yaml.load(f:read("*a")) + f:close() + if obj then return obj end + end + return {} + else nuage.err("Unknown cloud init type: " .. citype) end - return {} end local function load_userdata() @@ -1114,6 +1200,7 @@ elseif line == "#cloud-config" then users, chpasswd, write_files_deferred, + phone_home, final_message, power_state_change, } diff --git a/libexec/nuageinit/tests/nuageinit.sh b/libexec/nuageinit/tests/nuageinit.sh index 2b4d316fd5ff..b225289718e6 100644 --- a/libexec/nuageinit/tests/nuageinit.sh +++ b/libexec/nuageinit/tests/nuageinit.sh @@ -47,6 +47,7 @@ atf_test_case config2_userdata_fqdn_and_hostname atf_test_case config2_userdata_write_files atf_test_case config2_userdata_encode_base64 atf_test_case config2_userdata_final_message +atf_test_case config2_userdata_phone_home setup_test_adduser() { @@ -1416,6 +1417,37 @@ EOF /usr/libexec/nuageinit "${PWD}"/media/nuageinit postnet } +config2_userdata_phone_home_body() +{ + mkdir -p media/nuageinit + setup_test_adduser + export NUAGE_RUN_TESTS=1 + printf '{"hostname": "myhost", "uuid": "abc-123", "public_keys": ["ssh-rsa AAAAB...", "ssh-ed25519 AAAAC..."]}' > media/nuageinit/meta_data.json + cat > media/nuageinit/user_data << 'EOF' +#cloud-config +phone_home: + url: "http://example.com/endpoint" + post: + - hostname + - instance_id + tries: 1 +EOF + atf_check -o match:"fetch -q -o /dev/null --post-data 'hostname=myhost&instance_id=abc-123' 'http://example.com/endpoint'" \ + /usr/libexec/nuageinit "${PWD}"/media/nuageinit postnet + + # Test "all" post + printf '{"hostname": "myhost"}' > media/nuageinit/meta_data.json + cat > media/nuageinit/user_data << 'EOF' +#cloud-config +phone_home: + url: "http://example.com/endpoint" + post: all + tries: 1 +EOF + atf_check -o match:"fetch -q -o /dev/null --post-data 'hostname=myhost&fqdn=myhost' 'http://example.com/endpoint'" \ + /usr/libexec/nuageinit "${PWD}"/media/nuageinit postnet +} + atf_init_test_cases() { atf_add_test_case args @@ -1458,4 +1490,5 @@ atf_init_test_cases() atf_add_test_case config2_userdata_write_files atf_add_test_case config2_userdata_encode_base64 atf_add_test_case config2_userdata_final_message + atf_add_test_case config2_userdata_phone_home }
