fix smb
This commit is contained in:
parent
27a11ae3ee
commit
400a218fc7
@ -196,6 +196,42 @@ def check_network_dir_access(
|
|||||||
return _check_samba_dir_access(str(path), samba_conn, "Сетевая папка")
|
return _check_samba_dir_access(str(path), samba_conn, "Сетевая папка")
|
||||||
|
|
||||||
|
|
||||||
|
def check_dir_write_access(
|
||||||
|
target_dir: str, samba_conn, source_name: str
|
||||||
|
) -> tuple[bool, str | None]:
|
||||||
|
probe_prefix = f".sfm_write_probe_{int(datetime.now().timestamp() * 1000)}"
|
||||||
|
probe_src = join_path(target_dir, f"{probe_prefix}.tmp")
|
||||||
|
probe_dst = join_path(target_dir, f"{probe_prefix}_renamed.tmp")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with samba_conn:
|
||||||
|
if not samba_conn.path_exists(target_dir):
|
||||||
|
return False, f"{source_name} не найдена: {target_dir}"
|
||||||
|
_write_probe_file(probe_src, samba_conn)
|
||||||
|
if hasattr(samba_conn, "copy") and hasattr(samba_conn, "delete"):
|
||||||
|
samba_conn.copy(path_from=probe_src, path_to=probe_dst, replace=False)
|
||||||
|
samba_conn.delete(probe_src)
|
||||||
|
samba_conn.delete(probe_dst)
|
||||||
|
elif hasattr(samba_conn, "delete"):
|
||||||
|
samba_conn.delete(probe_src)
|
||||||
|
return True, None
|
||||||
|
except Exception as exc: # noqa: BLE001
|
||||||
|
# Best-effort cleanup for noisy probes.
|
||||||
|
with samba_conn:
|
||||||
|
for probe_path in (probe_src, probe_dst):
|
||||||
|
try:
|
||||||
|
if samba_conn.path_exists(probe_path) and hasattr(
|
||||||
|
samba_conn, "delete"
|
||||||
|
):
|
||||||
|
samba_conn.delete(probe_path)
|
||||||
|
except Exception: # noqa: BLE001
|
||||||
|
pass
|
||||||
|
return (
|
||||||
|
False,
|
||||||
|
f"Недостаточно прав на запись/переименование в папке: {target_dir}. {exc}",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def create_run_context(
|
def create_run_context(
|
||||||
input_dir: str, samba_conn, now: datetime | None = None
|
input_dir: str, samba_conn, now: datetime | None = None
|
||||||
) -> RunContext:
|
) -> RunContext:
|
||||||
@ -369,6 +405,27 @@ def _samba_move_file(path_from: str, path_to: str, samba_conn) -> None:
|
|||||||
samba_conn.delete(path_from)
|
samba_conn.delete(path_from)
|
||||||
|
|
||||||
|
|
||||||
|
def _write_probe_file(remote_path: str, samba_conn) -> None:
|
||||||
|
if hasattr(samba_conn, "open"):
|
||||||
|
with samba_conn.open(remote_path, mode="wb") as remote_file:
|
||||||
|
remote_file.write(b"sfm-probe")
|
||||||
|
return
|
||||||
|
if hasattr(samba_conn, "upload"):
|
||||||
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
|
local_probe = Path(temp_dir) / "probe.tmp"
|
||||||
|
local_probe.write_bytes(b"sfm-probe")
|
||||||
|
try:
|
||||||
|
samba_conn.upload(
|
||||||
|
remote_file_path=remote_path,
|
||||||
|
local_file_path=str(local_probe),
|
||||||
|
replace=False,
|
||||||
|
)
|
||||||
|
except TypeError:
|
||||||
|
samba_conn.upload(path_from=str(local_probe), path_to=remote_path)
|
||||||
|
return
|
||||||
|
raise RuntimeError("Коннектор SAMBA не поддерживает проверку записи (open/upload).")
|
||||||
|
|
||||||
|
|
||||||
def _extract_server(smb_base_path: str) -> str:
|
def _extract_server(smb_base_path: str) -> str:
|
||||||
server = urlparse(smb_base_path).netloc
|
server = urlparse(smb_base_path).netloc
|
||||||
if not server:
|
if not server:
|
||||||
|
|||||||
@ -12,6 +12,7 @@ from .config import (
|
|||||||
join_path,
|
join_path,
|
||||||
)
|
)
|
||||||
from .file_manager import (
|
from .file_manager import (
|
||||||
|
check_dir_write_access,
|
||||||
check_input_dir_access,
|
check_input_dir_access,
|
||||||
connect_samba,
|
connect_samba,
|
||||||
create_run_context,
|
create_run_context,
|
||||||
@ -80,6 +81,29 @@ def run_batch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
run_context = create_run_context(input_dir=input_dir, samba_conn=samba_conn)
|
run_context = create_run_context(input_dir=input_dir, samba_conn=samba_conn)
|
||||||
|
checks = [
|
||||||
|
(run_context.run_dir, "Папка Out (текущий запуск)"),
|
||||||
|
(run_context.processed_dir, "Папка Processed"),
|
||||||
|
(run_context.error_dir, "Папка Err"),
|
||||||
|
]
|
||||||
|
for target_dir, label in checks:
|
||||||
|
is_ok, write_error = check_dir_write_access(
|
||||||
|
target_dir=target_dir,
|
||||||
|
samba_conn=samba_conn,
|
||||||
|
source_name=label,
|
||||||
|
)
|
||||||
|
if not is_ok:
|
||||||
|
return BatchResult(
|
||||||
|
status="error",
|
||||||
|
processed=0,
|
||||||
|
partial=0,
|
||||||
|
errors=1,
|
||||||
|
report_path="",
|
||||||
|
protocol_path="",
|
||||||
|
log_path="",
|
||||||
|
messages=[write_error or f"Нет прав на запись в: {target_dir}"],
|
||||||
|
)
|
||||||
|
|
||||||
protocol_rows: list[ProtocolRow] = []
|
protocol_rows: list[ProtocolRow] = []
|
||||||
log_lines: list[str] = []
|
log_lines: list[str] = []
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import shutil
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from app.pipeline.file_manager import (
|
from app.pipeline.file_manager import (
|
||||||
|
check_dir_write_access,
|
||||||
create_run_context,
|
create_run_context,
|
||||||
move_file_to_error,
|
move_file_to_error,
|
||||||
next_run_number,
|
next_run_number,
|
||||||
@ -57,6 +58,11 @@ class FakeSamba:
|
|||||||
if target.exists():
|
if target.exists():
|
||||||
target.unlink()
|
target.unlink()
|
||||||
|
|
||||||
|
def open(self, path: str, mode: str = "rb"):
|
||||||
|
target = self._to_local(path)
|
||||||
|
target.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
return target.open(mode)
|
||||||
|
|
||||||
|
|
||||||
def test_scan_input_files_splits_valid_and_invalid(tmp_path: Path) -> None:
|
def test_scan_input_files_splits_valid_and_invalid(tmp_path: Path) -> None:
|
||||||
samba = FakeSamba(tmp_path)
|
samba = FakeSamba(tmp_path)
|
||||||
@ -112,3 +118,36 @@ def test_move_file_to_error_adds_suffix_on_collision(tmp_path: Path) -> None:
|
|||||||
)
|
)
|
||||||
assert target.endswith("file_1.xml")
|
assert target.endswith("file_1.xml")
|
||||||
assert (error_dir / "file_1.xml").exists()
|
assert (error_dir / "file_1.xml").exists()
|
||||||
|
|
||||||
|
|
||||||
|
def test_check_dir_write_access_success(tmp_path: Path) -> None:
|
||||||
|
samba = FakeSamba(tmp_path)
|
||||||
|
target_dir = tmp_path / "Exchange" / "SMBDEMO" / "Out"
|
||||||
|
target_dir.mkdir(parents=True)
|
||||||
|
|
||||||
|
ok, error = check_dir_write_access(
|
||||||
|
target_dir="Exchange\\SMBDEMO\\Out",
|
||||||
|
samba_conn=samba,
|
||||||
|
source_name="Out",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert ok is True
|
||||||
|
assert error is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_check_dir_write_access_fails_without_open_or_upload(tmp_path: Path) -> None:
|
||||||
|
class NoWriteSamba(FakeSamba):
|
||||||
|
open = None # type: ignore[assignment]
|
||||||
|
|
||||||
|
samba = NoWriteSamba(tmp_path)
|
||||||
|
target_dir = tmp_path / "Exchange" / "SMBDEMO" / "Out"
|
||||||
|
target_dir.mkdir(parents=True)
|
||||||
|
|
||||||
|
ok, error = check_dir_write_access(
|
||||||
|
target_dir="Exchange\\SMBDEMO\\Out",
|
||||||
|
samba_conn=samba,
|
||||||
|
source_name="Out",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert ok is False
|
||||||
|
assert error is not None
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user