git: 58653bf4d0fb - main - nuageinit: implement phone_home support
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 06 Jun 2026 06:14:21 UTC
The branch main has been updated by bapt:
URL: https://cgit.FreeBSD.org/src/commit/?id=58653bf4d0fb8ccd5de146d671ec101a1df0ede0
commit 58653bf4d0fb8ccd5de146d671ec101a1df0ede0
Author: Baptiste Daroussin <bapt@FreeBSD.org>
AuthorDate: 2026-06-05 21:28:25 +0000
Commit: Baptiste Daroussin <bapt@FreeBSD.org>
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
}