Stage SMB CF/CFE inputs for Windows Agent
CI / python (push) Has been cancelled
CI / rust (push) Has been cancelled

This commit is contained in:
2026-05-22 07:40:16 +03:00
parent 519f10dd6b
commit aa36d58a73
3 changed files with 59 additions and 3 deletions
@@ -44,6 +44,7 @@ async def html5_ai_structure_run(
prepare: Callable[..., dict[str, Any]], prepare: Callable[..., dict[str, Any]],
work_root: Path, work_root: Path,
start_binary_job: Callable[..., Any] | None = None, start_binary_job: Callable[..., Any] | None = None,
stage_binary_input: Callable[..., Any] | None = None,
save_run_state: Callable[[str, dict[str, Any]], None] | None = None, save_run_state: Callable[[str, dict[str, Any]], None] | None = None,
load_credentials: Callable[[str], SmbCredentials | None] | None = None, load_credentials: Callable[[str], SmbCredentials | None] | None = None,
save_credentials: Callable[[str, SmbCredentials], None] | None = None, save_credentials: Callable[[str, SmbCredentials], None] | None = None,
@@ -85,11 +86,26 @@ async def html5_ai_structure_run(
if binary_match is not None: if binary_match is not None:
if start_binary_job is None or save_run_state is None: if start_binary_job is None or save_run_state is None:
return render_html5_ai_structure_error("Сервис подготовки CF/CFE через Windows Agent не подключен.") return render_html5_ai_structure_error("Сервис подготовки CF/CFE через Windows Agent не подключен.")
binary_input_path = input_path
if is_unc_path(input_path) and local_input.exists() and stage_binary_input is not None:
try:
binary_input_path = await stage_binary_input(
project_id=project_id,
effective_project_id=effective_project_id,
local_input=local_input,
username=username,
password=password,
domain=domain or None,
)
except HTTPException as error:
return render_html5_ai_structure_error(str(error.detail))
except RuntimeError as error:
return render_html5_ai_structure_error(str(error))
try: try:
job = await start_binary_job( job = await start_binary_job(
project_id=project_id, project_id=project_id,
effective_project_id=effective_project_id, effective_project_id=effective_project_id,
input_path=input_path, input_path=binary_input_path,
detected_binary_relative_path=binary_match.get("relative_path"), detected_binary_relative_path=binary_match.get("relative_path"),
detected_binary_relative_paths=binary_match.get("binary_relative_paths"), detected_binary_relative_paths=binary_match.get("binary_relative_paths"),
) )
+35 -1
View File
@@ -193,7 +193,7 @@ from api_server.snapshot_module_service import (
module_sources_for_object as _snapshot_module_sources_for_object, module_sources_for_object as _snapshot_module_sources_for_object,
snapshot_bsl_completion_items as _snapshot_bsl_completion_items, snapshot_bsl_completion_items as _snapshot_bsl_completion_items,
) )
from api_server.smb_paths import is_unc_path from api_server.smb_paths import copy_local_tree_to_smb, is_unc_path
from api_server.time_utils import current_timestamp as _current_timestamp from api_server.time_utils import current_timestamp as _current_timestamp
from impact_engine import object_impact, routine_impact from impact_engine import object_impact, routine_impact
from incremental_indexer import rebuild_changed_file from incremental_indexer import rebuild_changed_file
@@ -657,6 +657,39 @@ async def _queue_ai_structure_agent_step(
) )
async def _stage_ai_structure_binary_input_for_agent(
*,
project_id: str,
effective_project_id: str,
local_input: Path,
username: str,
password: str,
domain: str | None = None,
) -> str:
settings = _project_settings_or_404(project_id)
agent_id = _agent_id_for_source(settings, ImportSourceKind.CF_FILE)
if not agent_id:
raise HTTPException(status_code=400, detail="В настройках проекта не выбран Windows Agent для CF/CFE.")
agent_status = _agent_status_with_liveness(_agent_statuses.get(agent_id, AgentStatus(agent_id=agent_id)))
roots = [str(item).strip() for item in getattr(agent_status, "network_roots", []) if str(item).strip()]
if not roots:
raise HTTPException(
status_code=400,
detail=f"У Windows Agent {agent_id} не настроены доступные сетевые корни для staging CF/CFE.",
)
if not local_input.exists():
raise HTTPException(status_code=404, detail=f"Сервер не нашел локальную копию входных файлов: {local_input}")
stage_root = ntpath.join(roots[0], "SFERA", "ai-structure-staging", f"{effective_project_id}-{uuid4().hex}")
copy_local_tree_to_smb(
source=local_input,
target=stage_root,
username=username,
password=password,
domain=domain or None,
)
return stage_root
async def _start_ai_structure_agent_job( async def _start_ai_structure_agent_job(
*, *,
project_id: str, project_id: str,
@@ -2117,6 +2150,7 @@ async def html5_project_ai_structure_run(project_id: str, request: Request) -> R
prepare=_prepare_ai_structure, prepare=_prepare_ai_structure,
work_root=_storage.root / "ai_structure_work", work_root=_storage.root / "ai_structure_work",
start_binary_job=_start_ai_structure_agent_job, start_binary_job=_start_ai_structure_agent_job,
stage_binary_input=_stage_ai_structure_binary_input_for_agent,
save_run_state=_save_ai_structure_agent_run, save_run_state=_save_ai_structure_agent_run,
load_credentials=_load_ai_structure_smb_credentials, load_credentials=_load_ai_structure_smb_credentials,
save_credentials=_save_ai_structure_smb_credentials, save_credentials=_save_ai_structure_smb_credentials,
+7 -1
View File
@@ -2091,6 +2091,10 @@ def test_html5_ai_structure_routes_unc_directory_with_cf_through_windows_agent(m
started.update(kwargs) started.update(kwargs)
return FakeJob() return FakeJob()
async def fake_stage_binary_input(**kwargs):
started["staged_from"] = kwargs["local_input"]
return r"\\192.168.220.220\mst\SFERA\ai-structure-staging\unc-demo"
saved_runs: dict[str, dict[str, object]] = {} saved_runs: dict[str, dict[str, object]] = {}
monkeypatch.setattr(controller, "copy_smb_tree_to_local", fake_copy_smb_tree_to_local) monkeypatch.setattr(controller, "copy_smb_tree_to_local", fake_copy_smb_tree_to_local)
@@ -2108,15 +2112,17 @@ def test_html5_ai_structure_routes_unc_directory_with_cf_through_windows_agent(m
prepare=lambda **_: {}, prepare=lambda **_: {},
work_root=tmp_path / "work", work_root=tmp_path / "work",
start_binary_job=fake_start_binary_job, start_binary_job=fake_start_binary_job,
stage_binary_input=fake_stage_binary_input,
save_run_state=lambda job_id, payload: saved_runs.setdefault(job_id, payload), save_run_state=lambda job_id, payload: saved_runs.setdefault(job_id, payload),
) )
) )
assert "Windows Agent" in html assert "Windows Agent" in html
assert copied_targets assert copied_targets
assert started["input_path"] == r"\\192.168.220.200\mst\1c\MARKA\CODEX\CF" assert started["input_path"] == r"\\192.168.220.220\mst\SFERA\ai-structure-staging\unc-demo"
assert started["detected_binary_relative_path"] == "base.cf" assert started["detected_binary_relative_path"] == "base.cf"
assert started["detected_binary_relative_paths"] == ["base.cf"] assert started["detected_binary_relative_paths"] == ["base.cf"]
assert started["staged_from"] == copied_targets[0][1]
assert "agent-import-test" in saved_runs assert "agent-import-test" in saved_runs