Pause autoinstall on network screen
This commit is contained in:
parent
9217511f84
commit
e589e48511
@ -10,6 +10,8 @@ sudo bash install.sh
|
|||||||
|
|
||||||
Server reboots automatically after NVIDIA drivers install. Phase 2 runs on its own after reboot.
|
Server reboots automatically after NVIDIA drivers install. Phase 2 runs on its own after reboot.
|
||||||
|
|
||||||
|
On the custom ISO, Ubuntu autoinstall now pauses on the installer network screen so the operator can choose the final IP address from the VM console before installation continues.
|
||||||
|
|
||||||
## What Gets Installed (Entry Tier)
|
## What Gets Installed (Entry Tier)
|
||||||
|
|
||||||
| Service | Port | Notes |
|
| Service | Port | Notes |
|
||||||
|
|||||||
@ -1,14 +1,18 @@
|
|||||||
#cloud-config
|
#cloud-config
|
||||||
autoinstall:
|
autoinstall:
|
||||||
version: 1
|
version: 1
|
||||||
|
interactive-sections:
|
||||||
|
- network
|
||||||
|
|
||||||
# ── Locale & keyboard ──────────────────────────
|
# ── Locale & keyboard ──────────────────────────
|
||||||
locale: en_IN.UTF-8
|
locale: en_IN.UTF-8
|
||||||
keyboard:
|
keyboard:
|
||||||
layout: us
|
layout: us
|
||||||
|
|
||||||
# ── Network: DHCP on first ethernet ───────────
|
# ── Network: stop on installer network screen ─
|
||||||
# Final network config is set by the web setup UI (browser on port 80)
|
# Subiquity will show the network UI and use the values below as defaults.
|
||||||
|
# This lets the operator set the final static IP from the VM console before
|
||||||
|
# installation completes.
|
||||||
network:
|
network:
|
||||||
network:
|
network:
|
||||||
version: 2
|
version: 2
|
||||||
|
|||||||
@ -58,6 +58,19 @@ def validate_static_network(ip, prefix, gateway, dns):
|
|||||||
raise ValueError("CIDR prefix must be between 1 and 32")
|
raise ValueError("CIDR prefix must be between 1 and 32")
|
||||||
return str(prefix_int)
|
return str(prefix_int)
|
||||||
|
|
||||||
|
def is_ip_in_use(ip):
|
||||||
|
"""Best-effort conflict check before taking a static IP."""
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
["ping", "-c", "1", "-W", "1", ip],
|
||||||
|
stdout=subprocess.DEVNULL,
|
||||||
|
stderr=subprocess.DEVNULL,
|
||||||
|
check=False,
|
||||||
|
)
|
||||||
|
return result.returncode == 0
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
def apply_static_ip(iface, ip, prefix, gateway, dns):
|
def apply_static_ip(iface, ip, prefix, gateway, dns):
|
||||||
prefix = validate_static_network(ip, prefix, gateway, dns)
|
prefix = validate_static_network(ip, prefix, gateway, dns)
|
||||||
config = f"""network:
|
config = f"""network:
|
||||||
@ -270,6 +283,9 @@ HTML = r"""<!DOCTYPE html>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="static-fields" id="static-fields">
|
<div class="static-fields" id="static-fields">
|
||||||
|
<div class="alert alert-info">
|
||||||
|
We will ping the IP before applying it. If it replies, we will block the change to avoid taking an address that is already in use.
|
||||||
|
</div>
|
||||||
<div class="ip-row">
|
<div class="ip-row">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>IP Address</label>
|
<label>IP Address</label>
|
||||||
@ -437,7 +453,15 @@ function applyStaticIP() {
|
|||||||
dns: document.getElementById('ip-dns').value,
|
dns: document.getElementById('ip-dns').value,
|
||||||
};
|
};
|
||||||
fetch('/api/network', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(body) })
|
fetch('/api/network', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(body) })
|
||||||
.then(r=>r.json()).then(d=>{ if(!d.ok) alert('Network config failed: ' + d.error); });
|
.then(r=>r.json()).then(d=>{
|
||||||
|
if(!d.ok) {
|
||||||
|
alert('Network config failed: ' + d.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (d.warning) {
|
||||||
|
alert(d.warning);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Tier ───────────────────────────────────────────────────
|
// ── Tier ───────────────────────────────────────────────────
|
||||||
@ -663,7 +687,20 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
if body.get("mode") == "static":
|
if body.get("mode") == "static":
|
||||||
ifaces = get_interfaces()
|
ifaces = get_interfaces()
|
||||||
iface = ifaces[0] if ifaces else "eth0"
|
iface = ifaces[0] if ifaces else "eth0"
|
||||||
|
validate_static_network(body["ip"], body["prefix"], body["gateway"], body["dns"])
|
||||||
|
if is_ip_in_use(body["ip"]):
|
||||||
|
self.send_json({
|
||||||
|
"ok": False,
|
||||||
|
"error": f"IP address {body['ip']} is already replying to ping. Choose a different address."
|
||||||
|
}, 409)
|
||||||
|
return
|
||||||
apply_static_ip(iface, body["ip"], body["prefix"], body["gateway"], body["dns"])
|
apply_static_ip(iface, body["ip"], body["prefix"], body["gateway"], body["dns"])
|
||||||
|
self.send_json({
|
||||||
|
"ok": True,
|
||||||
|
"ip": get_ip(),
|
||||||
|
"warning": "Ping check passed before applying the static IP. Note: a non-reply does not guarantee the address is unused if another host blocks ICMP."
|
||||||
|
})
|
||||||
|
return
|
||||||
self.send_json({"ok": True, "ip": get_ip()})
|
self.send_json({"ok": True, "ip": get_ip()})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.send_json({"ok": False, "error": str(e)}, 500)
|
self.send_json({"ok": False, "error": str(e)}, 500)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user