experimental/ssh: resolve bare python/pip to the environment interpreter#5888
Open
anton-107 wants to merge 2 commits into
Open
experimental/ssh: resolve bare python/pip to the environment interpreter#5888anton-107 wants to merge 2 commits into
anton-107 wants to merge 2 commits into
Conversation
In an interactive `databricks ssh connect` session, bare `python`/`pip` resolved to the system or cluster-libraries interpreter rather than the environment interpreter at `$DATABRICKS_VIRTUAL_ENV`, so packages installed in the environment could not be imported without extra setup. Two things clobbered the environment-first PATH that sshd forwards via SetEnv: a login shell (`bash -l`) re-sourced /etc/profile, rebuilding PATH from scratch; and any interactive bash sources /etc/bash.bashrc, which on serverless runs activate_root_python_environment.sh and prepends the cluster-libraries python ahead of the environment interpreter. Fix both layers: - Client: launch an interactive non-login shell (`bash -i`) so /etc/profile is no longer re-sourced. - Server: seed a guarded, idempotent `~/.bashrc` snippet that re-prepends the environment interpreter's bin directory. ~/.bashrc is sourced after /etc/bash.bashrc, so it wins; /etc/bash.bashrc and /etc/profile.d are root-owned and not writable by the non-root serverless user. The seed is best-effort: a write failure logs a warning and does not abort the tunnel. Co-authored-by: Isaac
Contributor
Waiting for approvalBased on git history, these people are best suited to review:
Eligible reviewers: Suggestions based on git history. See OWNERS for ownership rules. |
Collaborator
Integration test reportCommit: 9b622a5
8 interesting tests: 4 RECOVERED, 4 SKIP
Top 10 slowest tests (at least 2 minutes):
|
…ompute Add experimental/ssh/CLAUDE.md capturing the verification discipline for `ssh connect` changes: confirm the built binary matches HEAD, build release archives with `./task snapshot-release` (not `./task build`) for --releases-dir, and delete the versioned workspace directory before re-verifying a rebuilt dev binary (same-version dev uploads are otherwise skipped). Also notes that the server and login session share a user/$HOME on serverless, so a per-compute symptom is usually a stale upload rather than a real difference. Co-authored-by: Isaac
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
In an interactive
databricks ssh connectsession, barepython/pipresolved to the wrong interpreter (system or cluster-libraries python) instead of the environment interpreter at$DATABRICKS_VIRTUAL_ENV, so packages installed in the environment (including with--base-environment) could not be imported without extra setup.import <env-package>failed withModuleNotFoundError. (DECO-27499)Root cause (two layers)
sshd forwards a snapshot of the environment-first
PATHinto each session via aSetEnvline, but two things clobbered it in an interactive shell:exec bash -l;-lre-sources/etc/profile, which rebuildsPATHfrom scratch, dropping the environment bin dir → barepython= system python.-ior-l) sources/etc/bash.bashrc, which on serverless runsactivate_root_python_environment.shand prepends.../cluster_libraries/python/binahead of the environment interpreter → barepython= cluster-libraries python.The non-interactive
-- <cmd>path was already correct (sshd runs it via$SHELL -c, sourcing neither file).Fix (two coordinated changes)
client.go): launch an interactive non-login shell (bash -i) so/etc/profileis no longer re-sourced.server.go): seed a guarded, idempotent~/.bashrcsnippet that re-prepends the environment interpreter's bin directory.~/.bashrcis sourced after/etc/bash.bashrc, so it wins;/etc/bash.bashrcand/etc/profile.dare root-owned and not writable by the non-root serverless user, so~/.bashrcis the only usable hook. The seed is best-effort — a write failure logs a warning and does not abort the tunnel (mirrors the existing/run/sshdhandling).Why server-side and not client-side
Each
--namegets a fresh ephemeral$HOME, so a client-side edit wouldn't persist. A pure client-side re-prepend viabash --rcfile <(...)was rejected because the remote command is parsed by the login shell (/bin/sh/dash on some images), where process substitution is a syntax error and would breakconnect.Scope
Applied on all compute, guarded by
$DATABRICKS_VIRTUAL_ENVbeing set. The bootstrap sets that variable tosys.executable(an absolute path) on every compute type, sodirnamealways yields the correct interpreter's bin directory.Testing
go test ./experimental/ssh/...green, including newTestSeedEnvActivation(create / append / trailing-newline / idempotent-preserves-content / guard-present).bash -iassertions updated inclient_internal_test.go.Manually verified against real compute
Confirmed end-to-end across all three compute types — in each interactive session,
which pythonresolved to the environment interpreter (dirname($DATABRICKS_VIRTUAL_ENV)) rather than the system or cluster-libraries python, and importing an environment-only package succeeded:--base-environment(cowsay);import cowsayworked.GPU_1xA10) — with the same custom--base-environment;import cowsayworked.which pythonresolved to the environment interpreter.This pull request and its description were written by Isaac.