From 6c1a8185aacbd64dd20a9e665fe64ac20a4abe8c Mon Sep 17 00:00:00 2001 From: Alex Vandiver Date: Fri, 23 Aug 2024 21:48:04 +0000 Subject: [PATCH] setup_path: Ensure that the right venv is activated. `setup_path()` previously only checked that some `zulip-py3-venv` was the `sys.prefix`, not that it was the one associated with this deployment. When `uwsgi` is started, it is started from `bin/uwsgi` within a `zulip-py3-venv` virtualenv, and as such sets `sys.executable` to that, resulting in uwsgi workers picking up the library path of that virtualenv. On first start, `sys.path` thus already matches the expected virtualenv, and the `setup_path` in `zproject.wsgi` does nothing. If a rolling restart was later done into a deployment with a different virtualenv, the `zproject.wsgi` call to `setup_path()` did not change `sys.path` to the new virtualenv, since it was already running within _a_ virtualenv. This led to dependency version mismatches, and potentially even more disastrous consequences if the old (but still erroneously in use) virtualenv was later garbage-collected. PR #26771 was a previous attempt to resolve this, but failed due to not thinking of the uwsgi binary itself as possibly providing a virtualenv path. We leave the `chdir` hooks from that in-place, since it cannot hurt for the "master" uwsgi process to be chdir'd to `/`, and the `hook-post-fork` `chdir` is reasonable as well. Resolve the virtualenv in `setup_path()`, and activate it if it differs from the one that is currently active. To be sure that no other old virtualenvs are used, we also filter out any paths which appear to be from other Zulip virtualenvs. --- scripts/lib/setup_path.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/lib/setup_path.py b/scripts/lib/setup_path.py index 2eb1a27803..751038c19f 100644 --- a/scripts/lib/setup_path.py +++ b/scripts/lib/setup_path.py @@ -7,9 +7,10 @@ import sys def setup_path() -> None: - if os.path.basename(sys.prefix) != "zulip-py3-venv": - BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - venv = os.path.join(BASE_DIR, "zulip-py3-venv") + BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + venv = os.path.realpath(os.path.join(BASE_DIR, "zulip-py3-venv")) + if sys.prefix != venv: + sys.path = list(filter(lambda p: "/zulip-py3-venv/" not in p, sys.path)) activate_this = os.path.join(venv, "bin", "activate_this.py") activate_locals = dict(__file__=activate_this) with open(activate_this) as f: