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:
@ -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)
|
||||
Reference in New Issue
Block a user