diff --git a/emmc-provisioning/dashboard/app.py b/emmc-provisioning/dashboard/app.py
index 21ef57e..7e191c8 100644
--- a/emmc-provisioning/dashboard/app.py
+++ b/emmc-provisioning/dashboard/app.py
@@ -1636,12 +1636,15 @@ def api_build_cloudinit():
meta_data = body.get("meta_data") or DEFAULT_META_DATA
network_config = body.get("network_config") or DEFAULT_NETWORK_CONFIG
set_as_golden_after = bool(body.get("set_as_golden_after"))
+ image_name = (body.get("image_name") or "").strip()[:64]
+ image_name = re.sub(r"[^\w\-]", "", image_name) # only alphanumeric, underscore, dash
try:
BUILD_REQUEST_FILE.parent.mkdir(parents=True, exist_ok=True)
with open(BUILD_REQUEST_FILE, "w") as f:
json.dump({
"url": url,
"variant": variant,
+ "image_name": image_name or None,
"user_data": user_data,
"meta_data": meta_data,
"network_config": network_config,
diff --git a/emmc-provisioning/dashboard/templates/cloudinit_build.html b/emmc-provisioning/dashboard/templates/cloudinit_build.html
index 1e8b8db..174fa79 100644
--- a/emmc-provisioning/dashboard/templates/cloudinit_build.html
+++ b/emmc-provisioning/dashboard/templates/cloudinit_build.html
@@ -70,6 +70,11 @@
+
+
+
+ + date suffix
+
@@ -143,7 +148,9 @@
function startBuild() {
var btn = document.getElementById('buildCloudInitBtn');
if (btn) btn.disabled = true;
+ var nameEl = document.getElementById('buildImageName');
var body = { variant: document.getElementById('buildVariant').value, set_as_golden_after: document.getElementById('buildSetGolden').checked };
+ if (nameEl && nameEl.value.trim()) body.image_name = nameEl.value.trim();
body.user_data = document.getElementById('buildUserData').value.trim();
body.meta_data = document.getElementById('buildMetaData').value.trim();
body.network_config = document.getElementById('buildNetworkConfig').value.trim();
diff --git a/emmc-provisioning/dashboard/templates/index.html b/emmc-provisioning/dashboard/templates/index.html
index 045a331..fafd088 100644
--- a/emmc-provisioning/dashboard/templates/index.html
+++ b/emmc-provisioning/dashboard/templates/index.html
@@ -437,6 +437,11 @@
+
+
+
+ + date suffix (e.g. 20251204-143022)
+
(use for Deploy without clicking manually)
@@ -913,9 +918,11 @@
var md = document.getElementById('buildMetaData');
var nc = document.getElementById('buildNetworkConfig');
var setGolden = document.getElementById('buildSetGolden');
+ var nameEl = document.getElementById('buildImageName');
var body = {
variant: getBuildVariant(),
set_as_golden_after: setGolden && setGolden.checked,
+ image_name: (nameEl && nameEl.value.trim()) ? nameEl.value.trim() : undefined,
user_data: (ud && ud.value.trim()) ? ud.value.trim() : undefined,
meta_data: (md && md.value.trim()) ? md.value.trim() : undefined,
network_config: (nc && nc.value.trim()) ? nc.value.trim() : undefined
diff --git a/emmc-provisioning/host/build-cloudinit-image.sh b/emmc-provisioning/host/build-cloudinit-image.sh
index c709a59..b38999a 100644
--- a/emmc-provisioning/host/build-cloudinit-image.sh
+++ b/emmc-provisioning/host/build-cloudinit-image.sh
@@ -47,14 +47,24 @@ with open(f"{out}/url", "w") as f:
f.write(d.get("url", ""))
with open(f"{out}/set_golden", "w") as f:
f.write("1" if d.get("set_as_golden_after") else "0")
+name = (d.get("image_name") or "").strip()[:64]
+name = "".join(c for c in name if c.isalnum() or c in "_-")
+with open(f"{out}/image_name", "w") as f:
+ f.write(name)
PY
URL=$(cat "$TEMP_DIR/url")
VARIANT=$(cat "$TEMP_DIR/variant")
SET_AS_GOLDEN=$(cat "$TEMP_DIR/set_golden")
+IMAGE_NAME="$(cat "$TEMP_DIR/image_name" 2>/dev/null || true)"
[[ -n "$URL" ]] || { write_status "error" "" "" "Missing url in request"; exit 1; }
-OUT_NAME="raspios-${VARIANT}-cloudinit-$(date +%Y%m%d-%H%M%S).img"
+DATE_SUFFIX="$(date +%Y%m%d-%H%M%S)"
+if [[ -n "$IMAGE_NAME" ]]; then
+ OUT_NAME="${IMAGE_NAME}-${DATE_SUFFIX}.img"
+else
+ OUT_NAME="raspios-${VARIANT}-cloudinit-${DATE_SUFFIX}.img"
+fi
OUT_PATH="$OUTPUT_DIR/$OUT_NAME"
BASENAME=$(basename "$URL")