Files
ipam/backend/app/services/ip_service.py
T
Your Name 1e1e5957e8 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 记录
2026-07-18 09:45:30 +08:00

144 lines
4.7 KiB
Python

from typing import List, Optional, Dict, Any
from sqlalchemy.orm import Session
from datetime import datetime
from app.models.network import IPAddress as IPAddressModel
from app.models.network import Network as NetworkModel
from app.models.network import IPStatus
from app.schemas.network import IPAddressUpdate, IPAddressCreate
class IPService:
"""IP地址管理服务"""
@staticmethod
def get_by_id(db: Session, ip_id: int) -> Optional[IPAddressModel]:
"""根据ID获取IP"""
return db.query(IPAddressModel).filter(IPAddressModel.id == ip_id).first()
@staticmethod
def get_by_ip(db: Session, ip_address: str) -> Optional[IPAddressModel]:
"""根据IP地址获取"""
return db.query(IPAddressModel).filter(IPAddressModel.ip_address == ip_address).first()
@staticmethod
def get_list(
db: Session,
network_id: Optional[int] = None,
status: Optional[IPStatus] = None,
skip: int = 0,
limit: int = 100,
search: Optional[str] = None
) -> tuple[int, List[IPAddressModel]]:
"""获取IP列表"""
query = db.query(IPAddressModel)
if network_id:
query = query.filter(IPAddressModel.network_id == network_id)
if status:
query = query.filter(IPAddressModel.status == status)
if search:
search_pattern = f"%{search}%"
query = query.filter(
(IPAddressModel.ip_address.like(search_pattern)) |
(IPAddressModel.mac_address.like(search_pattern)) |
(IPAddressModel.hostname.like(search_pattern)) |
(IPAddressModel.owner.like(search_pattern))
)
total = query.count()
items = query.order_by(IPAddressModel.ip_address).offset(skip).limit(limit).all()
return total, items
@staticmethod
def create(db: Session, ip_in: IPAddressCreate) -> IPAddressModel:
"""手动创建IP(通常由网段创建自动创建)"""
db_ip = IPAddressModel(**ip_in.model_dump())
db.add(db_ip)
db.commit()
db.refresh(db_ip)
return db_ip
@staticmethod
def update(db: Session, ip_id: int, ip_in: IPAddressUpdate) -> Optional[IPAddressModel]:
"""更新IP信息"""
db_ip = IPService.get_by_id(db, ip_id)
if not db_ip:
return None
update_data = ip_in.model_dump(exclude_unset=True)
for field, value in update_data.items():
setattr(db_ip, field, value)
db.commit()
db.refresh(db_ip)
return db_ip
@staticmethod
def update_status(db: Session, ip_address: str, status: IPStatus,
mac_address: Optional[str] = None,
hostname: Optional[str] = None) -> Optional[IPAddressModel]:
"""更新IP状态和扫描信息"""
db_ip = IPService.get_by_ip(db, ip_address)
if not db_ip:
return None
db_ip.status = status
db_ip.last_seen = datetime.utcnow()
if mac_address:
db_ip.mac_address = mac_address
if hostname:
db_ip.hostname = hostname
db.commit()
db.refresh(db_ip)
return db_ip
@staticmethod
def set_reserved(db: Session, ip_id: int, reserved: bool = True) -> Optional[IPAddressModel]:
"""设置/取消保留IP"""
db_ip = IPService.get_by_id(db, ip_id)
if not db_ip:
return None
db_ip.status = IPStatus.RESERVED if reserved else IPStatus.AVAILABLE
db.commit()
db.refresh(db_ip)
return db_ip
@staticmethod
def bulk_update_status(db: Session, results: List[Dict[str, Any]]):
"""批量更新IP状态
Args:
results: 扫描结果列表,每个元素包含 ip_address, status, mac_address, hostname
"""
for result in results:
ip_address = result.get('ip_address')
status = result.get('status')
mac_address = result.get('mac_address')
hostname = result.get('hostname')
db_ip = IPService.get_by_ip(db, ip_address)
if db_ip:
db_ip.status = status
db_ip.last_seen = datetime.utcnow()
if mac_address:
db_ip.mac_address = mac_address
if hostname:
db_ip.hostname = hostname
db.commit()
@staticmethod
def get_by_network(db: Session, network_id: int) -> List[IPAddressModel]:
"""获取指定网段下的所有IP"""
return db.query(IPAddressModel).filter(
IPAddressModel.network_id == network_id
).order_by(IPAddressModel.ip_address).all()