1e1e5957e8
- 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 记录
162 lines
5.0 KiB
Python
162 lines
5.0 KiB
Python
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 |