feat(NetworkConfigManager): add optional interface names for servers; enhance interface name generation logic with DNS parsing and user-defined names
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m41s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m41s
This commit is contained in:
@@ -138,6 +138,8 @@ function NetworkConfigManager() {
|
|||||||
const [templateServer2, setTemplateServer2] = useState('');
|
const [templateServer2, setTemplateServer2] = useState('');
|
||||||
const [templateType, setTemplateType] = useState('GRE');
|
const [templateType, setTemplateType] = useState('GRE');
|
||||||
const [templateNamePrefix, setTemplateNamePrefix] = useState('');
|
const [templateNamePrefix, setTemplateNamePrefix] = useState('');
|
||||||
|
const [templateName1, setTemplateName1] = useState(''); // Опциональное имя для сервера 1
|
||||||
|
const [templateName2, setTemplateName2] = useState(''); // Опциональное имя для сервера 2
|
||||||
|
|
||||||
// === MikroTik Code Generation ===
|
// === MikroTik Code Generation ===
|
||||||
const [mikrotikCodeModalOpen, setMikrotikCodeModalOpen] = useState(false);
|
const [mikrotikCodeModalOpen, setMikrotikCodeModalOpen] = useState(false);
|
||||||
@@ -441,12 +443,44 @@ function NetworkConfigManager() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// === Генерация имени интерфейса на основе серверов ===
|
// === Генерация имени интерфейса на основе серверов ===
|
||||||
const generateInterfaceName = (server1, server2, type, prefix = '') => {
|
// Для сервера 1: берем часть из DNS сервера 2 (например, msk) и имя хоста сервера 2 (ihor)
|
||||||
const server1Name = server1?.dns?.split('.')[0] || server1?.ip?.split('.').join('-') || 'server1';
|
// Для сервера 2: берем часть из DNS сервера 1 (например, swe) и имя хоста сервера 1 (hiphost)
|
||||||
const server2Name = server2?.dns?.split('.')[0] || server2?.ip?.split('.').join('-') || 'server2';
|
const generateInterfaceName = (currentServer, otherServer, type, prefix = '') => {
|
||||||
const typeLower = type.toLowerCase();
|
// Парсим DNS имена
|
||||||
|
const parseDnsParts = (dns) => {
|
||||||
|
if (!dns) return null;
|
||||||
|
const parts = dns.split('.');
|
||||||
|
if (parts.length >= 2) {
|
||||||
|
return {
|
||||||
|
hostname: parts[0], // первая часть (имя хоста)
|
||||||
|
location: parts[1] // вторая часть (локация, например msk, swe)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const currentParts = parseDnsParts(currentServer?.dns);
|
||||||
|
const otherParts = parseDnsParts(otherServer?.dns);
|
||||||
|
|
||||||
|
let name;
|
||||||
|
|
||||||
|
if (currentParts && otherParts) {
|
||||||
|
// Используем локацию из другого сервера и имя хоста из другого сервера
|
||||||
|
// Например: для сервера 1 (hiphost.swe.shx.su) с сервером 2 (ihor.msk.rt.shx.su)
|
||||||
|
// Имя на сервере 1: msk-ihor
|
||||||
|
name = `${otherParts.location}-${otherParts.hostname}`;
|
||||||
|
} else if (currentServer?.dns) {
|
||||||
|
// Fallback: используем первую часть DNS
|
||||||
|
name = currentServer.dns.split('.')[0];
|
||||||
|
} else if (currentServer?.ip) {
|
||||||
|
// Fallback: используем IP
|
||||||
|
name = currentServer.ip.split('.').join('-');
|
||||||
|
} else {
|
||||||
|
name = 'server';
|
||||||
|
}
|
||||||
|
|
||||||
const prefixPart = prefix ? `${prefix}-` : '';
|
const prefixPart = prefix ? `${prefix}-` : '';
|
||||||
return `${prefixPart}${typeLower}-${server1Name}-${server2Name}`;
|
return `${prefixPart}${name}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
// === Создание интерфейса из шаблона ===
|
// === Создание интерфейса из шаблона ===
|
||||||
@@ -469,9 +503,9 @@ function NetworkConfigManager() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Генерируем имена интерфейсов
|
// Генерируем имена интерфейсов (используем опциональные имена если указаны)
|
||||||
const name1 = generateInterfaceName(server1, server2, templateType, templateNamePrefix);
|
const name1 = templateName1.trim() || generateInterfaceName(server1, server2, templateType, templateNamePrefix);
|
||||||
const name2 = generateInterfaceName(server2, server1, templateType, templateNamePrefix);
|
const name2 = templateName2.trim() || generateInterfaceName(server2, server1, templateType, templateNamePrefix);
|
||||||
|
|
||||||
// Генерируем IP адреса
|
// Генерируем IP адреса
|
||||||
const localIp = generateFreePrivateIp(null, false, null);
|
const localIp = generateFreePrivateIp(null, false, null);
|
||||||
@@ -518,6 +552,8 @@ function NetworkConfigManager() {
|
|||||||
setTemplateServer2('');
|
setTemplateServer2('');
|
||||||
setTemplateType('GRE');
|
setTemplateType('GRE');
|
||||||
setTemplateNamePrefix('');
|
setTemplateNamePrefix('');
|
||||||
|
setTemplateName1('');
|
||||||
|
setTemplateName2('');
|
||||||
};
|
};
|
||||||
|
|
||||||
// === CRUD для Interfaces ===
|
// === CRUD для Interfaces ===
|
||||||
@@ -2749,6 +2785,8 @@ function NetworkConfigManager() {
|
|||||||
setTemplateServer2('');
|
setTemplateServer2('');
|
||||||
setTemplateType('GRE');
|
setTemplateType('GRE');
|
||||||
setTemplateNamePrefix('');
|
setTemplateNamePrefix('');
|
||||||
|
setTemplateName1('');
|
||||||
|
setTemplateName2('');
|
||||||
}}
|
}}
|
||||||
onSubmit={handleCreateInterfaceFromTemplate}
|
onSubmit={handleCreateInterfaceFromTemplate}
|
||||||
title="Создать интерфейс из шаблона"
|
title="Создать интерфейс из шаблона"
|
||||||
@@ -2819,38 +2857,70 @@ function NetworkConfigManager() {
|
|||||||
const server2 = getServerInfo(templateServer2);
|
const server2 = getServerInfo(templateServer2);
|
||||||
if (!server1 || !server2) return null;
|
if (!server1 || !server2) return null;
|
||||||
|
|
||||||
const previewName1 = generateInterfaceName(server1, server2, templateType, templateNamePrefix);
|
const autoName1 = generateInterfaceName(server1, server2, templateType, templateNamePrefix);
|
||||||
const previewName2 = generateInterfaceName(server2, server1, templateType, templateNamePrefix);
|
const autoName2 = generateInterfaceName(server2, server1, templateType, templateNamePrefix);
|
||||||
|
const previewName1 = templateName1.trim() || autoName1;
|
||||||
|
const previewName2 = templateName2.trim() || autoName2;
|
||||||
const previewLocalIp = generateFreePrivateIp(null, false, null);
|
const previewLocalIp = generateFreePrivateIp(null, false, null);
|
||||||
const previewRemoteIp = previewLocalIp ? generateFreePrivateIp(null, true, previewLocalIp) : null;
|
const previewRemoteIp = previewLocalIp ? generateFreePrivateIp(null, true, previewLocalIp) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="col-12">
|
<>
|
||||||
<div className="card card-sm border">
|
<div className="col-md-6">
|
||||||
<div className="card-body">
|
<label className="form-label">
|
||||||
<h6 className="card-title mb-3">Предпросмотр интерфейса:</h6>
|
Имя интерфейса (сервер 1)
|
||||||
<div className="row g-2">
|
{!templateName1 && <span className="text-muted small ms-1">(авто: {autoName1})</span>}
|
||||||
<div className="col-md-6">
|
</label>
|
||||||
<div className="small text-muted mb-1">Сервер 1 ({server1.dns || server1.ip}):</div>
|
<input
|
||||||
<div><strong>Имя:</strong> <code>{previewName1}</code></div>
|
type="text"
|
||||||
<div><strong>Local IP:</strong> <code>{previewLocalIp || '—'}</code></div>
|
className="form-control"
|
||||||
</div>
|
value={templateName1}
|
||||||
<div className="col-md-6">
|
onChange={(e) => setTemplateName1(e.target.value)}
|
||||||
<div className="small text-muted mb-1">Сервер 2 ({server2.dns || server2.ip}):</div>
|
placeholder={autoName1}
|
||||||
<div><strong>Имя:</strong> <code>{previewName2}</code></div>
|
/>
|
||||||
<div><strong>Local IP:</strong> <code>{previewRemoteIp || '—'}</code></div>
|
<div className="form-text">Оставьте пустым для автогенерации</div>
|
||||||
</div>
|
</div>
|
||||||
{previewLocalIp && previewRemoteIp && (
|
<div className="col-md-6">
|
||||||
<div className="col-12 mt-2">
|
<label className="form-label">
|
||||||
<div className="badge bg-success-lt text-success">
|
Имя интерфейса (сервер 2)
|
||||||
{previewLocalIp} ↔ {previewRemoteIp}
|
{!templateName2 && <span className="text-muted small ms-1">(авто: {autoName2})</span>}
|
||||||
</div>
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="form-control"
|
||||||
|
value={templateName2}
|
||||||
|
onChange={(e) => setTemplateName2(e.target.value)}
|
||||||
|
placeholder={autoName2}
|
||||||
|
/>
|
||||||
|
<div className="form-text">Оставьте пустым для автогенерации</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-12">
|
||||||
|
<div className="card card-sm border">
|
||||||
|
<div className="card-body">
|
||||||
|
<h6 className="card-title mb-3">Предпросмотр интерфейса:</h6>
|
||||||
|
<div className="row g-2">
|
||||||
|
<div className="col-md-6">
|
||||||
|
<div className="small text-muted mb-1">Сервер 1 ({server1.dns || server1.ip}):</div>
|
||||||
|
<div><strong>Имя:</strong> <code>{previewName1}</code></div>
|
||||||
|
<div><strong>Local IP:</strong> <code>{previewLocalIp || '—'}</code></div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
<div className="col-md-6">
|
||||||
|
<div className="small text-muted mb-1">Сервер 2 ({server2.dns || server2.ip}):</div>
|
||||||
|
<div><strong>Имя:</strong> <code>{previewName2}</code></div>
|
||||||
|
<div><strong>Local IP:</strong> <code>{previewRemoteIp || '—'}</code></div>
|
||||||
|
</div>
|
||||||
|
{previewLocalIp && previewRemoteIp && (
|
||||||
|
<div className="col-12 mt-2">
|
||||||
|
<div className="badge bg-success-lt text-success">
|
||||||
|
{previewLocalIp} ↔ {previewRemoteIp}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
})()}
|
})()}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user