add hostname provisioning step

This commit is contained in:
2025-09-01 16:50:18 +02:00
parent 3c03f2a58c
commit 2be380f614

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
import ipaddress, os, re, subprocess, tempfile, json, datetime
import ipaddress, os, re, subprocess, tempfile, json, datetime, shlex
from pathlib import Path
from dotenv import load_dotenv
@@ -111,13 +111,66 @@ def step_wireguard_provision(iot_host: str, client_name: str):
return {"wg_name": name, "wg_iface": iface}
def step_set_hostname(iot_host: str, hostname: str | None):
"""Placeholder: set hostname on the device via custom script under /home/caster/bumble-auracast/src/server.
"""Set hostname on the device by running the project's provision script over SSH.
Intention: SSH into device and run a script, e.g. /home/caster/bumble-auracast/src/server/set-hostname <hostname>.
Currently does nothing.
Executes: /home/caster/bumble-auracast/src/auracast/server/provision_domain_hostname.sh <hostname> <domain>
Domain is always 'local'. Returns a dict including whether the hostname appears changed.
"""
print("⏭️ [placeholder] Skipping hostname change (no-op). Intended hostname:", hostname)
return {"hostname": hostname}
if not hostname:
print("⏭️ hostname: no hostname provided, skipping")
return {"hostname": None, "changed": False}
# Known locations where the script might live on the device
candidates = [
"/home/caster/bumble-auracast/src/auracast/server/provision_domain_hostname.sh",
"/home/caster/bumble-auracast/src/server/provision_domain_hostname.sh",
]
domain = "local"
# Build remote command. Use sudo since hostname changes typically require elevated privileges.
quoted_name = shlex.quote(hostname)
quoted_domain = shlex.quote(domain)
# Build a remote snippet that picks the first existing candidate and runs it via bash
# Using bash avoids executable-bit/shebang issues.
remote_candidates = " ".join(shlex.quote(c) for c in candidates)
remote = (
"set -e\n"
f"for p in {remote_candidates}; do\n"
" if [ -f \"$p\" ]; then sp=\"$p\"; break; fi\n"
"done\n"
"if [ -z \"${sp:-}\" ]; then echo 'script not found in any candidate path' >&2; exit 1; fi\n"
f"sudo bash \"$sp\" {quoted_name} {quoted_domain}\n"
"hostname 2>/dev/null || true\n"
)
ssh_cmd = ["ssh", "-p", str(SSH_PORT)]
if SSH_KEY:
ssh_cmd += ["-i", SSH_KEY]
ssh_cmd += [f"{SSH_USER}@{iot_host}", remote]
proc = subprocess.run(ssh_cmd, check=False, capture_output=True, text=True)
stdout = (proc.stdout or "").strip()
stderr = (proc.stderr or "").strip()
# After running the script, re-check the hostname from the device
facts_post = get_device_facts(iot_host)
new_hostname = facts_post.get("hostname")
changed = bool(new_hostname) and (new_hostname == hostname)
if proc.returncode != 0:
print(f"❌ hostname: remote script failed rc={proc.returncode}: {stderr}")
else:
print(f"✅ hostname: script executed. device hostname now '{new_hostname}' (rc={proc.returncode})")
return {
"hostname": hostname,
"domain": domain,
"device_hostname": new_hostname,
"changed": changed,
"rc": proc.returncode,
"out": stdout[-500:], # tail to keep logs compact
"err": stderr[-500:],
}
def step_update_app(iot_host: str, services: list[str] | None = None):
"""Placeholder: start/enable required system services on the device.