Add NHN Cloud API integration with async task support
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled

- NHN Cloud API packages: token, vpc, compute, nks, storage
- REST API endpoints with Swagger documentation
- Async task processing for long-running operations
- CORS configuration for frontend integration
- Enhanced logging for debugging API calls

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-14 01:29:21 +09:00
parent 256fed485e
commit 8c7739ffad
32 changed files with 4059 additions and 0 deletions

644
API_SPEC.md Normal file
View File

@ -0,0 +1,644 @@
# NHN Cloud API 명세서
## 기본 정보
- **Base URL**: `http://{server}:8900/api/nhn`
- **Swagger UI**: `http://{server}:8900/swagger/`
- **Content-Type**: `application/json`
---
## 인증 방식
모든 API 호출 시 아래 헤더를 포함해야 합니다:
| 헤더 | 필수 | 설명 |
|------|------|------|
| `X-NHN-Region` | O | NHN Cloud 리전 (`kr1`: 판교, `kr2`: 평촌) |
| `X-NHN-Token` | O | NHN Cloud API 토큰 |
| `X-NHN-Tenant-ID` | △ | 테넌트 ID (Compute API에서 필수) |
| `X-NHN-Storage-Account` | △ | 스토리지 계정 (Storage API에서 필수) |
---
## 1. Token API
### 1.1 토큰 생성
NHN Cloud API 인증 토큰을 발급받습니다.
```
POST /api/nhn/token/
```
**Request Body**
```json
{
"tenant_id": "04a2c5b7de7e4d66b970ad950081a7c3",
"username": "user@example.com",
"password": "your-api-password"
}
```
**Response (200 OK)**
```json
{
"token": "gAAAAABm...",
"tenant_id": "04a2c5b7de7e4d66b970ad950081a7c3",
"expires_at": "2024-01-15T12:00:00Z"
}
```
**Error Response (401)**
```json
{
"error": "인증 실패 메시지",
"code": 401
}
```
---
## 2. Compute API
### 2.1 Flavor 목록 조회
```
GET /api/nhn/compute/flavors/
```
**Headers**
```
X-NHN-Region: kr2
X-NHN-Token: {token}
X-NHN-Tenant-ID: {tenant_id}
```
**Response (200 OK)**
```json
{
"flavors": [
{
"id": "flavor-id-123",
"name": "m2.c2m4",
"vcpus": 2,
"ram": 4096,
"disk": 0
}
]
}
```
---
### 2.2 Keypair 목록 조회
```
GET /api/nhn/compute/keypairs/
```
**Response (200 OK)**
```json
{
"keypairs": [
{
"keypair": {
"name": "my-keypair",
"public_key": "ssh-rsa AAAA...",
"fingerprint": "xx:xx:xx..."
}
}
]
}
```
---
### 2.3 이미지 목록 조회
```
GET /api/nhn/compute/images/
```
**Response (200 OK)**
```json
{
"images": [
{
"id": "image-id-123",
"name": "Ubuntu 20.04",
"status": "active",
"created_at": "2024-01-01T00:00:00Z"
}
]
}
```
---
### 2.4 인스턴스 목록 조회
```
GET /api/nhn/compute/instances/
```
**Response (200 OK)**
```json
{
"servers": [
{
"id": "server-id-123",
"name": "my-instance",
"status": "ACTIVE",
"addresses": {
"Default Network": [
{"addr": "192.168.0.10", "version": 4}
]
},
"created": "2024-01-01T00:00:00Z"
}
]
}
```
---
### 2.5 인스턴스 상세 조회
```
GET /api/nhn/compute/instances/{server_id}/
```
**Response (200 OK)**
```json
{
"server": {
"id": "server-id-123",
"name": "my-instance",
"status": "ACTIVE",
"flavor": {"id": "flavor-id"},
"image": {"id": "image-id"},
"addresses": {...},
"created": "2024-01-01T00:00:00Z"
}
}
```
---
### 2.6 인스턴스 생성
```
POST /api/nhn/compute/instances/create/
```
**Request Body**
```json
{
"name": "my-new-instance",
"image_id": "image-id-123",
"flavor_id": "flavor-id-123",
"subnet_id": "subnet-id-123",
"keypair_name": "my-keypair",
"volume_size": 50,
"security_groups": ["default"],
"availability_zone": "kr-pub-a"
}
```
| 필드 | 타입 | 필수 | 설명 |
|------|------|------|------|
| name | string | O | 인스턴스 이름 |
| image_id | string | O | 이미지 ID |
| flavor_id | string | O | Flavor ID |
| subnet_id | string | O | 서브넷 ID |
| keypair_name | string | O | Keypair 이름 |
| volume_size | integer | X | 볼륨 크기 (GB, 기본 50) |
| security_groups | array | X | 보안 그룹 (기본 ["default"]) |
| availability_zone | string | X | 가용 영역 |
**Response (201 Created)**
```json
{
"server": {
"id": "new-server-id",
"name": "my-new-instance",
...
}
}
```
---
### 2.7 인스턴스 삭제
```
DELETE /api/nhn/compute/instances/{server_id}/
```
**Response (204 No Content)**
---
### 2.8 인스턴스 액션 (시작/정지/재부팅)
```
POST /api/nhn/compute/instances/{server_id}/action/
```
**Request Body**
```json
{
"action": "start" // "start" | "stop" | "reboot"
}
```
**Response (200 OK)**
```json
{
"status": "success",
"action": "start"
}
```
---
## 3. VPC API
### 3.1 VPC 목록 조회
```
GET /api/nhn/vpc/
```
**Headers**
```
X-NHN-Region: kr2
X-NHN-Token: {token}
```
**Response (200 OK)**
```json
{
"vpcs": [
{
"id": "vpc-id-123",
"name": "my-vpc",
"cidrv4": "10.0.0.0/16",
"state": "available"
}
]
}
```
---
### 3.2 VPC 생성
```
POST /api/nhn/vpc/create/
```
**Request Body**
```json
{
"name": "my-new-vpc",
"cidr": "10.0.0.0/16"
}
```
**Response (201 Created)**
```json
{
"vpc": {
"id": "new-vpc-id",
"name": "my-new-vpc",
"cidrv4": "10.0.0.0/16"
}
}
```
---
### 3.3 VPC 상세 조회
```
GET /api/nhn/vpc/{vpc_id}/
```
---
### 3.4 VPC 삭제
```
DELETE /api/nhn/vpc/{vpc_id}/
```
**Response (204 No Content)**
---
### 3.5 서브넷 목록 조회
```
GET /api/nhn/subnet/
```
**Response (200 OK)**
```json
{
"vpcsubnets": [
{
"id": "subnet-id-123",
"name": "my-subnet",
"vpc_id": "vpc-id-123",
"cidr": "10.0.1.0/24",
"gateway": "10.0.1.1"
}
]
}
```
---
### 3.6 서브넷 생성
```
POST /api/nhn/subnet/create/
```
**Request Body**
```json
{
"vpc_id": "vpc-id-123",
"name": "my-new-subnet",
"cidr": "10.0.1.0/24"
}
```
---
### 3.7 서브넷 상세 조회 / 삭제
```
GET /api/nhn/subnet/{subnet_id}/
DELETE /api/nhn/subnet/{subnet_id}/
```
---
### 3.8 Floating IP 목록 조회
```
GET /api/nhn/floatingip/
```
**Response (200 OK)**
```json
{
"floatingips": [
{
"id": "fip-id-123",
"floating_ip_address": "133.186.xxx.xxx",
"status": "ACTIVE",
"port_id": "port-id-123"
}
]
}
```
---
## 4. NKS (Kubernetes) API
### 4.1 클러스터 목록 조회
```
GET /api/nhn/nks/clusters/
```
**Headers**
```
X-NHN-Region: kr2
X-NHN-Token: {token}
```
**Response (200 OK)**
```json
{
"clusters": [
{
"uuid": "cluster-uuid-123",
"name": "my-cluster",
"status": "CREATE_COMPLETE",
"node_count": 3
}
]
}
```
---
### 4.2 클러스터 상세 조회
```
GET /api/nhn/nks/clusters/{cluster_name}/
```
---
### 4.3 클러스터 kubeconfig 조회
```
GET /api/nhn/nks/clusters/{cluster_name}/config/
```
**Response (200 OK)**
```json
{
"config": "apiVersion: v1\nclusters:\n- cluster:..."
}
```
---
### 4.4 클러스터 생성
```
POST /api/nhn/nks/clusters/create/
```
**Request Body**
```json
{
"cluster_name": "my-k8s-cluster",
"vpc_id": "vpc-id-123",
"subnet_id": "subnet-id-123",
"instance_type": "m2.c4m8",
"keypair_name": "my-keypair",
"kubernetes_version": "v1.28.3",
"availability_zone": "kr-pub-a",
"is_public": true,
"external_network_id": "ext-net-id",
"external_subnet_id": "ext-subnet-id",
"node_count": 3,
"boot_volume_size": 50,
"boot_volume_type": "General SSD"
}
```
| 필드 | 타입 | 필수 | 설명 |
|------|------|------|------|
| cluster_name | string | O | 클러스터 이름 |
| vpc_id | string | O | VPC ID |
| subnet_id | string | O | 서브넷 ID |
| instance_type | string | O | 인스턴스 타입 (Flavor ID) |
| keypair_name | string | O | Keypair 이름 |
| kubernetes_version | string | O | K8s 버전 (예: v1.28.3) |
| availability_zone | string | O | 가용 영역 |
| is_public | boolean | X | Public 클러스터 여부 (기본 true) |
| external_network_id | string | △ | 외부 네트워크 ID (Public 필수) |
| external_subnet_id | string | △ | 외부 서브넷 ID (Public 필수) |
| node_count | integer | X | 노드 수 (기본 1) |
| boot_volume_size | integer | X | 부팅 볼륨 크기 (기본 50GB) |
| boot_volume_type | string | X | 볼륨 타입 (기본 General SSD) |
---
### 4.5 클러스터 삭제
```
DELETE /api/nhn/nks/clusters/{cluster_name}/
```
**Response (204 No Content)**
---
## 5. Object Storage API
### 5.1 컨테이너 목록 조회
```
GET /api/nhn/storage/containers/
```
**Headers**
```
X-NHN-Region: kr2
X-NHN-Token: {token}
X-NHN-Storage-Account: AUTH_xxxxxxxx
```
**Response (200 OK)**
```json
{
"containers": ["container1", "container2", "container3"]
}
```
---
### 5.2 컨테이너 생성
```
POST /api/nhn/storage/containers/create/
```
**Request Body**
```json
{
"name": "my-new-container"
}
```
**Response (201 Created)**
```json
{
"status": 201,
"container": "my-new-container"
}
```
---
### 5.3 컨테이너 오브젝트 목록 조회
```
GET /api/nhn/storage/containers/{container_name}/
```
**Response (200 OK)**
```json
{
"objects": ["file1.txt", "file2.png", "folder/file3.json"]
}
```
---
### 5.4 컨테이너 삭제
```
DELETE /api/nhn/storage/containers/{container_name}/
```
**Response (204 No Content)**
---
## 에러 응답
모든 API는 실패 시 아래 형식으로 에러를 반환합니다:
```json
{
"error": "에러 메시지",
"code": 400
}
```
| HTTP Status | 설명 |
|-------------|------|
| 400 | 잘못된 요청 (파라미터 오류) |
| 401 | 인증 실패 (토큰 없음/만료) |
| 403 | 권한 없음 |
| 404 | 리소스 없음 |
| 500 | 서버 내부 오류 |
---
## 프론트엔드 사용 예시 (JavaScript)
```javascript
// 1. 토큰 발급
const tokenResponse = await fetch('/api/nhn/token/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
tenant_id: 'your-tenant-id',
username: 'user@example.com',
password: 'your-password'
})
});
const { token, tenant_id } = await tokenResponse.json();
// 2. API 호출 (인스턴스 목록)
const instancesResponse = await fetch('/api/nhn/compute/instances/', {
headers: {
'X-NHN-Region': 'kr2',
'X-NHN-Token': token,
'X-NHN-Tenant-ID': tenant_id
}
});
const instances = await instancesResponse.json();
```
---
## 리전 정보
| 리전 코드 | 위치 |
|-----------|------|
| kr1 | 판교 |
| kr2 | 평촌 |