修改测试案例
This commit is contained in:
@@ -7,6 +7,7 @@ import logging
|
|||||||
import time
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Any, Optional, List
|
from typing import Dict, Any, Optional, List
|
||||||
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import docker # type: ignore
|
import docker # type: ignore
|
||||||
@@ -76,6 +77,14 @@ class DockerContainerManager:
|
|||||||
remove: bool = True,
|
remove: bool = True,
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""在容器中执行命令,返回执行结果。"""
|
"""在容器中执行命令,返回执行结果。"""
|
||||||
|
# 确保挂载目录存在且可写
|
||||||
|
for host_path, spec in volumes.items():
|
||||||
|
p = Path(host_path)
|
||||||
|
p.mkdir(parents=True, exist_ok=True)
|
||||||
|
try:
|
||||||
|
p.chmod(0o777)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
if self._engine == "docker-sdk" and self._client is not None:
|
if self._engine == "docker-sdk" and self._client is not None:
|
||||||
return self._run_with_docker_sdk(
|
return self._run_with_docker_sdk(
|
||||||
command, volumes, environment, working_dir, name, detach, remove
|
command, volumes, environment, working_dir, name, detach, remove
|
||||||
@@ -144,12 +153,36 @@ class DockerContainerManager:
|
|||||||
threads: int = 4,
|
threads: int = 4,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""在容器中运行 BtToxin_Digger 主分析(工作目录挂载到 /workspace)。"""
|
"""在容器中运行 BtToxin_Digger 主分析(单目录方案)。"""
|
||||||
command: List[str] = [
|
|
||||||
|
# 1) 在宿主输出目录下准备 input_files,并复制输入文件
|
||||||
|
work_input_dir = (output_dir / "input_files").resolve()
|
||||||
|
work_input_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
if sequence_type == "nucl":
|
||||||
|
pattern = f"*{scaf_suffix}"
|
||||||
|
elif sequence_type == "orfs":
|
||||||
|
pattern = f"*{kwargs.get('orfs_suffix', '.ffn')}"
|
||||||
|
elif sequence_type == "prot":
|
||||||
|
pattern = f"*{kwargs.get('prot_suffix', '.faa')}"
|
||||||
|
elif sequence_type == "reads":
|
||||||
|
pattern = "*"
|
||||||
|
else:
|
||||||
|
pattern = "*"
|
||||||
|
|
||||||
|
copied_files = 0
|
||||||
|
for f in input_dir.glob(pattern):
|
||||||
|
if f.is_file():
|
||||||
|
shutil.copy2(f, work_input_dir / f.name)
|
||||||
|
copied_files += 1
|
||||||
|
logger.info(f"已复制 {copied_files} 个输入文件到 {work_input_dir}")
|
||||||
|
|
||||||
|
base_cmd: List[str] = [
|
||||||
"/usr/local/env-execute",
|
"/usr/local/env-execute",
|
||||||
"BtToxin_Digger",
|
"BtToxin_Digger",
|
||||||
"--SeqPath",
|
"--SeqPath",
|
||||||
"/data/input",
|
"/workspace/input_files",
|
||||||
"--SequenceType",
|
"--SequenceType",
|
||||||
sequence_type,
|
sequence_type,
|
||||||
"--threads",
|
"--threads",
|
||||||
@@ -157,32 +190,32 @@ class DockerContainerManager:
|
|||||||
]
|
]
|
||||||
|
|
||||||
if sequence_type == "nucl":
|
if sequence_type == "nucl":
|
||||||
command += ["--Scaf_suffix", scaf_suffix]
|
base_cmd += ["--Scaf_suffix", scaf_suffix]
|
||||||
elif sequence_type == "orfs":
|
elif sequence_type == "orfs":
|
||||||
command += ["--orfs_suffix", kwargs.get("orfs_suffix", ".ffn")]
|
base_cmd += ["--orfs_suffix", kwargs.get("orfs_suffix", ".ffn")]
|
||||||
elif sequence_type == "prot":
|
elif sequence_type == "prot":
|
||||||
command += ["--prot_suffix", kwargs.get("prot_suffix", ".faa")]
|
base_cmd += ["--prot_suffix", kwargs.get("prot_suffix", ".faa")]
|
||||||
elif sequence_type == "reads":
|
elif sequence_type == "reads":
|
||||||
platform = kwargs.get("platform", "illumina")
|
platform = kwargs.get("platform", "illumina")
|
||||||
command += ["--platform", platform]
|
base_cmd += ["--platform", platform]
|
||||||
if platform == "illumina":
|
if platform == "illumina":
|
||||||
r1 = kwargs.get("reads1_suffix", "_R1.fastq.gz")
|
r1 = kwargs.get("reads1_suffix", "_R1.fastq.gz")
|
||||||
r2 = kwargs.get("reads2_suffix", "_R2.fastq.gz")
|
r2 = kwargs.get("reads2_suffix", "_R2.fastq.gz")
|
||||||
sfx = kwargs.get("suffix_len") or len(r1)
|
sfx = kwargs.get("suffix_len") or len(r1)
|
||||||
v = self.validate_reads_filenames(input_dir, platform, r1, r2, sfx)
|
v = self.validate_reads_filenames(work_input_dir, platform, r1, r2, sfx)
|
||||||
if not v.get("valid"):
|
if not v.get("valid"):
|
||||||
raise ValueError(f"Reads 文件验证失败: {v.get('error')}")
|
raise ValueError(f"Reads 文件验证失败: {v.get('error')}")
|
||||||
sfx = v.get("suggested_suffix_len", sfx)
|
sfx = v.get("suggested_suffix_len", sfx)
|
||||||
command += ["--reads1", r1, "--reads2", r2, "--suffix_len", str(sfx)]
|
base_cmd += ["--reads1", r1, "--reads2", r2, "--suffix_len", str(sfx)]
|
||||||
elif platform in ("pacbio", "oxford"):
|
elif platform in ("pacbio", "oxford"):
|
||||||
r = kwargs.get("reads1_suffix", ".fastq.gz")
|
r = kwargs.get("reads1_suffix", ".fastq.gz")
|
||||||
gsize = kwargs.get("genome_size", "6.07m")
|
gsize = kwargs.get("genome_size", "6.07m")
|
||||||
sfx = kwargs.get("suffix_len") or len(r)
|
sfx = kwargs.get("suffix_len") or len(r)
|
||||||
v = self.validate_reads_filenames(input_dir, platform, r, None, sfx)
|
v = self.validate_reads_filenames(work_input_dir, platform, r, None, sfx)
|
||||||
if not v.get("valid"):
|
if not v.get("valid"):
|
||||||
raise ValueError(f"Reads 文件验证失败: {v.get('error')}")
|
raise ValueError(f"Reads 文件验证失败: {v.get('error')}")
|
||||||
sfx = v.get("suggested_suffix_len", sfx)
|
sfx = v.get("suggested_suffix_len", sfx)
|
||||||
command += ["--reads1", r, "--genomeSize", gsize, "--suffix_len", str(sfx)]
|
base_cmd += ["--reads1", r, "--genomeSize", gsize, "--suffix_len", str(sfx)]
|
||||||
elif platform == "hybrid":
|
elif platform == "hybrid":
|
||||||
short1 = kwargs.get("short1")
|
short1 = kwargs.get("short1")
|
||||||
short2 = kwargs.get("short2")
|
short2 = kwargs.get("short2")
|
||||||
@@ -190,9 +223,9 @@ class DockerContainerManager:
|
|||||||
if not all([short1, short2, long]):
|
if not all([short1, short2, long]):
|
||||||
raise ValueError("hybrid 需要 short1/short2/long 三个完整文件名")
|
raise ValueError("hybrid 需要 short1/short2/long 三个完整文件名")
|
||||||
for fn in (short1, short2, long):
|
for fn in (short1, short2, long):
|
||||||
if not (input_dir / fn).exists():
|
if not (work_input_dir / fn).exists():
|
||||||
raise ValueError(f"文件不存在: {fn}")
|
raise ValueError(f"文件不存在: {fn}")
|
||||||
command += [
|
base_cmd += [
|
||||||
"--short1",
|
"--short1",
|
||||||
short1,
|
short1,
|
||||||
"--short2",
|
"--short2",
|
||||||
@@ -204,19 +237,23 @@ class DockerContainerManager:
|
|||||||
]
|
]
|
||||||
|
|
||||||
if kwargs.get("assemble_only"):
|
if kwargs.get("assemble_only"):
|
||||||
command.append("--assemble_only")
|
base_cmd.append("--assemble_only")
|
||||||
|
|
||||||
|
# 2) 只挂载输出目录(含 input_files)与日志目录
|
||||||
volumes = {
|
volumes = {
|
||||||
str(input_dir.resolve()): {"bind": "/data/input", "mode": "ro"},
|
|
||||||
str(output_dir.resolve()): {"bind": "/workspace", "mode": "rw"},
|
str(output_dir.resolve()): {"bind": "/workspace", "mode": "rw"},
|
||||||
str(log_dir.resolve()): {"bind": "/data/logs", "mode": "rw"},
|
str(log_dir.resolve()): {"bind": "/data/logs", "mode": "rw"},
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("开始 BtToxin_Digger 分析...")
|
logger.info("开始 BtToxin_Digger 分析...")
|
||||||
|
|
||||||
|
final_cmd = base_cmd
|
||||||
|
working_dir = "/workspace"
|
||||||
|
|
||||||
result = self.run_command_in_container(
|
result = self.run_command_in_container(
|
||||||
command=command,
|
command=final_cmd,
|
||||||
volumes=volumes,
|
volumes=volumes,
|
||||||
working_dir="/workspace",
|
working_dir=working_dir,
|
||||||
name=f"bttoxin_digger_{int(time.time())}",
|
name=f"bttoxin_digger_{int(time.time())}",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -270,6 +307,8 @@ class DockerContainerManager:
|
|||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
assert self._client is not None
|
assert self._client is not None
|
||||||
try:
|
try:
|
||||||
|
# 注意:docker SDK 在 detach=False 时返回的是日志字节串,而非容器对象。
|
||||||
|
# 这里统一以 detach=True 运行,然后等待并抓取日志,最后按需删除容器。
|
||||||
container = self._client.containers.run(
|
container = self._client.containers.run(
|
||||||
image=self.image,
|
image=self.image,
|
||||||
command=command,
|
command=command,
|
||||||
@@ -278,13 +317,12 @@ class DockerContainerManager:
|
|||||||
working_dir=working_dir,
|
working_dir=working_dir,
|
||||||
platform=self.platform,
|
platform=self.platform,
|
||||||
name=name,
|
name=name,
|
||||||
detach=detach,
|
user="0:0", # 以 root 运行,避免挂载目录权限问题
|
||||||
remove=False, # 等获取日志后再删
|
detach=True,
|
||||||
|
remove=False, # 获取日志后再删
|
||||||
stdout=True,
|
stdout=True,
|
||||||
stderr=True,
|
stderr=True,
|
||||||
)
|
)
|
||||||
if detach:
|
|
||||||
return {"success": True, "container_id": container.id, "status": "running"}
|
|
||||||
exit_info = container.wait()
|
exit_info = container.wait()
|
||||||
code = exit_info.get("StatusCode", 1)
|
code = exit_info.get("StatusCode", 1)
|
||||||
logs = container.logs().decode("utf-8", errors="ignore")
|
logs = container.logs().decode("utf-8", errors="ignore")
|
||||||
@@ -312,12 +350,18 @@ class DockerContainerManager:
|
|||||||
cmd: List[str] = [cli, "run", "--rm" if remove and not detach else ""]
|
cmd: List[str] = [cli, "run", "--rm" if remove and not detach else ""]
|
||||||
cmd = [c for c in cmd if c]
|
cmd = [c for c in cmd if c]
|
||||||
cmd += ["--platform", self.platform]
|
cmd += ["--platform", self.platform]
|
||||||
|
# 以 root 运行,避免权限问题
|
||||||
|
cmd += ["--user", "0:0"]
|
||||||
if name:
|
if name:
|
||||||
cmd += ["--name", name]
|
cmd += ["--name", name]
|
||||||
for host, spec in volumes.items():
|
for host, spec in volumes.items():
|
||||||
bind = spec.get("bind")
|
bind = spec.get("bind")
|
||||||
mode = spec.get("mode", "rw")
|
mode = spec.get("mode", "rw")
|
||||||
cmd += ["-v", f"{host}:{bind}:{mode}"]
|
# Podman(Linux) 下附加 :Z 处理 SELinux 标注;其他平台保持不变
|
||||||
|
mount_mode = mode
|
||||||
|
if self._engine == "podman-cli" and os.name == "posix" and sys.platform.startswith("linux"):
|
||||||
|
mount_mode = f"{mode},Z"
|
||||||
|
cmd += ["-v", f"{host}:{bind}:{mount_mode}"]
|
||||||
for k, v in (environment or {}).items():
|
for k, v in (environment or {}).items():
|
||||||
cmd += ["-e", f"{k}={v}"]
|
cmd += ["-e", f"{k}={v}"]
|
||||||
cmd += ["-w", working_dir, self.image]
|
cmd += ["-w", working_dir, self.image]
|
||||||
|
|||||||
Reference in New Issue
Block a user