diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py index 0dee480b3..03d095e12 100644 --- a/freqtrade/commands/build_config_commands.py +++ b/freqtrade/commands/build_config_commands.py @@ -5,6 +5,7 @@ from typing import Any, Dict, List from questionary import Separator, prompt +from freqtrade.configuration.directory_operations import chown_user_directory from freqtrade.constants import UNLIMITED_STAKE_AMOUNT from freqtrade.exceptions import OperationalException from freqtrade.exchange import MAP_EXCHANGE_CHILDCLASS, available_exchanges @@ -216,6 +217,7 @@ def start_new_config(args: Dict[str, Any]) -> None: """ config_path = Path(args['config'][0]) + chown_user_directory(config_path.parent) if config_path.exists(): overwrite = ask_user_overwrite(config_path) if overwrite: diff --git a/freqtrade/configuration/directory_operations.py b/freqtrade/configuration/directory_operations.py index 1ce8d1461..ca305c260 100644 --- a/freqtrade/configuration/directory_operations.py +++ b/freqtrade/configuration/directory_operations.py @@ -24,6 +24,21 @@ def create_datadir(config: Dict[str, Any], datadir: Optional[str] = None) -> Pat return folder +def chown_user_directory(directory: Path) -> None: + """ + Use Sudo to change permissions of the home-directory if necessary + Only applies when running in docker! + """ + import os + if os.environ.get('FT_APP_ENV') == 'docker': + try: + import subprocess + subprocess.check_output( + ['sudo', 'chown', '-R', 'ftuser:', str(directory.resolve())]) + except Exception: + logger.warning(f"Could not chown {directory}") + + def create_userdata_dir(directory: str, create_dir: bool = False) -> Path: """ Create userdata directory structure. @@ -37,6 +52,7 @@ def create_userdata_dir(directory: str, create_dir: bool = False) -> Path: sub_dirs = ["backtest_results", "data", "hyperopts", "hyperopt_results", "logs", "notebooks", "plot", "strategies", ] folder = Path(directory) + chown_user_directory(folder) if not folder.is_dir(): if create_dir: folder.mkdir(parents=True) diff --git a/tests/test_directory_operations.py b/tests/test_directory_operations.py index a8058c514..a11200526 100644 --- a/tests/test_directory_operations.py +++ b/tests/test_directory_operations.py @@ -1,11 +1,12 @@ # pragma pylint: disable=missing-docstring, protected-access, invalid-name +import os from pathlib import Path from unittest.mock import MagicMock import pytest -from freqtrade.configuration.directory_operations import (copy_sample_files, create_datadir, - create_userdata_dir) +from freqtrade.configuration.directory_operations import (chown_user_directory, copy_sample_files, + create_datadir, create_userdata_dir) from freqtrade.exceptions import OperationalException from tests.conftest import log_has, log_has_re @@ -31,6 +32,24 @@ def test_create_userdata_dir(mocker, default_conf, caplog) -> None: assert str(x) == str(Path("/tmp/bar")) +def test_create_userdata_dir_and_chown(mocker, tmpdir, caplog) -> None: + sp_mock = mocker.patch('subprocess.check_output') + path = Path(tmpdir / 'bar') + assert not path.is_dir() + + x = create_userdata_dir(str(path), create_dir=True) + assert sp_mock.call_count == 0 + assert log_has(f'Created user-data directory: {path}', caplog) + assert isinstance(x, Path) + assert path.is_dir() + assert (path / 'data').is_dir() + + os.environ['FT_APP_ENV'] = 'docker' + chown_user_directory(path / 'data') + assert sp_mock.call_count == 1 + del os.environ['FT_APP_ENV'] + + def test_create_userdata_dir_exists(mocker, default_conf, caplog) -> None: mocker.patch.object(Path, "is_dir", MagicMock(return_value=True)) md = mocker.patch.object(Path, 'mkdir', MagicMock())