v0.0.9 | Add Load Balancer API
All checks were successful
Build And Test / build-and-push (push) Successful in 53s
All checks were successful
Build And Test / build-and-push (push) Successful in 53s
- 로드밸런서 CRUD API 추가 - 리스너, 풀, 멤버, 헬스 모니터 API 추가 - L7 정책/룰, IP ACL 그룹/타깃 API 추가 - 쿼타 조회 API 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
18
nhn/migrations/0002_alter_asynctask_task_type.py
Normal file
18
nhn/migrations/0002_alter_asynctask_task_type.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.14 on 2026-01-15 14:35
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('nhn', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='asynctask',
|
||||
name='task_type',
|
||||
field=models.CharField(choices=[('instance_create', '인스턴스 생성'), ('instance_delete', '인스턴스 삭제'), ('instance_action', '인스턴스 액션'), ('vpc_create', 'VPC 생성'), ('vpc_delete', 'VPC 삭제'), ('subnet_create', '서브넷 생성'), ('subnet_delete', '서브넷 삭제'), ('nks_create', 'NKS 클러스터 생성'), ('nks_delete', 'NKS 클러스터 삭제'), ('storage_create', '스토리지 컨테이너 생성'), ('storage_delete', '스토리지 컨테이너 삭제'), ('lb_create', '로드밸런서 생성'), ('lb_delete', '로드밸런서 삭제')], max_length=50),
|
||||
),
|
||||
]
|
||||
@ -33,6 +33,9 @@ class AsyncTask(models.Model):
|
||||
# Storage
|
||||
STORAGE_CREATE = "storage_create", "스토리지 컨테이너 생성"
|
||||
STORAGE_DELETE = "storage_delete", "스토리지 컨테이너 삭제"
|
||||
# Load Balancer
|
||||
LB_CREATE = "lb_create", "로드밸런서 생성"
|
||||
LB_DELETE = "lb_delete", "로드밸런서 삭제"
|
||||
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
task_type = models.CharField(max_length=50, choices=TaskType.choices)
|
||||
|
||||
@ -4,6 +4,7 @@ from .vpc import ApiVpc
|
||||
from .nks import ApiNks
|
||||
from .storage import ApiStorageObject
|
||||
from .dnsplus import ApiDnsPlus
|
||||
from .loadbalancer import ApiLoadBalancer
|
||||
|
||||
__all__ = [
|
||||
"NHNCloudToken",
|
||||
@ -12,4 +13,5 @@ __all__ = [
|
||||
"ApiNks",
|
||||
"ApiStorageObject",
|
||||
"ApiDnsPlus",
|
||||
"ApiLoadBalancer",
|
||||
]
|
||||
|
||||
931
nhn/packages/loadbalancer.py
Normal file
931
nhn/packages/loadbalancer.py
Normal file
@ -0,0 +1,931 @@
|
||||
"""
|
||||
NHN Cloud Load Balancer API Module
|
||||
|
||||
로드밸런서, 리스너, 풀, 멤버, 헬스 모니터, L7 정책 관리
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Optional, List
|
||||
|
||||
from .base import BaseAPI, NHNCloudEndpoints, Region
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ApiLoadBalancer(BaseAPI):
|
||||
"""NHN Cloud Load Balancer API 클래스"""
|
||||
|
||||
def __init__(self, region: str, token: str):
|
||||
"""
|
||||
Args:
|
||||
region: 리전 (kr1: 판교, kr2: 평촌)
|
||||
token: API 인증 토큰
|
||||
"""
|
||||
super().__init__(region, token)
|
||||
|
||||
if self.region == Region.KR1:
|
||||
self.lb_url = NHNCloudEndpoints.NETWORK_KR1
|
||||
else:
|
||||
self.lb_url = NHNCloudEndpoints.NETWORK_KR2
|
||||
|
||||
# ==================== Load Balancer ====================
|
||||
|
||||
def get_loadbalancer_list(
|
||||
self,
|
||||
id: Optional[str] = None,
|
||||
name: Optional[str] = None,
|
||||
provisioning_status: Optional[str] = None,
|
||||
vip_address: Optional[str] = None,
|
||||
vip_subnet_id: Optional[str] = None,
|
||||
) -> dict:
|
||||
"""
|
||||
로드밸런서 목록 조회
|
||||
|
||||
Args:
|
||||
id: 로드밸런서 ID로 필터링
|
||||
name: 로드밸런서 이름으로 필터링
|
||||
provisioning_status: 프로비저닝 상태로 필터링 (ACTIVE, PENDING_CREATE 등)
|
||||
vip_address: VIP 주소로 필터링
|
||||
vip_subnet_id: VIP 서브넷 ID로 필터링
|
||||
"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/loadbalancers"
|
||||
params = {}
|
||||
if id:
|
||||
params["id"] = id
|
||||
if name:
|
||||
params["name"] = name
|
||||
if provisioning_status:
|
||||
params["provisioning_status"] = provisioning_status
|
||||
if vip_address:
|
||||
params["vip_address"] = vip_address
|
||||
if vip_subnet_id:
|
||||
params["vip_subnet_id"] = vip_subnet_id
|
||||
|
||||
logger.info(f"[NHN API] 로드밸런서 목록 조회 요청 - URL={url}")
|
||||
result = self._get(url, params=params if params else None)
|
||||
lb_count = len(result.get("loadbalancers", []))
|
||||
logger.info(f"[NHN API] 로드밸런서 목록 조회 완료 - count={lb_count}")
|
||||
return result
|
||||
|
||||
def get_loadbalancer_info(self, loadbalancer_id: str) -> dict:
|
||||
"""로드밸런서 상세 조회"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/loadbalancers/{loadbalancer_id}"
|
||||
logger.info(f"[NHN API] 로드밸런서 상세 조회 요청 - loadbalancer_id={loadbalancer_id}")
|
||||
result = self._get(url)
|
||||
logger.info(f"[NHN API] 로드밸런서 상세 조회 완료 - loadbalancer_id={loadbalancer_id}")
|
||||
return result
|
||||
|
||||
def create_loadbalancer(
|
||||
self,
|
||||
vip_subnet_id: str,
|
||||
name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
vip_address: Optional[str] = None,
|
||||
admin_state_up: bool = True,
|
||||
loadbalancer_type: str = "shared",
|
||||
) -> dict:
|
||||
"""
|
||||
로드밸런서 생성
|
||||
|
||||
Args:
|
||||
vip_subnet_id: VIP가 할당될 서브넷 ID (필수)
|
||||
name: 로드밸런서 이름
|
||||
description: 설명
|
||||
vip_address: VIP 주소 (지정하지 않으면 자동 할당)
|
||||
admin_state_up: 관리자 상태
|
||||
loadbalancer_type: 로드밸런서 타입 (shared 또는 dedicated)
|
||||
"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/loadbalancers"
|
||||
payload = {
|
||||
"loadbalancer": {
|
||||
"vip_subnet_id": vip_subnet_id,
|
||||
"admin_state_up": admin_state_up,
|
||||
"loadbalancer_type": loadbalancer_type,
|
||||
}
|
||||
}
|
||||
if name:
|
||||
payload["loadbalancer"]["name"] = name
|
||||
if description:
|
||||
payload["loadbalancer"]["description"] = description
|
||||
if vip_address:
|
||||
payload["loadbalancer"]["vip_address"] = vip_address
|
||||
|
||||
logger.info(f"[NHN API] 로드밸런서 생성 요청 - name={name}, vip_subnet_id={vip_subnet_id}")
|
||||
return self._post(url, payload)
|
||||
|
||||
def update_loadbalancer(
|
||||
self,
|
||||
loadbalancer_id: str,
|
||||
name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
admin_state_up: Optional[bool] = None,
|
||||
) -> dict:
|
||||
"""
|
||||
로드밸런서 수정
|
||||
|
||||
Args:
|
||||
loadbalancer_id: 로드밸런서 ID
|
||||
name: 변경할 이름
|
||||
description: 변경할 설명
|
||||
admin_state_up: 관리자 상태
|
||||
"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/loadbalancers/{loadbalancer_id}"
|
||||
payload = {"loadbalancer": {}}
|
||||
if name is not None:
|
||||
payload["loadbalancer"]["name"] = name
|
||||
if description is not None:
|
||||
payload["loadbalancer"]["description"] = description
|
||||
if admin_state_up is not None:
|
||||
payload["loadbalancer"]["admin_state_up"] = admin_state_up
|
||||
|
||||
logger.info(f"[NHN API] 로드밸런서 수정 요청 - loadbalancer_id={loadbalancer_id}")
|
||||
return self._put(url, payload)
|
||||
|
||||
def delete_loadbalancer(self, loadbalancer_id: str) -> dict:
|
||||
"""로드밸런서 삭제"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/loadbalancers/{loadbalancer_id}"
|
||||
logger.info(f"[NHN API] 로드밸런서 삭제 요청 - loadbalancer_id={loadbalancer_id}")
|
||||
return self._delete(url)
|
||||
|
||||
# ==================== Listener ====================
|
||||
|
||||
def get_listener_list(
|
||||
self,
|
||||
loadbalancer_id: Optional[str] = None,
|
||||
protocol: Optional[str] = None,
|
||||
protocol_port: Optional[int] = None,
|
||||
) -> dict:
|
||||
"""
|
||||
리스너 목록 조회
|
||||
|
||||
Args:
|
||||
loadbalancer_id: 로드밸런서 ID로 필터링
|
||||
protocol: 프로토콜로 필터링 (TCP, HTTP, HTTPS, TERMINATED_HTTPS)
|
||||
protocol_port: 포트 번호로 필터링
|
||||
"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/listeners"
|
||||
params = {}
|
||||
if loadbalancer_id:
|
||||
params["loadbalancer_id"] = loadbalancer_id
|
||||
if protocol:
|
||||
params["protocol"] = protocol
|
||||
if protocol_port:
|
||||
params["protocol_port"] = protocol_port
|
||||
|
||||
logger.info(f"[NHN API] 리스너 목록 조회 요청")
|
||||
result = self._get(url, params=params if params else None)
|
||||
listener_count = len(result.get("listeners", []))
|
||||
logger.info(f"[NHN API] 리스너 목록 조회 완료 - count={listener_count}")
|
||||
return result
|
||||
|
||||
def get_listener_info(self, listener_id: str) -> dict:
|
||||
"""리스너 상세 조회"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/listeners/{listener_id}"
|
||||
logger.info(f"[NHN API] 리스너 상세 조회 요청 - listener_id={listener_id}")
|
||||
return self._get(url)
|
||||
|
||||
def create_listener(
|
||||
self,
|
||||
loadbalancer_id: str,
|
||||
protocol: str,
|
||||
protocol_port: int,
|
||||
name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
default_pool_id: Optional[str] = None,
|
||||
connection_limit: int = -1,
|
||||
keepalive_timeout: int = 300,
|
||||
admin_state_up: bool = True,
|
||||
default_tls_container_ref: Optional[str] = None,
|
||||
sni_container_refs: Optional[List[str]] = None,
|
||||
insert_headers: Optional[dict] = None,
|
||||
) -> dict:
|
||||
"""
|
||||
리스너 생성
|
||||
|
||||
Args:
|
||||
loadbalancer_id: 로드밸런서 ID (필수)
|
||||
protocol: 프로토콜 (TCP, HTTP, HTTPS, TERMINATED_HTTPS)
|
||||
protocol_port: 포트 번호 (1-65535)
|
||||
name: 리스너 이름
|
||||
description: 설명
|
||||
default_pool_id: 기본 풀 ID
|
||||
connection_limit: 연결 제한 (-1: 무제한)
|
||||
keepalive_timeout: Keepalive 타임아웃 (초)
|
||||
admin_state_up: 관리자 상태
|
||||
default_tls_container_ref: TLS 인증서 컨테이너 참조 (TERMINATED_HTTPS 사용 시)
|
||||
sni_container_refs: SNI 인증서 컨테이너 참조 목록
|
||||
insert_headers: 삽입할 헤더 (X-Forwarded-For, X-Forwarded-Port 등)
|
||||
"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/listeners"
|
||||
payload = {
|
||||
"listener": {
|
||||
"loadbalancer_id": loadbalancer_id,
|
||||
"protocol": protocol,
|
||||
"protocol_port": protocol_port,
|
||||
"connection_limit": connection_limit,
|
||||
"keepalive_timeout": keepalive_timeout,
|
||||
"admin_state_up": admin_state_up,
|
||||
}
|
||||
}
|
||||
if name:
|
||||
payload["listener"]["name"] = name
|
||||
if description:
|
||||
payload["listener"]["description"] = description
|
||||
if default_pool_id:
|
||||
payload["listener"]["default_pool_id"] = default_pool_id
|
||||
if default_tls_container_ref:
|
||||
payload["listener"]["default_tls_container_ref"] = default_tls_container_ref
|
||||
if sni_container_refs:
|
||||
payload["listener"]["sni_container_refs"] = sni_container_refs
|
||||
if insert_headers:
|
||||
payload["listener"]["insert_headers"] = insert_headers
|
||||
|
||||
logger.info(f"[NHN API] 리스너 생성 요청 - protocol={protocol}, port={protocol_port}")
|
||||
return self._post(url, payload)
|
||||
|
||||
def update_listener(
|
||||
self,
|
||||
listener_id: str,
|
||||
name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
default_pool_id: Optional[str] = None,
|
||||
connection_limit: Optional[int] = None,
|
||||
keepalive_timeout: Optional[int] = None,
|
||||
admin_state_up: Optional[bool] = None,
|
||||
default_tls_container_ref: Optional[str] = None,
|
||||
sni_container_refs: Optional[List[str]] = None,
|
||||
insert_headers: Optional[dict] = None,
|
||||
) -> dict:
|
||||
"""리스너 수정"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/listeners/{listener_id}"
|
||||
payload = {"listener": {}}
|
||||
if name is not None:
|
||||
payload["listener"]["name"] = name
|
||||
if description is not None:
|
||||
payload["listener"]["description"] = description
|
||||
if default_pool_id is not None:
|
||||
payload["listener"]["default_pool_id"] = default_pool_id
|
||||
if connection_limit is not None:
|
||||
payload["listener"]["connection_limit"] = connection_limit
|
||||
if keepalive_timeout is not None:
|
||||
payload["listener"]["keepalive_timeout"] = keepalive_timeout
|
||||
if admin_state_up is not None:
|
||||
payload["listener"]["admin_state_up"] = admin_state_up
|
||||
if default_tls_container_ref is not None:
|
||||
payload["listener"]["default_tls_container_ref"] = default_tls_container_ref
|
||||
if sni_container_refs is not None:
|
||||
payload["listener"]["sni_container_refs"] = sni_container_refs
|
||||
if insert_headers is not None:
|
||||
payload["listener"]["insert_headers"] = insert_headers
|
||||
|
||||
logger.info(f"[NHN API] 리스너 수정 요청 - listener_id={listener_id}")
|
||||
return self._put(url, payload)
|
||||
|
||||
def delete_listener(self, listener_id: str) -> dict:
|
||||
"""리스너 삭제"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/listeners/{listener_id}"
|
||||
logger.info(f"[NHN API] 리스너 삭제 요청 - listener_id={listener_id}")
|
||||
return self._delete(url)
|
||||
|
||||
# ==================== Pool ====================
|
||||
|
||||
def get_pool_list(
|
||||
self,
|
||||
loadbalancer_id: Optional[str] = None,
|
||||
protocol: Optional[str] = None,
|
||||
lb_algorithm: Optional[str] = None,
|
||||
) -> dict:
|
||||
"""
|
||||
풀 목록 조회
|
||||
|
||||
Args:
|
||||
loadbalancer_id: 로드밸런서 ID로 필터링
|
||||
protocol: 프로토콜로 필터링
|
||||
lb_algorithm: 로드밸런싱 알고리즘으로 필터링
|
||||
"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/pools"
|
||||
params = {}
|
||||
if loadbalancer_id:
|
||||
params["loadbalancer_id"] = loadbalancer_id
|
||||
if protocol:
|
||||
params["protocol"] = protocol
|
||||
if lb_algorithm:
|
||||
params["lb_algorithm"] = lb_algorithm
|
||||
|
||||
logger.info(f"[NHN API] 풀 목록 조회 요청")
|
||||
result = self._get(url, params=params if params else None)
|
||||
pool_count = len(result.get("pools", []))
|
||||
logger.info(f"[NHN API] 풀 목록 조회 완료 - count={pool_count}")
|
||||
return result
|
||||
|
||||
def get_pool_info(self, pool_id: str) -> dict:
|
||||
"""풀 상세 조회"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/pools/{pool_id}"
|
||||
logger.info(f"[NHN API] 풀 상세 조회 요청 - pool_id={pool_id}")
|
||||
return self._get(url)
|
||||
|
||||
def create_pool(
|
||||
self,
|
||||
lb_algorithm: str,
|
||||
protocol: str,
|
||||
loadbalancer_id: Optional[str] = None,
|
||||
listener_id: Optional[str] = None,
|
||||
name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
admin_state_up: bool = True,
|
||||
session_persistence: Optional[dict] = None,
|
||||
) -> dict:
|
||||
"""
|
||||
풀 생성
|
||||
|
||||
Args:
|
||||
lb_algorithm: 로드밸런싱 알고리즘 (ROUND_ROBIN, LEAST_CONNECTIONS, SOURCE_IP)
|
||||
protocol: 프로토콜 (TCP, HTTP, HTTPS, PROXY)
|
||||
loadbalancer_id: 로드밸런서 ID (listener_id와 둘 중 하나 필수)
|
||||
listener_id: 리스너 ID (loadbalancer_id와 둘 중 하나 필수)
|
||||
name: 풀 이름
|
||||
description: 설명
|
||||
admin_state_up: 관리자 상태
|
||||
session_persistence: 세션 지속성 설정 {type, cookie_name}
|
||||
- type: SOURCE_IP, HTTP_COOKIE, APP_COOKIE
|
||||
- cookie_name: APP_COOKIE 타입 사용 시 쿠키 이름
|
||||
"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/pools"
|
||||
payload = {
|
||||
"pool": {
|
||||
"lb_algorithm": lb_algorithm,
|
||||
"protocol": protocol,
|
||||
"admin_state_up": admin_state_up,
|
||||
}
|
||||
}
|
||||
if loadbalancer_id:
|
||||
payload["pool"]["loadbalancer_id"] = loadbalancer_id
|
||||
if listener_id:
|
||||
payload["pool"]["listener_id"] = listener_id
|
||||
if name:
|
||||
payload["pool"]["name"] = name
|
||||
if description:
|
||||
payload["pool"]["description"] = description
|
||||
if session_persistence:
|
||||
payload["pool"]["session_persistence"] = session_persistence
|
||||
|
||||
logger.info(f"[NHN API] 풀 생성 요청 - algorithm={lb_algorithm}, protocol={protocol}")
|
||||
return self._post(url, payload)
|
||||
|
||||
def update_pool(
|
||||
self,
|
||||
pool_id: str,
|
||||
name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
lb_algorithm: Optional[str] = None,
|
||||
admin_state_up: Optional[bool] = None,
|
||||
session_persistence: Optional[dict] = None,
|
||||
) -> dict:
|
||||
"""풀 수정"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/pools/{pool_id}"
|
||||
payload = {"pool": {}}
|
||||
if name is not None:
|
||||
payload["pool"]["name"] = name
|
||||
if description is not None:
|
||||
payload["pool"]["description"] = description
|
||||
if lb_algorithm is not None:
|
||||
payload["pool"]["lb_algorithm"] = lb_algorithm
|
||||
if admin_state_up is not None:
|
||||
payload["pool"]["admin_state_up"] = admin_state_up
|
||||
if session_persistence is not None:
|
||||
payload["pool"]["session_persistence"] = session_persistence
|
||||
|
||||
logger.info(f"[NHN API] 풀 수정 요청 - pool_id={pool_id}")
|
||||
return self._put(url, payload)
|
||||
|
||||
def delete_pool(self, pool_id: str) -> dict:
|
||||
"""풀 삭제"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/pools/{pool_id}"
|
||||
logger.info(f"[NHN API] 풀 삭제 요청 - pool_id={pool_id}")
|
||||
return self._delete(url)
|
||||
|
||||
# ==================== Member ====================
|
||||
|
||||
def get_member_list(self, pool_id: str) -> dict:
|
||||
"""풀의 멤버 목록 조회"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/pools/{pool_id}/members"
|
||||
logger.info(f"[NHN API] 멤버 목록 조회 요청 - pool_id={pool_id}")
|
||||
result = self._get(url)
|
||||
member_count = len(result.get("members", []))
|
||||
logger.info(f"[NHN API] 멤버 목록 조회 완료 - count={member_count}")
|
||||
return result
|
||||
|
||||
def get_member_info(self, pool_id: str, member_id: str) -> dict:
|
||||
"""멤버 상세 조회"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/pools/{pool_id}/members/{member_id}"
|
||||
logger.info(f"[NHN API] 멤버 상세 조회 요청 - pool_id={pool_id}, member_id={member_id}")
|
||||
return self._get(url)
|
||||
|
||||
def create_member(
|
||||
self,
|
||||
pool_id: str,
|
||||
address: str,
|
||||
protocol_port: int,
|
||||
subnet_id: Optional[str] = None,
|
||||
weight: int = 1,
|
||||
admin_state_up: bool = True,
|
||||
) -> dict:
|
||||
"""
|
||||
멤버 추가
|
||||
|
||||
Args:
|
||||
pool_id: 풀 ID
|
||||
address: 멤버 IP 주소
|
||||
protocol_port: 멤버 포트 번호
|
||||
subnet_id: 멤버가 속한 서브넷 ID
|
||||
weight: 가중치 (1-256)
|
||||
admin_state_up: 관리자 상태
|
||||
"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/pools/{pool_id}/members"
|
||||
payload = {
|
||||
"member": {
|
||||
"address": address,
|
||||
"protocol_port": protocol_port,
|
||||
"weight": weight,
|
||||
"admin_state_up": admin_state_up,
|
||||
}
|
||||
}
|
||||
if subnet_id:
|
||||
payload["member"]["subnet_id"] = subnet_id
|
||||
|
||||
logger.info(f"[NHN API] 멤버 추가 요청 - pool_id={pool_id}, address={address}:{protocol_port}")
|
||||
return self._post(url, payload)
|
||||
|
||||
def update_member(
|
||||
self,
|
||||
pool_id: str,
|
||||
member_id: str,
|
||||
weight: Optional[int] = None,
|
||||
admin_state_up: Optional[bool] = None,
|
||||
) -> dict:
|
||||
"""멤버 수정"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/pools/{pool_id}/members/{member_id}"
|
||||
payload = {"member": {}}
|
||||
if weight is not None:
|
||||
payload["member"]["weight"] = weight
|
||||
if admin_state_up is not None:
|
||||
payload["member"]["admin_state_up"] = admin_state_up
|
||||
|
||||
logger.info(f"[NHN API] 멤버 수정 요청 - pool_id={pool_id}, member_id={member_id}")
|
||||
return self._put(url, payload)
|
||||
|
||||
def delete_member(self, pool_id: str, member_id: str) -> dict:
|
||||
"""멤버 삭제"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/pools/{pool_id}/members/{member_id}"
|
||||
logger.info(f"[NHN API] 멤버 삭제 요청 - pool_id={pool_id}, member_id={member_id}")
|
||||
return self._delete(url)
|
||||
|
||||
# ==================== Health Monitor ====================
|
||||
|
||||
def get_healthmonitor_list(self, pool_id: Optional[str] = None) -> dict:
|
||||
"""헬스 모니터 목록 조회"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/healthmonitors"
|
||||
params = {}
|
||||
if pool_id:
|
||||
params["pool_id"] = pool_id
|
||||
|
||||
logger.info(f"[NHN API] 헬스 모니터 목록 조회 요청")
|
||||
result = self._get(url, params=params if params else None)
|
||||
hm_count = len(result.get("healthmonitors", []))
|
||||
logger.info(f"[NHN API] 헬스 모니터 목록 조회 완료 - count={hm_count}")
|
||||
return result
|
||||
|
||||
def get_healthmonitor_info(self, healthmonitor_id: str) -> dict:
|
||||
"""헬스 모니터 상세 조회"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/healthmonitors/{healthmonitor_id}"
|
||||
logger.info(f"[NHN API] 헬스 모니터 상세 조회 요청 - healthmonitor_id={healthmonitor_id}")
|
||||
return self._get(url)
|
||||
|
||||
def create_healthmonitor(
|
||||
self,
|
||||
pool_id: str,
|
||||
type: str,
|
||||
delay: int,
|
||||
timeout: int,
|
||||
max_retries: int,
|
||||
max_retries_down: int = 3,
|
||||
http_method: str = "GET",
|
||||
url_path: str = "/",
|
||||
expected_codes: str = "200",
|
||||
admin_state_up: bool = True,
|
||||
host_header: Optional[str] = None,
|
||||
) -> dict:
|
||||
"""
|
||||
헬스 모니터 생성
|
||||
|
||||
Args:
|
||||
pool_id: 풀 ID
|
||||
type: 헬스 체크 타입 (TCP, HTTP, HTTPS)
|
||||
delay: 헬스 체크 간격 (초)
|
||||
timeout: 응답 대기 시간 (초)
|
||||
max_retries: 최대 재시도 횟수 (정상 판정)
|
||||
max_retries_down: 최대 재시도 횟수 (비정상 판정)
|
||||
http_method: HTTP 메서드 (HTTP/HTTPS 타입 시)
|
||||
url_path: URL 경로 (HTTP/HTTPS 타입 시)
|
||||
expected_codes: 예상 응답 코드 (예: "200", "200,201", "200-204")
|
||||
admin_state_up: 관리자 상태
|
||||
host_header: Host 헤더 값
|
||||
"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/healthmonitors"
|
||||
payload = {
|
||||
"healthmonitor": {
|
||||
"pool_id": pool_id,
|
||||
"type": type,
|
||||
"delay": delay,
|
||||
"timeout": timeout,
|
||||
"max_retries": max_retries,
|
||||
"max_retries_down": max_retries_down,
|
||||
"admin_state_up": admin_state_up,
|
||||
}
|
||||
}
|
||||
# HTTP/HTTPS 전용 옵션
|
||||
if type in ["HTTP", "HTTPS"]:
|
||||
payload["healthmonitor"]["http_method"] = http_method
|
||||
payload["healthmonitor"]["url_path"] = url_path
|
||||
payload["healthmonitor"]["expected_codes"] = expected_codes
|
||||
if host_header:
|
||||
payload["healthmonitor"]["host_header"] = host_header
|
||||
|
||||
logger.info(f"[NHN API] 헬스 모니터 생성 요청 - pool_id={pool_id}, type={type}")
|
||||
return self._post(url, payload)
|
||||
|
||||
def update_healthmonitor(
|
||||
self,
|
||||
healthmonitor_id: str,
|
||||
delay: Optional[int] = None,
|
||||
timeout: Optional[int] = None,
|
||||
max_retries: Optional[int] = None,
|
||||
max_retries_down: Optional[int] = None,
|
||||
http_method: Optional[str] = None,
|
||||
url_path: Optional[str] = None,
|
||||
expected_codes: Optional[str] = None,
|
||||
admin_state_up: Optional[bool] = None,
|
||||
host_header: Optional[str] = None,
|
||||
) -> dict:
|
||||
"""헬스 모니터 수정"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/healthmonitors/{healthmonitor_id}"
|
||||
payload = {"healthmonitor": {}}
|
||||
if delay is not None:
|
||||
payload["healthmonitor"]["delay"] = delay
|
||||
if timeout is not None:
|
||||
payload["healthmonitor"]["timeout"] = timeout
|
||||
if max_retries is not None:
|
||||
payload["healthmonitor"]["max_retries"] = max_retries
|
||||
if max_retries_down is not None:
|
||||
payload["healthmonitor"]["max_retries_down"] = max_retries_down
|
||||
if http_method is not None:
|
||||
payload["healthmonitor"]["http_method"] = http_method
|
||||
if url_path is not None:
|
||||
payload["healthmonitor"]["url_path"] = url_path
|
||||
if expected_codes is not None:
|
||||
payload["healthmonitor"]["expected_codes"] = expected_codes
|
||||
if admin_state_up is not None:
|
||||
payload["healthmonitor"]["admin_state_up"] = admin_state_up
|
||||
if host_header is not None:
|
||||
payload["healthmonitor"]["host_header"] = host_header
|
||||
|
||||
logger.info(f"[NHN API] 헬스 모니터 수정 요청 - healthmonitor_id={healthmonitor_id}")
|
||||
return self._put(url, payload)
|
||||
|
||||
def delete_healthmonitor(self, healthmonitor_id: str) -> dict:
|
||||
"""헬스 모니터 삭제"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/healthmonitors/{healthmonitor_id}"
|
||||
logger.info(f"[NHN API] 헬스 모니터 삭제 요청 - healthmonitor_id={healthmonitor_id}")
|
||||
return self._delete(url)
|
||||
|
||||
# ==================== L7 Policy ====================
|
||||
|
||||
def get_l7policy_list(self, listener_id: Optional[str] = None) -> dict:
|
||||
"""L7 정책 목록 조회"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/l7policies"
|
||||
params = {}
|
||||
if listener_id:
|
||||
params["listener_id"] = listener_id
|
||||
|
||||
logger.info(f"[NHN API] L7 정책 목록 조회 요청")
|
||||
result = self._get(url, params=params if params else None)
|
||||
policy_count = len(result.get("l7policies", []))
|
||||
logger.info(f"[NHN API] L7 정책 목록 조회 완료 - count={policy_count}")
|
||||
return result
|
||||
|
||||
def get_l7policy_info(self, l7policy_id: str) -> dict:
|
||||
"""L7 정책 상세 조회"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/l7policies/{l7policy_id}"
|
||||
logger.info(f"[NHN API] L7 정책 상세 조회 요청 - l7policy_id={l7policy_id}")
|
||||
return self._get(url)
|
||||
|
||||
def create_l7policy(
|
||||
self,
|
||||
listener_id: str,
|
||||
action: str,
|
||||
position: int = 1,
|
||||
name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
redirect_pool_id: Optional[str] = None,
|
||||
redirect_url: Optional[str] = None,
|
||||
admin_state_up: bool = True,
|
||||
) -> dict:
|
||||
"""
|
||||
L7 정책 생성
|
||||
|
||||
Args:
|
||||
listener_id: 리스너 ID
|
||||
action: 액션 (REDIRECT_TO_POOL, REDIRECT_TO_URL, REJECT)
|
||||
position: 정책 우선순위 (낮을수록 먼저 적용)
|
||||
name: 정책 이름
|
||||
description: 설명
|
||||
redirect_pool_id: 리다이렉트 대상 풀 ID (REDIRECT_TO_POOL 액션 시)
|
||||
redirect_url: 리다이렉트 URL (REDIRECT_TO_URL 액션 시)
|
||||
admin_state_up: 관리자 상태
|
||||
"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/l7policies"
|
||||
payload = {
|
||||
"l7policy": {
|
||||
"listener_id": listener_id,
|
||||
"action": action,
|
||||
"position": position,
|
||||
"admin_state_up": admin_state_up,
|
||||
}
|
||||
}
|
||||
if name:
|
||||
payload["l7policy"]["name"] = name
|
||||
if description:
|
||||
payload["l7policy"]["description"] = description
|
||||
if redirect_pool_id:
|
||||
payload["l7policy"]["redirect_pool_id"] = redirect_pool_id
|
||||
if redirect_url:
|
||||
payload["l7policy"]["redirect_url"] = redirect_url
|
||||
|
||||
logger.info(f"[NHN API] L7 정책 생성 요청 - listener_id={listener_id}, action={action}")
|
||||
return self._post(url, payload)
|
||||
|
||||
def update_l7policy(
|
||||
self,
|
||||
l7policy_id: str,
|
||||
name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
action: Optional[str] = None,
|
||||
position: Optional[int] = None,
|
||||
redirect_pool_id: Optional[str] = None,
|
||||
redirect_url: Optional[str] = None,
|
||||
admin_state_up: Optional[bool] = None,
|
||||
) -> dict:
|
||||
"""L7 정책 수정"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/l7policies/{l7policy_id}"
|
||||
payload = {"l7policy": {}}
|
||||
if name is not None:
|
||||
payload["l7policy"]["name"] = name
|
||||
if description is not None:
|
||||
payload["l7policy"]["description"] = description
|
||||
if action is not None:
|
||||
payload["l7policy"]["action"] = action
|
||||
if position is not None:
|
||||
payload["l7policy"]["position"] = position
|
||||
if redirect_pool_id is not None:
|
||||
payload["l7policy"]["redirect_pool_id"] = redirect_pool_id
|
||||
if redirect_url is not None:
|
||||
payload["l7policy"]["redirect_url"] = redirect_url
|
||||
if admin_state_up is not None:
|
||||
payload["l7policy"]["admin_state_up"] = admin_state_up
|
||||
|
||||
logger.info(f"[NHN API] L7 정책 수정 요청 - l7policy_id={l7policy_id}")
|
||||
return self._put(url, payload)
|
||||
|
||||
def delete_l7policy(self, l7policy_id: str) -> dict:
|
||||
"""L7 정책 삭제"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/l7policies/{l7policy_id}"
|
||||
logger.info(f"[NHN API] L7 정책 삭제 요청 - l7policy_id={l7policy_id}")
|
||||
return self._delete(url)
|
||||
|
||||
# ==================== L7 Rule ====================
|
||||
|
||||
def get_l7rule_list(self, l7policy_id: str) -> dict:
|
||||
"""L7 룰 목록 조회"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/l7policies/{l7policy_id}/rules"
|
||||
logger.info(f"[NHN API] L7 룰 목록 조회 요청 - l7policy_id={l7policy_id}")
|
||||
result = self._get(url)
|
||||
rule_count = len(result.get("rules", []))
|
||||
logger.info(f"[NHN API] L7 룰 목록 조회 완료 - count={rule_count}")
|
||||
return result
|
||||
|
||||
def get_l7rule_info(self, l7policy_id: str, l7rule_id: str) -> dict:
|
||||
"""L7 룰 상세 조회"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/l7policies/{l7policy_id}/rules/{l7rule_id}"
|
||||
logger.info(f"[NHN API] L7 룰 상세 조회 요청 - l7policy_id={l7policy_id}, l7rule_id={l7rule_id}")
|
||||
return self._get(url)
|
||||
|
||||
def create_l7rule(
|
||||
self,
|
||||
l7policy_id: str,
|
||||
type: str,
|
||||
compare_type: str,
|
||||
value: str,
|
||||
key: Optional[str] = None,
|
||||
invert: bool = False,
|
||||
admin_state_up: bool = True,
|
||||
) -> dict:
|
||||
"""
|
||||
L7 룰 생성
|
||||
|
||||
Args:
|
||||
l7policy_id: L7 정책 ID
|
||||
type: 룰 타입 (COOKIE, FILE_TYPE, HEADER, HOST_NAME, PATH)
|
||||
compare_type: 비교 방식 (CONTAINS, ENDS_WITH, STARTS_WITH, EQUAL_TO, REGEX)
|
||||
value: 비교할 값
|
||||
key: 키 값 (COOKIE, HEADER 타입 사용 시)
|
||||
invert: 조건 반전 여부
|
||||
admin_state_up: 관리자 상태
|
||||
"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/l7policies/{l7policy_id}/rules"
|
||||
payload = {
|
||||
"rule": {
|
||||
"type": type,
|
||||
"compare_type": compare_type,
|
||||
"value": value,
|
||||
"invert": invert,
|
||||
"admin_state_up": admin_state_up,
|
||||
}
|
||||
}
|
||||
if key:
|
||||
payload["rule"]["key"] = key
|
||||
|
||||
logger.info(f"[NHN API] L7 룰 생성 요청 - l7policy_id={l7policy_id}, type={type}")
|
||||
return self._post(url, payload)
|
||||
|
||||
def update_l7rule(
|
||||
self,
|
||||
l7policy_id: str,
|
||||
l7rule_id: str,
|
||||
type: Optional[str] = None,
|
||||
compare_type: Optional[str] = None,
|
||||
value: Optional[str] = None,
|
||||
key: Optional[str] = None,
|
||||
invert: Optional[bool] = None,
|
||||
admin_state_up: Optional[bool] = None,
|
||||
) -> dict:
|
||||
"""L7 룰 수정"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/l7policies/{l7policy_id}/rules/{l7rule_id}"
|
||||
payload = {"rule": {}}
|
||||
if type is not None:
|
||||
payload["rule"]["type"] = type
|
||||
if compare_type is not None:
|
||||
payload["rule"]["compare_type"] = compare_type
|
||||
if value is not None:
|
||||
payload["rule"]["value"] = value
|
||||
if key is not None:
|
||||
payload["rule"]["key"] = key
|
||||
if invert is not None:
|
||||
payload["rule"]["invert"] = invert
|
||||
if admin_state_up is not None:
|
||||
payload["rule"]["admin_state_up"] = admin_state_up
|
||||
|
||||
logger.info(f"[NHN API] L7 룰 수정 요청 - l7policy_id={l7policy_id}, l7rule_id={l7rule_id}")
|
||||
return self._put(url, payload)
|
||||
|
||||
def delete_l7rule(self, l7policy_id: str, l7rule_id: str) -> dict:
|
||||
"""L7 룰 삭제"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/l7policies/{l7policy_id}/rules/{l7rule_id}"
|
||||
logger.info(f"[NHN API] L7 룰 삭제 요청 - l7policy_id={l7policy_id}, l7rule_id={l7rule_id}")
|
||||
return self._delete(url)
|
||||
|
||||
# ==================== IP ACL Group ====================
|
||||
|
||||
def get_ipacl_group_list(self) -> dict:
|
||||
"""IP ACL 그룹 목록 조회"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/ipacl-groups"
|
||||
logger.info(f"[NHN API] IP ACL 그룹 목록 조회 요청")
|
||||
result = self._get(url)
|
||||
group_count = len(result.get("ipacl_groups", []))
|
||||
logger.info(f"[NHN API] IP ACL 그룹 목록 조회 완료 - count={group_count}")
|
||||
return result
|
||||
|
||||
def get_ipacl_group_info(self, ipacl_group_id: str) -> dict:
|
||||
"""IP ACL 그룹 상세 조회"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/ipacl-groups/{ipacl_group_id}"
|
||||
logger.info(f"[NHN API] IP ACL 그룹 상세 조회 요청 - ipacl_group_id={ipacl_group_id}")
|
||||
return self._get(url)
|
||||
|
||||
def create_ipacl_group(
|
||||
self,
|
||||
action: str,
|
||||
name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
ipacl_targets: Optional[List[dict]] = None,
|
||||
loadbalancers: Optional[List[str]] = None,
|
||||
) -> dict:
|
||||
"""
|
||||
IP ACL 그룹 생성
|
||||
|
||||
Args:
|
||||
action: 액션 (ALLOW 또는 DENY)
|
||||
name: 그룹 이름
|
||||
description: 설명
|
||||
ipacl_targets: IP ACL 타깃 목록 [{ip_address, description}]
|
||||
loadbalancers: 적용할 로드밸런서 ID 목록
|
||||
"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/ipacl-groups"
|
||||
payload = {
|
||||
"ipacl_group": {
|
||||
"action": action,
|
||||
}
|
||||
}
|
||||
if name:
|
||||
payload["ipacl_group"]["name"] = name
|
||||
if description:
|
||||
payload["ipacl_group"]["description"] = description
|
||||
if ipacl_targets:
|
||||
payload["ipacl_group"]["ipacl_targets"] = ipacl_targets
|
||||
if loadbalancers:
|
||||
payload["ipacl_group"]["loadbalancers"] = [{"loadbalancer_id": lb_id} for lb_id in loadbalancers]
|
||||
|
||||
logger.info(f"[NHN API] IP ACL 그룹 생성 요청 - action={action}")
|
||||
return self._post(url, payload)
|
||||
|
||||
def update_ipacl_group(
|
||||
self,
|
||||
ipacl_group_id: str,
|
||||
name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
loadbalancers: Optional[List[str]] = None,
|
||||
) -> dict:
|
||||
"""IP ACL 그룹 수정"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/ipacl-groups/{ipacl_group_id}"
|
||||
payload = {"ipacl_group": {}}
|
||||
if name is not None:
|
||||
payload["ipacl_group"]["name"] = name
|
||||
if description is not None:
|
||||
payload["ipacl_group"]["description"] = description
|
||||
if loadbalancers is not None:
|
||||
payload["ipacl_group"]["loadbalancers"] = [{"loadbalancer_id": lb_id} for lb_id in loadbalancers]
|
||||
|
||||
logger.info(f"[NHN API] IP ACL 그룹 수정 요청 - ipacl_group_id={ipacl_group_id}")
|
||||
return self._put(url, payload)
|
||||
|
||||
def delete_ipacl_group(self, ipacl_group_id: str) -> dict:
|
||||
"""IP ACL 그룹 삭제"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/ipacl-groups/{ipacl_group_id}"
|
||||
logger.info(f"[NHN API] IP ACL 그룹 삭제 요청 - ipacl_group_id={ipacl_group_id}")
|
||||
return self._delete(url)
|
||||
|
||||
# ==================== IP ACL Target ====================
|
||||
|
||||
def create_ipacl_target(
|
||||
self,
|
||||
ipacl_group_id: str,
|
||||
ip_address: str,
|
||||
description: Optional[str] = None,
|
||||
) -> dict:
|
||||
"""
|
||||
IP ACL 타깃 추가
|
||||
|
||||
Args:
|
||||
ipacl_group_id: IP ACL 그룹 ID
|
||||
ip_address: IP 주소 또는 CIDR (예: 10.0.0.1, 10.0.0.0/24)
|
||||
description: 설명
|
||||
"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/ipacl-targets"
|
||||
payload = {
|
||||
"ipacl_target": {
|
||||
"ipacl_group_id": ipacl_group_id,
|
||||
"ip_address": ip_address,
|
||||
}
|
||||
}
|
||||
if description:
|
||||
payload["ipacl_target"]["description"] = description
|
||||
|
||||
logger.info(f"[NHN API] IP ACL 타깃 추가 요청 - ipacl_group_id={ipacl_group_id}, ip_address={ip_address}")
|
||||
return self._post(url, payload)
|
||||
|
||||
def update_ipacl_target(
|
||||
self,
|
||||
ipacl_target_id: str,
|
||||
description: str,
|
||||
) -> dict:
|
||||
"""IP ACL 타깃 수정 (설명만 수정 가능)"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/ipacl-targets/{ipacl_target_id}"
|
||||
payload = {
|
||||
"ipacl_target": {
|
||||
"description": description,
|
||||
}
|
||||
}
|
||||
logger.info(f"[NHN API] IP ACL 타깃 수정 요청 - ipacl_target_id={ipacl_target_id}")
|
||||
return self._put(url, payload)
|
||||
|
||||
def delete_ipacl_target(self, ipacl_target_id: str) -> dict:
|
||||
"""IP ACL 타깃 삭제"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/ipacl-targets/{ipacl_target_id}"
|
||||
logger.info(f"[NHN API] IP ACL 타깃 삭제 요청 - ipacl_target_id={ipacl_target_id}")
|
||||
return self._delete(url)
|
||||
|
||||
# ==================== Quota ====================
|
||||
|
||||
def get_quota(self) -> dict:
|
||||
"""로드밸런서 쿼타 조회"""
|
||||
url = f"{self.lb_url}/v2.0/lbaas/quotas/default"
|
||||
logger.info(f"[NHN API] 로드밸런서 쿼타 조회 요청")
|
||||
return self._get(url)
|
||||
@ -644,3 +644,574 @@ class DnsIdListSerializer(serializers.Serializer):
|
||||
help_text="ID 목록",
|
||||
min_length=1,
|
||||
)
|
||||
|
||||
|
||||
# ==================== Load Balancer ====================
|
||||
|
||||
|
||||
class LoadBalancerSerializer(serializers.Serializer):
|
||||
"""로드밸런서 생성 요청"""
|
||||
|
||||
vip_subnet_id = serializers.CharField(
|
||||
help_text="VIP가 할당될 서브넷 ID (필수)",
|
||||
)
|
||||
name = serializers.CharField(
|
||||
help_text="로드밸런서 이름",
|
||||
required=False,
|
||||
max_length=255,
|
||||
)
|
||||
description = serializers.CharField(
|
||||
help_text="설명",
|
||||
required=False,
|
||||
allow_blank=True,
|
||||
)
|
||||
vip_address = serializers.CharField(
|
||||
help_text="VIP 주소 (지정하지 않으면 자동 할당)",
|
||||
required=False,
|
||||
)
|
||||
admin_state_up = serializers.BooleanField(
|
||||
help_text="관리자 상태",
|
||||
default=True,
|
||||
)
|
||||
loadbalancer_type = serializers.ChoiceField(
|
||||
choices=["shared", "dedicated"],
|
||||
help_text="로드밸런서 타입 (shared: 공유형, dedicated: 전용형)",
|
||||
default="shared",
|
||||
)
|
||||
|
||||
|
||||
class LoadBalancerUpdateSerializer(serializers.Serializer):
|
||||
"""로드밸런서 수정 요청"""
|
||||
|
||||
name = serializers.CharField(
|
||||
help_text="로드밸런서 이름",
|
||||
required=False,
|
||||
max_length=255,
|
||||
)
|
||||
description = serializers.CharField(
|
||||
help_text="설명",
|
||||
required=False,
|
||||
allow_blank=True,
|
||||
)
|
||||
admin_state_up = serializers.BooleanField(
|
||||
help_text="관리자 상태",
|
||||
required=False,
|
||||
)
|
||||
|
||||
|
||||
class LBListenerSerializer(serializers.Serializer):
|
||||
"""리스너 생성 요청"""
|
||||
|
||||
loadbalancer_id = serializers.CharField(
|
||||
help_text="로드밸런서 ID",
|
||||
)
|
||||
protocol = serializers.ChoiceField(
|
||||
choices=["TCP", "HTTP", "HTTPS", "TERMINATED_HTTPS"],
|
||||
help_text="프로토콜",
|
||||
)
|
||||
protocol_port = serializers.IntegerField(
|
||||
help_text="포트 번호 (1-65535)",
|
||||
min_value=1,
|
||||
max_value=65535,
|
||||
)
|
||||
name = serializers.CharField(
|
||||
help_text="리스너 이름",
|
||||
required=False,
|
||||
max_length=255,
|
||||
)
|
||||
description = serializers.CharField(
|
||||
help_text="설명",
|
||||
required=False,
|
||||
allow_blank=True,
|
||||
)
|
||||
default_pool_id = serializers.CharField(
|
||||
help_text="기본 풀 ID",
|
||||
required=False,
|
||||
)
|
||||
connection_limit = serializers.IntegerField(
|
||||
help_text="연결 제한 (-1: 무제한)",
|
||||
default=-1,
|
||||
)
|
||||
keepalive_timeout = serializers.IntegerField(
|
||||
help_text="Keepalive 타임아웃 (초)",
|
||||
default=300,
|
||||
)
|
||||
admin_state_up = serializers.BooleanField(
|
||||
help_text="관리자 상태",
|
||||
default=True,
|
||||
)
|
||||
default_tls_container_ref = serializers.CharField(
|
||||
help_text="TLS 인증서 컨테이너 참조 (TERMINATED_HTTPS 사용 시)",
|
||||
required=False,
|
||||
)
|
||||
|
||||
|
||||
class LBListenerUpdateSerializer(serializers.Serializer):
|
||||
"""리스너 수정 요청"""
|
||||
|
||||
name = serializers.CharField(
|
||||
help_text="리스너 이름",
|
||||
required=False,
|
||||
max_length=255,
|
||||
)
|
||||
description = serializers.CharField(
|
||||
help_text="설명",
|
||||
required=False,
|
||||
allow_blank=True,
|
||||
)
|
||||
default_pool_id = serializers.CharField(
|
||||
help_text="기본 풀 ID",
|
||||
required=False,
|
||||
allow_null=True,
|
||||
)
|
||||
connection_limit = serializers.IntegerField(
|
||||
help_text="연결 제한 (-1: 무제한)",
|
||||
required=False,
|
||||
)
|
||||
keepalive_timeout = serializers.IntegerField(
|
||||
help_text="Keepalive 타임아웃 (초)",
|
||||
required=False,
|
||||
)
|
||||
admin_state_up = serializers.BooleanField(
|
||||
help_text="관리자 상태",
|
||||
required=False,
|
||||
)
|
||||
|
||||
|
||||
class SessionPersistenceSerializer(serializers.Serializer):
|
||||
"""세션 지속성 설정"""
|
||||
|
||||
type = serializers.ChoiceField(
|
||||
choices=["SOURCE_IP", "HTTP_COOKIE", "APP_COOKIE"],
|
||||
help_text="세션 지속성 타입",
|
||||
)
|
||||
cookie_name = serializers.CharField(
|
||||
help_text="쿠키 이름 (APP_COOKIE 타입 사용 시)",
|
||||
required=False,
|
||||
)
|
||||
|
||||
|
||||
class LBPoolSerializer(serializers.Serializer):
|
||||
"""풀 생성 요청"""
|
||||
|
||||
lb_algorithm = serializers.ChoiceField(
|
||||
choices=["ROUND_ROBIN", "LEAST_CONNECTIONS", "SOURCE_IP"],
|
||||
help_text="로드밸런싱 알고리즘",
|
||||
)
|
||||
protocol = serializers.ChoiceField(
|
||||
choices=["TCP", "HTTP", "HTTPS", "PROXY"],
|
||||
help_text="프로토콜",
|
||||
)
|
||||
loadbalancer_id = serializers.CharField(
|
||||
help_text="로드밸런서 ID (listener_id와 둘 중 하나 필수)",
|
||||
required=False,
|
||||
)
|
||||
listener_id = serializers.CharField(
|
||||
help_text="리스너 ID (loadbalancer_id와 둘 중 하나 필수)",
|
||||
required=False,
|
||||
)
|
||||
name = serializers.CharField(
|
||||
help_text="풀 이름",
|
||||
required=False,
|
||||
max_length=255,
|
||||
)
|
||||
description = serializers.CharField(
|
||||
help_text="설명",
|
||||
required=False,
|
||||
allow_blank=True,
|
||||
)
|
||||
admin_state_up = serializers.BooleanField(
|
||||
help_text="관리자 상태",
|
||||
default=True,
|
||||
)
|
||||
session_persistence = SessionPersistenceSerializer(
|
||||
help_text="세션 지속성 설정",
|
||||
required=False,
|
||||
)
|
||||
|
||||
|
||||
class LBPoolUpdateSerializer(serializers.Serializer):
|
||||
"""풀 수정 요청"""
|
||||
|
||||
name = serializers.CharField(
|
||||
help_text="풀 이름",
|
||||
required=False,
|
||||
max_length=255,
|
||||
)
|
||||
description = serializers.CharField(
|
||||
help_text="설명",
|
||||
required=False,
|
||||
allow_blank=True,
|
||||
)
|
||||
lb_algorithm = serializers.ChoiceField(
|
||||
choices=["ROUND_ROBIN", "LEAST_CONNECTIONS", "SOURCE_IP"],
|
||||
help_text="로드밸런싱 알고리즘",
|
||||
required=False,
|
||||
)
|
||||
admin_state_up = serializers.BooleanField(
|
||||
help_text="관리자 상태",
|
||||
required=False,
|
||||
)
|
||||
session_persistence = SessionPersistenceSerializer(
|
||||
help_text="세션 지속성 설정",
|
||||
required=False,
|
||||
allow_null=True,
|
||||
)
|
||||
|
||||
|
||||
class LBMemberSerializer(serializers.Serializer):
|
||||
"""멤버 추가 요청"""
|
||||
|
||||
address = serializers.CharField(
|
||||
help_text="멤버 IP 주소",
|
||||
)
|
||||
protocol_port = serializers.IntegerField(
|
||||
help_text="멤버 포트 번호",
|
||||
min_value=1,
|
||||
max_value=65535,
|
||||
)
|
||||
subnet_id = serializers.CharField(
|
||||
help_text="멤버가 속한 서브넷 ID",
|
||||
required=False,
|
||||
)
|
||||
weight = serializers.IntegerField(
|
||||
help_text="가중치 (1-256)",
|
||||
default=1,
|
||||
min_value=1,
|
||||
max_value=256,
|
||||
)
|
||||
admin_state_up = serializers.BooleanField(
|
||||
help_text="관리자 상태",
|
||||
default=True,
|
||||
)
|
||||
|
||||
|
||||
class LBMemberUpdateSerializer(serializers.Serializer):
|
||||
"""멤버 수정 요청"""
|
||||
|
||||
weight = serializers.IntegerField(
|
||||
help_text="가중치 (1-256)",
|
||||
required=False,
|
||||
min_value=1,
|
||||
max_value=256,
|
||||
)
|
||||
admin_state_up = serializers.BooleanField(
|
||||
help_text="관리자 상태",
|
||||
required=False,
|
||||
)
|
||||
|
||||
|
||||
class LBHealthMonitorSerializer(serializers.Serializer):
|
||||
"""헬스 모니터 생성 요청"""
|
||||
|
||||
pool_id = serializers.CharField(
|
||||
help_text="풀 ID",
|
||||
)
|
||||
type = serializers.ChoiceField(
|
||||
choices=["TCP", "HTTP", "HTTPS"],
|
||||
help_text="헬스 체크 타입",
|
||||
)
|
||||
delay = serializers.IntegerField(
|
||||
help_text="헬스 체크 간격 (초)",
|
||||
min_value=1,
|
||||
)
|
||||
timeout = serializers.IntegerField(
|
||||
help_text="응답 대기 시간 (초)",
|
||||
min_value=1,
|
||||
)
|
||||
max_retries = serializers.IntegerField(
|
||||
help_text="최대 재시도 횟수 (정상 판정)",
|
||||
min_value=1,
|
||||
max_value=10,
|
||||
)
|
||||
max_retries_down = serializers.IntegerField(
|
||||
help_text="최대 재시도 횟수 (비정상 판정)",
|
||||
default=3,
|
||||
min_value=1,
|
||||
max_value=10,
|
||||
)
|
||||
http_method = serializers.ChoiceField(
|
||||
choices=["GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "OPTIONS", "CONNECT", "PATCH"],
|
||||
help_text="HTTP 메서드 (HTTP/HTTPS 타입 시)",
|
||||
default="GET",
|
||||
)
|
||||
url_path = serializers.CharField(
|
||||
help_text="URL 경로 (HTTP/HTTPS 타입 시)",
|
||||
default="/",
|
||||
)
|
||||
expected_codes = serializers.CharField(
|
||||
help_text="예상 응답 코드 (예: 200, 200,201, 200-204)",
|
||||
default="200",
|
||||
)
|
||||
admin_state_up = serializers.BooleanField(
|
||||
help_text="관리자 상태",
|
||||
default=True,
|
||||
)
|
||||
host_header = serializers.CharField(
|
||||
help_text="Host 헤더 값",
|
||||
required=False,
|
||||
)
|
||||
|
||||
|
||||
class LBHealthMonitorUpdateSerializer(serializers.Serializer):
|
||||
"""헬스 모니터 수정 요청"""
|
||||
|
||||
delay = serializers.IntegerField(
|
||||
help_text="헬스 체크 간격 (초)",
|
||||
required=False,
|
||||
min_value=1,
|
||||
)
|
||||
timeout = serializers.IntegerField(
|
||||
help_text="응답 대기 시간 (초)",
|
||||
required=False,
|
||||
min_value=1,
|
||||
)
|
||||
max_retries = serializers.IntegerField(
|
||||
help_text="최대 재시도 횟수 (정상 판정)",
|
||||
required=False,
|
||||
min_value=1,
|
||||
max_value=10,
|
||||
)
|
||||
max_retries_down = serializers.IntegerField(
|
||||
help_text="최대 재시도 횟수 (비정상 판정)",
|
||||
required=False,
|
||||
min_value=1,
|
||||
max_value=10,
|
||||
)
|
||||
http_method = serializers.ChoiceField(
|
||||
choices=["GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "OPTIONS", "CONNECT", "PATCH"],
|
||||
help_text="HTTP 메서드",
|
||||
required=False,
|
||||
)
|
||||
url_path = serializers.CharField(
|
||||
help_text="URL 경로",
|
||||
required=False,
|
||||
)
|
||||
expected_codes = serializers.CharField(
|
||||
help_text="예상 응답 코드",
|
||||
required=False,
|
||||
)
|
||||
admin_state_up = serializers.BooleanField(
|
||||
help_text="관리자 상태",
|
||||
required=False,
|
||||
)
|
||||
host_header = serializers.CharField(
|
||||
help_text="Host 헤더 값",
|
||||
required=False,
|
||||
)
|
||||
|
||||
|
||||
class LBL7PolicySerializer(serializers.Serializer):
|
||||
"""L7 정책 생성 요청"""
|
||||
|
||||
listener_id = serializers.CharField(
|
||||
help_text="리스너 ID",
|
||||
)
|
||||
action = serializers.ChoiceField(
|
||||
choices=["REDIRECT_TO_POOL", "REDIRECT_TO_URL", "REJECT"],
|
||||
help_text="액션",
|
||||
)
|
||||
position = serializers.IntegerField(
|
||||
help_text="정책 우선순위 (낮을수록 먼저 적용)",
|
||||
default=1,
|
||||
min_value=1,
|
||||
)
|
||||
name = serializers.CharField(
|
||||
help_text="정책 이름",
|
||||
required=False,
|
||||
max_length=255,
|
||||
)
|
||||
description = serializers.CharField(
|
||||
help_text="설명",
|
||||
required=False,
|
||||
allow_blank=True,
|
||||
)
|
||||
redirect_pool_id = serializers.CharField(
|
||||
help_text="리다이렉트 대상 풀 ID (REDIRECT_TO_POOL 액션 시)",
|
||||
required=False,
|
||||
)
|
||||
redirect_url = serializers.CharField(
|
||||
help_text="리다이렉트 URL (REDIRECT_TO_URL 액션 시)",
|
||||
required=False,
|
||||
)
|
||||
admin_state_up = serializers.BooleanField(
|
||||
help_text="관리자 상태",
|
||||
default=True,
|
||||
)
|
||||
|
||||
|
||||
class LBL7PolicyUpdateSerializer(serializers.Serializer):
|
||||
"""L7 정책 수정 요청"""
|
||||
|
||||
name = serializers.CharField(
|
||||
help_text="정책 이름",
|
||||
required=False,
|
||||
max_length=255,
|
||||
)
|
||||
description = serializers.CharField(
|
||||
help_text="설명",
|
||||
required=False,
|
||||
allow_blank=True,
|
||||
)
|
||||
action = serializers.ChoiceField(
|
||||
choices=["REDIRECT_TO_POOL", "REDIRECT_TO_URL", "REJECT"],
|
||||
help_text="액션",
|
||||
required=False,
|
||||
)
|
||||
position = serializers.IntegerField(
|
||||
help_text="정책 우선순위",
|
||||
required=False,
|
||||
min_value=1,
|
||||
)
|
||||
redirect_pool_id = serializers.CharField(
|
||||
help_text="리다이렉트 대상 풀 ID",
|
||||
required=False,
|
||||
allow_null=True,
|
||||
)
|
||||
redirect_url = serializers.CharField(
|
||||
help_text="리다이렉트 URL",
|
||||
required=False,
|
||||
allow_null=True,
|
||||
)
|
||||
admin_state_up = serializers.BooleanField(
|
||||
help_text="관리자 상태",
|
||||
required=False,
|
||||
)
|
||||
|
||||
|
||||
class LBL7RuleSerializer(serializers.Serializer):
|
||||
"""L7 룰 생성 요청"""
|
||||
|
||||
type = serializers.ChoiceField(
|
||||
choices=["COOKIE", "FILE_TYPE", "HEADER", "HOST_NAME", "PATH"],
|
||||
help_text="룰 타입",
|
||||
)
|
||||
compare_type = serializers.ChoiceField(
|
||||
choices=["CONTAINS", "ENDS_WITH", "STARTS_WITH", "EQUAL_TO", "REGEX"],
|
||||
help_text="비교 방식",
|
||||
)
|
||||
value = serializers.CharField(
|
||||
help_text="비교할 값",
|
||||
)
|
||||
key = serializers.CharField(
|
||||
help_text="키 값 (COOKIE, HEADER 타입 사용 시)",
|
||||
required=False,
|
||||
)
|
||||
invert = serializers.BooleanField(
|
||||
help_text="조건 반전 여부",
|
||||
default=False,
|
||||
)
|
||||
admin_state_up = serializers.BooleanField(
|
||||
help_text="관리자 상태",
|
||||
default=True,
|
||||
)
|
||||
|
||||
|
||||
class LBL7RuleUpdateSerializer(serializers.Serializer):
|
||||
"""L7 룰 수정 요청"""
|
||||
|
||||
type = serializers.ChoiceField(
|
||||
choices=["COOKIE", "FILE_TYPE", "HEADER", "HOST_NAME", "PATH"],
|
||||
help_text="룰 타입",
|
||||
required=False,
|
||||
)
|
||||
compare_type = serializers.ChoiceField(
|
||||
choices=["CONTAINS", "ENDS_WITH", "STARTS_WITH", "EQUAL_TO", "REGEX"],
|
||||
help_text="비교 방식",
|
||||
required=False,
|
||||
)
|
||||
value = serializers.CharField(
|
||||
help_text="비교할 값",
|
||||
required=False,
|
||||
)
|
||||
key = serializers.CharField(
|
||||
help_text="키 값",
|
||||
required=False,
|
||||
allow_null=True,
|
||||
)
|
||||
invert = serializers.BooleanField(
|
||||
help_text="조건 반전 여부",
|
||||
required=False,
|
||||
)
|
||||
admin_state_up = serializers.BooleanField(
|
||||
help_text="관리자 상태",
|
||||
required=False,
|
||||
)
|
||||
|
||||
|
||||
class LBIpAclTargetSerializer(serializers.Serializer):
|
||||
"""IP ACL 타깃"""
|
||||
|
||||
ip_address = serializers.CharField(
|
||||
help_text="IP 주소 또는 CIDR (예: 10.0.0.1, 10.0.0.0/24)",
|
||||
)
|
||||
description = serializers.CharField(
|
||||
help_text="설명",
|
||||
required=False,
|
||||
allow_blank=True,
|
||||
)
|
||||
|
||||
|
||||
class LBIpAclGroupSerializer(serializers.Serializer):
|
||||
"""IP ACL 그룹 생성 요청"""
|
||||
|
||||
action = serializers.ChoiceField(
|
||||
choices=["ALLOW", "DENY"],
|
||||
help_text="액션 (ALLOW 또는 DENY)",
|
||||
)
|
||||
name = serializers.CharField(
|
||||
help_text="그룹 이름",
|
||||
required=False,
|
||||
max_length=255,
|
||||
)
|
||||
description = serializers.CharField(
|
||||
help_text="설명",
|
||||
required=False,
|
||||
allow_blank=True,
|
||||
)
|
||||
ipacl_targets = serializers.ListField(
|
||||
child=LBIpAclTargetSerializer(),
|
||||
help_text="IP ACL 타깃 목록",
|
||||
required=False,
|
||||
)
|
||||
loadbalancers = serializers.ListField(
|
||||
child=serializers.CharField(),
|
||||
help_text="적용할 로드밸런서 ID 목록",
|
||||
required=False,
|
||||
)
|
||||
|
||||
|
||||
class LBIpAclGroupUpdateSerializer(serializers.Serializer):
|
||||
"""IP ACL 그룹 수정 요청"""
|
||||
|
||||
name = serializers.CharField(
|
||||
help_text="그룹 이름",
|
||||
required=False,
|
||||
max_length=255,
|
||||
)
|
||||
description = serializers.CharField(
|
||||
help_text="설명",
|
||||
required=False,
|
||||
allow_blank=True,
|
||||
)
|
||||
loadbalancers = serializers.ListField(
|
||||
child=serializers.CharField(),
|
||||
help_text="적용할 로드밸런서 ID 목록",
|
||||
required=False,
|
||||
)
|
||||
|
||||
|
||||
class LBIpAclTargetCreateSerializer(serializers.Serializer):
|
||||
"""IP ACL 타깃 추가 요청"""
|
||||
|
||||
ipacl_group_id = serializers.CharField(
|
||||
help_text="IP ACL 그룹 ID",
|
||||
)
|
||||
ip_address = serializers.CharField(
|
||||
help_text="IP 주소 또는 CIDR (예: 10.0.0.1, 10.0.0.0/24)",
|
||||
)
|
||||
description = serializers.CharField(
|
||||
help_text="설명",
|
||||
required=False,
|
||||
allow_blank=True,
|
||||
)
|
||||
|
||||
61
nhn/tasks.py
61
nhn/tasks.py
@ -396,3 +396,64 @@ def delete_storage_container_async(region, token, storage_account, container_nam
|
||||
)
|
||||
|
||||
return task
|
||||
|
||||
|
||||
# ==================== Load Balancer 비동기 작업 ====================
|
||||
|
||||
|
||||
def create_loadbalancer_async(region, token, lb_data):
|
||||
"""
|
||||
로드밸런서 비동기 생성
|
||||
|
||||
Args:
|
||||
region: 리전
|
||||
token: API 토큰
|
||||
lb_data: 로드밸런서 생성 데이터 (dict)
|
||||
|
||||
Returns:
|
||||
AsyncTask: 생성된 작업 객체
|
||||
"""
|
||||
from .models import AsyncTask
|
||||
from .packages.loadbalancer import ApiLoadBalancer
|
||||
|
||||
task = AsyncTask.objects.create(
|
||||
task_type=AsyncTask.TaskType.LB_CREATE,
|
||||
request_data=lb_data,
|
||||
resource_name=lb_data.get("name", ""),
|
||||
)
|
||||
|
||||
api = ApiLoadBalancer(region, token)
|
||||
execute_async_task(
|
||||
task_id=task.id,
|
||||
task_func=api.create_loadbalancer,
|
||||
vip_subnet_id=lb_data["vip_subnet_id"],
|
||||
name=lb_data.get("name"),
|
||||
description=lb_data.get("description"),
|
||||
vip_address=lb_data.get("vip_address"),
|
||||
admin_state_up=lb_data.get("admin_state_up", True),
|
||||
loadbalancer_type=lb_data.get("loadbalancer_type", "shared"),
|
||||
)
|
||||
|
||||
return task
|
||||
|
||||
|
||||
def delete_loadbalancer_async(region, token, loadbalancer_id, loadbalancer_name=""):
|
||||
"""로드밸런서 비동기 삭제"""
|
||||
from .models import AsyncTask
|
||||
from .packages.loadbalancer import ApiLoadBalancer
|
||||
|
||||
task = AsyncTask.objects.create(
|
||||
task_type=AsyncTask.TaskType.LB_DELETE,
|
||||
request_data={"loadbalancer_id": loadbalancer_id},
|
||||
resource_name=loadbalancer_name,
|
||||
resource_id=loadbalancer_id,
|
||||
)
|
||||
|
||||
api = ApiLoadBalancer(region, token)
|
||||
execute_async_task(
|
||||
task_id=task.id,
|
||||
task_func=api.delete_loadbalancer,
|
||||
loadbalancer_id=loadbalancer_id,
|
||||
)
|
||||
|
||||
return task
|
||||
|
||||
45
nhn/urls.py
45
nhn/urls.py
@ -94,4 +94,49 @@ urlpatterns = [
|
||||
path("dns/health-checks/", views.DnsHealthCheckListView.as_view(), name="dns-healthcheck-list"),
|
||||
path("dns/health-checks/create/", views.DnsHealthCheckCreateView.as_view(), name="dns-healthcheck-create"),
|
||||
path("dns/health-checks/<str:health_check_id>/", views.DnsHealthCheckDetailView.as_view(), name="dns-healthcheck-detail"),
|
||||
|
||||
# ==================== Load Balancer ====================
|
||||
path("lb/loadbalancers/", views.LoadBalancerListView.as_view(), name="lb-list"),
|
||||
path("lb/loadbalancers/create/", views.LoadBalancerCreateView.as_view(), name="lb-create"),
|
||||
path("lb/loadbalancers/<str:loadbalancer_id>/", views.LoadBalancerDetailView.as_view(), name="lb-detail"),
|
||||
|
||||
# ==================== LB Listener ====================
|
||||
path("lb/listeners/", views.LBListenerListView.as_view(), name="lb-listener-list"),
|
||||
path("lb/listeners/create/", views.LBListenerCreateView.as_view(), name="lb-listener-create"),
|
||||
path("lb/listeners/<str:listener_id>/", views.LBListenerDetailView.as_view(), name="lb-listener-detail"),
|
||||
|
||||
# ==================== LB Pool ====================
|
||||
path("lb/pools/", views.LBPoolListView.as_view(), name="lb-pool-list"),
|
||||
path("lb/pools/create/", views.LBPoolCreateView.as_view(), name="lb-pool-create"),
|
||||
path("lb/pools/<str:pool_id>/", views.LBPoolDetailView.as_view(), name="lb-pool-detail"),
|
||||
|
||||
# ==================== LB Member ====================
|
||||
path("lb/pools/<str:pool_id>/members/", views.LBMemberListView.as_view(), name="lb-member-list"),
|
||||
path("lb/pools/<str:pool_id>/members/create/", views.LBMemberCreateView.as_view(), name="lb-member-create"),
|
||||
path("lb/pools/<str:pool_id>/members/<str:member_id>/", views.LBMemberDetailView.as_view(), name="lb-member-detail"),
|
||||
|
||||
# ==================== LB Health Monitor ====================
|
||||
path("lb/healthmonitors/", views.LBHealthMonitorListView.as_view(), name="lb-healthmonitor-list"),
|
||||
path("lb/healthmonitors/create/", views.LBHealthMonitorCreateView.as_view(), name="lb-healthmonitor-create"),
|
||||
path("lb/healthmonitors/<str:healthmonitor_id>/", views.LBHealthMonitorDetailView.as_view(), name="lb-healthmonitor-detail"),
|
||||
|
||||
# ==================== LB L7 Policy ====================
|
||||
path("lb/l7policies/", views.LBL7PolicyListView.as_view(), name="lb-l7policy-list"),
|
||||
path("lb/l7policies/create/", views.LBL7PolicyCreateView.as_view(), name="lb-l7policy-create"),
|
||||
path("lb/l7policies/<str:l7policy_id>/", views.LBL7PolicyDetailView.as_view(), name="lb-l7policy-detail"),
|
||||
|
||||
# ==================== LB L7 Rule ====================
|
||||
path("lb/l7policies/<str:l7policy_id>/rules/", views.LBL7RuleListView.as_view(), name="lb-l7rule-list"),
|
||||
path("lb/l7policies/<str:l7policy_id>/rules/create/", views.LBL7RuleCreateView.as_view(), name="lb-l7rule-create"),
|
||||
path("lb/l7policies/<str:l7policy_id>/rules/<str:l7rule_id>/", views.LBL7RuleDetailView.as_view(), name="lb-l7rule-detail"),
|
||||
|
||||
# ==================== LB IP ACL ====================
|
||||
path("lb/ipacl-groups/", views.LBIpAclGroupListView.as_view(), name="lb-ipacl-group-list"),
|
||||
path("lb/ipacl-groups/create/", views.LBIpAclGroupCreateView.as_view(), name="lb-ipacl-group-create"),
|
||||
path("lb/ipacl-groups/<str:ipacl_group_id>/", views.LBIpAclGroupDetailView.as_view(), name="lb-ipacl-group-detail"),
|
||||
path("lb/ipacl-targets/create/", views.LBIpAclTargetCreateView.as_view(), name="lb-ipacl-target-create"),
|
||||
path("lb/ipacl-targets/<str:ipacl_target_id>/", views.LBIpAclTargetDetailView.as_view(), name="lb-ipacl-target-detail"),
|
||||
|
||||
# ==================== LB Quota ====================
|
||||
path("lb/quota/", views.LBQuotaView.as_view(), name="lb-quota"),
|
||||
]
|
||||
|
||||
1026
nhn/views.py
1026
nhn/views.py
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user