diff --git a/frontend/src/NetworkConfigManager.jsx b/frontend/src/NetworkConfigManager.jsx index b9d4b50..f605331 100644 --- a/frontend/src/NetworkConfigManager.jsx +++ b/frontend/src/NetworkConfigManager.jsx @@ -146,6 +146,7 @@ function NetworkConfigManager() { const [templateIpsecPasswordId, setTemplateIpsecPasswordId] = useState(''); // Выбранный IPSec пароль const [templateIpPoolId, setTemplateIpPoolId] = useState(''); // Выбранный IP пул const [templateTunnelCount, setTemplateTunnelCount] = useState(1); // Количество туннелей для создания + const [templateServerPairs, setTemplateServerPairs] = useState([]); // Массив пар серверов для множественного создания // === IPSec Passwords Management === const [ipsecPasswords, setIpsecPasswords] = useState([]); @@ -511,41 +512,36 @@ function NetworkConfigManager() { const handleCreateInterfaceFromTemplate = () => { const tunnelCount = Math.max(1, Math.min(100, parseInt(templateTunnelCount) || 1)); // Ограничиваем от 1 до 100 - // Если количество туннелей больше 1, создаем туннели между разными парами серверов + // Если количество туннелей больше 1, используем выбранные пары серверов if (tunnelCount > 1) { - // Получаем список всех серверов - const availableServers = servers.filter(s => s.id && s.ip); - - if (availableServers.length < 2) { - notify.error('Недостаточно серверов для создания нескольких туннелей (нужно минимум 2)'); + // Проверяем, что все пары заполнены + if (templateServerPairs.length !== tunnelCount) { + notify.error(`Необходимо настроить ${tunnelCount} пар серверов`); return; } - // Генерируем все возможные пары серверов - const serverPairs = []; - for (let i = 0; i < availableServers.length; i++) { - for (let j = i + 1; j < availableServers.length; j++) { - serverPairs.push([availableServers[i].id, availableServers[j].id]); + const invalidPairs = templateServerPairs.filter((pair, index) => { + if (!pair.server1 || !pair.server2) { + return true; } - } + if (pair.server1 === pair.server2) { + return true; + } + return false; + }); - if (serverPairs.length < tunnelCount) { - notify.error(`Недостаточно пар серверов для создания ${tunnelCount} туннелей. Доступно пар: ${serverPairs.length}`); + if (invalidPairs.length > 0) { + notify.error('Не все пары серверов настроены корректно. Проверьте, что выбраны разные серверы для каждой пары.'); return; } - // Берем первые N пар - const pairsToUse = serverPairs.slice(0, tunnelCount); - const newInterfaces = []; const usedIps = new Set(getAllUsedIpsSet); // Создаем туннели для каждой пары - pairsToUse.forEach((pair, index) => { - const server1Id = pair[0]; - const server2Id = pair[1]; - const server1 = getServerInfo(server1Id); - const server2 = getServerInfo(server2Id); + templateServerPairs.forEach((pair, index) => { + const server1 = getServerInfo(pair.server1); + const server2 = getServerInfo(pair.server2); if (!server1 || !server2) { notify.error(`Не удалось найти информацию о серверах для пары ${index + 1}`); @@ -555,8 +551,12 @@ function NetworkConfigManager() { // Генерируем имена интерфейсов const baseName1 = generateInterfaceName(server1, server2, templateType, templateNamePrefix); const baseName2 = generateInterfaceName(server2, server1, templateType, templateNamePrefix); - const name1 = templateName1.trim() ? `${templateName1.trim()}-${index + 1}` : baseName1; - const name2 = templateName2.trim() ? `${templateName2.trim()}-${index + 1}` : baseName2; + const name1 = pair.name1?.trim() || baseName1; + const name2 = pair.name2?.trim() || baseName2; + + // Используем настройки из пары или глобальные + const pairIpsecPasswordId = pair.ipsecPasswordId || templateIpsecPasswordId; + const pairIpPoolId = pair.ipPoolId || templateIpPoolId; // Генерируем IP адреса (учитываем уже использованные в этой итерации) // Важно: Local IP и Remote IP должны быть разными и в одной сети /30 @@ -566,9 +566,9 @@ function NetworkConfigManager() { const maxAttempts = 1000; while ((!localIp || !remoteIp || localIp === remoteIp) && attempts < maxAttempts) { - const candidateLocal = generateFreePrivateIp(null, false, null, templateIpPoolId || null); + const candidateLocal = generateFreePrivateIp(null, false, null, pairIpPoolId || null); if (candidateLocal && !usedIps.has(candidateLocal)) { - const candidateRemote = generateFreePrivateIp(null, true, candidateLocal, templateIpPoolId || null); + const candidateRemote = generateFreePrivateIp(null, true, candidateLocal, pairIpPoolId || null); if (candidateRemote && !usedIps.has(candidateRemote) && candidateRemote !== candidateLocal) { localIp = candidateLocal; remoteIp = candidateRemote; @@ -593,10 +593,10 @@ function NetworkConfigManager() { type: templateType, localIp: localIp, remoteIp: remoteIp, - serverId: server1Id, - serverId2: server2Id, - ipsecPasswordId: (templateType === 'IPSec' || templateType === 'GRE') && templateIpsecPasswordId ? templateIpsecPasswordId : '', - ipPoolId: templateIpPoolId || '' + serverId: pair.server1, + serverId2: pair.server2, + ipsecPasswordId: (templateType === 'IPSec' || templateType === 'GRE') && pairIpsecPasswordId ? pairIpsecPasswordId : '', + ipPoolId: pairIpPoolId || '' }; // Проверяем конфликты с существующими интерфейсами @@ -619,7 +619,7 @@ function NetworkConfigManager() { tunnelInterfaces: [...prev.tunnelInterfaces, ...newInterfaces], })); - notify.success(`Создано туннелей: ${newInterfaces.length} между разными парами серверов`); + notify.success(`Создано туннелей: ${newInterfaces.length}`); // Закрываем модал и сбрасываем значения setInterfaceTemplateModalOpen(false); @@ -632,6 +632,7 @@ function NetworkConfigManager() { setTemplateIpsecPasswordId(''); setTemplateIpPoolId(''); setTemplateTunnelCount(1); + setTemplateServerPairs([]); return; } @@ -3297,6 +3298,7 @@ function NetworkConfigManager() { setTemplateIpsecPasswordId(''); setTemplateIpPoolId(''); setTemplateTunnelCount(1); + setTemplateServerPairs([]); }} onSubmit={handleCreateInterfaceFromTemplate} title="Создать интерфейс из шаблона" @@ -3313,14 +3315,32 @@ function NetworkConfigManager() { value={templateTunnelCount} onChange={(e) => { const value = parseInt(e.target.value) || 1; - setTemplateTunnelCount(Math.max(1, Math.min(100, value))); + const newCount = Math.max(1, Math.min(100, value)); + setTemplateTunnelCount(newCount); + // Синхронизируем количество пар + if (newCount > templateServerPairs.length) { + const newPairs = [...templateServerPairs]; + while (newPairs.length < newCount) { + newPairs.push({ + server1: '', + server2: '', + name1: '', + name2: '', + ipsecPasswordId: '', + ipPoolId: '' + }); + } + setTemplateServerPairs(newPairs); + } else if (newCount < templateServerPairs.length) { + setTemplateServerPairs(templateServerPairs.slice(0, newCount)); + } }} min="1" max="100" />