Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #7253: Tribler does not run if the state directory does not already exist #7257

Merged
merged 2 commits into from
Jan 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion scripts/exit_node/run_exit_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def make_config(options) -> TriblerConfig:
else:
raise ValueError('ipv8_port option is not set, and HELPER_BASE/HELPER_INDEX env vars are not defined')

statedir = Path(os.path.join(get_root_state_directory(), "tunnel-%d") % ipv8_port)
statedir = Path(os.path.join(get_root_state_directory(create=True), "tunnel-%d") % ipv8_port)
config = TriblerConfig.load(state_dir=statedir)
config.tunnel_community.random_slots = options.random_slots
config.tunnel_community.competing_slots = options.competing_slots
Expand Down
2 changes: 1 addition & 1 deletion src/run_tribler.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def init_boot_logger():
parsed_args = RunTriblerArgsParser().parse_args()
logger.info(f'Run Tribler: {parsed_args}')

root_state_dir = get_root_state_directory()
root_state_dir = get_root_state_directory(create=True)
logger.info(f'Root state dir: {root_state_dir}')

api_port = os.environ.get('CORE_API_PORT')
Expand Down
21 changes: 14 additions & 7 deletions src/run_tribler_headless.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
from asyncio import ensure_future, get_event_loop, sleep
from datetime import date
from socket import inet_aton
from typing import Optional

from tribler.core.config.tribler_config import TriblerConfig
from tribler.core.components.session import Session
from tribler.core.utilities.osutils import get_appstate_dir, get_root_state_directory
from tribler.core.utilities.path_util import Path
from tribler.core.utilities.process_checker import ProcessChecker
from tribler.core.utilities.process_manager import ProcessKind, ProcessManager, TriblerProcess, \
set_global_process_manager


class IPPortAction(argparse.Action):
Expand Down Expand Up @@ -43,7 +45,7 @@ def __init__(self):
"""
self.session = None
self._stopping = False
self.process_checker = None
self.process_manager: Optional[ProcessManager] = None

def log_incoming_remote_search(self, sock_addr, keywords):
d = date.today()
Expand All @@ -63,7 +65,7 @@ async def signal_handler(sig):
await self.session.shutdown()
print("Tribler shut down")
get_event_loop().stop()
self.process_checker.remove_lock()
self.process_manager.current_process.finish()

signal.signal(signal.SIGINT, lambda sig, _: ensure_future(signal_handler(sig)))
signal.signal(signal.SIGTERM, lambda sig, _: ensure_future(signal_handler(sig)))
Expand All @@ -72,11 +74,16 @@ async def signal_handler(sig):
config = TriblerConfig.load(state_dir=statedir)

# Check if we are already running a Tribler instance
root_state_dir = get_root_state_directory()
root_state_dir = get_root_state_directory(create=True)

self.process_checker = ProcessChecker(root_state_dir)
self.process_checker.check_and_restart_if_necessary()
self.process_checker.create_lock()
current_process = TriblerProcess.current_process(ProcessKind.Core)
self.process_manager = ProcessManager(root_state_dir, current_process)
set_global_process_manager(self.process_manager)

if not self.process_manager.current_process.become_primary():
msg = 'Another Core process is already running'
print(msg)
self.process_manager.sys_exit(1, msg)

print("Starting Tribler")

Expand Down
20 changes: 15 additions & 5 deletions src/tribler/core/utilities/osutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,19 @@ def merge_dir(src_dir, dest_dir):
shutil.copy(src_file, dest_sub_dir)


def get_root_state_directory(home_dir_postfix='.Tribler'):
def get_root_state_directory(home_dir_postfix='.Tribler', create=False) -> Path:
"""Get the default application state directory."""
if 'TSTATEDIR' in os.environ:
path = os.environ['TSTATEDIR']
return Path(path) if os.path.isabs(path) else Path(os.getcwd(), path)
return Path(get_appstate_dir(), home_dir_postfix)
if state_dir := os.environ.get('TSTATEDIR'):
root_state_dir = Path(state_dir) if os.path.isabs(state_dir) else Path(os.getcwd(), state_dir)
else:
root_state_dir = Path(get_appstate_dir(), home_dir_postfix)

if root_state_dir.exists():
if not root_state_dir.is_dir():
raise OSError(errno.ENOTDIR, 'Root state path is not a directory', str(root_state_dir))
elif create:
root_state_dir.mkdir(parents=True, exist_ok=True)
else:
raise OSError(errno.ENOENT, 'Root directory does not exist', str(root_state_dir))

return root_state_dir
43 changes: 43 additions & 0 deletions src/tribler/core/utilities/tests/test_osutils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import os
import sys
from pathlib import Path
from unittest.mock import Mock, patch

import pytest

from tribler.core.utilities.osutils import (
dir_copy,
Expand All @@ -9,6 +12,7 @@
get_desktop_dir,
get_home_dir,
get_picture_dir,
get_root_state_directory,
is_android,
)

Expand Down Expand Up @@ -124,3 +128,42 @@ def test_dir_copy(tmpdir):
dir_copy(src_dir, dest_dir2, merge_if_exists=True)
assert len(os.listdir(src_dir)) == len(os.listdir(dest_dir2))
assert Path(dest_dir2, dummy_file).read_text() == "source: hello world"


@patch.dict(os.environ, {'TSTATEDIR': '/absolute/path'})
def test_get_root_state_directory_env(tmp_path):
(tmp_path / '.Tribler').mkdir()
with patch.dict(os.environ, {'TSTATEDIR': str(tmp_path)}):
path = get_root_state_directory()
assert path == tmp_path


@patch('tribler.core.utilities.osutils.get_appstate_dir')
def test_get_root_state_directory(get_appstate_dir_mock: Mock, tmp_path):
get_appstate_dir_mock.return_value = tmp_path
(tmp_path / '.Tribler').mkdir()
path = get_root_state_directory()
assert path.name == '.Tribler'


@patch('tribler.core.utilities.osutils.get_appstate_dir')
def test_get_root_state_directory_does_not_exist(get_appstate_dir_mock: Mock, tmp_path):
get_appstate_dir_mock.return_value = tmp_path
with pytest.raises(FileNotFoundError, match=r'^\[Errno 2\] Root directory does not exist:'):
get_root_state_directory()


@patch('tribler.core.utilities.osutils.get_appstate_dir')
def test_get_root_state_directory_not_a_dir(get_appstate_dir_mock: Mock, tmp_path):
(tmp_path / 'some_file').write_text('')
get_appstate_dir_mock.return_value = tmp_path
with pytest.raises(NotADirectoryError, match=r'^\[Errno 20\] Root state path is not a directory:'):
get_root_state_directory(home_dir_postfix='some_file')


@patch('tribler.core.utilities.osutils.get_appstate_dir')
def test_get_root_state_directory_create(get_appstate_dir_mock: Mock, tmp_path):
get_appstate_dir_mock.return_value = tmp_path
path = get_root_state_directory(create=True)
assert path.name == '.Tribler'
assert path.exists()
2 changes: 1 addition & 1 deletion src/tribler/core/utilities/tiny_tribler_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ async def _start_session(self):
def _check_already_running(self):
self.logger.info(f'Check if we are already running a Tribler instance in: {self.config.state_dir}')

root_state_dir = get_root_state_directory()
root_state_dir = get_root_state_directory(create=True)
current_process = TriblerProcess.current_process(ProcessKind.Core)
self.process_manager = ProcessManager(root_state_dir, current_process)
set_global_process_manager(self.process_manager)
Expand Down