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, "Сетевая папка")
|
||||
|
||||
|
||||
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(
|
||||
input_dir: str, samba_conn, now: datetime | None = None
|
||||
) -> RunContext:
|
||||
@ -369,6 +405,27 @@ def _samba_move_file(path_from: str, path_to: str, samba_conn) -> None:
|
||||
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:
|
||||
server = urlparse(smb_base_path).netloc
|
||||
if not server:
|
||||
|
||||
@ -12,6 +12,7 @@ from .config import (
|
||||
join_path,
|
||||
)
|
||||
from .file_manager import (
|
||||
check_dir_write_access,
|
||||
check_input_dir_access,
|
||||
connect_samba,
|
||||
create_run_context,
|
||||
@ -80,6 +81,29 @@ def run_batch(
|
||||
)
|
||||
|
||||
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] = []
|
||||
log_lines: list[str] = []
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ import shutil
|
||||
from pathlib import Path
|
||||
|
||||
from app.pipeline.file_manager import (
|
||||
check_dir_write_access,
|
||||
create_run_context,
|
||||
move_file_to_error,
|
||||
next_run_number,
|
||||
@ -57,6 +58,11 @@ class FakeSamba:
|
||||
if target.exists():
|
||||
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:
|
||||
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 (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