feat(NetworkConfigManager): add optional second interface name for dual server configurations; enhance UI to support interface naming for both servers
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m38s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m38s
This commit is contained in:
@@ -54,6 +54,7 @@
|
|||||||
{
|
{
|
||||||
"id": "if-gre-swe-de",
|
"id": "if-gre-swe-de",
|
||||||
"name": "gre-swe-de",
|
"name": "gre-swe-de",
|
||||||
|
"name2": "gre-de-swe",
|
||||||
"type": "GRE",
|
"type": "GRE",
|
||||||
"localIp": "10.10.0.1",
|
"localIp": "10.10.0.1",
|
||||||
"remoteIp": "10.10.0.2",
|
"remoteIp": "10.10.0.2",
|
||||||
@@ -63,6 +64,7 @@
|
|||||||
{
|
{
|
||||||
"id": "if-wg-swe-nl",
|
"id": "if-wg-swe-nl",
|
||||||
"name": "wg0",
|
"name": "wg0",
|
||||||
|
"name2": "wg1",
|
||||||
"type": "WireGuard",
|
"type": "WireGuard",
|
||||||
"localIp": "10.20.0.1",
|
"localIp": "10.20.0.1",
|
||||||
"remoteIp": "10.20.0.2",
|
"remoteIp": "10.20.0.2",
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ const getEmptyGateway = () => ({
|
|||||||
const getEmptyInterface = () => ({
|
const getEmptyInterface = () => ({
|
||||||
id: `if-${Date.now()}-${Math.random().toString(16).slice(2, 6)}`,
|
id: `if-${Date.now()}-${Math.random().toString(16).slice(2, 6)}`,
|
||||||
name: '',
|
name: '',
|
||||||
|
name2: '', // Имя интерфейса на втором сервере (опционально)
|
||||||
type: 'GRE',
|
type: 'GRE',
|
||||||
localIp: '',
|
localIp: '',
|
||||||
remoteIp: '',
|
remoteIp: '',
|
||||||
@@ -511,8 +512,10 @@ function NetworkConfigManager() {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
let code = '\n# === Настройка IP адресов интерфейсов на обоих серверах ===\n';
|
let code = '\n# ====================================================================\n';
|
||||||
code += '# Эти команды нужно выполнить на соответствующих серверах\n\n';
|
code += '# === НАСТРОЙКА IP АДРЕСОВ ИНТЕРФЕЙСОВ НА ОБОИХ СЕРВЕРАХ ===\n';
|
||||||
|
code += '# Эти команды нужно выполнить на соответствующих серверах\n';
|
||||||
|
code += '# ====================================================================\n\n';
|
||||||
|
|
||||||
// Группируем по серверам
|
// Группируем по серверам
|
||||||
const interfacesByServer = {};
|
const interfacesByServer = {};
|
||||||
@@ -524,43 +527,84 @@ function NetworkConfigManager() {
|
|||||||
|
|
||||||
const server1Name = server1.dns || server1.ip || iface.serverId;
|
const server1Name = server1.dns || server1.ip || iface.serverId;
|
||||||
const server2Name = server2.dns || server2.ip || iface.serverId2;
|
const server2Name = server2.dns || server2.ip || iface.serverId2;
|
||||||
const interfaceName = iface.name || `${iface.type}-tunnel`;
|
|
||||||
|
|
||||||
// Для первого сервера - используем localIp
|
// Имя интерфейса для первого сервера
|
||||||
|
const interfaceName1 = iface.name || `${iface.type}-tunnel`;
|
||||||
|
// Имя интерфейса для второго сервера (может отличаться)
|
||||||
|
const interfaceName2 = iface.name2 || iface.name || `${iface.type}-tunnel`;
|
||||||
|
|
||||||
|
// Для первого сервера - используем localIp как local, remoteIp как remote
|
||||||
if (!interfacesByServer[server1Name]) {
|
if (!interfacesByServer[server1Name]) {
|
||||||
interfacesByServer[server1Name] = [];
|
interfacesByServer[server1Name] = {
|
||||||
|
serverInfo: server1,
|
||||||
|
interfaces: []
|
||||||
|
};
|
||||||
}
|
}
|
||||||
interfacesByServer[server1Name].push({
|
interfacesByServer[server1Name].interfaces.push({
|
||||||
interfaceName,
|
interfaceName: interfaceName1,
|
||||||
ip: iface.localIp,
|
localIp: iface.localIp,
|
||||||
type: iface.type,
|
|
||||||
remoteIp: iface.remoteIp,
|
remoteIp: iface.remoteIp,
|
||||||
server2Name
|
type: iface.type,
|
||||||
|
server2Name,
|
||||||
|
server2Info: server2
|
||||||
});
|
});
|
||||||
|
|
||||||
// Для второго сервера - используем remoteIp
|
// Для второго сервера - МЕНЯЕМ МЕСТАМИ: remoteIp становится localIp, localIp становится remoteIp
|
||||||
if (!interfacesByServer[server2Name]) {
|
if (!interfacesByServer[server2Name]) {
|
||||||
interfacesByServer[server2Name] = [];
|
interfacesByServer[server2Name] = {
|
||||||
|
serverInfo: server2,
|
||||||
|
interfaces: []
|
||||||
|
};
|
||||||
}
|
}
|
||||||
interfacesByServer[server2Name].push({
|
interfacesByServer[server2Name].interfaces.push({
|
||||||
interfaceName,
|
interfaceName: interfaceName2,
|
||||||
ip: iface.remoteIp,
|
localIp: iface.remoteIp, // На втором сервере remoteIp первого становится localIp
|
||||||
|
remoteIp: iface.localIp, // На втором сервере localIp первого становится remoteIp
|
||||||
type: iface.type,
|
type: iface.type,
|
||||||
remoteIp: iface.localIp, // Для второго сервера remoteIp - это localIp первого
|
server2Name: server1Name,
|
||||||
server2Name: server1Name
|
server2Info: server1
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.entries(interfacesByServer).forEach(([serverName, interfaces]) => {
|
// Сортируем серверы по имени для консистентности
|
||||||
code += `\n# --- Команды для сервера: ${serverName} ---\n`;
|
const sortedServers = Object.entries(interfacesByServer).sort(([a], [b]) => a.localeCompare(b));
|
||||||
interfaces.forEach(iface => {
|
|
||||||
code += `# Интерфейс: ${iface.interfaceName} (${iface.type}) - связь с ${iface.server2Name}\n`;
|
sortedServers.forEach(([serverName, serverData], index) => {
|
||||||
code += `/ip address add address=${iface.ip}/32 interface="${iface.interfaceName}" comment="Interface: ${iface.interfaceName} (${iface.type}) to ${iface.server2Name}"\n`;
|
const server = serverData.serverInfo;
|
||||||
|
|
||||||
|
// Отдельный блок для каждого сервера
|
||||||
|
code += '\n';
|
||||||
|
code += '# ' + '='.repeat(70) + '\n';
|
||||||
|
code += `# СЕРВЕР ${index + 1}: ${serverName}\n`;
|
||||||
|
if (server.provider) {
|
||||||
|
code += `# Провайдер: ${server.provider}\n`;
|
||||||
|
}
|
||||||
|
if (server.country) {
|
||||||
|
code += `# Страна: ${server.country}\n`;
|
||||||
|
}
|
||||||
|
if (server.ip && server.ip !== serverName) {
|
||||||
|
code += `# IP: ${server.ip}\n`;
|
||||||
|
}
|
||||||
|
code += '# ' + '='.repeat(70) + '\n';
|
||||||
|
code += '\n';
|
||||||
|
|
||||||
|
serverData.interfaces.forEach((iface, ifaceIndex) => {
|
||||||
|
code += `# Интерфейс ${ifaceIndex + 1}: ${iface.interfaceName} (${iface.type})\n`;
|
||||||
|
code += `# Связь с сервером: ${iface.server2Name}\n`;
|
||||||
|
code += `# Local IP: ${iface.localIp}\n`;
|
||||||
|
code += `# Remote IP: ${iface.remoteIp}\n`;
|
||||||
|
code += `/ip address add address=${iface.localIp}/32 interface="${iface.interfaceName}" comment="Interface: ${iface.interfaceName} (${iface.type}) to ${iface.server2Name}"\n`;
|
||||||
|
code += '\n';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
code += '# Проверка настроенных адресов на этом сервере:\n';
|
||||||
|
code += '# /ip address print\n';
|
||||||
|
code += '\n';
|
||||||
});
|
});
|
||||||
|
|
||||||
code += '\n# Проверка настроенных адресов:\n';
|
code += '# ' + '='.repeat(70) + '\n';
|
||||||
code += '# /ip address print\n';
|
code += '# КОНЕЦ КОНФИГУРАЦИИ IP АДРЕСОВ ИНТЕРФЕЙСОВ\n';
|
||||||
|
code += '# ' + '='.repeat(70) + '\n';
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
@@ -967,6 +1011,7 @@ function NetworkConfigManager() {
|
|||||||
<IconServer size={12} className="text-muted" />
|
<IconServer size={12} className="text-muted" />
|
||||||
<span className="text-muted">Сервер 1:</span>
|
<span className="text-muted">Сервер 1:</span>
|
||||||
<span>{server.dns || server.ip}</span>
|
<span>{server.dns || server.ip}</span>
|
||||||
|
{iface.name && <span className="text-muted ms-1">({iface.name})</span>}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{server2 && (
|
{server2 && (
|
||||||
@@ -974,6 +1019,9 @@ function NetworkConfigManager() {
|
|||||||
<IconServer size={12} className="text-muted" />
|
<IconServer size={12} className="text-muted" />
|
||||||
<span className="text-muted">Сервер 2:</span>
|
<span className="text-muted">Сервер 2:</span>
|
||||||
<span>{server2.dns || server2.ip}</span>
|
<span>{server2.dns || server2.ip}</span>
|
||||||
|
{(iface.name2 || iface.name) && (
|
||||||
|
<span className="text-muted ms-1">({iface.name2 || iface.name})</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -1714,7 +1762,7 @@ function NetworkConfigManager() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="col-md-6">
|
<div className="col-md-6">
|
||||||
<FormField
|
<FormField
|
||||||
label="Имя интерфейса"
|
label="Имя интерфейса (сервер 1)"
|
||||||
name="name"
|
name="name"
|
||||||
value={editingInterface.name}
|
value={editingInterface.name}
|
||||||
onChange={(val) => setEditingInterface({ ...editingInterface, name: val })}
|
onChange={(val) => setEditingInterface({ ...editingInterface, name: val })}
|
||||||
@@ -1722,6 +1770,18 @@ function NetworkConfigManager() {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{editingInterface.serverId2 && (
|
||||||
|
<div className="col-md-6">
|
||||||
|
<FormField
|
||||||
|
label="Имя интерфейса (сервер 2)"
|
||||||
|
name="name2"
|
||||||
|
value={editingInterface.name2 || ''}
|
||||||
|
onChange={(val) => setEditingInterface({ ...editingInterface, name2: val })}
|
||||||
|
placeholder="gre-tunnel2"
|
||||||
|
/>
|
||||||
|
<div className="form-text">Если не указано, будет использовано имя с сервера 1</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="col-md-6">
|
<div className="col-md-6">
|
||||||
<FormField
|
<FormField
|
||||||
label="Тип"
|
label="Тип"
|
||||||
|
|||||||
Reference in New Issue
Block a user