first commit
This commit is contained in:
127
app/api/tunnel.py
Normal file
127
app/api/tunnel.py
Normal file
@@ -0,0 +1,127 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.orm import Session
|
||||
from app.database import get_db
|
||||
from app.schemas.tunnel import (
|
||||
TunnelCreateRequest,
|
||||
TunnelCreateResponse,
|
||||
TunnelStatusResponse,
|
||||
TunnelCloseResponse,
|
||||
TunnelInfo
|
||||
)
|
||||
from app.schemas.auth import CurrentUser
|
||||
from app.api.auth import get_current_user
|
||||
from app.services.ssh_tunnel_service import ssh_tunnel_manager
|
||||
from app.services.proxmox_service import proxmox_service
|
||||
from app.models.vm import VMAccess
|
||||
from app.utils.exceptions import NotFoundError, BadRequestError
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.post("/create", response_model=TunnelCreateResponse)
|
||||
async def create_tunnel(
|
||||
request: TunnelCreateRequest,
|
||||
current_user: CurrentUser = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
SSH 터널 생성
|
||||
|
||||
VM에 접속하기 위한 SSH Local Port Forwarding 터널을 생성합니다.
|
||||
클라이언트는 반환된 local_port로 RDP 연결을 시도해야 합니다.
|
||||
"""
|
||||
# VM IP 주소 확인
|
||||
# 1. 요청에 IP가 포함되어 있으면 사용 (Guest Agent 없이도 가능)
|
||||
ip_address = request.vm_ip
|
||||
|
||||
# 2. 없으면 Guest Agent로 조회
|
||||
if not ip_address:
|
||||
try:
|
||||
ip_address = await proxmox_service.get_vm_ip(request.node, request.vm_id)
|
||||
if ip_address:
|
||||
print(f"✅ Guest Agent에서 IP 조회 성공: {ip_address}")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Guest Agent IP 조회 실패: {str(e)}")
|
||||
ip_address = None
|
||||
|
||||
# 3. Guest Agent 실패 시 VMAccess 테이블의 static_ip 사용
|
||||
if not ip_address:
|
||||
vm_access = db.query(VMAccess).filter(
|
||||
VMAccess.user_id == current_user.id,
|
||||
VMAccess.vm_id == request.vm_id,
|
||||
VMAccess.node == request.node
|
||||
).first()
|
||||
|
||||
if vm_access and vm_access.static_ip:
|
||||
ip_address = vm_access.static_ip
|
||||
print(f"✅ Static IP 사용: {ip_address}")
|
||||
else:
|
||||
raise BadRequestError(
|
||||
"VM의 IP 주소를 확인할 수 없습니다. "
|
||||
"관리자 패널에서 고정 IP를 설정하거나 QEMU Guest Agent를 설치하세요."
|
||||
)
|
||||
|
||||
try:
|
||||
# SSH 터널 생성
|
||||
tunnel_info = await ssh_tunnel_manager.create_tunnel(
|
||||
user_id=current_user.id,
|
||||
vm_id=request.vm_id,
|
||||
remote_host=ip_address,
|
||||
remote_port=3389 # RDP 포트
|
||||
)
|
||||
|
||||
return TunnelCreateResponse(
|
||||
success=True,
|
||||
message="SSH 터널이 생성되었습니다",
|
||||
session_id=tunnel_info["session_id"],
|
||||
tunnel_info=TunnelInfo(
|
||||
session_id=tunnel_info["session_id"],
|
||||
local_port=tunnel_info["local_port"],
|
||||
remote_host=tunnel_info["remote_host"],
|
||||
remote_port=tunnel_info["remote_port"],
|
||||
vm_id=request.vm_id,
|
||||
is_active=True,
|
||||
created_at=None # 자동 설정
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
return TunnelCreateResponse(
|
||||
success=False,
|
||||
message=f"터널 생성 실패: {str(e)}",
|
||||
session_id="",
|
||||
tunnel_info=None
|
||||
)
|
||||
|
||||
@router.get("/{session_id}/status", response_model=TunnelStatusResponse)
|
||||
async def get_tunnel_status(
|
||||
session_id: str,
|
||||
current_user: CurrentUser = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
터널 상태 조회
|
||||
|
||||
활성 터널의 상태를 확인합니다.
|
||||
"""
|
||||
status = await ssh_tunnel_manager.get_tunnel_status(session_id)
|
||||
|
||||
if not status:
|
||||
raise NotFoundError("터널을 찾을 수 없습니다")
|
||||
|
||||
return TunnelStatusResponse(**status)
|
||||
|
||||
@router.delete("/{session_id}", response_model=TunnelCloseResponse)
|
||||
async def close_tunnel(
|
||||
session_id: str,
|
||||
current_user: CurrentUser = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
터널 종료
|
||||
|
||||
SSH 터널을 종료하고 리소스를 정리합니다.
|
||||
"""
|
||||
success = await ssh_tunnel_manager.close_tunnel(session_id)
|
||||
|
||||
return TunnelCloseResponse(
|
||||
success=success,
|
||||
message="터널이 종료되었습니다" if success else "터널 종료에 실패했습니다",
|
||||
session_id=session_id
|
||||
)
|
||||
Reference in New Issue
Block a user