Compare commits
39 Commits
fix-variab
...
python-uv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca72c97a32 | ||
|
|
9a5baa8e53 | ||
|
|
0e3d835609 | ||
|
|
7a8a0bb163 | ||
|
|
deff3b0045 | ||
|
|
1b885ce2c2 | ||
|
|
cec82a9cd2 | ||
|
|
8a792c9c9d | ||
|
|
0ea405415e | ||
|
|
d598731913 | ||
|
|
5a96d64183 | ||
|
|
a017459e12 | ||
|
|
eff3e1c43a | ||
|
|
844acbf00b | ||
|
|
e0040fe3b3 | ||
|
|
d0bad936f0 | ||
|
|
63340e6ce2 | ||
|
|
c839bae160 | ||
|
|
253452013c | ||
|
|
af70339d07 | ||
|
|
a01c26f0e2 | ||
|
|
b1bcdae01d | ||
|
|
b1a4f2ab50 | ||
|
|
1ad54e887e | ||
|
|
a446660345 | ||
|
|
c21182f502 | ||
|
|
54698b3eef | ||
|
|
59e8004f99 | ||
|
|
1271a65b5a | ||
|
|
414b9c338b | ||
|
|
53909750ef | ||
|
|
60e7fa764c | ||
|
|
a0c86ef4c7 | ||
|
|
5805554ac8 | ||
|
|
bd7607d162 | ||
|
|
7985a7bafa | ||
|
|
13896a5741 | ||
|
|
e881ed5e00 | ||
|
|
d6a654aaff |
@@ -30,14 +30,15 @@ use windmill_common::ee::{maybe_renew_license_key_on_start, LICENSE_KEY_ID, LICE
|
|||||||
|
|
||||||
use windmill_common::{
|
use windmill_common::{
|
||||||
global_settings::{
|
global_settings::{
|
||||||
BASE_URL_SETTING, BUNFIG_INSTALL_SCOPES_SETTING, CRITICAL_ERROR_CHANNELS_SETTING,
|
BASE_URL_SETTING, BUNFIG_INSTALL_SCOPES_SETTING, CRITICAL_ALERT_MUTE_UI_SETTING,
|
||||||
CUSTOM_TAGS_SETTING, DEFAULT_TAGS_PER_WORKSPACE_SETTING, DEFAULT_TAGS_WORKSPACES_SETTING,
|
CRITICAL_ERROR_CHANNELS_SETTING, CUSTOM_TAGS_SETTING, DEFAULT_TAGS_PER_WORKSPACE_SETTING,
|
||||||
ENV_SETTINGS, EXPOSE_DEBUG_METRICS_SETTING, EXPOSE_METRICS_SETTING,
|
DEFAULT_TAGS_WORKSPACES_SETTING, ENV_SETTINGS, EXPOSE_DEBUG_METRICS_SETTING,
|
||||||
EXTRA_PIP_INDEX_URL_SETTING, HUB_BASE_URL_SETTING, JOB_DEFAULT_TIMEOUT_SECS_SETTING,
|
EXPOSE_METRICS_SETTING, EXTRA_PIP_INDEX_URL_SETTING, HUB_BASE_URL_SETTING,
|
||||||
JWT_SECRET_SETTING, KEEP_JOB_DIR_SETTING, LICENSE_KEY_SETTING, NPM_CONFIG_REGISTRY_SETTING,
|
JOB_DEFAULT_TIMEOUT_SECS_SETTING, JWT_SECRET_SETTING, KEEP_JOB_DIR_SETTING,
|
||||||
OAUTH_SETTING, PIP_INDEX_URL_SETTING, REQUEST_SIZE_LIMIT_SETTING, CRITICAL_ALERT_MUTE_UI_SETTING,
|
LICENSE_KEY_SETTING, NPM_CONFIG_REGISTRY_SETTING, OAUTH_SETTING, PIP_INDEX_URL_SETTING,
|
||||||
REQUIRE_PREEXISTING_USER_FOR_OAUTH_SETTING, RETENTION_PERIOD_SECS_SETTING,
|
REQUEST_SIZE_LIMIT_SETTING, REQUIRE_PREEXISTING_USER_FOR_OAUTH_SETTING,
|
||||||
SAML_METADATA_SETTING, SCIM_TOKEN_SETTING, SMTP_SETTING, TIMEOUT_WAIT_RESULT_SETTING,
|
RETENTION_PERIOD_SECS_SETTING, SAML_METADATA_SETTING, SCIM_TOKEN_SETTING, SMTP_SETTING,
|
||||||
|
TIMEOUT_WAIT_RESULT_SETTING,
|
||||||
},
|
},
|
||||||
scripts::ScriptLang,
|
scripts::ScriptLang,
|
||||||
stats_ee::schedule_stats,
|
stats_ee::schedule_stats,
|
||||||
@@ -66,18 +67,19 @@ use windmill_worker::{
|
|||||||
get_hub_script_content_and_requirements, BUN_BUNDLE_CACHE_DIR, BUN_CACHE_DIR,
|
get_hub_script_content_and_requirements, BUN_BUNDLE_CACHE_DIR, BUN_CACHE_DIR,
|
||||||
BUN_DEPSTAR_CACHE_DIR, DENO_CACHE_DIR, DENO_CACHE_DIR_DEPS, DENO_CACHE_DIR_NPM,
|
BUN_DEPSTAR_CACHE_DIR, DENO_CACHE_DIR, DENO_CACHE_DIR_DEPS, DENO_CACHE_DIR_NPM,
|
||||||
GO_BIN_CACHE_DIR, GO_CACHE_DIR, LOCK_CACHE_DIR, PIP_CACHE_DIR, POWERSHELL_CACHE_DIR,
|
GO_BIN_CACHE_DIR, GO_CACHE_DIR, LOCK_CACHE_DIR, PIP_CACHE_DIR, POWERSHELL_CACHE_DIR,
|
||||||
RUST_CACHE_DIR, TAR_PIP_CACHE_DIR, TMP_LOGS_DIR, UV_CACHE_DIR,
|
PY311_CACHE_DIR, RUST_CACHE_DIR, TAR_PIP_CACHE_DIR, TMP_LOGS_DIR, UV_CACHE_DIR,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::monitor::{
|
use crate::monitor::{
|
||||||
initial_load, load_keep_job_dir, load_metrics_debug_enabled, load_require_preexisting_user,
|
initial_load, load_keep_job_dir, load_metrics_debug_enabled, load_require_preexisting_user,
|
||||||
load_tag_per_workspace_enabled, load_tag_per_workspace_workspaces, monitor_db, monitor_pool,
|
load_tag_per_workspace_enabled, load_tag_per_workspace_workspaces, monitor_db, monitor_pool,
|
||||||
reload_base_url_setting, reload_bunfig_install_scopes_setting,
|
reload_base_url_setting, reload_bunfig_install_scopes_setting,
|
||||||
reload_critical_error_channels_setting, reload_extra_pip_index_url_setting,
|
reload_critical_alert_mute_ui_setting, reload_critical_error_channels_setting,
|
||||||
reload_hub_base_url_setting, reload_job_default_timeout_setting, reload_jwt_secret_setting,
|
reload_extra_pip_index_url_setting, reload_hub_base_url_setting,
|
||||||
reload_license_key, reload_npm_config_registry_setting, reload_pip_index_url_setting,
|
reload_job_default_timeout_setting, reload_jwt_secret_setting, reload_license_key,
|
||||||
|
reload_npm_config_registry_setting, reload_pip_index_url_setting,
|
||||||
reload_retention_period_setting, reload_scim_token_setting, reload_smtp_config,
|
reload_retention_period_setting, reload_scim_token_setting, reload_smtp_config,
|
||||||
reload_worker_config, reload_critical_alert_mute_ui_setting,
|
reload_worker_config,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "parquet")]
|
#[cfg(feature = "parquet")]
|
||||||
@@ -995,8 +997,9 @@ pub async fn run_workers<R: rsmq_async::RsmqConnection + Send + Sync + Clone + '
|
|||||||
for x in [
|
for x in [
|
||||||
LOCK_CACHE_DIR,
|
LOCK_CACHE_DIR,
|
||||||
TMP_LOGS_DIR,
|
TMP_LOGS_DIR,
|
||||||
PIP_CACHE_DIR,
|
|
||||||
UV_CACHE_DIR,
|
UV_CACHE_DIR,
|
||||||
|
PY311_CACHE_DIR,
|
||||||
|
PIP_CACHE_DIR,
|
||||||
TAR_PIP_CACHE_DIR,
|
TAR_PIP_CACHE_DIR,
|
||||||
DENO_CACHE_DIR,
|
DENO_CACHE_DIR,
|
||||||
DENO_CACHE_DIR_DEPS,
|
DENO_CACHE_DIR_DEPS,
|
||||||
|
|||||||
@@ -310,6 +310,8 @@ fn parse_file<T: FromStr>(path: &str) -> Option<T> {
|
|||||||
pub struct PythonAnnotations {
|
pub struct PythonAnnotations {
|
||||||
pub no_cache: bool,
|
pub no_cache: bool,
|
||||||
pub no_uv: bool,
|
pub no_uv: bool,
|
||||||
|
pub no_uv_install: bool,
|
||||||
|
pub no_uv_compile: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[annotations("//")]
|
#[annotations("//")]
|
||||||
|
|||||||
93
backend/windmill-worker/nsjail/download.py.pip.config.proto
Normal file
93
backend/windmill-worker/nsjail/download.py.pip.config.proto
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
name: "python download pip"
|
||||||
|
|
||||||
|
mode: ONCE
|
||||||
|
hostname: "python"
|
||||||
|
log_level: ERROR
|
||||||
|
time_limit: 900
|
||||||
|
|
||||||
|
rlimit_as: 2048
|
||||||
|
rlimit_cpu: 1000
|
||||||
|
rlimit_fsize: 1024
|
||||||
|
rlimit_nofile: 64
|
||||||
|
|
||||||
|
envar: "HOME=/user"
|
||||||
|
envar: "LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH"
|
||||||
|
|
||||||
|
cwd: "/tmp"
|
||||||
|
|
||||||
|
clone_newnet: false
|
||||||
|
clone_newuser: {CLONE_NEWUSER}
|
||||||
|
|
||||||
|
keep_caps: true
|
||||||
|
keep_env: true
|
||||||
|
|
||||||
|
mount {
|
||||||
|
src: "/bin"
|
||||||
|
dst: "/bin"
|
||||||
|
is_bind: true
|
||||||
|
}
|
||||||
|
|
||||||
|
mount {
|
||||||
|
src: "/lib"
|
||||||
|
dst: "/lib"
|
||||||
|
is_bind: true
|
||||||
|
}
|
||||||
|
|
||||||
|
mount {
|
||||||
|
src: "/lib64"
|
||||||
|
dst: "/lib64"
|
||||||
|
is_bind: true
|
||||||
|
mandatory: false
|
||||||
|
}
|
||||||
|
|
||||||
|
mount {
|
||||||
|
src: "/usr"
|
||||||
|
dst: "/usr"
|
||||||
|
is_bind: true
|
||||||
|
}
|
||||||
|
|
||||||
|
mount {
|
||||||
|
src: "/etc"
|
||||||
|
dst: "/etc"
|
||||||
|
is_bind: true
|
||||||
|
}
|
||||||
|
|
||||||
|
mount {
|
||||||
|
src: "/dev/null"
|
||||||
|
dst: "/dev/null"
|
||||||
|
is_bind: true
|
||||||
|
rw: true
|
||||||
|
}
|
||||||
|
|
||||||
|
mount {
|
||||||
|
dst: "/tmp"
|
||||||
|
fstype: "tmpfs"
|
||||||
|
rw: true
|
||||||
|
options: "size=500000000"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mount {
|
||||||
|
src: "{WORKER_DIR}/download_deps.py.pip.sh"
|
||||||
|
dst: "/download_deps.sh"
|
||||||
|
is_bind: true
|
||||||
|
}
|
||||||
|
|
||||||
|
mount {
|
||||||
|
src: "{CACHE_DIR}"
|
||||||
|
dst: "{CACHE_DIR}"
|
||||||
|
is_bind: true
|
||||||
|
rw: true
|
||||||
|
}
|
||||||
|
|
||||||
|
mount {
|
||||||
|
src: "/dev/urandom"
|
||||||
|
dst: "/dev/urandom"
|
||||||
|
is_bind: true
|
||||||
|
}
|
||||||
|
|
||||||
|
exec_bin {
|
||||||
|
path: "/bin/sh"
|
||||||
|
arg: "/download_deps.sh"
|
||||||
|
}
|
||||||
|
|
||||||
24
backend/windmill-worker/nsjail/download_deps.py.pip.sh
Executable file
24
backend/windmill-worker/nsjail/download_deps.py.pip.sh
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#/bin/sh
|
||||||
|
|
||||||
|
INDEX_URL_ARG=$([ -z "$INDEX_URL" ] && echo ""|| echo "--index-url $INDEX_URL" )
|
||||||
|
EXTRA_INDEX_URL_ARG=$([ -z "$EXTRA_INDEX_URL" ] && echo ""|| echo "--extra-index-url $EXTRA_INDEX_URL" )
|
||||||
|
TRUSTED_HOST_ARG=$([ -z "$TRUSTED_HOST" ] && echo "" || echo "--trusted-host $TRUSTED_HOST")
|
||||||
|
|
||||||
|
if [ ! -z "$INDEX_URL" ]
|
||||||
|
then
|
||||||
|
echo "\$INDEX_URL is set to $INDEX_URL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z "$EXTRA_INDEX_URL" ]
|
||||||
|
then
|
||||||
|
echo "\$EXTRA_INDEX_URL is set to $EXTRA_INDEX_URL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z "$TRUSTED_HOST" ]
|
||||||
|
then
|
||||||
|
echo "\$TRUSTED_HOST is set to $TRUSTED_HOST"
|
||||||
|
fi
|
||||||
|
|
||||||
|
CMD="/usr/local/bin/python3 -m pip install -v \"$REQ\" -I -t \"$TARGET\" --no-cache --no-color --no-deps --isolated --no-warn-conflicts --disable-pip-version-check $INDEX_URL_ARG $EXTRA_INDEX_URL_ARG $TRUSTED_HOST_ARG"
|
||||||
|
echo $CMD
|
||||||
|
eval $CMD
|
||||||
@@ -19,6 +19,18 @@ then
|
|||||||
echo "\$TRUSTED_HOST is set to $TRUSTED_HOST"
|
echo "\$TRUSTED_HOST is set to $TRUSTED_HOST"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
CMD="/usr/local/bin/python3 -m pip install -v \"$REQ\" -I -t \"$TARGET\" --no-cache --no-color --no-deps --isolated --no-warn-conflicts --disable-pip-version-check $INDEX_URL_ARG $EXTRA_INDEX_URL_ARG $TRUSTED_HOST_ARG"
|
CMD="/usr/local/bin/uv pip install
|
||||||
|
\"$REQ\"
|
||||||
|
--target \"$TARGET\"
|
||||||
|
--no-cache
|
||||||
|
--no-config
|
||||||
|
--no-color
|
||||||
|
--no-deps
|
||||||
|
--link-mode=copy
|
||||||
|
$INDEX_URL_ARG $EXTRA_INDEX_URL_ARG $TRUSTED_HOST_ARG
|
||||||
|
--index-strategy unsafe-best-match
|
||||||
|
--system
|
||||||
|
"
|
||||||
|
|
||||||
echo $CMD
|
echo $CMD
|
||||||
eval $CMD
|
eval $CMD
|
||||||
|
|||||||
@@ -116,6 +116,8 @@ async fn handle_ansible_python_deps(
|
|||||||
job_dir,
|
job_dir,
|
||||||
worker_dir,
|
worker_dir,
|
||||||
&mut Some(occupancy_metrics),
|
&mut Some(occupancy_metrics),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
additional_python_paths.append(&mut venv_path);
|
additional_python_paths.append(&mut venv_path);
|
||||||
|
|||||||
@@ -20,13 +20,21 @@ use std::sync::Arc;
|
|||||||
pub async fn build_tar_and_push(
|
pub async fn build_tar_and_push(
|
||||||
s3_client: Arc<dyn ObjectStore>,
|
s3_client: Arc<dyn ObjectStore>,
|
||||||
folder: String,
|
folder: String,
|
||||||
|
no_uv: bool,
|
||||||
) -> error::Result<()> {
|
) -> error::Result<()> {
|
||||||
use object_store::path::Path;
|
use object_store::path::Path;
|
||||||
|
|
||||||
|
use crate::PY311_CACHE_DIR;
|
||||||
|
|
||||||
tracing::info!("Started building and pushing piptar {folder}");
|
tracing::info!("Started building and pushing piptar {folder}");
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let folder_name = folder.split("/").last().unwrap();
|
let folder_name = folder.split("/").last().unwrap();
|
||||||
let tar_path = format!("{PIP_CACHE_DIR}/{folder_name}_tar.tar",);
|
let prefix = if no_uv {
|
||||||
|
PIP_CACHE_DIR
|
||||||
|
} else {
|
||||||
|
PY311_CACHE_DIR
|
||||||
|
};
|
||||||
|
let tar_path = format!("{prefix}/{folder_name}_tar.tar",);
|
||||||
|
|
||||||
let tar_file = std::fs::File::create(&tar_path)?;
|
let tar_file = std::fs::File::create(&tar_path)?;
|
||||||
let mut tar = tar::Builder::new(tar_file);
|
let mut tar = tar::Builder::new(tar_file);
|
||||||
@@ -46,7 +54,10 @@ pub async fn build_tar_and_push(
|
|||||||
// })?;
|
// })?;
|
||||||
if let Err(e) = s3_client
|
if let Err(e) = s3_client
|
||||||
.put(
|
.put(
|
||||||
&Path::from(format!("/tar/pip/{folder_name}.tar")),
|
&Path::from(format!(
|
||||||
|
"/tar/{}/{folder_name}.tar",
|
||||||
|
if no_uv { "pip" } else { "python_311" }
|
||||||
|
)),
|
||||||
std::fs::read(&tar_path)?.into(),
|
std::fs::read(&tar_path)?.into(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@@ -71,7 +82,11 @@ pub async fn build_tar_and_push(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "enterprise", feature = "parquet"))]
|
#[cfg(all(feature = "enterprise", feature = "parquet"))]
|
||||||
pub async fn pull_from_tar(client: Arc<dyn ObjectStore>, folder: String) -> error::Result<()> {
|
pub async fn pull_from_tar(
|
||||||
|
client: Arc<dyn ObjectStore>,
|
||||||
|
folder: String,
|
||||||
|
no_uv: bool,
|
||||||
|
) -> error::Result<()> {
|
||||||
use windmill_common::s3_helpers::attempt_fetch_bytes;
|
use windmill_common::s3_helpers::attempt_fetch_bytes;
|
||||||
|
|
||||||
let folder_name = folder.split("/").last().unwrap();
|
let folder_name = folder.split("/").last().unwrap();
|
||||||
@@ -79,7 +94,10 @@ pub async fn pull_from_tar(client: Arc<dyn ObjectStore>, folder: String) -> erro
|
|||||||
tracing::info!("Attempting to pull piptar {folder_name} from bucket");
|
tracing::info!("Attempting to pull piptar {folder_name} from bucket");
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let tar_path = format!("tar/pip/{folder_name}.tar");
|
let tar_path = format!(
|
||||||
|
"tar/{}/{folder_name}.tar",
|
||||||
|
if no_uv { "pip" } else { "python_311" }
|
||||||
|
);
|
||||||
let bytes = attempt_fetch_bytes(client, &tar_path).await?;
|
let bytes = attempt_fetch_bytes(client, &tar_path).await?;
|
||||||
|
|
||||||
// tracing::info!("B: {target} {folder}");
|
// tracing::info!("B: {target} {folder}");
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ lazy_static::lazy_static! {
|
|||||||
static ref USE_PIP_COMPILE: bool = std::env::var("USE_PIP_COMPILE")
|
static ref USE_PIP_COMPILE: bool = std::env::var("USE_PIP_COMPILE")
|
||||||
.ok().map(|flag| flag == "true").unwrap_or(false);
|
.ok().map(|flag| flag == "true").unwrap_or(false);
|
||||||
|
|
||||||
|
/// Use pip install
|
||||||
|
static ref USE_PIP_INSTALL: bool = std::env::var("USE_PIP_INSTALL")
|
||||||
|
.ok().map(|flag| flag == "true").unwrap_or(false);
|
||||||
|
|
||||||
|
|
||||||
static ref RELATIVE_IMPORT_REGEX: Regex = Regex::new(r#"(import|from)\s(((u|f)\.)|\.)"#).unwrap();
|
static ref RELATIVE_IMPORT_REGEX: Regex = Regex::new(r#"(import|from)\s(((u|f)\.)|\.)"#).unwrap();
|
||||||
|
|
||||||
@@ -50,6 +54,8 @@ lazy_static::lazy_static! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const NSJAIL_CONFIG_DOWNLOAD_PY_CONTENT: &str = include_str!("../nsjail/download.py.config.proto");
|
const NSJAIL_CONFIG_DOWNLOAD_PY_CONTENT: &str = include_str!("../nsjail/download.py.config.proto");
|
||||||
|
const NSJAIL_CONFIG_DOWNLOAD_PY_CONTENT_FALLBACK: &str =
|
||||||
|
include_str!("../nsjail/download.py.pip.config.proto");
|
||||||
const NSJAIL_CONFIG_RUN_PYTHON3_CONTENT: &str = include_str!("../nsjail/run.python3.config.proto");
|
const NSJAIL_CONFIG_RUN_PYTHON3_CONTENT: &str = include_str!("../nsjail/run.python3.config.proto");
|
||||||
const RELATIVE_PYTHON_LOADER: &str = include_str!("../loader.py");
|
const RELATIVE_PYTHON_LOADER: &str = include_str!("../loader.py");
|
||||||
|
|
||||||
@@ -66,8 +72,8 @@ use crate::{
|
|||||||
},
|
},
|
||||||
handle_child::handle_child,
|
handle_child::handle_child,
|
||||||
AuthedClientBackgroundTask, DISABLE_NSJAIL, DISABLE_NUSER, HOME_ENV, LOCK_CACHE_DIR,
|
AuthedClientBackgroundTask, DISABLE_NSJAIL, DISABLE_NUSER, HOME_ENV, LOCK_CACHE_DIR,
|
||||||
NSJAIL_PATH, PATH_ENV, PIP_CACHE_DIR, PIP_EXTRA_INDEX_URL, PIP_INDEX_URL, PROXY_ENVS, TZ_ENV,
|
NSJAIL_PATH, PATH_ENV, PIP_CACHE_DIR, PIP_EXTRA_INDEX_URL, PIP_INDEX_URL, PROXY_ENVS,
|
||||||
UV_CACHE_DIR,
|
PY311_CACHE_DIR, TZ_ENV, UV_CACHE_DIR,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@@ -901,10 +907,10 @@ async fn handle_python_deps(
|
|||||||
.unwrap_or_else(|| vec![])
|
.unwrap_or_else(|| vec![])
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
|
let annotations = windmill_common::worker::PythonAnnotations::parse(inner_content);
|
||||||
let requirements = match requirements_o {
|
let requirements = match requirements_o {
|
||||||
Some(r) => r,
|
Some(r) => r,
|
||||||
None => {
|
None => {
|
||||||
let annotation = windmill_common::worker::PythonAnnotations::parse(inner_content);
|
|
||||||
let mut already_visited = vec![];
|
let mut already_visited = vec![];
|
||||||
|
|
||||||
let requirements = windmill_parser_py_imports::parse_python_imports(
|
let requirements = windmill_parser_py_imports::parse_python_imports(
|
||||||
@@ -929,8 +935,8 @@ async fn handle_python_deps(
|
|||||||
worker_name,
|
worker_name,
|
||||||
w_id,
|
w_id,
|
||||||
occupancy_metrics,
|
occupancy_metrics,
|
||||||
annotation.no_uv,
|
annotations.no_uv || annotations.no_uv_compile,
|
||||||
annotation.no_cache,
|
annotations.no_cache,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
@@ -955,6 +961,8 @@ async fn handle_python_deps(
|
|||||||
job_dir,
|
job_dir,
|
||||||
worker_dir,
|
worker_dir,
|
||||||
occupancy_metrics,
|
occupancy_metrics,
|
||||||
|
annotations.no_uv || annotations.no_uv_install,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
additional_python_paths.append(&mut venv_path);
|
additional_python_paths.append(&mut venv_path);
|
||||||
@@ -966,6 +974,7 @@ lazy_static::lazy_static! {
|
|||||||
static ref PIP_SECRET_VARIABLE: Regex = Regex::new(r"\$\{PIP_SECRET:([^\s\}]+)\}").unwrap();
|
static ref PIP_SECRET_VARIABLE: Regex = Regex::new(r"\$\{PIP_SECRET:([^\s\}]+)\}").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// pip install, include cached or pull from S3
|
||||||
pub async fn handle_python_reqs(
|
pub async fn handle_python_reqs(
|
||||||
requirements: Vec<&str>,
|
requirements: Vec<&str>,
|
||||||
job_id: &Uuid,
|
job_id: &Uuid,
|
||||||
@@ -977,12 +986,22 @@ pub async fn handle_python_reqs(
|
|||||||
job_dir: &str,
|
job_dir: &str,
|
||||||
worker_dir: &str,
|
worker_dir: &str,
|
||||||
occupancy_metrics: &mut Option<&mut OccupancyMetrics>,
|
occupancy_metrics: &mut Option<&mut OccupancyMetrics>,
|
||||||
|
// TODO: Remove (Deprecated)
|
||||||
|
mut no_uv_install: bool,
|
||||||
|
is_ansible: bool,
|
||||||
) -> error::Result<Vec<String>> {
|
) -> error::Result<Vec<String>> {
|
||||||
let mut req_paths: Vec<String> = vec![];
|
let mut req_paths: Vec<String> = vec![];
|
||||||
let mut vars = vec![("PATH", PATH_ENV.as_str())];
|
let mut vars = vec![("PATH", PATH_ENV.as_str())];
|
||||||
let pip_extra_index_url;
|
let pip_extra_index_url;
|
||||||
let pip_index_url;
|
let pip_index_url;
|
||||||
|
|
||||||
|
no_uv_install |= *USE_PIP_INSTALL;
|
||||||
|
|
||||||
|
if no_uv_install && !is_ansible {
|
||||||
|
append_logs(&job_id, w_id, "\nFallback to pip (Deprecated!)\n", db).await;
|
||||||
|
tracing::warn!("Fallback to pip");
|
||||||
|
}
|
||||||
|
|
||||||
if !*DISABLE_NSJAIL {
|
if !*DISABLE_NSJAIL {
|
||||||
pip_extra_index_url = PIP_EXTRA_INDEX_URL
|
pip_extra_index_url = PIP_EXTRA_INDEX_URL
|
||||||
.read()
|
.read()
|
||||||
@@ -1013,10 +1032,21 @@ pub async fn handle_python_reqs(
|
|||||||
let _ = write_file(
|
let _ = write_file(
|
||||||
job_dir,
|
job_dir,
|
||||||
"download.config.proto",
|
"download.config.proto",
|
||||||
&NSJAIL_CONFIG_DOWNLOAD_PY_CONTENT
|
&(if no_uv_install {
|
||||||
.replace("{WORKER_DIR}", &worker_dir)
|
NSJAIL_CONFIG_DOWNLOAD_PY_CONTENT_FALLBACK
|
||||||
.replace("{CACHE_DIR}", PIP_CACHE_DIR)
|
} else {
|
||||||
.replace("{CLONE_NEWUSER}", &(!*DISABLE_NUSER).to_string()),
|
NSJAIL_CONFIG_DOWNLOAD_PY_CONTENT
|
||||||
|
})
|
||||||
|
.replace("{WORKER_DIR}", &worker_dir)
|
||||||
|
.replace(
|
||||||
|
"{CACHE_DIR}",
|
||||||
|
if no_uv_install {
|
||||||
|
PIP_CACHE_DIR
|
||||||
|
} else {
|
||||||
|
PY311_CACHE_DIR
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.replace("{CLONE_NEWUSER}", &(!*DISABLE_NUSER).to_string()),
|
||||||
)?;
|
)?;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1026,8 +1056,14 @@ pub async fn handle_python_reqs(
|
|||||||
if req.starts_with('#') {
|
if req.starts_with('#') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
let py_prefix = if no_uv_install {
|
||||||
|
PIP_CACHE_DIR
|
||||||
|
} else {
|
||||||
|
PY311_CACHE_DIR
|
||||||
|
};
|
||||||
|
|
||||||
let venv_p = format!(
|
let venv_p = format!(
|
||||||
"{PIP_CACHE_DIR}/{}",
|
"{py_prefix}/{}",
|
||||||
req.replace(' ', "").replace('/', "").replace(':', "")
|
req.replace(' ', "").replace('/', "").replace(':', "")
|
||||||
);
|
);
|
||||||
if metadata(&venv_p).await.is_ok() {
|
if metadata(&venv_p).await.is_ok() {
|
||||||
@@ -1073,7 +1109,10 @@ pub async fn handle_python_reqs(
|
|||||||
.map(|(req, venv_p)| {
|
.map(|(req, venv_p)| {
|
||||||
let os = os.clone();
|
let os = os.clone();
|
||||||
async move {
|
async move {
|
||||||
if pull_from_tar(os, venv_p.clone()).await.is_ok() {
|
if pull_from_tar(os, venv_p.clone(), no_uv_install)
|
||||||
|
.await
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
PullFromTar::Pulled(venv_p.to_string())
|
PullFromTar::Pulled(venv_p.to_string())
|
||||||
} else {
|
} else {
|
||||||
PullFromTar::NotPulled(req.to_string(), venv_p.to_string())
|
PullFromTar::NotPulled(req.to_string(), venv_p.to_string())
|
||||||
@@ -1114,7 +1153,7 @@ pub async fn handle_python_reqs(
|
|||||||
|
|
||||||
for (req, venv_p) in req_with_penv {
|
for (req, venv_p) in req_with_penv {
|
||||||
let mut logs1 = String::new();
|
let mut logs1 = String::new();
|
||||||
logs1.push_str("\n\n--- PIP INSTALL ---\n");
|
logs1.push_str("\n\n--- UV PIP INSTALL ---\n");
|
||||||
logs1.push_str(&format!("\n{req} is being installed for the first time.\n It will be cached for all ulterior uses."));
|
logs1.push_str(&format!("\n{req} is being installed for the first time.\n It will be cached for all ulterior uses."));
|
||||||
append_logs(&job_id, w_id, logs1, db).await;
|
append_logs(&job_id, w_id, logs1, db).await;
|
||||||
|
|
||||||
@@ -1150,21 +1189,47 @@ pub async fn handle_python_reqs(
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let req = format!("{}", req);
|
let req = format!("{}", req);
|
||||||
|
|
||||||
let mut command_args = vec![
|
let mut command_args = if no_uv_install {
|
||||||
PYTHON_PATH.as_str(),
|
vec![
|
||||||
"-m",
|
PYTHON_PATH.as_str(),
|
||||||
"pip",
|
"-m",
|
||||||
"install",
|
"pip",
|
||||||
&req,
|
"install",
|
||||||
"-I",
|
&req,
|
||||||
"--no-deps",
|
"-I",
|
||||||
"--no-color",
|
"--no-deps",
|
||||||
"--isolated",
|
"--no-color",
|
||||||
"--no-warn-conflicts",
|
"--isolated",
|
||||||
"--disable-pip-version-check",
|
"--no-warn-conflicts",
|
||||||
"-t",
|
"--disable-pip-version-check",
|
||||||
venv_p.as_str(),
|
"-t",
|
||||||
];
|
venv_p.as_str(),
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
vec![
|
||||||
|
UV_PATH.as_str(),
|
||||||
|
"pip",
|
||||||
|
"install",
|
||||||
|
&req,
|
||||||
|
"--no-deps",
|
||||||
|
"--no-color",
|
||||||
|
// "-p",
|
||||||
|
// "3.11",
|
||||||
|
// Prevent uv from discovering configuration files.
|
||||||
|
"--no-config",
|
||||||
|
"--link-mode=copy",
|
||||||
|
// TODO: Doublecheck it
|
||||||
|
"--system",
|
||||||
|
// Prefer main index over extra
|
||||||
|
// https://docs.astral.sh/uv/pip/compatibility/#packages-that-exist-on-multiple-indexes
|
||||||
|
// TODO: Use env variable that can be toggled from UI
|
||||||
|
"--index-strategy",
|
||||||
|
"unsafe-best-match",
|
||||||
|
"--target",
|
||||||
|
venv_p.as_str(),
|
||||||
|
"--no-cache",
|
||||||
|
]
|
||||||
|
};
|
||||||
let pip_extra_index_url = PIP_EXTRA_INDEX_URL
|
let pip_extra_index_url = PIP_EXTRA_INDEX_URL
|
||||||
.read()
|
.read()
|
||||||
.await
|
.await
|
||||||
@@ -1196,7 +1261,7 @@ pub async fn handle_python_reqs(
|
|||||||
|
|
||||||
envs.push(("HOME", HOME_ENV.as_str()));
|
envs.push(("HOME", HOME_ENV.as_str()));
|
||||||
|
|
||||||
tracing::debug!("pip install command: {:?}", command_args);
|
tracing::debug!("uv pip install command: {:?}", command_args);
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
@@ -1207,7 +1272,12 @@ pub async fn handle_python_reqs(
|
|||||||
.envs(envs)
|
.envs(envs)
|
||||||
.args([
|
.args([
|
||||||
"-x",
|
"-x",
|
||||||
&format!("{}/pip-{}.lock", LOCK_CACHE_DIR, fssafe_req),
|
&format!(
|
||||||
|
"{}/{}-{}.lock",
|
||||||
|
LOCK_CACHE_DIR,
|
||||||
|
if no_uv_install { "pip" } else { "py311" },
|
||||||
|
fssafe_req
|
||||||
|
),
|
||||||
"--command",
|
"--command",
|
||||||
&command_args.join(" "),
|
&command_args.join(" "),
|
||||||
])
|
])
|
||||||
@@ -1218,16 +1288,20 @@ pub async fn handle_python_reqs(
|
|||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
let mut pip_cmd = Command::new(PYTHON_PATH.as_str());
|
let installer_path = if no_uv_install { command_args[0] } else { "uv" };
|
||||||
pip_cmd
|
let mut cmd: Command = Command::new(&installer_path);
|
||||||
.env_clear()
|
cmd.env_clear()
|
||||||
.envs(envs)
|
.envs(envs)
|
||||||
.envs(PROXY_ENVS.clone())
|
.envs(PROXY_ENVS.clone())
|
||||||
.env("SystemRoot", SYSTEM_ROOT.as_str())
|
.env("SystemRoot", SYSTEM_ROOT.as_str())
|
||||||
|
.env(
|
||||||
|
"TMP",
|
||||||
|
std::env::var("TMP").unwrap_or_else(|_| String::from("/tmp")),
|
||||||
|
)
|
||||||
.args(&command_args[1..])
|
.args(&command_args[1..])
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::piped());
|
.stderr(Stdio::piped());
|
||||||
start_child_process(pip_cmd, PYTHON_PATH.as_str()).await?
|
start_child_process(cmd, installer_path).await?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1240,7 +1314,7 @@ pub async fn handle_python_reqs(
|
|||||||
false,
|
false,
|
||||||
worker_name,
|
worker_name,
|
||||||
&w_id,
|
&w_id,
|
||||||
&format!("pip install {req}"),
|
&format!("uv pip install {req}"),
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
occupancy_metrics,
|
occupancy_metrics,
|
||||||
@@ -1260,7 +1334,7 @@ pub async fn handle_python_reqs(
|
|||||||
tracing::warn!("S3 cache not available in the pro plan");
|
tracing::warn!("S3 cache not available in the pro plan");
|
||||||
} else {
|
} else {
|
||||||
let venv_p = venv_p.clone();
|
let venv_p = venv_p.clone();
|
||||||
tokio::spawn(build_tar_and_push(os, venv_p));
|
tokio::spawn(build_tar_and_push(os, venv_p, no_uv_install));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
req_paths.push(venv_p);
|
req_paths.push(venv_p);
|
||||||
|
|||||||
@@ -236,7 +236,14 @@ pub const TMP_LOGS_DIR: &str = concatcp!(TMP_DIR, "/logs");
|
|||||||
pub const ROOT_CACHE_NOMOUNT_DIR: &str = concatcp!(TMP_DIR, "/cache_nomount/");
|
pub const ROOT_CACHE_NOMOUNT_DIR: &str = concatcp!(TMP_DIR, "/cache_nomount/");
|
||||||
|
|
||||||
pub const LOCK_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "lock");
|
pub const LOCK_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "lock");
|
||||||
|
// Used as fallback now
|
||||||
pub const PIP_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "pip");
|
pub const PIP_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "pip");
|
||||||
|
|
||||||
|
// pub const PY310_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "python_310");
|
||||||
|
pub const PY311_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "python_311");
|
||||||
|
// pub const PY312_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "python_312");
|
||||||
|
// pub const PY313_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "python_313");
|
||||||
|
|
||||||
pub const UV_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "uv");
|
pub const UV_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "uv");
|
||||||
pub const TAR_PIP_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "tar/pip");
|
pub const TAR_PIP_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "tar/pip");
|
||||||
pub const DENO_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "deno");
|
pub const DENO_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "deno");
|
||||||
@@ -257,6 +264,7 @@ const NUM_SECS_PING: u64 = 5;
|
|||||||
const NUM_SECS_READINGS: u64 = 60;
|
const NUM_SECS_READINGS: u64 = 60;
|
||||||
|
|
||||||
const INCLUDE_DEPS_PY_SH_CONTENT: &str = include_str!("../nsjail/download_deps.py.sh");
|
const INCLUDE_DEPS_PY_SH_CONTENT: &str = include_str!("../nsjail/download_deps.py.sh");
|
||||||
|
const INCLUDE_DEPS_PY_SH_CONTENT_FALLBACK: &str = include_str!("../nsjail/download_deps.py.pip.sh");
|
||||||
|
|
||||||
pub const DEFAULT_CLOUD_TIMEOUT: u64 = 900;
|
pub const DEFAULT_CLOUD_TIMEOUT: u64 = 900;
|
||||||
pub const DEFAULT_SELFHOSTED_TIMEOUT: u64 = 604800; // 7 days
|
pub const DEFAULT_SELFHOSTED_TIMEOUT: u64 = 604800; // 7 days
|
||||||
@@ -311,6 +319,7 @@ lazy_static::lazy_static! {
|
|||||||
.and_then(|x| x.parse::<bool>().ok())
|
.and_then(|x| x.parse::<bool>().ok())
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
// pub static ref DISABLE_NSJAIL: bool = false;
|
||||||
pub static ref DISABLE_NSJAIL: bool = std::env::var("DISABLE_NSJAIL")
|
pub static ref DISABLE_NSJAIL: bool = std::env::var("DISABLE_NSJAIL")
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|x| x.parse::<bool>().ok())
|
.and_then(|x| x.parse::<bool>().ok())
|
||||||
@@ -740,6 +749,13 @@ pub async fn run_worker<R: rsmq_async::RsmqConnection + Send + Sync + Clone + 's
|
|||||||
"download_deps.py.sh",
|
"download_deps.py.sh",
|
||||||
INCLUDE_DEPS_PY_SH_CONTENT,
|
INCLUDE_DEPS_PY_SH_CONTENT,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TODO: Remove (Deprecated)
|
||||||
|
let _ = write_file(
|
||||||
|
&worker_dir,
|
||||||
|
"download_deps.py.pip.sh",
|
||||||
|
INCLUDE_DEPS_PY_SH_CONTENT_FALLBACK,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut last_ping = Instant::now() - Duration::from_secs(NUM_SECS_PING + 1);
|
let mut last_ping = Instant::now() - Duration::from_secs(NUM_SECS_PING + 1);
|
||||||
|
|||||||
@@ -1312,6 +1312,8 @@ async fn python_dep(
|
|||||||
job_dir,
|
job_dir,
|
||||||
worker_dir,
|
worker_dir,
|
||||||
occupancy_metrics,
|
occupancy_metrics,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user