fix(ipam): 修复IP管理页面网段筛选不生效及下拉框过窄
- Ips.vue: el-select 添加 width: 280px,修复网段下拉框过窄 - Ips.vue: query 参数 networkId → network_id(与 FastAPI snake_case 一致) - Scan.vue: el-select 用 network.id 代替整个 network 对象作为 value,修复切换网段不生效 - enhanced_scan_service.py: 替换失效的 scapy ARP 扫描为 arp-scan 命令;扫描结果自动创建缺失 IP 记录
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
from typing import List, Dict, Any, Optional
|
||||
from celery import Task
|
||||
import logging
|
||||
|
||||
from app.core.database import SessionLocal
|
||||
from app.services.network_service import NetworkService
|
||||
from app.services.enhanced_scan_service import EnhancedScanService
|
||||
from app.services.scan_service import ScanService
|
||||
from app.models.network import TaskStatus, ScanTask, IPAddress
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def register_tasks(celery_app):
|
||||
"""
|
||||
注册任务到 Celery 应用
|
||||
"""
|
||||
|
||||
@celery_app.task(bind=True)
|
||||
def scan_network_task(self, network_id: int,
|
||||
enable_ping: bool = True,
|
||||
enable_arp: bool = True,
|
||||
enable_dns: bool = True,
|
||||
timeout: int = 2):
|
||||
"""
|
||||
Celery 异步任务:扫描指定网段
|
||||
"""
|
||||
task_id = self.request.id
|
||||
db = SessionLocal()
|
||||
|
||||
try:
|
||||
# 获取网段信息
|
||||
network = NetworkService.get_by_id(db, network_id)
|
||||
if not network:
|
||||
logger.error(f"网段 {network_id} 不存在")
|
||||
return {'status': 'failed', 'error': '网段不存在'}
|
||||
|
||||
logger.info(f"开始扫描网段: {network.cidr}")
|
||||
|
||||
# 更新任务状态为运行中
|
||||
# 查找已存在的任务记录
|
||||
db_task = db.query(ScanTask).filter(ScanTask.celery_task_id == task_id).first()
|
||||
if not db_task:
|
||||
db_task = ScanService.create_scan_task(db, 'ping', network_id)
|
||||
db_task.celery_task_id = task_id
|
||||
db.commit()
|
||||
db.refresh(db_task)
|
||||
|
||||
ScanService.update_task_status(db, db_task.id, TaskStatus.RUNNING, progress=0)
|
||||
|
||||
# 执行扫描
|
||||
results = EnhancedScanService.scan_network(
|
||||
network.cidr,
|
||||
enable_ping=enable_ping,
|
||||
enable_arp=enable_arp,
|
||||
enable_dns=enable_dns,
|
||||
timeout=timeout
|
||||
)
|
||||
|
||||
# 批量更新IP信息
|
||||
stats = EnhancedScanService.bulk_update_ips_from_scan(db, results)
|
||||
|
||||
# 更新任务状态
|
||||
ScanService.update_task_status(
|
||||
db,
|
||||
db_task.id,
|
||||
TaskStatus.COMPLETED,
|
||||
progress=100,
|
||||
total_count=stats['total_scanned'],
|
||||
success_count=stats['online_count']
|
||||
)
|
||||
|
||||
logger.info(f"网段 {network.cidr} 扫描完成: 在线 {stats['online_count']} 台, "
|
||||
f"发现MAC {stats['mac_found_count']} 个, 主机名 {stats['hostname_found_count']} 个")
|
||||
|
||||
return {
|
||||
'status': 'completed',
|
||||
'network_id': network_id,
|
||||
'cidr': network.cidr,
|
||||
'statistics': stats
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"扫描失败: {str(e)}", exc_info=True)
|
||||
if 'db_task' in locals() and db_task:
|
||||
ScanService.update_task_status(
|
||||
db,
|
||||
db_task.id,
|
||||
TaskStatus.FAILED,
|
||||
error_message=str(e)
|
||||
)
|
||||
raise
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
@celery_app.task(bind=True)
|
||||
def scan_single_ip_task(self, ip_address: str,
|
||||
enable_ping: bool = True,
|
||||
enable_arp: bool = True,
|
||||
enable_dns: bool = True):
|
||||
"""
|
||||
Celery 异步任务:扫描单个IP
|
||||
"""
|
||||
db = SessionLocal()
|
||||
try:
|
||||
result = EnhancedScanService.comprehensive_scan(
|
||||
ip_address,
|
||||
enable_ping=enable_ping,
|
||||
enable_arp=enable_arp,
|
||||
enable_dns=enable_dns
|
||||
)
|
||||
|
||||
# 更新IP信息
|
||||
EnhancedScanService.update_ip_from_scan_result(db, result)
|
||||
db.commit()
|
||||
return result
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
@celery_app.task(bind=True)
|
||||
def full_network_scan(self, enable_ping: bool = True,
|
||||
enable_arp: bool = True,
|
||||
enable_dns: bool = True):
|
||||
"""
|
||||
Celery 定时任务:扫描所有网段
|
||||
"""
|
||||
db = SessionLocal()
|
||||
try:
|
||||
_, all_networks = NetworkService.get_list(db, limit=1000)
|
||||
|
||||
total_stats = {
|
||||
'total_networks': len(all_networks),
|
||||
'total_ips': 0,
|
||||
'online_count': 0,
|
||||
'mac_found_count': 0,
|
||||
'hostname_found_count': 0
|
||||
}
|
||||
|
||||
logger.info(f"开始全量扫描: {len(all_networks)} 个网段")
|
||||
|
||||
for network in all_networks:
|
||||
try:
|
||||
results = EnhancedScanService.scan_network(
|
||||
network.cidr,
|
||||
enable_ping=enable_ping,
|
||||
enable_arp=enable_arp,
|
||||
enable_dns=enable_dns
|
||||
)
|
||||
|
||||
stats = EnhancedScanService.bulk_update_ips_from_scan(db, results)
|
||||
|
||||
total_stats['total_ips'] += stats['total_scanned']
|
||||
total_stats['online_count'] += stats['online_count']
|
||||
total_stats['mac_found_count'] += stats['mac_found_count']
|
||||
total_stats['hostname_found_count'] += stats['hostname_found_count']
|
||||
|
||||
logger.info(f"网段 {network.cidr} 扫描完成: 在线 {stats['online_count']} 台")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"网段 {network.cidr} 扫描失败: {str(e)}")
|
||||
|
||||
logger.info(f"全量扫描完成: {total_stats}")
|
||||
|
||||
return {
|
||||
'status': 'completed',
|
||||
'statistics': total_stats
|
||||
}
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
@celery_app.task(bind=True)
|
||||
def update_all_statistics(self):
|
||||
"""
|
||||
定时任务:更新所有网段统计信息
|
||||
"""
|
||||
db = SessionLocal()
|
||||
try:
|
||||
NetworkService.get_all_stats(db)
|
||||
logger.info("所有网段统计信息已更新")
|
||||
return {'status': 'completed'}
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
@celery_app.task(bind=True)
|
||||
def quick_status_update(self, ip_addresses: List[str]):
|
||||
"""
|
||||
快速更新多个IP的状态(用于实时扫描)
|
||||
"""
|
||||
db = SessionLocal()
|
||||
try:
|
||||
results = []
|
||||
|
||||
for ip in ip_addresses:
|
||||
result = EnhancedScanService.comprehensive_scan(ip, enable_ping=True, enable_arp=True, enable_dns=False)
|
||||
EnhancedScanService.update_ip_from_scan_result(db, result)
|
||||
results.append(result)
|
||||
|
||||
db.commit()
|
||||
|
||||
return {
|
||||
'scanned_count': len(ip_addresses),
|
||||
'online_count': sum(1 for r in results if r.get('success')),
|
||||
'results': results
|
||||
}
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
# 返回任务函数供外部使用
|
||||
return {
|
||||
'scan_network_task': scan_network_task,
|
||||
'scan_single_ip_task': scan_single_ip_task,
|
||||
'full_network_scan': full_network_scan,
|
||||
'update_all_statistics': update_all_statistics,
|
||||
'quick_status_update': quick_status_update
|
||||
}
|
||||
Reference in New Issue
Block a user