diff --git a/npm_install.py b/npm_install.py index 6ae9855..e26fadf 100644 --- a/npm_install.py +++ b/npm_install.py @@ -212,41 +212,100 @@ def sync_backup_nginx_conf(): def setup_certbot_venv(venv_dir: Path = Path("/opt/certbot")): + PYENV_ROOT = Path("/opt/npm/.pyenv") + PYENV_OWNER = "npm" + PYTHON_VERSION = "3.11.11" + PYENV_BIN_CANDIDATES = ["pyenv", "/usr/bin/pyenv", "/usr/lib/pyenv/bin/pyenv"] + try: apt_try_install([ - "python3-venv", "python3-dev", "gcc", "libffi-dev", "libssl-dev", - "pkg-config", "build-essential" + "pyenv", "build-essential", "gcc", "make", "pkg-config", + "libssl-dev", "zlib1g-dev", "libbz2-dev", "libreadline-dev", + "libsqlite3-dev", "tk-dev", "libncursesw5-dev", "libgdbm-dev", + "libffi-dev", "uuid-dev", "liblzma-dev", "ca-certificates", "curl" ]) except Exception: run(["apt-get", "update"], check=False) run(["apt-get", "install", "-y", - "python3-venv","python3-dev","gcc","libffi-dev","libssl-dev", - "pkg-config","build-essential"], check=False) + "pyenv", "build-essential", "gcc", "make", "pkg-config", + "libssl-dev", "zlib1g-dev", "libbz2-dev", "libreadline-dev", + "libsqlite3-dev", "tk-dev", "libncursesw5-dev", "libgdbm-dev", + "libffi-dev", "uuid-dev", "liblzma-dev", "ca-certificates", "curl" + ], check=False) + + Path("/opt/npm").mkdir(parents=True, exist_ok=True) + PYENV_ROOT.mkdir(parents=True, exist_ok=True) + run(["chown", "-R", f"{PYENV_OWNER}:{PYENV_OWNER}", "/opt/npm"], check=False) + + pyenv_bin = next((c for c in PYENV_BIN_CANDIDATES if shutil.which(c)), None) + if not pyenv_bin: + raise RuntimeError("Nie znaleziono 'pyenv' (spróbuj /usr/bin/pyenv lub /usr/lib/pyenv/bin/pyenv).") + + env_pyenv = os.environ.copy() + env_pyenv["PYENV_ROOT"] = str(PYENV_ROOT) + + with step(f"Installing Python {PYTHON_VERSION} via pyenv into {PYENV_ROOT}"): + run([ + "sudo", "-u", PYENV_OWNER, "-H", + "env", f"PYENV_ROOT={PYENV_ROOT}", pyenv_bin, + "install", "-s", PYTHON_VERSION + ], env=env_pyenv) + + profile_snippet = f"""# Auto-generated by setup_certbot_venv +# Ustawienia pyenv dla uzytkownika 'npm' +if [ -d "{PYENV_ROOT}" ]; then + export PYENV_ROOT="{PYENV_ROOT}" + export PATH="$PYENV_ROOT/bin:$PATH" + # Inicjalizacja tylko dla interaktywnych powlok uzytkownika 'npm' + case "$-" in *i*) _interactive=1 ;; *) _interactive=0 ;; esac + if [ "${{_interactive}}" = 1 ] && [ "${{USER:-}}" = "{PYENV_OWNER}" -o "${{SUDO_USER:-}}" = "{PYENV_OWNER}" ]; then + if command -v pyenv >/dev/null 2>&1; then + eval "$(pyenv init -)" + elif [ -x "{PYENV_ROOT}/bin/pyenv" ]; then + eval "$("{PYENV_ROOT}/bin/pyenv" init -)" + fi + fi +fi +""" + write_file(Path("/etc/profile.d/npm-pyenv.sh"), profile_snippet, 0o644) + + python311 = PYENV_ROOT / "versions" / PYTHON_VERSION / "bin" / "python3.11" + if not python311.exists(): + python311 = PYENV_ROOT / "versions" / PYTHON_VERSION / "bin" / "python3" + if not python311.exists(): + raise RuntimeError(f"Nie znaleziono interpretera Pythona {PYTHON_VERSION} w {PYENV_ROOT}/versions/.") venv_bin = venv_dir / "bin" pip_path = venv_bin / "pip" certbot_path = venv_bin / "certbot" - with step(f"Preparing Certbot venv at {venv_dir}"): + with step(f"Preparing Certbot venv at {venv_dir} (Python {PYTHON_VERSION})"): + venv_dir.mkdir(parents=True, exist_ok=True) if not venv_dir.exists() or not pip_path.exists(): - run(["python3", "-m", "venv", str(venv_dir)]) + run([str(python311), "-m", "venv", str(venv_dir)]) - run([str(pip_path), "install", "-U", "pip", "setuptools", "wheel"]) + env_build = os.environ.copy() + env_build["SETUPTOOLS_USE_DISTUTILS"] = "local" + run([str(pip_path), "install", "-U", "pip", "setuptools", "wheel"], env=env_build) run([str(pip_path), "install", "-U", - "cryptography", "cffi", "certbot", "tldextract"]) + "cryptography", "cffi", "certbot", "tldextract"], env=env_build) Path("/usr/local/bin").mkdir(parents=True, exist_ok=True) target = Path("/usr/local/bin/certbot") if target.exists() or target.is_symlink(): - try: target.unlink() - except Exception: pass + try: + target.unlink() + except Exception: + pass target.symlink_to(certbot_path) cb_ver = run_out([str(certbot_path), "--version"], check=False) or "" pip_ver = run_out([str(pip_path), "--version"], check=False) or "" print(f"Certbot: {cb_ver.strip()} | Pip: {pip_ver.strip()}") + run(["chown", "-R", f"{PYENV_OWNER}:{PYENV_OWNER}", str(PYENV_ROOT)], check=False) + def configure_letsencrypt(): with step("configure letsencrypt"): run(["chown", "-R", "npm:npm", "/opt/certbot"], check=False)