Skip to content

Commit 51d9c9a

Browse files
fix: prometheus multproc dir permissions error (#120)
* os.chmod to force permissions * Clear all files and dirs inside of multiproc dir instead of the dir itself * Only clear if it exists * Only clear subdirs * Fix circular import * Only remove directories beginning with * Try setting mode to 0o777 manually on creating dir * Try replicating the permissions used by mkdtemp * Use `gettempdir` * Remove all prometheus setup from python * Blindly add code from gpt 😬 * Tidy up gpt code... * Move to gunicorn conf.py * move back to main.py and refactor into prometheus.utils * Add pragma no cover * Fix issue with settings being accessed at import time * Remove type ignore * Improve docstring * Revert all logic to `core` * Remove `chmod` * Use try/except * Tidy up * Add pragma no cover
1 parent 4897567 commit 51d9c9a

File tree

3 files changed

+42
-15
lines changed

3 files changed

+42
-15
lines changed

src/common/core/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
DEFAULT_PROMETHEUS_MULTIPROC_DIR = "/tmp/flagsmith-prometheus"
1+
DEFAULT_PROMETHEUS_MULTIPROC_DIR_NAME = "flagsmith-prometheus"

src/common/core/main.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import contextlib
22
import logging
33
import os
4-
import shutil
54
import sys
65
import typing
6+
from tempfile import gettempdir
77

88
from django.core.management import (
99
execute_from_command_line as django_execute_from_command_line,
1010
)
1111

1212
from common.core.cli import healthcheck
13-
from common.core.constants import DEFAULT_PROMETHEUS_MULTIPROC_DIR
13+
from common.core.constants import DEFAULT_PROMETHEUS_MULTIPROC_DIR_NAME
14+
from common.core.utils import clear_directory, make_writable_directory
1415

1516
logger = logging.getLogger(__name__)
1617

@@ -35,6 +36,15 @@ def ensure_cli_env() -> typing.Generator[None, None, None]:
3536

3637
# TODO @khvn26 Move logging setup to here
3738

39+
# Prometheus multiproc support
40+
prom_dir = os.environ.setdefault(
41+
"PROMETHEUS_MULTIPROC_DIR",
42+
os.path.join(gettempdir(), DEFAULT_PROMETHEUS_MULTIPROC_DIR_NAME),
43+
)
44+
if os.path.exists(prom_dir):
45+
clear_directory(prom_dir)
46+
make_writable_directory(prom_dir)
47+
3848
# Currently we don't install Flagsmith modules as a package, so we need to add
3949
# $CWD to the Python path to be able to import them
4050
sys.path.append(os.getcwd())
@@ -43,18 +53,6 @@ def ensure_cli_env() -> typing.Generator[None, None, None]:
4353
# without resorting to it being set outside of the application
4454
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings.dev")
4555

46-
# Set up Prometheus' multiprocess mode
47-
prometheus_multiproc_dir_name = os.environ.setdefault(
48-
"PROMETHEUS_MULTIPROC_DIR",
49-
DEFAULT_PROMETHEUS_MULTIPROC_DIR,
50-
)
51-
shutil.rmtree(prometheus_multiproc_dir_name, ignore_errors=True)
52-
os.makedirs(prometheus_multiproc_dir_name, exist_ok=True)
53-
logger.info(
54-
"Re-created %s for Prometheus multi-process mode",
55-
prometheus_multiproc_dir_name,
56-
)
57-
5856
if "docgen" in sys.argv:
5957
os.environ["DOCGEN_MODE"] = "true"
6058

src/common/core/utils.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import json
22
import logging
3+
import os
34
import pathlib
45
import random
6+
import shutil
57
from functools import lru_cache
68
from itertools import cycle
79
from typing import (
@@ -198,3 +200,30 @@ def using_database_replica(
198200
return manager
199201

200202
return manager.db_manager(chosen_replica)
203+
204+
205+
def clear_directory(directory_path: str) -> None:
206+
"""
207+
Safely clear a directory including all subdirectories and files.
208+
"""
209+
for p in pathlib.Path(directory_path).rglob("*"):
210+
try:
211+
# Ensure that the cleanup doesn't silently fail on
212+
# files and subdirs created by other users.
213+
p.chmod(0o777)
214+
except (PermissionError, FileNotFoundError): # pragma: no cover
215+
pass
216+
217+
shutil.rmtree(directory_path, ignore_errors=True)
218+
219+
220+
def make_writable_directory(directory_path: str) -> None:
221+
os.makedirs(directory_path, exist_ok=True)
222+
223+
try:
224+
# While `mkdir` sets mode=0o777 by default, this can be affected by umask
225+
# resulting in lesser permissions for other users. This step ensures the
226+
# directory is writable for all users.
227+
os.chmod(directory_path, 0o777)
228+
except PermissionError: # pragma: no cover
229+
pass

0 commit comments

Comments
 (0)