Files
msa-django-nhn/nhn/views.py
icurfer 6207f6b83f
All checks were successful
Build And Test / build-and-push (push) Successful in 1m54s
v0.0.13 | Skip Django JWT auth for NHN API (Kong handles it)
- Add NHNBaseView with authentication_classes = []
- All NHN View classes now inherit from NHNBaseView
- Kong already validates JWT, no need for Django to re-validate

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 17:22:23 +09:00

3005 lines
117 KiB
Python

"""
NHN Cloud API Views
REST API 엔드포인트 정의
"""
import logging
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import AllowAny, IsAuthenticated
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from .serializers import (
TokenRequestSerializer,
TokenResponseSerializer,
ComputeInstanceSerializer,
VpcSerializer,
SubnetSerializer,
NksClusterSerializer,
NksNodeGroupSerializer,
NksNodeActionSerializer,
NksClusterResizeSerializer,
NksClusterUpgradeSerializer,
NksAutoscaleConfigSerializer,
NksNodeGroupUpgradeSerializer,
NksNodeGroupUpdateSerializer,
NksUserScriptSerializer,
NksApiEndpointIpAclSerializer,
StorageContainerSerializer,
ErrorResponseSerializer,
# DNS Plus
DnsZoneSerializer,
DnsZoneUpdateSerializer,
DnsRecordSetSerializer,
DnsRecordSetUpdateSerializer,
DnsPoolSerializer,
DnsPoolUpdateSerializer,
DnsGslbSerializer,
DnsGslbUpdateSerializer,
DnsPoolConnectSerializer,
DnsHealthCheckSerializer,
DnsHealthCheckUpdateSerializer,
DnsIdListSerializer,
# Load Balancer
LoadBalancerSerializer,
LoadBalancerUpdateSerializer,
LBListenerSerializer,
LBListenerUpdateSerializer,
LBPoolSerializer,
LBPoolUpdateSerializer,
LBMemberSerializer,
LBMemberUpdateSerializer,
LBHealthMonitorSerializer,
LBHealthMonitorUpdateSerializer,
LBL7PolicySerializer,
LBL7PolicyUpdateSerializer,
LBL7RuleSerializer,
LBL7RuleUpdateSerializer,
LBIpAclGroupSerializer,
LBIpAclGroupUpdateSerializer,
LBIpAclTargetCreateSerializer,
)
from .packages import NHNCloudToken, ApiCompute, ApiVpc, ApiNks, ApiStorageObject, ApiDnsPlus
from .packages.loadbalancer import ApiLoadBalancer
from .packages.base import NHNCloudAPIError
logger = logging.getLogger(__name__)
# ==================== Base View ====================
class NHNBaseView(APIView):
"""
NHN Cloud API 베이스 뷰
Kong이 이미 JWT 인증을 수행하므로 Django에서는 인증을 건너뜀
"""
authentication_classes = []
permission_classes = [AllowAny]
# ==================== Common Headers ====================
region_header = openapi.Parameter(
"X-NHN-Region",
openapi.IN_HEADER,
description="NHN Cloud 리전 (kr1: 판교, kr2: 평촌)",
type=openapi.TYPE_STRING,
default="kr2",
)
token_header = openapi.Parameter(
"X-NHN-Token",
openapi.IN_HEADER,
description="NHN Cloud API 토큰",
type=openapi.TYPE_STRING,
required=True,
)
tenant_header = openapi.Parameter(
"X-NHN-Tenant-ID",
openapi.IN_HEADER,
description="NHN Cloud 테넌트 ID",
type=openapi.TYPE_STRING,
required=True,
)
def get_nhn_headers(request):
"""요청 헤더에서 NHN Cloud 정보 추출"""
headers = {
"region": request.headers.get("X-NHN-Region", "kr2"),
"token": request.headers.get("X-NHN-Token"),
"tenant_id": request.headers.get("X-NHN-Tenant-ID"),
"storage_account": request.headers.get("X-NHN-Storage-Account"),
}
# 토큰은 앞 8자리만 로깅 (보안)
token_preview = headers["token"][:8] + "..." if headers["token"] else "None"
logger.info(f"[Request Headers] region={headers['region']}, token={token_preview}, tenant_id={headers['tenant_id']}")
return headers
# ==================== Token API ====================
class TokenCreateView(NHNBaseView):
"""토큰 생성 API"""
@swagger_auto_schema(
operation_summary="NHN Cloud API 토큰 생성",
operation_description="NHN Cloud API 인증 토큰을 생성합니다.",
request_body=TokenRequestSerializer,
responses={
200: TokenResponseSerializer,
400: ErrorResponseSerializer,
401: ErrorResponseSerializer,
},
)
def post(self, request):
logger.info(f"[Token] 토큰 생성 요청 수신 - client_ip={request.META.get('REMOTE_ADDR')}")
serializer = TokenRequestSerializer(data=request.data)
if not serializer.is_valid():
logger.warning(f"[Token] 요청 데이터 유효성 검사 실패: {serializer.errors}")
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
tenant_id = serializer.validated_data["tenant_id"]
username = serializer.validated_data["username"]
logger.info(f"[Token] 토큰 발급 시도 - tenant_id={tenant_id}, username={username}")
try:
token_manager = NHNCloudToken(
tenant_id=tenant_id,
username=username,
password=serializer.validated_data["password"],
)
result = token_manager.create_token()
token_preview = result.token[:8] + "..." if result.token else "None"
logger.info(f"[Token] 토큰 발급 성공 - tenant_id={tenant_id}, token={token_preview}, expires_at={result.expires_at}")
return Response(
{
"token": result.token,
"tenant_id": result.tenant_id,
"expires_at": result.expires_at,
},
status=status.HTTP_200_OK,
)
except NHNCloudAPIError as e:
logger.error(f"[Token] 토큰 발급 실패 - tenant_id={tenant_id}, username={username}, error={e.message}, code={e.code}")
return Response(
{"error": e.message, "code": e.code},
status=status.HTTP_401_UNAUTHORIZED,
)
# ==================== Compute API ====================
class ComputeFlavorListView(NHNBaseView):
"""Flavor 목록 조회 API"""
@swagger_auto_schema(
operation_summary="Flavor 목록 조회",
manual_parameters=[region_header, token_header, tenant_header],
responses={200: "Flavor 목록"},
)
def get(self, request):
headers = get_nhn_headers(request)
try:
api = ApiCompute(headers["region"], headers["tenant_id"], headers["token"])
return Response(api.get_flavor_list())
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class ComputeKeypairListView(NHNBaseView):
"""Keypair 목록 조회 API"""
@swagger_auto_schema(
operation_summary="Keypair 목록 조회",
manual_parameters=[region_header, token_header, tenant_header],
responses={200: "Keypair 목록"},
)
def get(self, request):
headers = get_nhn_headers(request)
try:
api = ApiCompute(headers["region"], headers["tenant_id"], headers["token"])
return Response(api.get_keypair_list())
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class ComputeImageListView(NHNBaseView):
"""이미지 목록 조회 API"""
@swagger_auto_schema(
operation_summary="이미지 목록 조회",
manual_parameters=[region_header, token_header, tenant_header],
responses={200: "이미지 목록"},
)
def get(self, request):
headers = get_nhn_headers(request)
try:
api = ApiCompute(headers["region"], headers["tenant_id"], headers["token"])
return Response(api.get_image_list())
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class ComputeInstanceListView(NHNBaseView):
"""인스턴스 목록 조회 API"""
@swagger_auto_schema(
operation_summary="인스턴스 목록 조회",
manual_parameters=[region_header, token_header, tenant_header],
responses={200: "인스턴스 목록"},
)
def get(self, request):
headers = get_nhn_headers(request)
try:
api = ApiCompute(headers["region"], headers["tenant_id"], headers["token"])
# detail=true 파라미터로 상세 조회 여부 결정
if request.query_params.get("detail", "true").lower() == "true":
return Response(api.get_instance_list_detail())
return Response(api.get_instance_list())
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class ComputeInstanceDetailView(NHNBaseView):
"""인스턴스 상세/삭제 API"""
@swagger_auto_schema(
operation_summary="인스턴스 상세 조회",
manual_parameters=[region_header, token_header, tenant_header],
responses={200: "인스턴스 상세 정보"},
)
def get(self, request, server_id):
headers = get_nhn_headers(request)
try:
api = ApiCompute(headers["region"], headers["tenant_id"], headers["token"])
return Response(api.get_instance_info(server_id))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="인스턴스 삭제 (비동기)",
manual_parameters=[region_header, token_header, tenant_header],
responses={202: "작업 ID 반환"},
)
def delete(self, request, server_id):
headers = get_nhn_headers(request)
try:
from .tasks import delete_instance_async
task = delete_instance_async(
region=headers["region"],
tenant_id=headers["tenant_id"],
token=headers["token"],
server_id=server_id,
server_name=request.query_params.get("name", ""),
)
return Response(
{"task_id": str(task.id), "status": task.status, "message": "인스턴스 삭제 작업이 시작되었습니다."},
status=status.HTTP_202_ACCEPTED,
)
except Exception as e:
logger.exception("인스턴스 삭제 작업 시작 실패")
return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
class ComputeInstanceCreateView(NHNBaseView):
"""인스턴스 생성 API (비동기)"""
@swagger_auto_schema(
operation_summary="인스턴스 생성 (비동기)",
manual_parameters=[region_header, token_header, tenant_header],
request_body=ComputeInstanceSerializer,
responses={202: "작업 ID 반환"},
)
def post(self, request):
headers = get_nhn_headers(request)
serializer = ComputeInstanceSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
from .tasks import create_instance_async
# 비동기 작업 시작
task = create_instance_async(
region=headers["region"],
tenant_id=headers["tenant_id"],
token=headers["token"],
instance_data=serializer.validated_data,
)
return Response(
{
"task_id": str(task.id),
"status": task.status,
"message": "인스턴스 생성 작업이 시작되었습니다.",
},
status=status.HTTP_202_ACCEPTED,
)
except Exception as e:
logger.exception("인스턴스 생성 작업 시작 실패")
return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
class ComputeInstanceActionView(NHNBaseView):
"""인스턴스 액션 API (시작/정지/재부팅) - 비동기"""
@swagger_auto_schema(
operation_summary="인스턴스 액션 (start/stop/reboot) - 비동기",
manual_parameters=[region_header, token_header, tenant_header],
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
"action": openapi.Schema(
type=openapi.TYPE_STRING,
enum=["start", "stop", "reboot"],
description="액션 타입",
),
},
required=["action"],
),
responses={202: "작업 ID 반환"},
)
def post(self, request, server_id):
headers = get_nhn_headers(request)
action = request.data.get("action")
if action not in ["start", "stop", "reboot"]:
return Response(
{"error": "Invalid action. Use: start, stop, reboot"},
status=status.HTTP_400_BAD_REQUEST,
)
try:
from .tasks import instance_action_async
task = instance_action_async(
region=headers["region"],
tenant_id=headers["tenant_id"],
token=headers["token"],
server_id=server_id,
action=action,
server_name=request.data.get("name", ""),
hard=request.data.get("hard", False),
)
return Response(
{"task_id": str(task.id), "status": task.status, "action": action, "message": f"인스턴스 {action} 작업이 시작되었습니다."},
status=status.HTTP_202_ACCEPTED,
)
except Exception as e:
logger.exception(f"인스턴스 {action} 작업 시작 실패")
return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
# ==================== VPC API ====================
class VpcListView(NHNBaseView):
"""VPC 목록 조회 API"""
@swagger_auto_schema(
operation_summary="VPC 목록 조회",
manual_parameters=[region_header, token_header],
responses={200: "VPC 목록"},
)
def get(self, request):
logger.info(f"[VPC] VPC 목록 조회 요청")
headers = get_nhn_headers(request)
try:
api = ApiVpc(headers["region"], headers["token"])
result = api.get_vpc_list()
vpc_count = len(result.get("vpcs", []))
logger.info(f"[VPC] VPC 목록 조회 성공 - count={vpc_count}")
return Response(result)
except NHNCloudAPIError as e:
logger.error(f"[VPC] VPC 목록 조회 실패 - error={e.message}")
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class VpcCreateView(NHNBaseView):
"""VPC 생성 API (비동기)"""
@swagger_auto_schema(
operation_summary="VPC 생성 (비동기)",
manual_parameters=[region_header, token_header],
request_body=VpcSerializer,
responses={202: "작업 ID 반환"},
)
def post(self, request):
headers = get_nhn_headers(request)
serializer = VpcSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
from .tasks import create_vpc_async
task = create_vpc_async(
region=headers["region"],
token=headers["token"],
name=serializer.validated_data["name"],
cidr=serializer.validated_data["cidr"],
)
return Response(
{"task_id": str(task.id), "status": task.status, "message": "VPC 생성 작업이 시작되었습니다."},
status=status.HTTP_202_ACCEPTED,
)
except Exception as e:
logger.exception("VPC 생성 작업 시작 실패")
return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
class VpcDetailView(NHNBaseView):
"""VPC 상세/삭제 API"""
@swagger_auto_schema(
operation_summary="VPC 상세 조회",
manual_parameters=[region_header, token_header],
responses={200: "VPC 상세 정보"},
)
def get(self, request, vpc_id):
logger.info(f"[VPC] VPC 상세 조회 요청 - vpc_id={vpc_id}")
headers = get_nhn_headers(request)
try:
api = ApiVpc(headers["region"], headers["token"])
result = api.get_vpc_info(vpc_id)
vpc_name = result.get("vpc", {}).get("name", "unknown")
logger.info(f"[VPC] VPC 상세 조회 성공 - vpc_id={vpc_id}, name={vpc_name}")
return Response(result)
except NHNCloudAPIError as e:
logger.error(f"[VPC] VPC 상세 조회 실패 - vpc_id={vpc_id}, error={e.message}")
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="VPC 삭제 (비동기)",
manual_parameters=[region_header, token_header],
responses={202: "작업 ID 반환"},
)
def delete(self, request, vpc_id):
logger.info(f"[VPC] VPC 삭제 요청 - vpc_id={vpc_id}")
headers = get_nhn_headers(request)
try:
from .tasks import delete_vpc_async
task = delete_vpc_async(
region=headers["region"],
token=headers["token"],
vpc_id=vpc_id,
vpc_name=request.query_params.get("name", ""),
)
logger.info(f"[VPC] VPC 삭제 작업 시작 - vpc_id={vpc_id}, task_id={task.id}")
return Response(
{"task_id": str(task.id), "status": task.status, "message": "VPC 삭제 작업이 시작되었습니다."},
status=status.HTTP_202_ACCEPTED,
)
except Exception as e:
logger.exception(f"[VPC] VPC 삭제 작업 시작 실패 - vpc_id={vpc_id}")
return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
class SubnetListView(NHNBaseView):
"""서브넷 목록 조회 API"""
@swagger_auto_schema(
operation_summary="서브넷 목록 조회",
manual_parameters=[region_header, token_header],
responses={200: "서브넷 목록"},
)
def get(self, request):
headers = get_nhn_headers(request)
try:
api = ApiVpc(headers["region"], headers["token"])
return Response(api.get_subnet_list())
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class SubnetCreateView(NHNBaseView):
"""서브넷 생성 API (비동기)"""
@swagger_auto_schema(
operation_summary="서브넷 생성 (비동기)",
manual_parameters=[region_header, token_header],
request_body=SubnetSerializer,
responses={202: "작업 ID 반환"},
)
def post(self, request):
headers = get_nhn_headers(request)
serializer = SubnetSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
from .tasks import create_subnet_async
task = create_subnet_async(
region=headers["region"],
token=headers["token"],
vpc_id=serializer.validated_data["vpc_id"],
cidr=serializer.validated_data["cidr"],
name=serializer.validated_data["name"],
)
return Response(
{"task_id": str(task.id), "status": task.status, "message": "서브넷 생성 작업이 시작되었습니다."},
status=status.HTTP_202_ACCEPTED,
)
except Exception as e:
logger.exception("서브넷 생성 작업 시작 실패")
return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
class SubnetDetailView(NHNBaseView):
"""서브넷 상세/삭제 API"""
@swagger_auto_schema(
operation_summary="서브넷 상세 조회",
manual_parameters=[region_header, token_header],
responses={200: "서브넷 상세 정보"},
)
def get(self, request, subnet_id):
headers = get_nhn_headers(request)
try:
api = ApiVpc(headers["region"], headers["token"])
return Response(api.get_subnet_info(subnet_id))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="서브넷 삭제 (비동기)",
manual_parameters=[region_header, token_header],
responses={202: "작업 ID 반환"},
)
def delete(self, request, subnet_id):
headers = get_nhn_headers(request)
try:
from .tasks import delete_subnet_async
task = delete_subnet_async(
region=headers["region"],
token=headers["token"],
subnet_id=subnet_id,
subnet_name=request.query_params.get("name", ""),
)
return Response(
{"task_id": str(task.id), "status": task.status, "message": "서브넷 삭제 작업이 시작되었습니다."},
status=status.HTTP_202_ACCEPTED,
)
except Exception as e:
logger.exception("서브넷 삭제 작업 시작 실패")
return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
class FloatingIpListView(NHNBaseView):
"""Floating IP 목록 조회 API"""
@swagger_auto_schema(
operation_summary="Floating IP 목록 조회",
manual_parameters=[region_header, token_header],
responses={200: "Floating IP 목록"},
)
def get(self, request):
headers = get_nhn_headers(request)
try:
api = ApiVpc(headers["region"], headers["token"])
return Response(api.get_floating_ip_list())
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
# ==================== Security Group API ====================
class SecurityGroupListView(NHNBaseView):
"""보안 그룹 목록 조회 API"""
@swagger_auto_schema(
operation_summary="보안 그룹 목록 조회",
manual_parameters=[region_header, token_header],
responses={200: "보안 그룹 목록"},
)
def get(self, request):
headers = get_nhn_headers(request)
try:
api = ApiVpc(headers["region"], headers["token"])
return Response(api.get_security_group_list())
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
# ==================== Async Task API ====================
class AsyncTaskListView(NHNBaseView):
"""비동기 작업 목록 조회 API"""
@swagger_auto_schema(
operation_summary="비동기 작업 목록 조회",
responses={200: "작업 목록"},
)
def get(self, request):
from .models import AsyncTask
# 최근 100개만 조회
tasks = AsyncTask.objects.all()[:100]
data = [
{
"id": str(task.id),
"task_type": task.task_type,
"status": task.status,
"resource_name": task.resource_name,
"resource_id": task.resource_id,
"error_message": task.error_message,
"created_at": task.created_at.isoformat(),
"completed_at": task.completed_at.isoformat() if task.completed_at else None,
}
for task in tasks
]
return Response({"tasks": data})
class AsyncTaskDetailView(NHNBaseView):
"""비동기 작업 상세 조회 API"""
@swagger_auto_schema(
operation_summary="비동기 작업 상태 조회",
responses={200: "작업 상태"},
)
def get(self, request, task_id):
from .models import AsyncTask
try:
task = AsyncTask.objects.get(id=task_id)
return Response(
{
"id": str(task.id),
"task_type": task.task_type,
"status": task.status,
"resource_name": task.resource_name,
"resource_id": task.resource_id,
"request_data": task.request_data,
"result_data": task.result_data,
"error_message": task.error_message,
"created_at": task.created_at.isoformat(),
"updated_at": task.updated_at.isoformat(),
"completed_at": task.completed_at.isoformat() if task.completed_at else None,
}
)
except AsyncTask.DoesNotExist:
return Response({"error": "작업을 찾을 수 없습니다."}, status=status.HTTP_404_NOT_FOUND)
# ==================== NKS API ====================
class NksSupportsView(NHNBaseView):
"""NKS 지원 버전 및 작업 종류 조회 API"""
@swagger_auto_schema(
operation_summary="지원되는 Kubernetes 버전 조회",
manual_parameters=[region_header, token_header],
responses={200: "지원 버전 및 작업 종류"},
)
def get(self, request):
headers = get_nhn_headers(request)
try:
api = ApiNks(headers["region"], headers["token"])
return Response(api.get_supports())
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class NksClusterListView(NHNBaseView):
"""NKS 클러스터 목록 조회 API"""
@swagger_auto_schema(
operation_summary="NKS 클러스터 목록 조회",
manual_parameters=[region_header, token_header],
responses={200: "클러스터 목록"},
)
def get(self, request):
headers = get_nhn_headers(request)
try:
api = ApiNks(headers["region"], headers["token"])
return Response(api.get_cluster_list())
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class NksClusterDetailView(NHNBaseView):
"""NKS 클러스터 상세/삭제 API"""
@swagger_auto_schema(
operation_summary="NKS 클러스터 상세 조회",
manual_parameters=[region_header, token_header],
responses={200: "클러스터 상세 정보"},
)
def get(self, request, cluster_name):
headers = get_nhn_headers(request)
try:
api = ApiNks(headers["region"], headers["token"])
return Response(api.get_cluster_info(cluster_name))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="NKS 클러스터 삭제 (비동기)",
manual_parameters=[region_header, token_header],
responses={202: "작업 ID 반환"},
)
def delete(self, request, cluster_name):
headers = get_nhn_headers(request)
try:
from .tasks import delete_nks_cluster_async
task = delete_nks_cluster_async(
region=headers["region"],
token=headers["token"],
cluster_name=cluster_name,
)
return Response(
{"task_id": str(task.id), "status": task.status, "message": "NKS 클러스터 삭제 작업이 시작되었습니다."},
status=status.HTTP_202_ACCEPTED,
)
except Exception as e:
logger.exception("NKS 클러스터 삭제 작업 시작 실패")
return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
class NksClusterConfigView(NHNBaseView):
"""NKS 클러스터 kubeconfig 조회 API"""
@swagger_auto_schema(
operation_summary="NKS 클러스터 kubeconfig 조회",
manual_parameters=[region_header, token_header],
responses={200: "kubeconfig"},
)
def get(self, request, cluster_name):
headers = get_nhn_headers(request)
try:
api = ApiNks(headers["region"], headers["token"])
config = api.get_cluster_config(cluster_name)
return Response({"config": config})
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class NksClusterCreateView(NHNBaseView):
"""NKS 클러스터 생성 API (비동기)"""
@swagger_auto_schema(
operation_summary="NKS 클러스터 생성 (비동기)",
manual_parameters=[region_header, token_header],
request_body=NksClusterSerializer,
responses={202: "작업 ID 반환"},
)
def post(self, request):
headers = get_nhn_headers(request)
serializer = NksClusterSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
cluster_data = serializer.validated_data.copy()
# Public 클러스터인 경우 External Network/Subnet 자동 조회
if cluster_data.get("is_public", True):
vpc_api = ApiVpc(headers["region"], headers["token"])
external_networks = vpc_api.get_external_network_id()
networks = external_networks.get("networks", [])
if not networks:
return Response(
{"error": "External Network를 찾을 수 없습니다."},
status=status.HTTP_400_BAD_REQUEST,
)
# 첫 번째 External Network 사용
external_network = networks[0]
cluster_data["external_network_id"] = external_network.get("id")
# External Network의 서브넷 가져오기
subnets = external_network.get("subnets", [])
if subnets:
cluster_data["external_subnet_id"] = subnets[0]
else:
return Response(
{"error": "External Subnet을 찾을 수 없습니다."},
status=status.HTTP_400_BAD_REQUEST,
)
logger.info(
f"[NKS] External Network 자동 설정 - network_id={cluster_data['external_network_id']}, "
f"subnet_id={cluster_data['external_subnet_id']}"
)
from .tasks import create_nks_cluster_async
task = create_nks_cluster_async(
region=headers["region"],
token=headers["token"],
cluster_data=cluster_data,
)
return Response(
{"task_id": str(task.id), "status": task.status, "message": "NKS 클러스터 생성 작업이 시작되었습니다."},
status=status.HTTP_202_ACCEPTED,
)
except NHNCloudAPIError as e:
logger.exception("External Network 조회 실패")
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
logger.exception("NKS 클러스터 생성 작업 시작 실패")
return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
class NksClusterResizeView(NHNBaseView):
"""NKS 클러스터 리사이즈 API"""
@swagger_auto_schema(
operation_summary="NKS 클러스터 노드 수 조정",
manual_parameters=[region_header, token_header],
request_body=NksClusterResizeSerializer,
responses={200: "리사이즈 결과"},
)
def post(self, request, cluster_name):
headers = get_nhn_headers(request)
serializer = NksClusterResizeSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiNks(headers["region"], headers["token"])
result = api.resize_cluster(cluster_name, serializer.validated_data["node_count"])
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class NksClusterUpgradeView(NHNBaseView):
"""NKS 클러스터 업그레이드 API"""
@swagger_auto_schema(
operation_summary="NKS 클러스터 Kubernetes 버전 업그레이드",
manual_parameters=[region_header, token_header],
request_body=NksClusterUpgradeSerializer,
responses={200: "업그레이드 결과"},
)
def post(self, request, cluster_name):
headers = get_nhn_headers(request)
serializer = NksClusterUpgradeSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiNks(headers["region"], headers["token"])
result = api.upgrade_cluster(cluster_name, serializer.validated_data["kubernetes_version"])
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class NksClusterEventsView(NHNBaseView):
"""NKS 클러스터 작업 이력 API"""
@swagger_auto_schema(
operation_summary="NKS 클러스터 작업 이력 조회",
manual_parameters=[region_header, token_header],
responses={200: "작업 이력 목록"},
)
def get(self, request, cluster_uuid):
headers = get_nhn_headers(request)
try:
api = ApiNks(headers["region"], headers["token"])
return Response(api.get_cluster_events(cluster_uuid))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class NksClusterEventDetailView(NHNBaseView):
"""NKS 클러스터 작업 이력 상세 API"""
@swagger_auto_schema(
operation_summary="NKS 클러스터 작업 이력 상세 조회",
manual_parameters=[region_header, token_header],
responses={200: "작업 이력 상세"},
)
def get(self, request, cluster_uuid, event_uuid):
headers = get_nhn_headers(request)
try:
api = ApiNks(headers["region"], headers["token"])
return Response(api.get_cluster_event(cluster_uuid, event_uuid))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class NksClusterCertificatesView(NHNBaseView):
"""NKS 클러스터 인증서 갱신 API"""
@swagger_auto_schema(
operation_summary="NKS 클러스터 인증서 갱신",
manual_parameters=[region_header, token_header],
responses={200: "갱신 결과"},
)
def post(self, request, cluster_name):
headers = get_nhn_headers(request)
try:
api = ApiNks(headers["region"], headers["token"])
result = api.renew_certificates(cluster_name)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class NksClusterIpAclView(NHNBaseView):
"""NKS 클러스터 API 엔드포인트 IP 접근 제어 API"""
@swagger_auto_schema(
operation_summary="API 엔드포인트 IP 접근 제어 조회",
manual_parameters=[region_header, token_header],
responses={200: "IP 접근 제어 설정"},
)
def get(self, request, cluster_name):
headers = get_nhn_headers(request)
try:
api = ApiNks(headers["region"], headers["token"])
return Response(api.get_api_endpoint_ipacl(cluster_name))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="API 엔드포인트 IP 접근 제어 설정",
manual_parameters=[region_header, token_header],
request_body=NksApiEndpointIpAclSerializer,
responses={200: "설정 결과"},
)
def post(self, request, cluster_name):
headers = get_nhn_headers(request)
serializer = NksApiEndpointIpAclSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiNks(headers["region"], headers["token"])
result = api.set_api_endpoint_ipacl(
cluster_name,
serializer.validated_data["enable"],
serializer.validated_data.get("allowed_cidrs"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
# ==================== NKS Node Group API ====================
class NksNodeGroupListView(NHNBaseView):
"""NKS 노드 그룹 목록 조회 API"""
@swagger_auto_schema(
operation_summary="노드 그룹 목록 조회",
manual_parameters=[region_header, token_header],
responses={200: "노드 그룹 목록"},
)
def get(self, request, cluster_name):
headers = get_nhn_headers(request)
try:
api = ApiNks(headers["region"], headers["token"])
return Response(api.get_nodegroup_list(cluster_name))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class NksNodeGroupCreateView(NHNBaseView):
"""NKS 노드 그룹 생성 API"""
@swagger_auto_schema(
operation_summary="노드 그룹 생성",
manual_parameters=[region_header, token_header],
request_body=NksNodeGroupSerializer,
responses={200: "생성된 노드 그룹 정보"},
)
def post(self, request, cluster_name):
headers = get_nhn_headers(request)
serializer = NksNodeGroupSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiNks(headers["region"], headers["token"])
result = api.create_nodegroup(
cluster_name=cluster_name,
nodegroup_name=serializer.validated_data["nodegroup_name"],
instance_type=serializer.validated_data["instance_type"],
node_count=serializer.validated_data.get("node_count", 1),
availability_zone=serializer.validated_data.get("availability_zone"),
boot_volume_size=serializer.validated_data.get("boot_volume_size", 50),
boot_volume_type=serializer.validated_data.get("boot_volume_type", "General SSD"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class NksNodeGroupDetailView(NHNBaseView):
"""NKS 노드 그룹 상세/삭제/수정 API"""
@swagger_auto_schema(
operation_summary="노드 그룹 상세 조회",
manual_parameters=[region_header, token_header],
responses={200: "노드 그룹 상세 정보"},
)
def get(self, request, cluster_name, nodegroup_name):
headers = get_nhn_headers(request)
try:
api = ApiNks(headers["region"], headers["token"])
return Response(api.get_nodegroup_info(cluster_name, nodegroup_name))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="노드 그룹 삭제",
manual_parameters=[region_header, token_header],
responses={200: "삭제 결과"},
)
def delete(self, request, cluster_name, nodegroup_name):
headers = get_nhn_headers(request)
try:
api = ApiNks(headers["region"], headers["token"])
result = api.delete_nodegroup(cluster_name, nodegroup_name)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="노드 그룹 설정 변경",
manual_parameters=[region_header, token_header],
request_body=NksNodeGroupUpdateSerializer,
responses={200: "변경된 노드 그룹 정보"},
)
def patch(self, request, cluster_name, nodegroup_name):
headers = get_nhn_headers(request)
serializer = NksNodeGroupUpdateSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiNks(headers["region"], headers["token"])
result = api.update_nodegroup(
cluster_name=cluster_name,
nodegroup_name=nodegroup_name,
instance_type=serializer.validated_data.get("instance_type"),
node_count=serializer.validated_data.get("node_count"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class NksNodeGroupUpgradeView(NHNBaseView):
"""NKS 노드 그룹 업그레이드 API"""
@swagger_auto_schema(
operation_summary="노드 그룹 Kubernetes 버전 업그레이드",
manual_parameters=[region_header, token_header],
request_body=NksNodeGroupUpgradeSerializer,
responses={200: "업그레이드 결과"},
)
def post(self, request, cluster_name, nodegroup_name):
headers = get_nhn_headers(request)
serializer = NksNodeGroupUpgradeSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiNks(headers["region"], headers["token"])
result = api.upgrade_nodegroup(
cluster_name=cluster_name,
nodegroup_name=nodegroup_name,
kubernetes_version=serializer.validated_data["kubernetes_version"],
max_unavailable_worker=serializer.validated_data.get("max_unavailable_worker", 1),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class NksNodeGroupUserScriptView(NHNBaseView):
"""NKS 노드 그룹 사용자 스크립트 API"""
@swagger_auto_schema(
operation_summary="노드 그룹 사용자 스크립트 설정",
manual_parameters=[region_header, token_header],
request_body=NksUserScriptSerializer,
responses={200: "설정 결과"},
)
def post(self, request, cluster_name, nodegroup_name):
headers = get_nhn_headers(request)
serializer = NksUserScriptSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiNks(headers["region"], headers["token"])
result = api.set_nodegroup_userscript(
cluster_name=cluster_name,
nodegroup_name=nodegroup_name,
userscript=serializer.validated_data["userscript"],
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class NksNodeStartView(NHNBaseView):
"""NKS 워커 노드 시작 API"""
@swagger_auto_schema(
operation_summary="워커 노드 시작",
manual_parameters=[region_header, token_header],
request_body=NksNodeActionSerializer,
responses={200: "시작 결과"},
)
def post(self, request, cluster_name, nodegroup_name):
headers = get_nhn_headers(request)
serializer = NksNodeActionSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiNks(headers["region"], headers["token"])
result = api.start_node(
cluster_name=cluster_name,
nodegroup_name=nodegroup_name,
node_id=serializer.validated_data["node_id"],
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class NksNodeStopView(NHNBaseView):
"""NKS 워커 노드 중지 API"""
@swagger_auto_schema(
operation_summary="워커 노드 중지",
manual_parameters=[region_header, token_header],
request_body=NksNodeActionSerializer,
responses={200: "중지 결과"},
)
def post(self, request, cluster_name, nodegroup_name):
headers = get_nhn_headers(request)
serializer = NksNodeActionSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiNks(headers["region"], headers["token"])
result = api.stop_node(
cluster_name=cluster_name,
nodegroup_name=nodegroup_name,
node_id=serializer.validated_data["node_id"],
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class NksAutoscaleConfigView(NHNBaseView):
"""NKS 오토스케일러 설정 API"""
@swagger_auto_schema(
operation_summary="오토스케일러 설정 조회",
manual_parameters=[region_header, token_header],
responses={200: "오토스케일러 설정"},
)
def get(self, request, cluster_name, nodegroup_name):
headers = get_nhn_headers(request)
try:
api = ApiNks(headers["region"], headers["token"])
return Response(api.get_autoscale_config(cluster_name, nodegroup_name))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="오토스케일러 설정 변경",
manual_parameters=[region_header, token_header],
request_body=NksAutoscaleConfigSerializer,
responses={200: "변경된 오토스케일러 설정"},
)
def post(self, request, cluster_name, nodegroup_name):
headers = get_nhn_headers(request)
serializer = NksAutoscaleConfigSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiNks(headers["region"], headers["token"])
result = api.set_autoscale_config(
cluster_name=cluster_name,
nodegroup_name=nodegroup_name,
ca_enable=serializer.validated_data["ca_enable"],
ca_max_node_count=serializer.validated_data.get("ca_max_node_count"),
ca_min_node_count=serializer.validated_data.get("ca_min_node_count"),
ca_scale_down_enable=serializer.validated_data.get("ca_scale_down_enable"),
ca_scale_down_delay_after_add=serializer.validated_data.get("ca_scale_down_delay_after_add"),
ca_scale_down_unneeded_time=serializer.validated_data.get("ca_scale_down_unneeded_time"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
# ==================== Storage API ====================
storage_account_header = openapi.Parameter(
"X-NHN-Storage-Account",
openapi.IN_HEADER,
description="NHN Cloud Object Storage 계정 (AUTH_...)",
type=openapi.TYPE_STRING,
required=True,
)
class StorageContainerListView(NHNBaseView):
"""스토리지 컨테이너 목록 조회 API"""
@swagger_auto_schema(
operation_summary="컨테이너 목록 조회",
manual_parameters=[region_header, token_header, storage_account_header],
responses={200: "컨테이너 목록"},
)
def get(self, request):
headers = get_nhn_headers(request)
try:
api = ApiStorageObject(
headers["region"], headers["token"], headers["storage_account"]
)
containers = api.get_container_list()
return Response({"containers": containers})
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class StorageContainerCreateView(NHNBaseView):
"""스토리지 컨테이너 생성 API (비동기)"""
@swagger_auto_schema(
operation_summary="컨테이너 생성 (비동기)",
manual_parameters=[region_header, token_header, storage_account_header],
request_body=StorageContainerSerializer,
responses={202: "작업 ID 반환"},
)
def post(self, request):
headers = get_nhn_headers(request)
serializer = StorageContainerSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
from .tasks import create_storage_container_async
task = create_storage_container_async(
region=headers["region"],
token=headers["token"],
storage_account=headers["storage_account"],
container_name=serializer.validated_data["name"],
)
return Response(
{"task_id": str(task.id), "status": task.status, "message": "컨테이너 생성 작업이 시작되었습니다."},
status=status.HTTP_202_ACCEPTED,
)
except Exception as e:
logger.exception("컨테이너 생성 작업 시작 실패")
return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
class StorageContainerDetailView(NHNBaseView):
"""스토리지 컨테이너 상세/삭제 API"""
@swagger_auto_schema(
operation_summary="컨테이너 오브젝트 목록 조회",
manual_parameters=[region_header, token_header, storage_account_header],
responses={200: "오브젝트 목록"},
)
def get(self, request, container_name):
headers = get_nhn_headers(request)
try:
api = ApiStorageObject(
headers["region"], headers["token"], headers["storage_account"]
)
objects = api.get_object_list(container_name)
return Response({"objects": objects})
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="컨테이너 삭제 (비동기)",
manual_parameters=[region_header, token_header, storage_account_header],
responses={202: "작업 ID 반환"},
)
def delete(self, request, container_name):
headers = get_nhn_headers(request)
try:
from .tasks import delete_storage_container_async
task = delete_storage_container_async(
region=headers["region"],
token=headers["token"],
storage_account=headers["storage_account"],
container_name=container_name,
)
return Response(
{"task_id": str(task.id), "status": task.status, "message": "컨테이너 삭제 작업이 시작되었습니다."},
status=status.HTTP_202_ACCEPTED,
)
except Exception as e:
logger.exception("컨테이너 삭제 작업 시작 실패")
return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
# ==================== DNS Plus API ====================
appkey_header = openapi.Parameter(
"X-NHN-Appkey",
openapi.IN_HEADER,
description="NHN Cloud 앱키",
type=openapi.TYPE_STRING,
required=True,
)
def get_appkey(request):
"""요청 헤더에서 앱키 추출"""
appkey = request.headers.get("X-NHN-Appkey")
if not appkey:
raise NHNCloudAPIError("X-NHN-Appkey 헤더가 필요합니다.", code=400)
return appkey
# ==================== DNS Zone API ====================
class DnsZoneListView(NHNBaseView):
"""DNS Zone 목록 조회 API"""
@swagger_auto_schema(
operation_summary="DNS Zone 목록 조회",
manual_parameters=[appkey_header],
responses={200: "Zone 목록"},
)
def get(self, request):
try:
appkey = get_appkey(request)
api = ApiDnsPlus(appkey)
page = int(request.query_params.get("page", 1))
limit = int(request.query_params.get("limit", 50))
search_name = request.query_params.get("search")
return Response(api.get_zone_list(
search_zone_name=search_name,
page=page,
limit=limit,
))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class DnsZoneCreateView(NHNBaseView):
"""DNS Zone 생성 API"""
@swagger_auto_schema(
operation_summary="DNS Zone 생성",
manual_parameters=[appkey_header],
request_body=DnsZoneSerializer,
responses={200: "생성된 Zone 정보"},
)
def post(self, request):
try:
appkey = get_appkey(request)
serializer = DnsZoneSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
api = ApiDnsPlus(appkey)
result = api.create_zone(
zone_name=serializer.validated_data["zone_name"],
description=serializer.validated_data.get("description"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class DnsZoneDetailView(NHNBaseView):
"""DNS Zone 상세/수정/삭제 API"""
@swagger_auto_schema(
operation_summary="DNS Zone 상세 조회",
manual_parameters=[appkey_header],
responses={200: "Zone 상세 정보"},
)
def get(self, request, zone_id):
try:
appkey = get_appkey(request)
api = ApiDnsPlus(appkey)
return Response(api.get_zone(zone_id))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="DNS Zone 수정",
manual_parameters=[appkey_header],
request_body=DnsZoneUpdateSerializer,
responses={200: "수정된 Zone 정보"},
)
def put(self, request, zone_id):
try:
appkey = get_appkey(request)
serializer = DnsZoneUpdateSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
api = ApiDnsPlus(appkey)
result = api.update_zone(zone_id, serializer.validated_data["description"])
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="DNS Zone 삭제",
manual_parameters=[appkey_header],
responses={200: "삭제 결과"},
)
def delete(self, request, zone_id):
try:
appkey = get_appkey(request)
api = ApiDnsPlus(appkey)
result = api.delete_zones([zone_id])
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
# ==================== DNS Record Set API ====================
class DnsRecordSetListView(NHNBaseView):
"""DNS 레코드 세트 목록 조회 API"""
@swagger_auto_schema(
operation_summary="레코드 세트 목록 조회",
manual_parameters=[appkey_header],
responses={200: "레코드 세트 목록"},
)
def get(self, request, zone_id):
try:
appkey = get_appkey(request)
api = ApiDnsPlus(appkey)
page = int(request.query_params.get("page", 1))
limit = int(request.query_params.get("limit", 50))
search_name = request.query_params.get("search")
recordset_type = request.query_params.get("type")
return Response(api.get_recordset_list(
zone_id=zone_id,
recordset_type_list=[recordset_type] if recordset_type else None,
search_recordset_name=search_name,
page=page,
limit=limit,
))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class DnsRecordSetCreateView(NHNBaseView):
"""DNS 레코드 세트 생성 API"""
@swagger_auto_schema(
operation_summary="레코드 세트 생성",
manual_parameters=[appkey_header],
request_body=DnsRecordSetSerializer,
responses={200: "생성된 레코드 세트 정보"},
)
def post(self, request, zone_id):
try:
appkey = get_appkey(request)
serializer = DnsRecordSetSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
api = ApiDnsPlus(appkey)
result = api.create_recordset(
zone_id=zone_id,
recordset_name=serializer.validated_data["recordset_name"],
recordset_type=serializer.validated_data["recordset_type"],
recordset_ttl=serializer.validated_data["recordset_ttl"],
record_list=serializer.validated_data["record_list"],
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class DnsRecordSetDetailView(NHNBaseView):
"""DNS 레코드 세트 상세/수정/삭제 API"""
@swagger_auto_schema(
operation_summary="레코드 세트 상세 조회",
manual_parameters=[appkey_header],
responses={200: "레코드 세트 상세 정보"},
)
def get(self, request, zone_id, recordset_id):
try:
appkey = get_appkey(request)
api = ApiDnsPlus(appkey)
return Response(api.get_recordset(zone_id, recordset_id))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="레코드 세트 수정",
manual_parameters=[appkey_header],
request_body=DnsRecordSetUpdateSerializer,
responses={200: "수정된 레코드 세트 정보"},
)
def put(self, request, zone_id, recordset_id):
try:
appkey = get_appkey(request)
serializer = DnsRecordSetUpdateSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
api = ApiDnsPlus(appkey)
result = api.update_recordset(
zone_id=zone_id,
recordset_id=recordset_id,
recordset_type=serializer.validated_data["recordset_type"],
recordset_ttl=serializer.validated_data["recordset_ttl"],
record_list=serializer.validated_data["record_list"],
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="레코드 세트 삭제",
manual_parameters=[appkey_header],
responses={200: "삭제 결과"},
)
def delete(self, request, zone_id, recordset_id):
try:
appkey = get_appkey(request)
api = ApiDnsPlus(appkey)
result = api.delete_recordsets(zone_id, [recordset_id])
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
# ==================== DNS Pool API ====================
class DnsPoolListView(NHNBaseView):
"""DNS Pool 목록 조회 API"""
@swagger_auto_schema(
operation_summary="Pool 목록 조회",
manual_parameters=[appkey_header],
responses={200: "Pool 목록"},
)
def get(self, request):
try:
appkey = get_appkey(request)
api = ApiDnsPlus(appkey)
page = int(request.query_params.get("page", 1))
limit = int(request.query_params.get("limit", 50))
search_name = request.query_params.get("search")
return Response(api.get_pool_list(
search_pool_name=search_name,
page=page,
limit=limit,
))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class DnsPoolCreateView(NHNBaseView):
"""DNS Pool 생성 API"""
@swagger_auto_schema(
operation_summary="Pool 생성",
manual_parameters=[appkey_header],
request_body=DnsPoolSerializer,
responses={200: "생성된 Pool 정보"},
)
def post(self, request):
try:
appkey = get_appkey(request)
serializer = DnsPoolSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
api = ApiDnsPlus(appkey)
result = api.create_pool(
pool_name=serializer.validated_data["pool_name"],
endpoint_list=serializer.validated_data["endpoint_list"],
pool_disabled=serializer.validated_data.get("pool_disabled", False),
health_check_id=serializer.validated_data.get("health_check_id"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class DnsPoolDetailView(NHNBaseView):
"""DNS Pool 상세/수정/삭제 API"""
@swagger_auto_schema(
operation_summary="Pool 상세 조회",
manual_parameters=[appkey_header],
responses={200: "Pool 상세 정보"},
)
def get(self, request, pool_id):
try:
appkey = get_appkey(request)
api = ApiDnsPlus(appkey)
return Response(api.get_pool(pool_id))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="Pool 수정",
manual_parameters=[appkey_header],
request_body=DnsPoolUpdateSerializer,
responses={200: "수정된 Pool 정보"},
)
def put(self, request, pool_id):
try:
appkey = get_appkey(request)
serializer = DnsPoolUpdateSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
api = ApiDnsPlus(appkey)
result = api.update_pool(
pool_id=pool_id,
pool_name=serializer.validated_data.get("pool_name"),
endpoint_list=serializer.validated_data.get("endpoint_list"),
pool_disabled=serializer.validated_data.get("pool_disabled"),
health_check_id=serializer.validated_data.get("health_check_id"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="Pool 삭제",
manual_parameters=[appkey_header],
responses={200: "삭제 결과"},
)
def delete(self, request, pool_id):
try:
appkey = get_appkey(request)
api = ApiDnsPlus(appkey)
result = api.delete_pools([pool_id])
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
# ==================== DNS GSLB API ====================
class DnsGslbListView(NHNBaseView):
"""DNS GSLB 목록 조회 API"""
@swagger_auto_schema(
operation_summary="GSLB 목록 조회",
manual_parameters=[appkey_header],
responses={200: "GSLB 목록"},
)
def get(self, request):
try:
appkey = get_appkey(request)
api = ApiDnsPlus(appkey)
page = int(request.query_params.get("page", 1))
limit = int(request.query_params.get("limit", 50))
search_name = request.query_params.get("search")
return Response(api.get_gslb_list(
search_gslb_name=search_name,
page=page,
limit=limit,
))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class DnsGslbCreateView(NHNBaseView):
"""DNS GSLB 생성 API"""
@swagger_auto_schema(
operation_summary="GSLB 생성",
manual_parameters=[appkey_header],
request_body=DnsGslbSerializer,
responses={200: "생성된 GSLB 정보"},
)
def post(self, request):
try:
appkey = get_appkey(request)
serializer = DnsGslbSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
api = ApiDnsPlus(appkey)
result = api.create_gslb(
gslb_name=serializer.validated_data["gslb_name"],
gslb_ttl=serializer.validated_data["gslb_ttl"],
gslb_routing_rule=serializer.validated_data["gslb_routing_rule"],
gslb_disabled=serializer.validated_data.get("gslb_disabled", False),
connected_pool_list=serializer.validated_data.get("connected_pool_list"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class DnsGslbDetailView(NHNBaseView):
"""DNS GSLB 상세/수정/삭제 API"""
@swagger_auto_schema(
operation_summary="GSLB 상세 조회",
manual_parameters=[appkey_header],
responses={200: "GSLB 상세 정보"},
)
def get(self, request, gslb_id):
try:
appkey = get_appkey(request)
api = ApiDnsPlus(appkey)
return Response(api.get_gslb(gslb_id))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="GSLB 수정",
manual_parameters=[appkey_header],
request_body=DnsGslbUpdateSerializer,
responses={200: "수정된 GSLB 정보"},
)
def put(self, request, gslb_id):
try:
appkey = get_appkey(request)
serializer = DnsGslbUpdateSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
api = ApiDnsPlus(appkey)
result = api.update_gslb(
gslb_id=gslb_id,
gslb_name=serializer.validated_data.get("gslb_name"),
gslb_ttl=serializer.validated_data.get("gslb_ttl"),
gslb_routing_rule=serializer.validated_data.get("gslb_routing_rule"),
gslb_disabled=serializer.validated_data.get("gslb_disabled"),
connected_pool_list=serializer.validated_data.get("connected_pool_list"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="GSLB 삭제",
manual_parameters=[appkey_header],
responses={200: "삭제 결과"},
)
def delete(self, request, gslb_id):
try:
appkey = get_appkey(request)
api = ApiDnsPlus(appkey)
result = api.delete_gslbs([gslb_id])
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class DnsGslbPoolConnectView(NHNBaseView):
"""GSLB에 Pool 연결/수정/해제 API"""
@swagger_auto_schema(
operation_summary="GSLB에 Pool 연결",
manual_parameters=[appkey_header],
request_body=DnsPoolConnectSerializer,
responses={200: "연결 결과"},
)
def post(self, request, gslb_id, pool_id):
try:
appkey = get_appkey(request)
serializer = DnsPoolConnectSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
api = ApiDnsPlus(appkey)
result = api.connect_pool(
gslb_id=gslb_id,
pool_id=pool_id,
connected_pool_order=serializer.validated_data["connected_pool_order"],
connected_pool_region_content=serializer.validated_data.get("connected_pool_region_content"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="연결된 Pool 수정",
manual_parameters=[appkey_header],
request_body=DnsPoolConnectSerializer,
responses={200: "수정 결과"},
)
def put(self, request, gslb_id, pool_id):
try:
appkey = get_appkey(request)
serializer = DnsPoolConnectSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
api = ApiDnsPlus(appkey)
result = api.update_connected_pool(
gslb_id=gslb_id,
pool_id=pool_id,
connected_pool_order=serializer.validated_data["connected_pool_order"],
connected_pool_region_content=serializer.validated_data.get("connected_pool_region_content"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="Pool 연결 해제",
manual_parameters=[appkey_header],
responses={200: "연결 해제 결과"},
)
def delete(self, request, gslb_id, pool_id):
try:
appkey = get_appkey(request)
api = ApiDnsPlus(appkey)
result = api.disconnect_pools(gslb_id, [pool_id])
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
# ==================== DNS Health Check API ====================
class DnsHealthCheckListView(NHNBaseView):
"""DNS Health Check 목록 조회 API"""
@swagger_auto_schema(
operation_summary="Health Check 목록 조회",
manual_parameters=[appkey_header],
responses={200: "Health Check 목록"},
)
def get(self, request):
try:
appkey = get_appkey(request)
api = ApiDnsPlus(appkey)
page = int(request.query_params.get("page", 1))
limit = int(request.query_params.get("limit", 50))
search_name = request.query_params.get("search")
return Response(api.get_health_check_list(
search_health_check_name=search_name,
page=page,
limit=limit,
))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class DnsHealthCheckCreateView(NHNBaseView):
"""DNS Health Check 생성 API"""
@swagger_auto_schema(
operation_summary="Health Check 생성",
manual_parameters=[appkey_header],
request_body=DnsHealthCheckSerializer,
responses={200: "생성된 Health Check 정보"},
)
def post(self, request):
try:
appkey = get_appkey(request)
serializer = DnsHealthCheckSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
api = ApiDnsPlus(appkey)
result = api.create_health_check(
health_check_name=serializer.validated_data["health_check_name"],
health_check_protocol=serializer.validated_data["health_check_protocol"],
health_check_port=serializer.validated_data["health_check_port"],
health_check_interval=serializer.validated_data.get("health_check_interval", 30),
health_check_timeout=serializer.validated_data.get("health_check_timeout", 5),
health_check_retries=serializer.validated_data.get("health_check_retries", 2),
health_check_path=serializer.validated_data.get("health_check_path"),
health_check_expected_codes=serializer.validated_data.get("health_check_expected_codes"),
health_check_expected_body=serializer.validated_data.get("health_check_expected_body"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class DnsHealthCheckDetailView(NHNBaseView):
"""DNS Health Check 상세/수정/삭제 API"""
@swagger_auto_schema(
operation_summary="Health Check 상세 조회",
manual_parameters=[appkey_header],
responses={200: "Health Check 상세 정보"},
)
def get(self, request, health_check_id):
try:
appkey = get_appkey(request)
api = ApiDnsPlus(appkey)
return Response(api.get_health_check(health_check_id))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="Health Check 수정",
manual_parameters=[appkey_header],
request_body=DnsHealthCheckUpdateSerializer,
responses={200: "수정된 Health Check 정보"},
)
def put(self, request, health_check_id):
try:
appkey = get_appkey(request)
serializer = DnsHealthCheckUpdateSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
api = ApiDnsPlus(appkey)
result = api.update_health_check(
health_check_id=health_check_id,
health_check_name=serializer.validated_data.get("health_check_name"),
health_check_protocol=serializer.validated_data.get("health_check_protocol"),
health_check_port=serializer.validated_data.get("health_check_port"),
health_check_interval=serializer.validated_data.get("health_check_interval"),
health_check_timeout=serializer.validated_data.get("health_check_timeout"),
health_check_retries=serializer.validated_data.get("health_check_retries"),
health_check_path=serializer.validated_data.get("health_check_path"),
health_check_expected_codes=serializer.validated_data.get("health_check_expected_codes"),
health_check_expected_body=serializer.validated_data.get("health_check_expected_body"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="Health Check 삭제",
manual_parameters=[appkey_header],
responses={200: "삭제 결과"},
)
def delete(self, request, health_check_id):
try:
appkey = get_appkey(request)
api = ApiDnsPlus(appkey)
result = api.delete_health_checks([health_check_id])
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
# ==================== Load Balancer API ====================
class LoadBalancerListView(NHNBaseView):
"""로드밸런서 목록 조회 API"""
@swagger_auto_schema(
operation_summary="로드밸런서 목록 조회",
manual_parameters=[region_header, token_header],
responses={200: "로드밸런서 목록"},
)
def get(self, request):
logger.info(f"[LB] 로드밸런서 목록 조회 요청")
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.get_loadbalancer_list(
name=request.query_params.get("name"),
provisioning_status=request.query_params.get("provisioning_status"),
vip_address=request.query_params.get("vip_address"),
)
lb_count = len(result.get("loadbalancers", []))
logger.info(f"[LB] 로드밸런서 목록 조회 성공 - count={lb_count}")
return Response(result)
except NHNCloudAPIError as e:
logger.error(f"[LB] 로드밸런서 목록 조회 실패 - error={e.message}")
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class LoadBalancerCreateView(NHNBaseView):
"""로드밸런서 생성 API (비동기)"""
@swagger_auto_schema(
operation_summary="로드밸런서 생성 (비동기)",
manual_parameters=[region_header, token_header],
request_body=LoadBalancerSerializer,
responses={202: "작업 ID 반환"},
)
def post(self, request):
headers = get_nhn_headers(request)
serializer = LoadBalancerSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
from .tasks import create_loadbalancer_async
task = create_loadbalancer_async(
region=headers["region"],
token=headers["token"],
lb_data=serializer.validated_data,
)
return Response(
{"task_id": str(task.id), "status": task.status, "message": "로드밸런서 생성 작업이 시작되었습니다."},
status=status.HTTP_202_ACCEPTED,
)
except Exception as e:
logger.exception("로드밸런서 생성 작업 시작 실패")
return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
class LoadBalancerDetailView(NHNBaseView):
"""로드밸런서 상세/수정/삭제 API"""
@swagger_auto_schema(
operation_summary="로드밸런서 상세 조회",
manual_parameters=[region_header, token_header],
responses={200: "로드밸런서 상세 정보"},
)
def get(self, request, loadbalancer_id):
logger.info(f"[LB] 로드밸런서 상세 조회 요청 - loadbalancer_id={loadbalancer_id}")
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.get_loadbalancer_info(loadbalancer_id)
logger.info(f"[LB] 로드밸런서 상세 조회 성공 - loadbalancer_id={loadbalancer_id}")
return Response(result)
except NHNCloudAPIError as e:
logger.error(f"[LB] 로드밸런서 상세 조회 실패 - loadbalancer_id={loadbalancer_id}, error={e.message}")
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="로드밸런서 수정",
manual_parameters=[region_header, token_header],
request_body=LoadBalancerUpdateSerializer,
responses={200: "수정된 로드밸런서 정보"},
)
def put(self, request, loadbalancer_id):
headers = get_nhn_headers(request)
serializer = LoadBalancerUpdateSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.update_loadbalancer(
loadbalancer_id=loadbalancer_id,
name=serializer.validated_data.get("name"),
description=serializer.validated_data.get("description"),
admin_state_up=serializer.validated_data.get("admin_state_up"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="로드밸런서 삭제 (비동기)",
manual_parameters=[region_header, token_header],
responses={202: "작업 ID 반환"},
)
def delete(self, request, loadbalancer_id):
logger.info(f"[LB] 로드밸런서 삭제 요청 - loadbalancer_id={loadbalancer_id}")
headers = get_nhn_headers(request)
try:
from .tasks import delete_loadbalancer_async
task = delete_loadbalancer_async(
region=headers["region"],
token=headers["token"],
loadbalancer_id=loadbalancer_id,
loadbalancer_name=request.query_params.get("name", ""),
)
logger.info(f"[LB] 로드밸런서 삭제 작업 시작 - loadbalancer_id={loadbalancer_id}, task_id={task.id}")
return Response(
{"task_id": str(task.id), "status": task.status, "message": "로드밸런서 삭제 작업이 시작되었습니다."},
status=status.HTTP_202_ACCEPTED,
)
except Exception as e:
logger.exception(f"[LB] 로드밸런서 삭제 작업 시작 실패 - loadbalancer_id={loadbalancer_id}")
return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
# ==================== LB Listener API ====================
class LBListenerListView(NHNBaseView):
"""리스너 목록 조회 API"""
@swagger_auto_schema(
operation_summary="리스너 목록 조회",
manual_parameters=[region_header, token_header],
responses={200: "리스너 목록"},
)
def get(self, request):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.get_listener_list(
loadbalancer_id=request.query_params.get("loadbalancer_id"),
protocol=request.query_params.get("protocol"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class LBListenerCreateView(NHNBaseView):
"""리스너 생성 API"""
@swagger_auto_schema(
operation_summary="리스너 생성",
manual_parameters=[region_header, token_header],
request_body=LBListenerSerializer,
responses={200: "생성된 리스너 정보"},
)
def post(self, request):
headers = get_nhn_headers(request)
serializer = LBListenerSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.create_listener(
loadbalancer_id=serializer.validated_data["loadbalancer_id"],
protocol=serializer.validated_data["protocol"],
protocol_port=serializer.validated_data["protocol_port"],
name=serializer.validated_data.get("name"),
description=serializer.validated_data.get("description"),
default_pool_id=serializer.validated_data.get("default_pool_id"),
connection_limit=serializer.validated_data.get("connection_limit", -1),
keepalive_timeout=serializer.validated_data.get("keepalive_timeout", 300),
admin_state_up=serializer.validated_data.get("admin_state_up", True),
default_tls_container_ref=serializer.validated_data.get("default_tls_container_ref"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class LBListenerDetailView(NHNBaseView):
"""리스너 상세/수정/삭제 API"""
@swagger_auto_schema(
operation_summary="리스너 상세 조회",
manual_parameters=[region_header, token_header],
responses={200: "리스너 상세 정보"},
)
def get(self, request, listener_id):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
return Response(api.get_listener_info(listener_id))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="리스너 수정",
manual_parameters=[region_header, token_header],
request_body=LBListenerUpdateSerializer,
responses={200: "수정된 리스너 정보"},
)
def put(self, request, listener_id):
headers = get_nhn_headers(request)
serializer = LBListenerUpdateSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.update_listener(
listener_id=listener_id,
name=serializer.validated_data.get("name"),
description=serializer.validated_data.get("description"),
default_pool_id=serializer.validated_data.get("default_pool_id"),
connection_limit=serializer.validated_data.get("connection_limit"),
keepalive_timeout=serializer.validated_data.get("keepalive_timeout"),
admin_state_up=serializer.validated_data.get("admin_state_up"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="리스너 삭제",
manual_parameters=[region_header, token_header],
responses={200: "삭제 결과"},
)
def delete(self, request, listener_id):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.delete_listener(listener_id)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
# ==================== LB Pool API ====================
class LBPoolListView(NHNBaseView):
"""풀 목록 조회 API"""
@swagger_auto_schema(
operation_summary="풀 목록 조회",
manual_parameters=[region_header, token_header],
responses={200: "풀 목록"},
)
def get(self, request):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.get_pool_list(
loadbalancer_id=request.query_params.get("loadbalancer_id"),
protocol=request.query_params.get("protocol"),
lb_algorithm=request.query_params.get("lb_algorithm"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class LBPoolCreateView(NHNBaseView):
"""풀 생성 API"""
@swagger_auto_schema(
operation_summary="풀 생성",
manual_parameters=[region_header, token_header],
request_body=LBPoolSerializer,
responses={200: "생성된 풀 정보"},
)
def post(self, request):
headers = get_nhn_headers(request)
serializer = LBPoolSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.create_pool(
lb_algorithm=serializer.validated_data["lb_algorithm"],
protocol=serializer.validated_data["protocol"],
loadbalancer_id=serializer.validated_data.get("loadbalancer_id"),
listener_id=serializer.validated_data.get("listener_id"),
name=serializer.validated_data.get("name"),
description=serializer.validated_data.get("description"),
admin_state_up=serializer.validated_data.get("admin_state_up", True),
session_persistence=serializer.validated_data.get("session_persistence"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class LBPoolDetailView(NHNBaseView):
"""풀 상세/수정/삭제 API"""
@swagger_auto_schema(
operation_summary="풀 상세 조회",
manual_parameters=[region_header, token_header],
responses={200: "풀 상세 정보"},
)
def get(self, request, pool_id):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
return Response(api.get_pool_info(pool_id))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="풀 수정",
manual_parameters=[region_header, token_header],
request_body=LBPoolUpdateSerializer,
responses={200: "수정된 풀 정보"},
)
def put(self, request, pool_id):
headers = get_nhn_headers(request)
serializer = LBPoolUpdateSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.update_pool(
pool_id=pool_id,
name=serializer.validated_data.get("name"),
description=serializer.validated_data.get("description"),
lb_algorithm=serializer.validated_data.get("lb_algorithm"),
admin_state_up=serializer.validated_data.get("admin_state_up"),
session_persistence=serializer.validated_data.get("session_persistence"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="풀 삭제",
manual_parameters=[region_header, token_header],
responses={200: "삭제 결과"},
)
def delete(self, request, pool_id):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.delete_pool(pool_id)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
# ==================== LB Member API ====================
class LBMemberListView(NHNBaseView):
"""멤버 목록 조회 API"""
@swagger_auto_schema(
operation_summary="멤버 목록 조회",
manual_parameters=[region_header, token_header],
responses={200: "멤버 목록"},
)
def get(self, request, pool_id):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
return Response(api.get_member_list(pool_id))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class LBMemberCreateView(NHNBaseView):
"""멤버 추가 API"""
@swagger_auto_schema(
operation_summary="멤버 추가",
manual_parameters=[region_header, token_header],
request_body=LBMemberSerializer,
responses={200: "추가된 멤버 정보"},
)
def post(self, request, pool_id):
headers = get_nhn_headers(request)
serializer = LBMemberSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.create_member(
pool_id=pool_id,
address=serializer.validated_data["address"],
protocol_port=serializer.validated_data["protocol_port"],
subnet_id=serializer.validated_data.get("subnet_id"),
weight=serializer.validated_data.get("weight", 1),
admin_state_up=serializer.validated_data.get("admin_state_up", True),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class LBMemberDetailView(NHNBaseView):
"""멤버 상세/수정/삭제 API"""
@swagger_auto_schema(
operation_summary="멤버 상세 조회",
manual_parameters=[region_header, token_header],
responses={200: "멤버 상세 정보"},
)
def get(self, request, pool_id, member_id):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
return Response(api.get_member_info(pool_id, member_id))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="멤버 수정",
manual_parameters=[region_header, token_header],
request_body=LBMemberUpdateSerializer,
responses={200: "수정된 멤버 정보"},
)
def put(self, request, pool_id, member_id):
headers = get_nhn_headers(request)
serializer = LBMemberUpdateSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.update_member(
pool_id=pool_id,
member_id=member_id,
weight=serializer.validated_data.get("weight"),
admin_state_up=serializer.validated_data.get("admin_state_up"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="멤버 삭제",
manual_parameters=[region_header, token_header],
responses={200: "삭제 결과"},
)
def delete(self, request, pool_id, member_id):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.delete_member(pool_id, member_id)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
# ==================== LB Health Monitor API ====================
class LBHealthMonitorListView(NHNBaseView):
"""헬스 모니터 목록 조회 API"""
@swagger_auto_schema(
operation_summary="헬스 모니터 목록 조회",
manual_parameters=[region_header, token_header],
responses={200: "헬스 모니터 목록"},
)
def get(self, request):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.get_healthmonitor_list(
pool_id=request.query_params.get("pool_id"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class LBHealthMonitorCreateView(NHNBaseView):
"""헬스 모니터 생성 API"""
@swagger_auto_schema(
operation_summary="헬스 모니터 생성",
manual_parameters=[region_header, token_header],
request_body=LBHealthMonitorSerializer,
responses={200: "생성된 헬스 모니터 정보"},
)
def post(self, request):
headers = get_nhn_headers(request)
serializer = LBHealthMonitorSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.create_healthmonitor(
pool_id=serializer.validated_data["pool_id"],
type=serializer.validated_data["type"],
delay=serializer.validated_data["delay"],
timeout=serializer.validated_data["timeout"],
max_retries=serializer.validated_data["max_retries"],
max_retries_down=serializer.validated_data.get("max_retries_down", 3),
http_method=serializer.validated_data.get("http_method", "GET"),
url_path=serializer.validated_data.get("url_path", "/"),
expected_codes=serializer.validated_data.get("expected_codes", "200"),
admin_state_up=serializer.validated_data.get("admin_state_up", True),
host_header=serializer.validated_data.get("host_header"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class LBHealthMonitorDetailView(NHNBaseView):
"""헬스 모니터 상세/수정/삭제 API"""
@swagger_auto_schema(
operation_summary="헬스 모니터 상세 조회",
manual_parameters=[region_header, token_header],
responses={200: "헬스 모니터 상세 정보"},
)
def get(self, request, healthmonitor_id):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
return Response(api.get_healthmonitor_info(healthmonitor_id))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="헬스 모니터 수정",
manual_parameters=[region_header, token_header],
request_body=LBHealthMonitorUpdateSerializer,
responses={200: "수정된 헬스 모니터 정보"},
)
def put(self, request, healthmonitor_id):
headers = get_nhn_headers(request)
serializer = LBHealthMonitorUpdateSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.update_healthmonitor(
healthmonitor_id=healthmonitor_id,
delay=serializer.validated_data.get("delay"),
timeout=serializer.validated_data.get("timeout"),
max_retries=serializer.validated_data.get("max_retries"),
max_retries_down=serializer.validated_data.get("max_retries_down"),
http_method=serializer.validated_data.get("http_method"),
url_path=serializer.validated_data.get("url_path"),
expected_codes=serializer.validated_data.get("expected_codes"),
admin_state_up=serializer.validated_data.get("admin_state_up"),
host_header=serializer.validated_data.get("host_header"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="헬스 모니터 삭제",
manual_parameters=[region_header, token_header],
responses={200: "삭제 결과"},
)
def delete(self, request, healthmonitor_id):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.delete_healthmonitor(healthmonitor_id)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
# ==================== LB L7 Policy API ====================
class LBL7PolicyListView(APIView):
"""L7 정책 목록 조회 API"""
@swagger_auto_schema(
operation_summary="L7 정책 목록 조회",
manual_parameters=[region_header, token_header],
responses={200: "L7 정책 목록"},
)
def get(self, request):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.get_l7policy_list(
listener_id=request.query_params.get("listener_id"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class LBL7PolicyCreateView(APIView):
"""L7 정책 생성 API"""
@swagger_auto_schema(
operation_summary="L7 정책 생성",
manual_parameters=[region_header, token_header],
request_body=LBL7PolicySerializer,
responses={200: "생성된 L7 정책 정보"},
)
def post(self, request):
headers = get_nhn_headers(request)
serializer = LBL7PolicySerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.create_l7policy(
listener_id=serializer.validated_data["listener_id"],
action=serializer.validated_data["action"],
position=serializer.validated_data.get("position", 1),
name=serializer.validated_data.get("name"),
description=serializer.validated_data.get("description"),
redirect_pool_id=serializer.validated_data.get("redirect_pool_id"),
redirect_url=serializer.validated_data.get("redirect_url"),
admin_state_up=serializer.validated_data.get("admin_state_up", True),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class LBL7PolicyDetailView(APIView):
"""L7 정책 상세/수정/삭제 API"""
@swagger_auto_schema(
operation_summary="L7 정책 상세 조회",
manual_parameters=[region_header, token_header],
responses={200: "L7 정책 상세 정보"},
)
def get(self, request, l7policy_id):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
return Response(api.get_l7policy_info(l7policy_id))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="L7 정책 수정",
manual_parameters=[region_header, token_header],
request_body=LBL7PolicyUpdateSerializer,
responses={200: "수정된 L7 정책 정보"},
)
def put(self, request, l7policy_id):
headers = get_nhn_headers(request)
serializer = LBL7PolicyUpdateSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.update_l7policy(
l7policy_id=l7policy_id,
name=serializer.validated_data.get("name"),
description=serializer.validated_data.get("description"),
action=serializer.validated_data.get("action"),
position=serializer.validated_data.get("position"),
redirect_pool_id=serializer.validated_data.get("redirect_pool_id"),
redirect_url=serializer.validated_data.get("redirect_url"),
admin_state_up=serializer.validated_data.get("admin_state_up"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="L7 정책 삭제",
manual_parameters=[region_header, token_header],
responses={200: "삭제 결과"},
)
def delete(self, request, l7policy_id):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.delete_l7policy(l7policy_id)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
# ==================== LB L7 Rule API ====================
class LBL7RuleListView(APIView):
"""L7 룰 목록 조회 API"""
@swagger_auto_schema(
operation_summary="L7 룰 목록 조회",
manual_parameters=[region_header, token_header],
responses={200: "L7 룰 목록"},
)
def get(self, request, l7policy_id):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
return Response(api.get_l7rule_list(l7policy_id))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class LBL7RuleCreateView(APIView):
"""L7 룰 생성 API"""
@swagger_auto_schema(
operation_summary="L7 룰 생성",
manual_parameters=[region_header, token_header],
request_body=LBL7RuleSerializer,
responses={200: "생성된 L7 룰 정보"},
)
def post(self, request, l7policy_id):
headers = get_nhn_headers(request)
serializer = LBL7RuleSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.create_l7rule(
l7policy_id=l7policy_id,
type=serializer.validated_data["type"],
compare_type=serializer.validated_data["compare_type"],
value=serializer.validated_data["value"],
key=serializer.validated_data.get("key"),
invert=serializer.validated_data.get("invert", False),
admin_state_up=serializer.validated_data.get("admin_state_up", True),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class LBL7RuleDetailView(APIView):
"""L7 룰 상세/수정/삭제 API"""
@swagger_auto_schema(
operation_summary="L7 룰 상세 조회",
manual_parameters=[region_header, token_header],
responses={200: "L7 룰 상세 정보"},
)
def get(self, request, l7policy_id, l7rule_id):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
return Response(api.get_l7rule_info(l7policy_id, l7rule_id))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="L7 룰 수정",
manual_parameters=[region_header, token_header],
request_body=LBL7RuleUpdateSerializer,
responses={200: "수정된 L7 룰 정보"},
)
def put(self, request, l7policy_id, l7rule_id):
headers = get_nhn_headers(request)
serializer = LBL7RuleUpdateSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.update_l7rule(
l7policy_id=l7policy_id,
l7rule_id=l7rule_id,
type=serializer.validated_data.get("type"),
compare_type=serializer.validated_data.get("compare_type"),
value=serializer.validated_data.get("value"),
key=serializer.validated_data.get("key"),
invert=serializer.validated_data.get("invert"),
admin_state_up=serializer.validated_data.get("admin_state_up"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="L7 룰 삭제",
manual_parameters=[region_header, token_header],
responses={200: "삭제 결과"},
)
def delete(self, request, l7policy_id, l7rule_id):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.delete_l7rule(l7policy_id, l7rule_id)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
# ==================== LB IP ACL Group API ====================
class LBIpAclGroupListView(NHNBaseView):
"""IP ACL 그룹 목록 조회 API"""
@swagger_auto_schema(
operation_summary="IP ACL 그룹 목록 조회",
manual_parameters=[region_header, token_header],
responses={200: "IP ACL 그룹 목록"},
)
def get(self, request):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
return Response(api.get_ipacl_group_list())
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class LBIpAclGroupCreateView(NHNBaseView):
"""IP ACL 그룹 생성 API"""
@swagger_auto_schema(
operation_summary="IP ACL 그룹 생성",
manual_parameters=[region_header, token_header],
request_body=LBIpAclGroupSerializer,
responses={200: "생성된 IP ACL 그룹 정보"},
)
def post(self, request):
headers = get_nhn_headers(request)
serializer = LBIpAclGroupSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.create_ipacl_group(
action=serializer.validated_data["action"],
name=serializer.validated_data.get("name"),
description=serializer.validated_data.get("description"),
ipacl_targets=serializer.validated_data.get("ipacl_targets"),
loadbalancers=serializer.validated_data.get("loadbalancers"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class LBIpAclGroupDetailView(NHNBaseView):
"""IP ACL 그룹 상세/수정/삭제 API"""
@swagger_auto_schema(
operation_summary="IP ACL 그룹 상세 조회",
manual_parameters=[region_header, token_header],
responses={200: "IP ACL 그룹 상세 정보"},
)
def get(self, request, ipacl_group_id):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
return Response(api.get_ipacl_group_info(ipacl_group_id))
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="IP ACL 그룹 수정",
manual_parameters=[region_header, token_header],
request_body=LBIpAclGroupUpdateSerializer,
responses={200: "수정된 IP ACL 그룹 정보"},
)
def put(self, request, ipacl_group_id):
headers = get_nhn_headers(request)
serializer = LBIpAclGroupUpdateSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.update_ipacl_group(
ipacl_group_id=ipacl_group_id,
name=serializer.validated_data.get("name"),
description=serializer.validated_data.get("description"),
loadbalancers=serializer.validated_data.get("loadbalancers"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="IP ACL 그룹 삭제",
manual_parameters=[region_header, token_header],
responses={200: "삭제 결과"},
)
def delete(self, request, ipacl_group_id):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.delete_ipacl_group(ipacl_group_id)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
# ==================== LB IP ACL Target API ====================
class LBIpAclTargetCreateView(NHNBaseView):
"""IP ACL 타깃 추가 API"""
@swagger_auto_schema(
operation_summary="IP ACL 타깃 추가",
manual_parameters=[region_header, token_header],
request_body=LBIpAclTargetCreateSerializer,
responses={200: "추가된 IP ACL 타깃 정보"},
)
def post(self, request):
headers = get_nhn_headers(request)
serializer = LBIpAclTargetCreateSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.create_ipacl_target(
ipacl_group_id=serializer.validated_data["ipacl_group_id"],
ip_address=serializer.validated_data["ip_address"],
description=serializer.validated_data.get("description"),
)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
class LBIpAclTargetDetailView(NHNBaseView):
"""IP ACL 타깃 수정/삭제 API"""
@swagger_auto_schema(
operation_summary="IP ACL 타깃 수정 (설명만)",
manual_parameters=[region_header, token_header],
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
"description": openapi.Schema(type=openapi.TYPE_STRING, description="설명"),
},
required=["description"],
),
responses={200: "수정된 IP ACL 타깃 정보"},
)
def put(self, request, ipacl_target_id):
headers = get_nhn_headers(request)
description = request.data.get("description")
if description is None:
return Response({"error": "description is required"}, status=status.HTTP_400_BAD_REQUEST)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.update_ipacl_target(ipacl_target_id, description)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_summary="IP ACL 타깃 삭제",
manual_parameters=[region_header, token_header],
responses={200: "삭제 결과"},
)
def delete(self, request, ipacl_target_id):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
result = api.delete_ipacl_target(ipacl_target_id)
return Response(result)
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)
# ==================== LB Quota API ====================
class LBQuotaView(NHNBaseView):
"""로드밸런서 쿼타 조회 API"""
@swagger_auto_schema(
operation_summary="로드밸런서 쿼타 조회",
manual_parameters=[region_header, token_header],
responses={200: "쿼타 정보"},
)
def get(self, request):
headers = get_nhn_headers(request)
try:
api = ApiLoadBalancer(headers["region"], headers["token"])
return Response(api.get_quota())
except NHNCloudAPIError as e:
return Response({"error": e.message}, status=status.HTTP_400_BAD_REQUEST)