Files
ipam/backend/app/api/v1/networks.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

180 lines
5.9 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 (
NetworkCreate, NetworkUpdate, Network, NetworkListResponse,
NetworkStats, IPAddressListResponse, IPAddressUpdate, IPAddress
)
from app.services.network_service import NetworkService
from app.services.audit_service import AuditService, AuditAction
router = APIRouter(
prefix="/networks",
tags=["网段管理"],
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=NetworkListResponse, summary="获取网段列表")
def get_networks(
skip: int = 0,
limit: int = 100,
group_name: Optional[str] = None,
db: Session = Depends(get_db)
):
"""获取所有网段列表"""
total, items = NetworkService.get_list(db, skip=skip, limit=limit, group_name=group_name)
return {"total": total, "items": items}
@router.get("/stats", response_model=list[NetworkStats], summary="获取所有网段统计")
def get_all_network_stats(db: Session = Depends(get_db)):
"""获取所有网段的统计信息"""
return NetworkService.get_all_stats(db)
@router.get("/{network_id}", response_model=Network, summary="获取网段详情")
def get_network(network_id: int, db: Session = Depends(get_db)):
"""根据ID获取网段详情"""
network = NetworkService.get_by_id(db, network_id)
if not network:
raise HTTPException(status_code=404, detail="网段不存在")
return network
@router.get("/{network_id}/stats", response_model=NetworkStats, summary="获取网段统计")
def get_network_stats(network_id: int, db: Session = Depends(get_db)):
"""获取指定网段的统计信息"""
stats = NetworkService.get_stats(db, network_id)
if not stats:
raise HTTPException(status_code=404, detail="网段不存在")
return stats
@router.get("/{network_id}/ips", response_model=IPAddressListResponse, summary="获取网段下的IP列表")
def get_network_ips(
network_id: int,
skip: int = 0,
limit: int = 200,
db: Session = Depends(get_db)
):
"""获取指定网段下的所有IP地址"""
from app.services.ip_service import IPService
total, items = IPService.get_list(db, network_id=network_id, skip=skip, limit=limit)
return {"total": total, "items": items}
@router.post("", response_model=Network, status_code=201, summary="创建网段")
def create_network(
network_in: NetworkCreate,
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""创建新网段,支持CIDR格式"""
existing = NetworkService.get_by_cidr(db, network_in.cidr)
if existing:
raise HTTPException(status_code=400, detail="该网段已存在")
ip, ua = _client_info(request)
try:
network = NetworkService.create(db, network_in)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
AuditService.record(
db,
action=AuditAction.NETWORK_CREATE,
user=current_user,
resource_type="network",
resource_id=network.id,
resource_name=network.cidr,
method="POST",
path=str(request.url.path),
ip_address=ip,
user_agent=ua,
detail={"cidr": network.cidr, "name": network.name},
)
return network
@router.put("/{network_id}", response_model=Network, summary="更新网段")
def update_network(
network_id: int,
network_in: NetworkUpdate,
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""更新网段信息"""
old = NetworkService.get_by_id(db, network_id)
if not old:
raise HTTPException(status_code=404, detail="网段不存在")
network = NetworkService.update(db, network_id, network_in)
if not network:
raise HTTPException(status_code=404, detail="网段不存在")
ip, ua = _client_info(request)
AuditService.record(
db,
action=AuditAction.NETWORK_UPDATE,
user=current_user,
resource_type="network",
resource_id=network.id,
resource_name=network.cidr,
method="PUT",
path=str(request.url.path),
ip_address=ip,
user_agent=ua,
detail={
"before": {"name": old.name, "gateway": old.gateway, "group_name": old.group_name, "vlan_id": old.vlan_id, "description": old.description},
"after": {"name": network.name, "gateway": network.gateway, "group_name": network.group_name, "vlan_id": network.vlan_id, "description": network.description},
},
)
return network
@router.delete("/{network_id}", summary="删除网段")
def delete_network(
network_id: int,
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""删除网段及其下的所有IP记录"""
network = NetworkService.get_by_id(db, network_id)
if not network:
raise HTTPException(status_code=404, detail="网段不存在")
cidr_snapshot = network.cidr
success = NetworkService.delete(db, network_id)
if not success:
raise HTTPException(status_code=404, detail="网段不存在")
ip, ua = _client_info(request)
AuditService.record(
db,
action=AuditAction.NETWORK_DELETE,
user=current_user,
resource_type="network",
resource_id=network_id,
resource_name=cidr_snapshot,
method="DELETE",
path=str(request.url.path),
ip_address=ip,
user_agent=ua,
detail={"cidr": cidr_snapshot},
)
return {"message": "删除成功"}