начата логика создания сервера
This commit is contained in:
6
ospabhost/backend/src/checkProxmoxConnection.ts
Normal file
6
ospabhost/backend/src/checkProxmoxConnection.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { checkProxmoxConnection } from './modules/server/proxmoxApi';
|
||||
|
||||
(async () => {
|
||||
const result = await checkProxmoxConnection();
|
||||
console.log('Проверка соединения с Proxmox:', result);
|
||||
})();
|
||||
@@ -29,10 +29,23 @@ app.use((req, res, next) => {
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/', (req, res) => {
|
||||
res.json({
|
||||
import { checkProxmoxConnection } from './modules/server/proxmoxApi';
|
||||
|
||||
app.get('/', async (req, res) => {
|
||||
// Проверка соединения с Proxmox
|
||||
let proxmoxStatus;
|
||||
try {
|
||||
proxmoxStatus = await checkProxmoxConnection();
|
||||
} catch (err) {
|
||||
proxmoxStatus = { status: 'fail', message: 'Ошибка проверки Proxmox', error: err };
|
||||
}
|
||||
|
||||
res.json({
|
||||
message: 'Сервер ospab.host запущен!',
|
||||
timestamp: new Date().toISOString()
|
||||
timestamp: new Date().toISOString(),
|
||||
port: PORT,
|
||||
database: process.env.DATABASE_URL ? 'подключена' : 'НЕ НАСТРОЕНА',
|
||||
proxmox: proxmoxStatus
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
60
ospabhost/backend/src/modules/server/proxmoxApi.ts
Normal file
60
ospabhost/backend/src/modules/server/proxmoxApi.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import axios from 'axios';
|
||||
import dotenv from 'dotenv';
|
||||
dotenv.config();
|
||||
|
||||
const PROXMOX_API_URL = process.env.PROXMOX_API_URL;
|
||||
const PROXMOX_TOKEN_ID = process.env.PROXMOX_TOKEN_ID;
|
||||
const PROXMOX_TOKEN_SECRET = process.env.PROXMOX_TOKEN_SECRET;
|
||||
|
||||
export async function createProxmoxContainer({ os, tariff, user }: any) {
|
||||
try {
|
||||
const node = process.env.PROXMOX_NODE;
|
||||
const diskTemplate = process.env.PROXMOX_DISK_TEMPLATE;
|
||||
if (!node || !diskTemplate) {
|
||||
return { status: 'fail', message: 'Не указаны PROXMOX_NODE или PROXMOX_DISK_TEMPLATE в .env' };
|
||||
}
|
||||
const vmId = Math.floor(10000 + Math.random() * 89999);
|
||||
const res = await axios.post(
|
||||
`${PROXMOX_API_URL}/nodes/${node}/qemu`,
|
||||
{
|
||||
vmid: vmId,
|
||||
name: `user${user.id}-vm${vmId}`,
|
||||
ostype: os.code || 'l26',
|
||||
cores: tariff.cores || 2,
|
||||
memory: tariff.memory || 2048,
|
||||
storage: diskTemplate,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Authorization': `PVEAPIToken=${PROXMOX_TOKEN_ID}=${PROXMOX_TOKEN_SECRET}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
if (res.data && res.data.data) {
|
||||
return { status: 'ok', proxmoxId: vmId, message: 'Сервер создан на Proxmox', proxmox: res.data.data };
|
||||
}
|
||||
return { status: 'fail', message: 'Не удалось создать сервер на Proxmox', details: res.data };
|
||||
} catch (err) {
|
||||
return { status: 'fail', message: 'Ошибка создания сервера на Proxmox', error: err };
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkProxmoxConnection() {
|
||||
try {
|
||||
const res = await axios.get(
|
||||
`${PROXMOX_API_URL}/version`,
|
||||
{
|
||||
headers: {
|
||||
'Authorization': `PVEAPIToken=${PROXMOX_TOKEN_ID}=${PROXMOX_TOKEN_SECRET}`
|
||||
}
|
||||
}
|
||||
);
|
||||
if (res.data && res.data.data) {
|
||||
return { status: 'ok', message: 'Соединение с Proxmox установлено', version: res.data.data.version };
|
||||
}
|
||||
return { status: 'fail', message: 'Не удалось получить версию Proxmox' };
|
||||
} catch (err) {
|
||||
return { status: 'fail', message: 'Ошибка соединения с Proxmox', error: err };
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,23 @@
|
||||
import { Router } from 'express';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
// import { createProxmoxContainer } from '../../proxmox/proxmoxApi'; // если есть интеграция
|
||||
import { authMiddleware } from '../auth/auth.middleware';
|
||||
import { checkProxmoxConnection, createProxmoxContainer } from './proxmoxApi';
|
||||
|
||||
const router = Router();
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// POST /api/server/create — создать сервер (контейнер)
|
||||
router.use(authMiddleware);
|
||||
|
||||
router.get('/proxmox-status', async (req, res) => {
|
||||
const status = await checkProxmoxConnection();
|
||||
res.json(status);
|
||||
});
|
||||
router.post('/create', async (req, res) => {
|
||||
try {
|
||||
const { tariffId, osId } = req.body;
|
||||
// TODO: получить userId из авторизации (req.user)
|
||||
const userId = 1; // временно, заменить на реального пользователя
|
||||
// Получаем userId из авторизации
|
||||
const userId = req.user?.id;
|
||||
if (!userId) return res.status(401).json({ error: 'Нет авторизации' });
|
||||
|
||||
// Получаем тариф и ОС
|
||||
const tariff = await prisma.tariff.findUnique({ where: { id: tariffId } });
|
||||
@@ -19,30 +26,52 @@ router.post('/create', async (req, res) => {
|
||||
return res.status(400).json({ error: 'Тариф или ОС не найдены' });
|
||||
}
|
||||
|
||||
// TODO: интеграция с Proxmox для создания контейнера
|
||||
// Если интеграция с Proxmox есть, то только при успешном создании контейнера создавать запись в БД
|
||||
// Например:
|
||||
// let proxmoxResult;
|
||||
// try {
|
||||
// proxmoxResult = await createProxmoxContainer({ ... });
|
||||
// } catch (proxmoxErr) {
|
||||
// console.error('Ошибка Proxmox:', proxmoxErr);
|
||||
// return res.status(500).json({ error: 'Ошибка создания контейнера на Proxmox' });
|
||||
// }
|
||||
// Проверяем баланс пользователя
|
||||
const user = await prisma.user.findUnique({ where: { id: userId } });
|
||||
if (!user) return res.status(404).json({ error: 'Пользователь не найден' });
|
||||
if (user.balance < tariff.price) {
|
||||
return res.status(400).json({ error: 'Недостаточно средств на балансе' });
|
||||
}
|
||||
|
||||
// Если всё успешно — создаём запись сервера в БД
|
||||
// 1. Создаём сервер на Proxmox
|
||||
let proxmoxResult;
|
||||
try {
|
||||
proxmoxResult = await createProxmoxContainer({ os, tariff, user });
|
||||
} catch (proxmoxErr) {
|
||||
console.error('Ошибка Proxmox:', proxmoxErr);
|
||||
return res.status(500).json({ error: 'Ошибка создания сервера на Proxmox', details: proxmoxErr });
|
||||
}
|
||||
if (!proxmoxResult || proxmoxResult.status !== 'ok') {
|
||||
return res.status(500).json({ error: 'Сервер не создан на Proxmox', details: proxmoxResult });
|
||||
}
|
||||
|
||||
// 2. Списываем средства
|
||||
await prisma.user.update({
|
||||
where: { id: userId },
|
||||
data: {
|
||||
balance: {
|
||||
decrement: tariff.price
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 3. Создаём запись о сервере в БД
|
||||
const node = process.env.PROXMOX_NODE;
|
||||
const diskTemplate = process.env.PROXMOX_DISK_TEMPLATE;
|
||||
const server = await prisma.server.create({
|
||||
data: {
|
||||
userId,
|
||||
tariffId,
|
||||
osId,
|
||||
status: 'creating',
|
||||
status: 'active',
|
||||
node,
|
||||
diskTemplate,
|
||||
proxmoxId: proxmoxResult.proxmoxId || null,
|
||||
},
|
||||
});
|
||||
res.json({ success: true, server });
|
||||
} catch (err) {
|
||||
console.error('Ошибка создания сервера:', err);
|
||||
// Не создавать сервер, если есть ошибка
|
||||
return res.status(500).json({ error: 'Ошибка создания сервера' });
|
||||
}
|
||||
});
|
||||
@@ -67,4 +96,22 @@ router.get('/', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/server/:id — получить один сервер пользователя по id
|
||||
router.get('/:id', async (req, res) => {
|
||||
try {
|
||||
// TODO: получить userId из авторизации (req.user)
|
||||
const userId = 1; // временно
|
||||
const serverId = Number(req.params.id);
|
||||
const server = await prisma.server.findFirst({
|
||||
where: { id: serverId, userId },
|
||||
include: { os: true, tariff: true },
|
||||
});
|
||||
if (!server) return res.status(404).json({ error: 'Сервер не найден' });
|
||||
res.json(server);
|
||||
} catch (err) {
|
||||
console.error('Ошибка получения сервера:', err);
|
||||
res.status(500).json({ error: 'Ошибка получения сервера' });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 209 KiB |
Reference in New Issue
Block a user