fix(updater): bootstrap fresh venv with deps; rebuild self-update argv from env
- _run_pip: on first venv use, install decnet with its full dep tree so the bootstrapped environment actually has typer/fastapi/uvicorn. Subsequent updates keep --no-deps for a near-no-op refresh. - run_update_self: do not reuse sys.argv to re-exec the updater. Inside the live process, sys.argv is the uvicorn subprocess invocation (--ssl-keyfile etc.), which 'decnet updater' CLI rejects. Reconstruct the operator-visible command from env vars set by updater.server.run.
This commit is contained in:
@@ -191,16 +191,20 @@ def _run_pip(
|
|||||||
"""
|
"""
|
||||||
idir = install_dir or release.parent.parent # releases/<slot> -> install_dir
|
idir = install_dir or release.parent.parent # releases/<slot> -> install_dir
|
||||||
venv_dir = _shared_venv(idir)
|
venv_dir = _shared_venv(idir)
|
||||||
if not venv_dir.exists():
|
fresh = not venv_dir.exists()
|
||||||
|
if fresh:
|
||||||
subprocess.run( # nosec B603
|
subprocess.run( # nosec B603
|
||||||
[sys.executable, "-m", "venv", str(venv_dir)],
|
[sys.executable, "-m", "venv", str(venv_dir)],
|
||||||
check=True, capture_output=True, text=True,
|
check=True, capture_output=True, text=True,
|
||||||
)
|
)
|
||||||
py = venv_dir / "bin" / "python"
|
py = venv_dir / "bin" / "python"
|
||||||
|
# First install into a fresh venv: pull full dep tree. Subsequent updates
|
||||||
|
# use --no-deps so pip only replaces the decnet package.
|
||||||
|
args = [str(py), "-m", "pip", "install", "--force-reinstall", str(release)]
|
||||||
|
if not fresh:
|
||||||
|
args.insert(-1, "--no-deps")
|
||||||
return subprocess.run( # nosec B603
|
return subprocess.run( # nosec B603
|
||||||
[str(py), "-m", "pip", "install", "--force-reinstall", "--no-deps",
|
args, check=False, capture_output=True, text=True,
|
||||||
str(release)],
|
|
||||||
check=False, capture_output=True, text=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -484,7 +488,20 @@ def run_update_self(
|
|||||||
_rotate(updater_install_dir)
|
_rotate(updater_install_dir)
|
||||||
_point_current_at(updater_install_dir, _active_dir(updater_install_dir))
|
_point_current_at(updater_install_dir, _active_dir(updater_install_dir))
|
||||||
|
|
||||||
argv = [str(_shared_venv(updater_install_dir) / "bin" / "decnet"), "updater"] + sys.argv[1:]
|
# Reconstruct the updater's original launch command from env vars set by
|
||||||
|
# `decnet.updater.server.run`. We can't reuse sys.argv: inside the app
|
||||||
|
# process this is the uvicorn subprocess invocation (--ssl-keyfile, etc.),
|
||||||
|
# not the operator-visible `decnet updater ...` command.
|
||||||
|
decnet_bin = str(_shared_venv(updater_install_dir) / "bin" / "decnet")
|
||||||
|
argv = [decnet_bin, "updater",
|
||||||
|
"--host", os.environ.get("DECNET_UPDATER_HOST", "0.0.0.0"), # nosec B104
|
||||||
|
"--port", os.environ.get("DECNET_UPDATER_PORT", "8766"),
|
||||||
|
"--updater-dir", os.environ.get("DECNET_UPDATER_BUNDLE_DIR",
|
||||||
|
str(pki.DEFAULT_AGENT_DIR.parent / "updater")),
|
||||||
|
"--install-dir", os.environ.get("DECNET_UPDATER_INSTALL_DIR",
|
||||||
|
str(updater_install_dir.parent)),
|
||||||
|
"--agent-dir", os.environ.get("DECNET_UPDATER_AGENT_DIR",
|
||||||
|
str(pki.DEFAULT_AGENT_DIR))]
|
||||||
if exec_cb is not None:
|
if exec_cb is not None:
|
||||||
exec_cb(argv) # tests stub this — we don't actually re-exec
|
exec_cb(argv) # tests stub this — we don't actually re-exec
|
||||||
return {"status": "self_update_queued", "argv": argv}
|
return {"status": "self_update_queued", "argv": argv}
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ def run(
|
|||||||
os.environ["DECNET_UPDATER_INSTALL_DIR"] = str(install_dir)
|
os.environ["DECNET_UPDATER_INSTALL_DIR"] = str(install_dir)
|
||||||
os.environ["DECNET_UPDATER_UPDATER_DIR"] = str(install_dir / "updater")
|
os.environ["DECNET_UPDATER_UPDATER_DIR"] = str(install_dir / "updater")
|
||||||
os.environ["DECNET_UPDATER_AGENT_DIR"] = str(agent_dir)
|
os.environ["DECNET_UPDATER_AGENT_DIR"] = str(agent_dir)
|
||||||
|
# Needed by run_update_self to rebuild the updater's launch argv.
|
||||||
|
os.environ["DECNET_UPDATER_BUNDLE_DIR"] = str(updater_dir)
|
||||||
|
os.environ["DECNET_UPDATER_HOST"] = str(host)
|
||||||
|
os.environ["DECNET_UPDATER_PORT"] = str(port)
|
||||||
|
|
||||||
keyfile = updater_dir / "updater.key"
|
keyfile = updater_dir / "updater.key"
|
||||||
certfile = updater_dir / "updater.crt"
|
certfile = updater_dir / "updater.crt"
|
||||||
|
|||||||
Reference in New Issue
Block a user