feat(NetworkConfigManager): implement recursive gateway code generation for enhanced routing configuration, including error handling for missing gateways and parent references
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m45s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m45s
This commit is contained in:
@@ -2202,8 +2202,125 @@ function NetworkConfigManager() {
|
||||
|
||||
setGeneratedMikrotikCode(filteredBlocks);
|
||||
setMikrotikCodeModalOpen(true);
|
||||
} else if (type === 'gateway') {
|
||||
// Получаем все gateways для этого сервера
|
||||
const serverGateways = (config.gateways || []).filter(gw => gw.serverId === serverId);
|
||||
|
||||
if (serverGateways.length === 0) {
|
||||
notify.error('Нет gateways для этого сервера');
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Генерируем код для рекурсивных маршрутов этого сервера
|
||||
const recursiveGateways = serverGateways.filter(gw => gw.type === 'recursive');
|
||||
|
||||
if (recursiveGateways.length === 0) {
|
||||
notify.error('Нет рекурсивных gateways для генерации кода');
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const blocks = [];
|
||||
const server = getServerInfo(serverId);
|
||||
const serverName = server?.dns || server?.ip || serverId;
|
||||
|
||||
// Генерируем код для каждого рекурсивного gateway
|
||||
recursiveGateways.forEach(gw => {
|
||||
if (!gw.ip) return;
|
||||
|
||||
// Поддержка старого формата (parentGatewayId) и нового (parentGateways)
|
||||
const parentGatewaysList = gw.parentGateways && Array.isArray(gw.parentGateways) && gw.parentGateways.length > 0
|
||||
? gw.parentGateways
|
||||
: (gw.parentGatewayId ? [{ id: gw.parentGatewayId, distance: undefined }] : []);
|
||||
|
||||
if (parentGatewaysList.length === 0) return;
|
||||
|
||||
let code = `# Рекурсивный маршрут для gateway: ${gw.ip}\n`;
|
||||
if (server?.provider) {
|
||||
code += `# Провайдер: ${server.provider}\n`;
|
||||
}
|
||||
if (server?.country) {
|
||||
code += `# Страна: ${server.country}\n`;
|
||||
}
|
||||
code += '\n';
|
||||
|
||||
let validRoutesCount = 0;
|
||||
|
||||
parentGatewaysList.forEach((parentRef) => {
|
||||
const parent = getParentGateway(parentRef.id);
|
||||
|
||||
if (!parent) {
|
||||
code += `# Родительский gateway/интерфейс "${parentRef.id}" не найден, пропущен\n`;
|
||||
return;
|
||||
}
|
||||
|
||||
// Определяем IP родителя в зависимости от типа
|
||||
const parentIp = parent.parentType === 'interface' ? parent.remoteIp : parent.ip;
|
||||
|
||||
if (!parentIp) {
|
||||
const parentType = parent.parentType === 'interface' ? 'интерфейс' : 'gateway';
|
||||
code += `# Родительский ${parentType} не имеет IP, пропущен\n`;
|
||||
return;
|
||||
}
|
||||
|
||||
validRoutesCount++;
|
||||
|
||||
// Создаём маршрут для рекурсивного gateway
|
||||
const parentLabel = parent.parentType === 'interface'
|
||||
? `интерфейс ${parent.name || parent.interfaceType || 'interface'} (${parent.remoteIp})`
|
||||
: `gateway ${parent.ip}`;
|
||||
|
||||
const distanceSuffix = parentRef.distance !== undefined && parentRef.distance !== null ? ` (distance: ${parentRef.distance})` : '';
|
||||
code += `# Рекурсивный gateway: ${gw.ip}${distanceSuffix}\n`;
|
||||
code += `# Родительский: ${parentLabel}\n`;
|
||||
|
||||
// Формируем gateway: для интерфейсов добавляем имя через %, для gateway - только IP
|
||||
const gatewayValue = parent.parentType === 'interface'
|
||||
? `${parentIp}%${parent.name || parent.interfaceType || 'interface'}`
|
||||
: parentIp;
|
||||
|
||||
// Создаём маршрут к IP рекурсивного gateway через родительский
|
||||
const comment = gw.description
|
||||
? `Recursive: ${gw.description} -> ${parentIp}${distanceSuffix}`
|
||||
: `Recursive: ${gw.ip} -> ${parentIp}${distanceSuffix}`;
|
||||
|
||||
const distanceParam = parentRef.distance !== undefined && parentRef.distance !== null ? ` distance=${parentRef.distance}` : '';
|
||||
code += `/ip route add dst-address=${gw.ip}/32 gateway=${gatewayValue}${distanceParam} comment="${comment}"\n`;
|
||||
|
||||
// Если у рекурсивного gateway есть описание с указанием на default route
|
||||
if (gw.description && (gw.description.toLowerCase().includes('default') || gw.description.toLowerCase().includes('0.0.0.0'))) {
|
||||
code += `# Дополнительный default route через рекурсивный gateway${distanceSuffix}\n`;
|
||||
const defaultComment = gw.description ? `Recursive: ${gw.description} (default)${distanceSuffix}` : `Recursive: ${gw.ip} (default)${distanceSuffix}`;
|
||||
code += `/ip route add dst-address=0.0.0.0/0 gateway=${gatewayValue}${distanceParam} comment="${defaultComment}"\n`;
|
||||
}
|
||||
code += '\n';
|
||||
});
|
||||
|
||||
code += '# Проверка созданных маршрутов:\n';
|
||||
code += '# /ip route print where comment~"Recursive"\n';
|
||||
code += `# Всего создано маршрутов: ${validRoutesCount}\n`;
|
||||
|
||||
if (validRoutesCount > 0) {
|
||||
blocks.push({
|
||||
type: 'recursive-routes',
|
||||
serverName,
|
||||
server,
|
||||
code
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (blocks.length === 0) {
|
||||
notify.error('Не удалось сгенерировать код для gateways этого сервера');
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setGeneratedMikrotikCode(blocks);
|
||||
setMikrotikCodeModalOpen(true);
|
||||
} else {
|
||||
notify.error('Генерация кода для gateways по серверу пока не реализована');
|
||||
notify.error('Неизвестный тип элемента');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error generating MikroTik code for server:', error);
|
||||
@@ -2638,14 +2755,14 @@ function NetworkConfigManager() {
|
||||
<span className="badge bg-primary text-white" style={{ fontSize: '0.875rem', padding: '6px 12px', fontWeight: '600', whiteSpace: 'nowrap' }}>
|
||||
{items.length} {type === 'gateway' ? (items.length === 1 ? 'gateway' : 'gateways') : (items.length === 1 ? 'интерфейс' : 'интерфейсов')}
|
||||
</span>
|
||||
{type === 'interface' && !isUnassigned && items.length > 0 && (
|
||||
{!isUnassigned && items.length > 0 && (
|
||||
<button
|
||||
className="btn btn-primary btn-sm flex-shrink-0"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleGenerateMikrotikCodeForServer(serverId, type);
|
||||
}}
|
||||
title="Получить код MikroTik для всех интерфейсов этого сервера"
|
||||
title={`Получить код MikroTik для всех ${type === 'gateway' ? 'gateways' : 'интерфейсов'} этого сервера`}
|
||||
style={{ whiteSpace: 'nowrap' }}
|
||||
>
|
||||
<IconCode size={16} className="me-1" />
|
||||
|
||||
Reference in New Issue
Block a user