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,162 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import Optional
|
||||
|
||||
from app.core.database import get_db
|
||||
from app.core.security import get_current_user
|
||||
from app.models.auth import User
|
||||
from app.schemas.network import IPAddressListResponse, IPAddressUpdate, IPAddress
|
||||
from app.models.network import IPStatus
|
||||
from app.services.ip_service import IPService
|
||||
from app.services.audit_service import AuditService, AuditAction
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/ips",
|
||||
tags=["IP地址管理"],
|
||||
dependencies=[Depends(get_current_user)],
|
||||
)
|
||||
|
||||
|
||||
def _client_info(request: Request) -> tuple[str, str]:
|
||||
return (
|
||||
request.client.host if request.client else "",
|
||||
(request.headers.get("user-agent") or "")[:500],
|
||||
)
|
||||
|
||||
|
||||
@router.get("", response_model=IPAddressListResponse, summary="获取IP列表")
|
||||
def get_ips(
|
||||
network_id: Optional[int] = None,
|
||||
status: Optional[IPStatus] = None,
|
||||
search: Optional[str] = None,
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""获取IP地址列表,支持过滤和搜索"""
|
||||
total, items = IPService.get_list(
|
||||
db,
|
||||
network_id=network_id,
|
||||
status=status,
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
search=search
|
||||
)
|
||||
return {"total": total, "items": items}
|
||||
|
||||
|
||||
@router.get("/{ip_id}", response_model=IPAddress, summary="获取IP详情")
|
||||
def get_ip(ip_id: int, db: Session = Depends(get_db)):
|
||||
"""根据ID获取IP详情"""
|
||||
ip = IPService.get_by_id(db, ip_id)
|
||||
if not ip:
|
||||
raise HTTPException(status_code=404, detail="IP不存在")
|
||||
return ip
|
||||
|
||||
|
||||
@router.get("/address/{ip_address}", response_model=IPAddress, summary="根据IP地址查询")
|
||||
def get_ip_by_address(ip_address: str, db: Session = Depends(get_db)):
|
||||
"""根据IP地址查询详细信息"""
|
||||
ip = IPService.get_by_ip(db, ip_address)
|
||||
if not ip:
|
||||
raise HTTPException(status_code=404, detail="IP不存在")
|
||||
return ip
|
||||
|
||||
|
||||
@router.put("/{ip_id}", response_model=IPAddress, summary="更新IP信息")
|
||||
def update_ip(
|
||||
ip_id: int,
|
||||
ip_in: IPAddressUpdate,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""更新IP地址的属性信息"""
|
||||
old = IPService.get_by_id(db, ip_id)
|
||||
if not old:
|
||||
raise HTTPException(status_code=404, detail="IP不存在")
|
||||
|
||||
ip = IPService.update(db, ip_id, ip_in)
|
||||
if not ip:
|
||||
raise HTTPException(status_code=404, detail="IP不存在")
|
||||
|
||||
c, u = _client_info(request)
|
||||
AuditService.record(
|
||||
db,
|
||||
action=AuditAction.IP_UPDATE,
|
||||
user=current_user,
|
||||
resource_type="ip",
|
||||
resource_id=str(ip.id),
|
||||
resource_name=ip.ip_address,
|
||||
method="PUT",
|
||||
path=str(request.url.path),
|
||||
ip_address=c,
|
||||
user_agent=u,
|
||||
detail={
|
||||
"before": {
|
||||
"owner": old.owner, "hostname": old.hostname, "mac_address": old.mac_address,
|
||||
"vendor": old.vendor, "status": old.status.value if old.status else None,
|
||||
"notes": old.notes, "switch_name": old.switch_name, "switch_port": old.switch_port,
|
||||
},
|
||||
"after": {
|
||||
"owner": ip.owner, "hostname": ip.hostname, "mac_address": ip.mac_address,
|
||||
"vendor": ip.vendor, "status": ip.status.value if ip.status else None,
|
||||
"notes": ip.notes, "switch_name": ip.switch_name, "switch_port": ip.switch_port,
|
||||
},
|
||||
},
|
||||
)
|
||||
return ip
|
||||
|
||||
|
||||
@router.post("/{ip_id}/reserve", response_model=IPAddress, summary="标记为保留IP")
|
||||
def reserve_ip(
|
||||
ip_id: int,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""将IP标记为保留状态,禁止分配"""
|
||||
ip = IPService.set_reserved(db, ip_id, reserved=True)
|
||||
if not ip:
|
||||
raise HTTPException(status_code=404, detail="IP不存在")
|
||||
c, u = _client_info(request)
|
||||
AuditService.record(
|
||||
db,
|
||||
action=AuditAction.IP_RESERVE,
|
||||
user=current_user,
|
||||
resource_type="ip",
|
||||
resource_id=str(ip.id),
|
||||
resource_name=ip.ip_address,
|
||||
method="POST",
|
||||
path=str(request.url.path),
|
||||
ip_address=c,
|
||||
user_agent=u,
|
||||
)
|
||||
return ip
|
||||
|
||||
|
||||
@router.post("/{ip_id}/unreserve", response_model=IPAddress, summary="取消保留IP")
|
||||
def unreserve_ip(
|
||||
ip_id: int,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""取消IP的保留状态"""
|
||||
ip = IPService.set_reserved(db, ip_id, reserved=False)
|
||||
if not ip:
|
||||
raise HTTPException(status_code=404, detail="IP不存在")
|
||||
c, u = _client_info(request)
|
||||
AuditService.record(
|
||||
db,
|
||||
action=AuditAction.IP_UNRESERVE,
|
||||
user=current_user,
|
||||
resource_type="ip",
|
||||
resource_id=str(ip.id),
|
||||
resource_name=ip.ip_address,
|
||||
method="POST",
|
||||
path=str(request.url.path),
|
||||
ip_address=c,
|
||||
user_agent=u,
|
||||
)
|
||||
return ip
|
||||
Reference in New Issue
Block a user