feat(mikrotikConfigRoutes, FilterManager): add run-script endpoint and integrate BGP update functionality in FilterManager
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 2m7s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 2m7s
This commit is contained in:
@@ -272,10 +272,46 @@ async function applyMikrotikConfig(req, res) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /api/mikrotik/run-script
|
||||||
|
* Body: { serverId, script?: string } — по умолчанию script=update_bgp_filter
|
||||||
|
*/
|
||||||
|
async function runScript(req, res) {
|
||||||
|
try {
|
||||||
|
const { serverId, script = 'update_bgp_filter' } = req.body || {};
|
||||||
|
if (!serverId) {
|
||||||
|
return sendError(res, 400, 'serverId is required', 'E_BAD_REQUEST');
|
||||||
|
}
|
||||||
|
|
||||||
|
const servers = await readServersFromS3();
|
||||||
|
const server = servers.find(s => (s.id || s.dns || s.ip) === serverId);
|
||||||
|
if (!server || server.type !== 'jumphost') {
|
||||||
|
return sendError(res, 400, 'Jumphost server not found', 'E_NOT_FOUND');
|
||||||
|
}
|
||||||
|
|
||||||
|
const creds = getMikrotikCredentials(server);
|
||||||
|
if (!creds) {
|
||||||
|
return sendError(res, 400, 'MikroTik credentials not configured for this server', 'E_CREDENTIALS');
|
||||||
|
}
|
||||||
|
|
||||||
|
const client = createRosClient(creds);
|
||||||
|
// /rest/execute — выполнение произвольной команды (как в CLI)
|
||||||
|
await client.command('execute', { script: `/system script run ${script}` });
|
||||||
|
|
||||||
|
return sendOk(res, { ok: true, message: `Скрипт ${script} запущен` });
|
||||||
|
} catch (error) {
|
||||||
|
const msg = error.response?.data?.message || error.message || 'Ошибка запуска скрипта';
|
||||||
|
const status = error.response?.status;
|
||||||
|
console.error('runScript:', error);
|
||||||
|
return sendError(res, status && status >= 400 ? status : 502, msg, 'E_SCRIPT');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
generateMikrotikConfig,
|
generateMikrotikConfig,
|
||||||
generateInterfaces,
|
generateInterfaces,
|
||||||
generateRecursiveRoutes,
|
generateRecursiveRoutes,
|
||||||
testMikrotikConnection,
|
testMikrotikConnection,
|
||||||
applyMikrotikConfig,
|
applyMikrotikConfig,
|
||||||
|
runScript,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -452,6 +452,7 @@ app.get('/api/mikrotik/generate-recursive-routes', mikrotikConfigRoutes.generate
|
|||||||
app.post('/api/mikrotik/test-connection', mikrotikConfigRoutes.testMikrotikConnection);
|
app.post('/api/mikrotik/test-connection', mikrotikConfigRoutes.testMikrotikConnection);
|
||||||
app.get('/api/mikrotik/ping', (req, res) => res.json({ ok: true, ts: Date.now() }));
|
app.get('/api/mikrotik/ping', (req, res) => res.json({ ok: true, ts: Date.now() }));
|
||||||
app.post('/api/mikrotik/apply', mikrotikConfigRoutes.applyMikrotikConfig);
|
app.post('/api/mikrotik/apply', mikrotikConfigRoutes.applyMikrotikConfig);
|
||||||
|
app.post('/api/mikrotik/run-script', mikrotikConfigRoutes.runScript);
|
||||||
|
|
||||||
// === MIKROTIK VALIDATION ===
|
// === MIKROTIK VALIDATION ===
|
||||||
app.post('/api/mikrotik/validate', async (req, res) => {
|
app.post('/api/mikrotik/validate', async (req, res) => {
|
||||||
|
|||||||
@@ -746,6 +746,7 @@ function FilterManager() {
|
|||||||
// Состояние для массовых действий
|
// Состояние для массовых действий
|
||||||
const [selectedFilterKeys, setSelectedFilterKeys] = useState(new Set());
|
const [selectedFilterKeys, setSelectedFilterKeys] = useState(new Set());
|
||||||
const [confirmState, setConfirmState] = useState({ open: false, text: '', onConfirm: null });
|
const [confirmState, setConfirmState] = useState({ open: false, text: '', onConfirm: null });
|
||||||
|
const [bgpUpdateLoading, setBgpUpdateLoading] = useState(false);
|
||||||
|
|
||||||
// Состояние для копирования правил с сервера
|
// Состояние для копирования правил с сервера
|
||||||
const [copyFromServerModalOpen, setCopyFromServerModalOpen] = useState(false);
|
const [copyFromServerModalOpen, setCopyFromServerModalOpen] = useState(false);
|
||||||
@@ -1070,6 +1071,22 @@ function FilterManager() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleBgpUpdate = async () => {
|
||||||
|
if (!selectedServer) return;
|
||||||
|
setBgpUpdateLoading(true);
|
||||||
|
setError('');
|
||||||
|
try {
|
||||||
|
await api.post('/mikrotik/run-script', { serverId: selectedServer.id, script: 'update_bgp_filter' });
|
||||||
|
setSuccess(`Скрипт update_bgp_filter запущен на ${selectedServer.name}`);
|
||||||
|
setTimeout(() => setSuccess(''), 3000);
|
||||||
|
} catch (err) {
|
||||||
|
const msg = err.response?.data?.message || err.message || 'Не удалось запустить скрипт';
|
||||||
|
setError(msg);
|
||||||
|
} finally {
|
||||||
|
setBgpUpdateLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleSaveServerConfig = async (serverId) => {
|
const handleSaveServerConfig = async (serverId) => {
|
||||||
try {
|
try {
|
||||||
const config = await generateMikrotikConfig();
|
const config = await generateMikrotikConfig();
|
||||||
@@ -1802,6 +1819,15 @@ function FilterManager() {
|
|||||||
<IconDeviceFloppy className="icon" />
|
<IconDeviceFloppy className="icon" />
|
||||||
Сохранить
|
Сохранить
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
className="btn btn-outline-primary"
|
||||||
|
onClick={handleBgpUpdate}
|
||||||
|
disabled={bgpUpdateLoading}
|
||||||
|
title="Запустить /system script run update_bgp_filter на выбранном MikroTik"
|
||||||
|
>
|
||||||
|
<IconRefresh className={`icon ${bgpUpdateLoading ? 'spin' : ''}`} />
|
||||||
|
{bgpUpdateLoading ? 'Запуск...' : 'Обновить BGP фильтры'}
|
||||||
|
</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user