fix install v2.15.X
This commit is contained in:
+77
-10
@@ -1053,10 +1053,51 @@ def _install_certbot_stack(pip_path: Path, certbot_path: Path, env_build: dict):
|
||||
_ensure_certbot_symlink(certbot_path)
|
||||
|
||||
|
||||
|
||||
def _venv_entrypoint_usable(path: Path, args: list[str] | None = None) -> tuple[bool, str]:
|
||||
"""Return whether a venv script/binary can be executed.
|
||||
|
||||
Debian/Ubuntu upgrades can leave /opt/certbot/bin/* wrappers with a stale
|
||||
shebang, for example /opt/certbot/bin/python3.11 no longer exists. In that
|
||||
case subprocess may raise FileNotFoundError even though the wrapper file
|
||||
itself exists. Treat that as a broken venv and rebuild it.
|
||||
"""
|
||||
args = args or ["--version"]
|
||||
|
||||
if not path.exists():
|
||||
return False, f"missing: {path}"
|
||||
|
||||
try:
|
||||
first_line = path.read_bytes().splitlines()[0].decode("utf-8", "ignore")
|
||||
except Exception:
|
||||
first_line = ""
|
||||
|
||||
if first_line.startswith("#!"):
|
||||
interpreter = first_line[2:].strip().split()[0]
|
||||
if interpreter and interpreter.startswith("/") and not Path(interpreter).exists():
|
||||
return False, f"stale interpreter in {path}: {interpreter}"
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[str(path)] + args,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
timeout=20,
|
||||
check=False,
|
||||
)
|
||||
if result.returncode == 0:
|
||||
return True, "ok"
|
||||
return False, f"{path} exited with code {result.returncode}"
|
||||
except FileNotFoundError as e:
|
||||
return False, f"cannot execute {path}: {e}"
|
||||
except Exception as e:
|
||||
return False, f"cannot execute {path}: {e}"
|
||||
|
||||
def ensure_certbot_venv_ready(venv_dir: Path = Path("/opt/certbot"), force_rebuild: bool = False):
|
||||
"""Fresh install: build full venv. Update: keep a complete existing venv.
|
||||
|
||||
Rebuild only when forced or when certbot/plugin packages are missing.
|
||||
Rebuild when forced, when packages are missing, or when the existing venv
|
||||
has stale entrypoints after an OS/Python upgrade.
|
||||
"""
|
||||
certbot_path = venv_dir / "bin" / "certbot"
|
||||
pip_path = venv_dir / "bin" / "pip"
|
||||
@@ -1065,23 +1106,45 @@ def ensure_certbot_venv_ready(venv_dir: Path = Path("/opt/certbot"), force_rebui
|
||||
with step("Removing certbot venv for forced rebuild"):
|
||||
shutil.rmtree(venv_dir, ignore_errors=True)
|
||||
|
||||
needs_rebuild = force_rebuild or not certbot_path.exists() or not pip_path.exists()
|
||||
needs_rebuild = force_rebuild
|
||||
rebuild_reason = "forced rebuild" if force_rebuild else ""
|
||||
|
||||
if not needs_rebuild:
|
||||
pip_ok, pip_reason = _venv_entrypoint_usable(pip_path, ["--version"])
|
||||
certbot_ok, certbot_reason = _venv_entrypoint_usable(certbot_path, ["--version"])
|
||||
if not pip_ok or not certbot_ok:
|
||||
needs_rebuild = True
|
||||
rebuild_reason = pip_reason if not pip_ok else certbot_reason
|
||||
|
||||
if not needs_rebuild:
|
||||
for pkg in CERTBOT_REQUIRED_PACKAGES:
|
||||
result = subprocess.run(
|
||||
[str(pip_path), "show", pkg],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
check=False,
|
||||
)
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[str(pip_path), "show", pkg],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
check=False,
|
||||
)
|
||||
except FileNotFoundError as e:
|
||||
needs_rebuild = True
|
||||
rebuild_reason = f"broken pip wrapper: {e}"
|
||||
break
|
||||
except Exception as e:
|
||||
needs_rebuild = True
|
||||
rebuild_reason = f"cannot verify certbot venv: {e}"
|
||||
break
|
||||
|
||||
if result.returncode != 0:
|
||||
needs_rebuild = True
|
||||
rebuild_reason = f"missing package: {pkg}"
|
||||
if DEBUG:
|
||||
print(f" Certbot venv missing package: {pkg}")
|
||||
break
|
||||
|
||||
if needs_rebuild:
|
||||
if venv_dir.exists():
|
||||
with step(f"Removing broken certbot venv ({rebuild_reason})"):
|
||||
shutil.rmtree(venv_dir, ignore_errors=True)
|
||||
setup_certbot_venv(venv_dir)
|
||||
else:
|
||||
_ensure_certbot_symlink(certbot_path)
|
||||
@@ -3851,8 +3914,12 @@ def update_only(
|
||||
print(" ✓ Updated /etc/angie/angie.conf")
|
||||
|
||||
if shutil.which("angie"):
|
||||
subprocess.run(["angie", "-t"], check=False)
|
||||
print(" ✓ Config syntax OK")
|
||||
try:
|
||||
run(["angie", "-t"], check=True)
|
||||
print(" ✓ Config syntax OK")
|
||||
except subprocess.CalledProcessError:
|
||||
print(" ✖ Config syntax failed - keeping backup for manual rollback")
|
||||
raise
|
||||
else:
|
||||
if DEBUG:
|
||||
print(" ⚠ /etc/angie/angie.conf unchanged (install mode)")
|
||||
|
||||
Reference in New Issue
Block a user