This commit is contained in:
Mateusz Gruszczyński committed 2026-10-07 22:22:54 +02:00
1 parent e84df445c6
commit e87a382a7e
109 files changed
+1092 -2925

No files matched your search

+128
View File
@@ -0,0 +1,128 @@
async fn create_virtual_environment(
python: &Path,
staging: &Path,
system_pip: bool,
shutdown: &tokio_util::sync::CancellationToken,
) -> bool {
let mut create = Command::new(python);
create.arg("-m").arg("venv").arg(staging);
if command_success(create, Duration::from_secs(180), shutdown).await {
return true;
}
if !system_pip {
return false;
}
let _ = tokio::fs::remove_dir_all(staging).await;
// Fall back to an application-local virtualenv bootstrap.
let bootstrap = staging.with_extension("virtualenv-bootstrap");
let _ = tokio::fs::remove_dir_all(&bootstrap).await;
let install_bootstrap = |break_system_packages: bool| {
let mut install = Command::new(python);
install.args([
"-m",
"pip",
"install",
"--disable-pip-version-check",
"--no-input",
"--no-cache-dir",
"--retries",
"3",
"--timeout",
"30",
]);
// Some distro pip builds enforce PEP 668 even for --target. Retrying with
// --break-system-packages is safe here because the destination is the
// private bootstrap directory; distribution site-packages are untouched.
if break_system_packages {
install.arg("--break-system-packages");
}
install.arg("--target").arg(&bootstrap).arg("virtualenv>=20,<21");
install
};
let installed = command_success(
install_bootstrap(false),
Duration::from_secs(300),
shutdown,
)
.await;
if !installed {
let _ = tokio::fs::remove_dir_all(&bootstrap).await;
if !command_success(
install_bootstrap(true),
Duration::from_secs(300),
shutdown,
)
.await
{
let _ = tokio::fs::remove_dir_all(&bootstrap).await;
return false;
}
}
let mut create = Command::new(python);
create
.arg("-c")
.arg("import runpy,sys; sys.path.insert(0,sys.argv[1]); sys.argv=['virtualenv',sys.argv[2]]; runpy.run_module('virtualenv',run_name='__main__')")
.arg(&bootstrap)
.arg(staging);
let created = command_success(create, Duration::from_secs(180), shutdown).await;
let _ = tokio::fs::remove_dir_all(&bootstrap).await;
created
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum BuildFailure {
CreateEnvironment,
PreparePip,
InstallPackages,
Validate,
}
async fn build_managed_environment(
python: &Path,
target: &Path,
system_pip: bool,
shutdown: &tokio_util::sync::CancellationToken,
) -> Result<(), BuildFailure> {
let legacy_stage = target.with_extension("installing");
let _ = tokio::fs::remove_dir_all(&legacy_stage).await;
let _ = tokio::fs::remove_dir_all(target).await;
let _ = tokio::fs::remove_file(target).await;
if !create_virtual_environment(python, target, system_pip, shutdown).await {
let _ = tokio::fs::remove_dir_all(target).await;
return Err(BuildFailure::CreateEnvironment);
}
let target_python = venv_python(target);
let mut pip_check = Command::new(&target_python);
pip_check.args(["-m", "pip", "--version"]);
if !command_success(pip_check, Duration::from_secs(30), shutdown).await {
let mut ensurepip = Command::new(&target_python);
ensurepip.args(["-m", "ensurepip", "--upgrade"]);
if !command_success(ensurepip, Duration::from_secs(120), shutdown).await {
let _ = tokio::fs::remove_dir_all(target).await;
return Err(BuildFailure::PreparePip);
}
}
let mut pip = Command::new(&target_python);
pip.args([
"-m",
"pip",
"install",
"--disable-pip-version-check",
"--no-input",
"--no-cache-dir",
"--retries",
"3",
"--timeout",
"30",
]);
pip.args(CERTBOT_PACKAGES.iter().copied());
if !command_success(pip, Duration::from_secs(600), shutdown).await {
let _ = tokio::fs::remove_dir_all(target).await;
return Err(BuildFailure::InstallPackages);
}
if !managed_environment_valid(target, shutdown).await {
let _ = tokio::fs::remove_dir_all(target).await;
return Err(BuildFailure::Validate);
}
Ok(())
}
+38 -115
View File
@@ -60,7 +60,7 @@ impl Manager {
struct RuntimeLaunch {
python: PathBuf,
prepend_path: Option<PathBuf>,
managed_certbot_python: Option<PathBuf>,
managed_certbot_executable: Option<PathBuf>,
}
fn find_on_path(name: &str) -> Option<PathBuf> {
@@ -107,6 +107,15 @@ fn venv_python(directory: &Path) -> PathBuf {
venv_bin(directory).join("python")
}
#[cfg(windows)]
fn venv_certbot(directory: &Path) -> PathBuf {
venv_bin(directory).join("certbot.exe")
}
#[cfg(not(windows))]
fn venv_certbot(directory: &Path) -> PathBuf {
venv_bin(directory).join("certbot")
}
async fn command_success(
mut command: Command,
timeout: Duration,
@@ -145,9 +154,12 @@ async fn managed_environment_valid(
if !command_success(imports, Duration::from_secs(20), shutdown).await {
return false;
}
let certbot = venv_bin(directory).join("certbot");
let mut version = Command::new(&python);
version.arg("-I").arg(certbot).arg("--version");
let certbot = venv_certbot(directory);
if !certbot.is_file() {
return false;
}
let mut version = Command::new(&certbot);
version.arg("--version");
command_success(version, Duration::from_secs(20), shutdown).await
}
@@ -172,107 +184,7 @@ async fn system_has_pip(python: &Path, shutdown: &tokio_util::sync::Cancellation
command_success(command, Duration::from_secs(20), shutdown).await
}
async fn create_virtual_environment(
python: &Path,
staging: &Path,
system_pip: bool,
shutdown: &tokio_util::sync::CancellationToken,
) -> bool {
let mut create = Command::new(python);
create.arg("-m").arg("venv").arg(staging);
if command_success(create, Duration::from_secs(180), shutdown).await {
return true;
}
if !system_pip {
return false;
}
let _ = tokio::fs::remove_dir_all(staging).await;
// Fall back to an application-local virtualenv bootstrap.
let bootstrap = staging.with_extension("virtualenv-bootstrap");
let _ = tokio::fs::remove_dir_all(&bootstrap).await;
let mut install = Command::new(python);
install.args([
"-m",
"pip",
"install",
"--disable-pip-version-check",
"--no-input",
"--no-cache-dir",
"--retries",
"3",
"--timeout",
"30",
"--target",
]);
install.arg(&bootstrap).arg("virtualenv>=20,<21");
if !command_success(install, Duration::from_secs(300), shutdown).await {
let _ = tokio::fs::remove_dir_all(&bootstrap).await;
return false;
}
let mut create = Command::new(python);
create
.arg("-c")
.arg("import runpy,sys; sys.path.insert(0,sys.argv[1]); sys.argv=['virtualenv',sys.argv[2]]; runpy.run_module('virtualenv',run_name='__main__')")
.arg(&bootstrap)
.arg(staging);
let created = command_success(create, Duration::from_secs(180), shutdown).await;
let _ = tokio::fs::remove_dir_all(&bootstrap).await;
created
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum BuildFailure {
Bootstrap,
Install,
}
async fn build_managed_environment(
python: &Path,
target: &Path,
system_pip: bool,
shutdown: &tokio_util::sync::CancellationToken,
) -> Result<(), BuildFailure> {
let legacy_stage = target.with_extension("installing");
let _ = tokio::fs::remove_dir_all(&legacy_stage).await;
let _ = tokio::fs::remove_dir_all(target).await;
let _ = tokio::fs::remove_file(target).await;
if !create_virtual_environment(python, target, system_pip, shutdown).await {
let _ = tokio::fs::remove_dir_all(target).await;
return Err(BuildFailure::Bootstrap);
}
let target_python = venv_python(target);
let mut pip_check = Command::new(&target_python);
pip_check.args(["-m", "pip", "--version"]);
if !command_success(pip_check, Duration::from_secs(30), shutdown).await {
let mut ensurepip = Command::new(&target_python);
ensurepip.args(["-m", "ensurepip", "--upgrade"]);
if !command_success(ensurepip, Duration::from_secs(120), shutdown).await {
let _ = tokio::fs::remove_dir_all(target).await;
return Err(BuildFailure::Bootstrap);
}
}
let mut pip = Command::new(&target_python);
pip.args([
"-m",
"pip",
"install",
"--disable-pip-version-check",
"--no-input",
"--no-cache-dir",
"--retries",
"3",
"--timeout",
"30",
]);
pip.args(CERTBOT_PACKAGES.iter().copied());
if !command_success(pip, Duration::from_secs(600), shutdown).await
|| !managed_environment_valid(target, shutdown).await
{
let _ = tokio::fs::remove_dir_all(target).await;
return Err(BuildFailure::Install);
}
Ok(())
}
include!("runtime_bootstrap.rs");
async fn ensure_runtime(state: &App) -> Result<RuntimeLaunch, String> {
let _permit = state
@@ -309,7 +221,7 @@ async fn ensure_runtime(state: &App) -> Result<RuntimeLaunch, String> {
return Ok(RuntimeLaunch {
python: venv_python(&managed),
prepend_path: Some(venv_bin(&managed)),
managed_certbot_python: Some(venv_python(&managed)),
managed_certbot_executable: Some(venv_certbot(&managed)),
});
}
let distro_certbot = find_on_path("certbot");
@@ -357,7 +269,7 @@ async fn ensure_runtime(state: &App) -> Result<RuntimeLaunch, String> {
return Ok(RuntimeLaunch {
python: venv_python(&managed),
prepend_path: Some(venv_bin(&managed)),
managed_certbot_python: Some(venv_python(&managed)),
managed_certbot_executable: Some(venv_certbot(&managed)),
});
}
if distro_certbot_available {
@@ -374,13 +286,23 @@ async fn ensure_runtime(state: &App) -> Result<RuntimeLaunch, String> {
return Ok(RuntimeLaunch {
python,
prepend_path: None,
managed_certbot_python: None,
managed_certbot_executable: None,
});
}
let message = if build == Err(BuildFailure::Bootstrap) && !system_pip {
"acme.runtime_pip_missing"
} else {
"acme.runtime_setup_failed"
tracing::warn!(
python = %python.display(),
managed = %managed.display(),
system_pip,
failure = ?build,
"managed ACME runtime setup failed; no system Certbot fallback available"
);
let message = match build {
Err(BuildFailure::CreateEnvironment) if !system_pip => "acme.runtime_pip_missing",
Err(BuildFailure::CreateEnvironment) => "acme.runtime_venv_failed",
Err(BuildFailure::PreparePip) => "acme.runtime_venv_pip_failed",
Err(BuildFailure::InstallPackages) => "acme.runtime_certbot_install_failed",
Err(BuildFailure::Validate) => "acme.runtime_certbot_validation_failed",
Ok(()) => "acme.runtime_setup_failed",
};
state.acme.set_runtime(RuntimeStatus {
status: "unavailable",
@@ -428,19 +350,20 @@ async fn worker(state: &App, directory: PathBuf, raw: Zeroizing<String>) -> Resu
command
.arg("-I")
.arg("-c")
.arg(include_str!("../../scripts/acme_provider.py"))
.arg(include_str!("../../scripts/runtime/acme_provider.py"))
.arg("--cert-dir")
.arg(&directory)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::null())
.kill_on_drop(true);
command.env_remove("RUSTPROXY_CERTBOT_EXECUTABLE");
command.env_remove("RUSTPROXY_CERTBOT_PYTHON");
if let Some(prepend) = launch.prepend_path.as_deref() {
command.env("PATH", merged_path(prepend)?);
}
if let Some(python) = launch.managed_certbot_python.as_deref() {
command.env("RUSTPROXY_CERTBOT_PYTHON", python);
if let Some(certbot) = launch.managed_certbot_executable.as_deref() {
command.env("RUSTPROXY_CERTBOT_EXECUTABLE", certbot);
}
#[cfg(unix)]
{