pyenv ubuntu
This commit is contained in:
201
npm_install.py
201
npm_install.py
@@ -211,133 +211,138 @@ def sync_backup_nginx_conf():
|
||||
print(f"Warning: sync failed for {p} -> {target}: {e}")
|
||||
|
||||
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
def setup_certbot_venv(venv_dir: Path = Path("/opt/certbot")):
|
||||
"""
|
||||
Tworzy środowisko venv dla Certbota, korzystając z pyenv.
|
||||
Debian: instaluje pyenv z APT.
|
||||
Ubuntu: instaluje zależności build i klonuje pyenv z Git (do /opt/npm/.pyenv).
|
||||
Wymaga pomocniczych funkcji: os_release(), apt_try_install(pkgs: list[str]), run(cmd: list[str], check=True).
|
||||
"""
|
||||
OSREL = os_release()
|
||||
|
||||
def _is_ubuntu() -> bool:
|
||||
return (OSREL.get("ID", "") or "").lower() == "ubuntu"
|
||||
|
||||
def ensure_pyenv_installed(pyenv_root: Path, owner: str):
|
||||
"""Na Ubuntu brak pakietu pyenv w APT — instalacja z Git, jeśli brak."""
|
||||
if shutil.which("pyenv") or (pyenv_root / "bin" / "pyenv").exists():
|
||||
return
|
||||
# minimalne narzędzia do klonowania
|
||||
apt_try_install(["git", "ca-certificates", "curl"])
|
||||
run([
|
||||
"sudo", "-u", owner, "bash", "-lc",
|
||||
f'git clone --depth=1 https://github.com/pyenv/pyenv.git "{pyenv_root}"'
|
||||
], check=False)
|
||||
|
||||
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"]
|
||||
PYENV_BIN_CANDIDATES = [
|
||||
"pyenv",
|
||||
"/usr/bin/pyenv",
|
||||
"/usr/lib/pyenv/bin/pyenv",
|
||||
str(PYENV_ROOT / "bin" / "pyenv"),
|
||||
]
|
||||
|
||||
try:
|
||||
apt_try_install([
|
||||
"pyenv", "build-essential", "gcc", "make", "pkg-config",
|
||||
# Zależności kompilacji Pythona
|
||||
build_deps = [
|
||||
"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",
|
||||
"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)
|
||||
"libffi-dev", "uuid-dev", "liblzma-dev", "ca-certificates", "curl", "git",
|
||||
]
|
||||
|
||||
# Debian: pyenv z APT; Ubuntu: tylko zależności build (pyenv z Git niżej)
|
||||
if _is_ubuntu():
|
||||
apt_try_install(build_deps)
|
||||
else:
|
||||
apt_try_install(["pyenv"] + build_deps)
|
||||
|
||||
# Przygotuj katalogi/owner
|
||||
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)
|
||||
|
||||
# Ubuntu: klon pyenv z Git, jeśli nie ma binarki
|
||||
ensure_pyenv_installed(PYENV_ROOT, PYENV_OWNER)
|
||||
|
||||
# Znajdź pyenv
|
||||
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.update({
|
||||
"HOME": "/opt/npm",
|
||||
"PYENV_ROOT": str(PYENV_ROOT),
|
||||
"PATH": "/usr/lib/pyenv/bin:/usr/bin:/bin"
|
||||
})
|
||||
with step(f"Installing Python {PYTHON_VERSION} via pyenv into {PYENV_ROOT}"):
|
||||
# 1) Upewnij się, że PYENV_ROOT istnieje i należy do 'npm'
|
||||
run(["mkdir", "-p", str(PYENV_ROOT)])
|
||||
run(["chown", "-R", f"{PYENV_OWNER}:{PYENV_OWNER}", "/opt/npm"], check=False)
|
||||
|
||||
# 2) Jeżeli lokalny pyenv nie istnieje – sklonuj go (pomija wrappera Debiana)
|
||||
run([
|
||||
"sudo", "-u", PYENV_OWNER, "bash", "-lc",
|
||||
'if [ ! -x "/opt/npm/.pyenv/bin/pyenv" ]; then '
|
||||
' command -v git >/dev/null 2>&1 || sudo apt-get install -y git; '
|
||||
' git clone --depth=1 https://github.com/pyenv/pyenv.git /opt/npm/.pyenv; '
|
||||
"fi"
|
||||
])
|
||||
|
||||
# 3) Z bardzo czystym środowiskiem (env -i) instalujemy CPython
|
||||
# – żadnych /etc/profile, żadnych wrapperów.
|
||||
install_cmd = (
|
||||
'export HOME=/opt/npm; '
|
||||
'export PYENV_ROOT=/opt/npm/.pyenv; '
|
||||
'export PATH="$PYENV_ROOT/bin:/usr/bin:/bin"; '
|
||||
'mkdir -p "$PYENV_ROOT"; cd "$HOME"; '
|
||||
f'pyenv install -s {PYTHON_VERSION}'
|
||||
)
|
||||
run([
|
||||
"sudo", "-u", PYENV_OWNER, "env", "-i",
|
||||
"HOME=/opt/npm",
|
||||
f"PYENV_ROOT={PYENV_ROOT}",
|
||||
f"PATH={PYENV_ROOT}/bin:/usr/bin:/bin",
|
||||
"bash", "-lc", install_cmd
|
||||
])
|
||||
|
||||
if (PYENV_ROOT / "bin" / "pyenv").exists():
|
||||
pyenv_bin = str(PYENV_ROOT / "bin" / "pyenv")
|
||||
else:
|
||||
raise RuntimeError("Nie znaleziono 'pyenv' (ani z APT, ani z Git).")
|
||||
|
||||
# Idempotentny snippet inicjujący pyenv dla użytkownika 'npm'
|
||||
profile_snippet = f"""# Auto-generated by setup_certbot_venv
|
||||
# Ustawienia pyenv dla uzytkownika '{PYENV_OWNER}'
|
||||
if [ -d "{PYENV_ROOT}" ]; then
|
||||
export PYENV_ROOT="{PYENV_ROOT}"
|
||||
# Dopnij lokalne binarki pyenv (git-install) idempotentnie
|
||||
case ":$PATH:" in *":$PYENV_ROOT/bin:"*) ;; *) PATH="$PYENV_ROOT/bin:$PATH";; esac
|
||||
# Dopnij systemowe binarki pyenv z pakietu Debiana idempotentnie
|
||||
case ":$PATH:" in *":/usr/lib/pyenv/bin:"*) ;; *) PATH="/usr/lib/pyenv/bin:$PATH";; esac
|
||||
export PATH
|
||||
# Inicjalizacja tylko dla interaktywnych powlok uzytkownika '{PYENV_OWNER}'
|
||||
case "$-" in *i*) _interactive=1 ;; *) _interactive=0 ;; esac
|
||||
if [ "$_interactive" = 1 ] && {{ [ "${{USER:-}}" = "{PYENV_OWNER}" ] || [ "${{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
|
||||
case ":$PATH:" in
|
||||
*":{PYENV_ROOT}/bin:"*) ;;
|
||||
*) export PATH="{PYENV_ROOT}/bin:$PATH" ;;
|
||||
esac
|
||||
eval "$({pyenv_bin} init -)"
|
||||
fi
|
||||
"""
|
||||
write_file(Path("/etc/profile.d/npm-pyenv.sh"), profile_snippet, 0o644)
|
||||
# Zapisz snippet do ~/.profile użytkownika 'npm' (idempotentnie)
|
||||
run([
|
||||
"sudo", "-u", PYENV_OWNER, "bash", "-lc",
|
||||
r'PROFILE="$HOME/.profile"; '
|
||||
r'grep -q "Auto-generated by setup_certbot_venv" "$PROFILE" || '
|
||||
f'printf "%s\n" {profile_snippet!r} >> "$PROFILE"'
|
||||
], check=False)
|
||||
|
||||
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/.")
|
||||
# Zainstaluj żądaną wersję Pythona (idempotentnie, -s = skip jeśli istnieje)
|
||||
run([
|
||||
"sudo", "-u", PYENV_OWNER, "bash", "-lc",
|
||||
f'export PYENV_ROOT="{PYENV_ROOT}"; export PATH="{{PYENV_ROOT}}/bin:$PATH"; '
|
||||
f'"{pyenv_bin}" install -s {PYTHON_VERSION}; '
|
||||
f'"{pyenv_bin}" versions'
|
||||
])
|
||||
|
||||
venv_bin = venv_dir / "bin"
|
||||
pip_path = venv_bin / "pip"
|
||||
certbot_path = venv_bin / "certbot"
|
||||
# Znajdź ścieżkę do zainstalowanego Pythona
|
||||
py_cmd = run([
|
||||
"sudo", "-u", PYENV_OWNER, "bash", "-lc",
|
||||
f'export PYENV_ROOT="{PYENV_ROOT}"; export PATH="{{PYENV_ROOT}}/bin:$PATH"; '
|
||||
f'PY=$( "{pyenv_bin}" prefix {PYTHON_VERSION} )/bin/python3; '
|
||||
r'echo "$PY"'
|
||||
])
|
||||
python_path = py_cmd.stdout.decode().strip()
|
||||
if not python_path:
|
||||
raise RuntimeError("Nie udało się ustalić ścieżki do python3 z pyenv.")
|
||||
|
||||
with step(f"Preparing Certbot venv at {venv_dir} (Python {PYTHON_VERSION})"):
|
||||
# Utwórz venv dla Certbota (idempotentnie)
|
||||
venv_dir = Path(venv_dir)
|
||||
venv_dir.mkdir(parents=True, exist_ok=True)
|
||||
if not venv_dir.exists() or not pip_path.exists():
|
||||
run([str(python311), "-m", "venv", str(venv_dir)])
|
||||
run([python_path, "-m", "venv", str(venv_dir)], check=True)
|
||||
|
||||
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"], env=env_build)
|
||||
# Zainstaluj/aktualizuj pip + certbot
|
||||
run([
|
||||
str(venv_dir / "bin" / "python"), "-m", "pip", "install", "--upgrade", "pip", "wheel", "setuptools"
|
||||
], check=True)
|
||||
run([
|
||||
str(venv_dir / "bin" / "pip"), "install", "--upgrade", "certbot"
|
||||
], check=True)
|
||||
|
||||
# Symlink (opcjonalnie) /usr/local/bin/certbot -> venv
|
||||
certbot_bin = venv_dir / "bin" / "certbot"
|
||||
if certbot_bin.exists():
|
||||
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
|
||||
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)
|
||||
run(["ln", "-sf", str(certbot_bin), "/usr/local/bin/certbot"], check=False)
|
||||
|
||||
return {
|
||||
"pyenv_bin": pyenv_bin,
|
||||
"python": python_path,
|
||||
"venv": str(venv_dir),
|
||||
"certbot": str(certbot_bin) if certbot_bin.exists() else None,
|
||||
"distro": OSREL.get("ID", ""),
|
||||
"version": OSREL.get("VERSION_ID", ""),
|
||||
}
|
||||
|
||||
|
||||
def configure_letsencrypt():
|
||||
|
||||
Reference in New Issue
Block a user