420 lines
13 KiB
Markdown
420 lines
13 KiB
Markdown
# Инструкция для разработчика главного сайта
|
||
|
||
## 📌 Контекст
|
||
|
||
**Главный сайт** (ospab.host):
|
||
- Каталог тарифов VPS
|
||
- Система оплаты
|
||
- Создание/удаление VPS на хостинге (Proxmox, VMware и т.д.)
|
||
|
||
**Панель управления** (ospab-panel):
|
||
- Клиентская зона для управления своими VPS
|
||
- Получает данные о VPS с главного сайта через API
|
||
- Пользователи видят актуальный статус своих серверов
|
||
|
||
## 🔗 Как они соединяются?
|
||
|
||
```
|
||
Главный сайт Панель управления
|
||
│ │
|
||
├─ Пользователь платит ←──┤
|
||
├─ Создается VPS на Proxmox
|
||
│ │
|
||
└─ POST /api/vps/sync ──────────────→ Сохраняет в БД
|
||
(отправляет данные) │
|
||
Клиент видит VPS
|
||
```
|
||
|
||
## 🚀 Что нужно сделать на главном сайте
|
||
|
||
### Шаг 1: Установить переменные окружения
|
||
|
||
Добавить в `.env`:
|
||
|
||
```bash
|
||
# URL Панели управления OSPAB
|
||
OSPAB_PANEL_URL=https://panel.ospab.host
|
||
# При локальной разработке:
|
||
# OSPAB_PANEL_URL=http://localhost:5050
|
||
|
||
# API ключ для синхронизации VPS
|
||
# ⚠️ ДОЛЖЕН СОВПАДАТЬ с VPS_SYNC_API_KEY на Панели!
|
||
VPS_SYNC_API_KEY=your_secret_api_key_here_min_32_chars_change_this
|
||
```
|
||
|
||
### Шаг 2: Получить значение VPS_SYNC_API_KEY
|
||
|
||
**Вариант 1: Сгенерировать свой ключ**
|
||
```bash
|
||
# Linux/Mac
|
||
openssl rand -hex 16
|
||
# Результат: 6c8a4f2e9b1d3c5a7f9e2b4c6a8d0f1e
|
||
# Добавить prefix и получится: 6c8a4f2e9b1d3c5a7f9e2b4c6a8d0f1e6c8a4f2e
|
||
```
|
||
|
||
**Вариант 2: Использовать готовый ключ**
|
||
- Свяжитесь с администратором панели
|
||
- Он установит ключ на своей стороне в `.env`
|
||
|
||
### Шаг 3: Создать сервис для синхронизации VPS
|
||
|
||
Создайте файл `services/ospab-vps-sync.ts`:
|
||
|
||
```typescript
|
||
/**
|
||
* VPS Sync Service - синхронизация с Панелью управления OSPAB
|
||
* Отправляет информацию о VPS через REST API
|
||
*/
|
||
|
||
interface VPSSyncData {
|
||
user_id: number; // ID пользователя в системе OSPAB
|
||
name: string; // Имя VPS (например: web-server-01)
|
||
cpu: number; // Количество ядер (1, 2, 4, 8, etc)
|
||
ram: number; // ОЗУ в GB (1, 2, 4, 8, 16, 32, etc)
|
||
disk: number; // Диск в GB (10, 50, 100, 500, 1000, etc)
|
||
os: string; // Операционная система (Ubuntu 22.04 LTS, CentOS 7, Debian 11, etc)
|
||
hypervisor?: string; // Тип гипервизора (proxmox по умолчанию, может быть vmware, hyperv, kvm, xen)
|
||
}
|
||
|
||
class VPSSyncService {
|
||
private panelUrl: string;
|
||
private apiKey: string;
|
||
|
||
constructor() {
|
||
this.panelUrl = process.env.OSPAB_PANEL_URL || '';
|
||
this.apiKey = process.env.VPS_SYNC_API_KEY || '';
|
||
|
||
if (!this.panelUrl || !this.apiKey) {
|
||
throw new Error('Missing OSPAB_PANEL_URL or VPS_SYNC_API_KEY environment variables');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Создать новый VPS на Панели управления
|
||
* Вызывается сразу после создания VPS на хостинге
|
||
*/
|
||
async createVPS(data: VPSSyncData) {
|
||
console.log(`[VPS Sync] Creating VPS: ${data.name} for user ${data.user_id}`);
|
||
|
||
const response = await fetch(`${this.panelUrl}/api/vps/sync`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-API-Key': this.apiKey,
|
||
},
|
||
body: JSON.stringify({
|
||
action: 'create',
|
||
vps: {
|
||
user_id: data.user_id,
|
||
name: data.name,
|
||
status: 'creating',
|
||
cpu: data.cpu,
|
||
ram: data.ram * 1024, // 🔴 ВАЖНО: конвертируем GB в MB!
|
||
disk: data.disk,
|
||
os: data.os,
|
||
hypervisor: data.hypervisor || 'proxmox',
|
||
},
|
||
}),
|
||
});
|
||
|
||
if (!response.ok) {
|
||
const error = await response.json();
|
||
throw new Error(`[VPS Sync] Create failed: ${error.message}`);
|
||
}
|
||
|
||
const result = await response.json();
|
||
console.log(`[VPS Sync] VPS created successfully, ID: ${result.vps.id}`);
|
||
return result.vps;
|
||
}
|
||
|
||
/**
|
||
* Обновить статус VPS
|
||
* Вызывается после изменения статуса (например, VPS запущен, остановлен, и т.д.)
|
||
*/
|
||
async updateVPSStatus(vpsId: number, status: string) {
|
||
console.log(`[VPS Sync] Updating VPS ${vpsId} status to: ${status}`);
|
||
|
||
const response = await fetch(`${this.panelUrl}/api/vps/sync`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-API-Key': this.apiKey,
|
||
},
|
||
body: JSON.stringify({
|
||
action: 'update',
|
||
vps: {
|
||
id: vpsId,
|
||
status: status,
|
||
},
|
||
}),
|
||
});
|
||
|
||
if (!response.ok) {
|
||
const error = await response.json();
|
||
throw new Error(`[VPS Sync] Update failed: ${error.message}`);
|
||
}
|
||
|
||
const result = await response.json();
|
||
console.log(`[VPS Sync] VPS ${vpsId} status updated to: ${status}`);
|
||
return result.vps;
|
||
}
|
||
|
||
/**
|
||
* Удалить VPS
|
||
* Вызывается когда клиент отменил услугу
|
||
*/
|
||
async deleteVPS(vpsId: number) {
|
||
console.log(`[VPS Sync] Deleting VPS ${vpsId}`);
|
||
|
||
const response = await fetch(`${this.panelUrl}/api/vps/sync`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-API-Key': this.apiKey,
|
||
},
|
||
body: JSON.stringify({
|
||
action: 'delete',
|
||
vps: {
|
||
id: vpsId,
|
||
},
|
||
}),
|
||
});
|
||
|
||
if (!response.ok) {
|
||
const error = await response.json();
|
||
throw new Error(`[VPS Sync] Delete failed: ${error.message}`);
|
||
}
|
||
|
||
console.log(`[VPS Sync] VPS ${vpsId} deleted successfully`);
|
||
return true;
|
||
}
|
||
}
|
||
|
||
export default new VPSSyncService();
|
||
```
|
||
|
||
### Шаг 4: Использовать сервис в основном коде
|
||
|
||
**Пример в Express маршруте (создание VPS):**
|
||
|
||
```typescript
|
||
import vpsSync from './services/ospab-vps-sync';
|
||
|
||
router.post('/api/vps/create', async (req, res) => {
|
||
try {
|
||
const { user_id, name, cpu, ram, disk, os } = req.body;
|
||
|
||
// 1️⃣ Создать VPS на хостинге (Proxmox, VMware, etc)
|
||
console.log('Creating VPS on Proxmox...');
|
||
const proxmoxVPS = await createVPSOnProxmox({
|
||
name,
|
||
cpu,
|
||
ram: ram * 1024, // GB to MB for Proxmox
|
||
disk,
|
||
os,
|
||
});
|
||
|
||
console.log('VPS created on Proxmox:', proxmoxVPS.id);
|
||
|
||
// 2️⃣ Синхронизировать с Панелью управления
|
||
console.log('Syncing with OSPAB Panel...');
|
||
const panelVPS = await vpsSync.createVPS({
|
||
user_id,
|
||
name,
|
||
cpu,
|
||
ram,
|
||
disk,
|
||
os,
|
||
});
|
||
|
||
console.log('VPS synced with panel, ID:', panelVPS.id);
|
||
|
||
// 3️⃣ Обновить статус когда VPS готов (через несколько минут)
|
||
// Рекомендуется использовать job queue (bull, rsmq, etc)
|
||
setTimeout(async () => {
|
||
try {
|
||
await vpsSync.updateVPSStatus(panelVPS.id, 'running');
|
||
console.log('VPS status updated to running');
|
||
} catch (err) {
|
||
console.error('Failed to update VPS status:', err);
|
||
}
|
||
}, 60000); // 1 минута
|
||
|
||
res.json({
|
||
success: true,
|
||
vps_id: panelVPS.id,
|
||
message: 'VPS created successfully',
|
||
});
|
||
} catch (error) {
|
||
console.error('Error creating VPS:', error);
|
||
res.status(500).json({
|
||
success: false,
|
||
message: error.message,
|
||
});
|
||
}
|
||
});
|
||
```
|
||
|
||
**Пример для удаления VPS:**
|
||
|
||
```typescript
|
||
router.post('/api/vps/delete', async (req, res) => {
|
||
try {
|
||
const { vps_id, proxmox_id } = req.body;
|
||
|
||
// 1️⃣ Удалить с хостинга
|
||
await deleteVPSFromProxmox(proxmox_id);
|
||
console.log('VPS deleted from Proxmox');
|
||
|
||
// 2️⃣ Удалить из Панели
|
||
await vpsSync.deleteVPS(vps_id);
|
||
console.log('VPS deleted from panel');
|
||
|
||
res.json({
|
||
success: true,
|
||
message: 'VPS deleted successfully',
|
||
});
|
||
} catch (error) {
|
||
console.error('Error deleting VPS:', error);
|
||
res.status(500).json({
|
||
success: false,
|
||
message: error.message,
|
||
});
|
||
}
|
||
});
|
||
```
|
||
|
||
## ⚠️ Важные моменты
|
||
|
||
### 1. Конвертация единиц
|
||
|
||
| Параметр | Главный сайт | Панель | Конвертация |
|
||
|----------|--------------|-------|-------------|
|
||
| RAM | GB | MB | ×1024 |
|
||
| Disk | GB | GB | ×1 |
|
||
| CPU | cores | cores | ×1 |
|
||
|
||
```typescript
|
||
// ❌ НЕПРАВИЛЬНО (забыли конвертировать)
|
||
vpsSync.createVPS({ ram: 8 }); // Панель получит 8 MB вместо 8 GB
|
||
|
||
// ✅ ПРАВИЛЬНО
|
||
vpsSync.createVPS({ ram: 8 * 1024 }); // Панель получит 8192 MB = 8 GB
|
||
```
|
||
|
||
### 2. User ID
|
||
|
||
`user_id` должен быть **ID из SSO системы** Панели управления:
|
||
|
||
```typescript
|
||
// ❌ НЕПРАВИЛЬНО (локальный ID главного сайта)
|
||
const userId = req.user.id; // 123 в БД главного сайта
|
||
|
||
// ✅ ПРАВИЛЬНО (ID из SSO)
|
||
const userId = req.user.sso_id; // 5 в системе OSPAB Panel
|
||
```
|
||
|
||
### 3. Обработка ошибок
|
||
|
||
```typescript
|
||
try {
|
||
await vpsSync.createVPS(vpsData);
|
||
} catch (error) {
|
||
// Важно логировать ошибку!
|
||
console.error('Failed to sync VPS:', error.message);
|
||
|
||
// Но НЕ прерывать создание VPS на хостинге
|
||
// VPS может быть создан, даже если панель недоступна
|
||
|
||
// Вариант: сохранить попытку синхронизации в БД
|
||
// и повторить попытку позже через job queue
|
||
}
|
||
```
|
||
|
||
### 4. Статусы VPS
|
||
|
||
```typescript
|
||
// Возможные статусы
|
||
'creating' // VPS создается
|
||
'running' // VPS запущен и готов
|
||
'stopped' // VPS остановлен
|
||
'suspended' // VPS приостановлен (например, за неоплату)
|
||
```
|
||
|
||
## 🧪 Тестирование
|
||
|
||
### Локальное тестирование
|
||
|
||
1. Запустить Панель управления локально:
|
||
```bash
|
||
go run ./cmd/server/main.go
|
||
# Будет доступна на http://localhost:5050
|
||
```
|
||
|
||
2. В `.env` главного сайта:
|
||
```env
|
||
OSPAB_PANEL_URL=http://localhost:5050
|
||
VPS_SYNC_API_KEY=your_secret_api_key_here_min_32_chars_change_this
|
||
```
|
||
|
||
3. Тестировать создание VPS через API главного сайта
|
||
|
||
### Тест через curl
|
||
|
||
```bash
|
||
curl -X POST http://localhost:5050/api/vps/sync \
|
||
-H "Content-Type: application/json" \
|
||
-H "X-API-Key: your_secret_api_key_here_min_32_chars_change_this" \
|
||
-d '{
|
||
"action": "create",
|
||
"vps": {
|
||
"user_id": 5,
|
||
"name": "test-vps",
|
||
"cpu": 2,
|
||
"ram": 2048,
|
||
"disk": 50,
|
||
"os": "Ubuntu 22.04 LTS",
|
||
"status": "creating",
|
||
"hypervisor": "proxmox"
|
||
}
|
||
}'
|
||
```
|
||
|
||
Ожидаемый ответ:
|
||
```json
|
||
{
|
||
"status": "success",
|
||
"message": "VPS synced successfully",
|
||
"vps": {
|
||
"id": 1,
|
||
"name": "test-vps",
|
||
"status": "creating",
|
||
"created_at": "2025-10-27T10:30:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 📚 Дополнительно
|
||
|
||
- Полная документация: `CLIENT_VPS_INTEGRATION.md`
|
||
- Примеры кода: `VPS_SYNC_EXAMPLES.md`
|
||
- Быстрый старт: `VPS_SYNC_QUICK_START.md`
|
||
|
||
## ❓ Часто задаваемые вопросы
|
||
|
||
**Q: Что если панель недоступна?**
|
||
A: VPS все равно создастся на хостинге. Добавьте retry logic и job queue (bull/rsmq) для повторных попыток синхронизации.
|
||
|
||
**Q: Может ли быть несовпадение данных?**
|
||
A: Да, если синхронизация сорвалась. Рекомендуется периодически проверять консистентность и добавить маршрут для ручной синхронизации.
|
||
|
||
**Q: Как обновлять IP адрес VPS?**
|
||
A: Текущий API синхронизирует только основные параметры. IP адрес может быть добавлен позже через расширение API.
|
||
|
||
**Q: Нужна ли двусторонняя синхронизация?**
|
||
A: Нет, панель только получает данные. Главный сайт - источник истины.
|
||
|
||
---
|
||
|
||
**Вопросы?** Смотрите документацию выше или свяжитесь с разработчиком панели.
|