diff --git a/backend/routes/mikrotikConfigRoutes.js b/backend/routes/mikrotikConfigRoutes.js
index ece721e..fa032a6 100644
--- a/backend/routes/mikrotikConfigRoutes.js
+++ b/backend/routes/mikrotikConfigRoutes.js
@@ -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 = {
generateMikrotikConfig,
generateInterfaces,
generateRecursiveRoutes,
testMikrotikConnection,
applyMikrotikConfig,
+ runScript,
};
diff --git a/backend/server.js b/backend/server.js
index e0dca61..f090df9 100644
--- a/backend/server.js
+++ b/backend/server.js
@@ -452,6 +452,7 @@ app.get('/api/mikrotik/generate-recursive-routes', mikrotikConfigRoutes.generate
app.post('/api/mikrotik/test-connection', mikrotikConfigRoutes.testMikrotikConnection);
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/run-script', mikrotikConfigRoutes.runScript);
// === MIKROTIK VALIDATION ===
app.post('/api/mikrotik/validate', async (req, res) => {
diff --git a/frontend/src/FilterManager.jsx b/frontend/src/FilterManager.jsx
index f09ad8f..1229038 100644
--- a/frontend/src/FilterManager.jsx
+++ b/frontend/src/FilterManager.jsx
@@ -746,6 +746,7 @@ function FilterManager() {
// Состояние для массовых действий
const [selectedFilterKeys, setSelectedFilterKeys] = useState(new Set());
const [confirmState, setConfirmState] = useState({ open: false, text: '', onConfirm: null });
+ const [bgpUpdateLoading, setBgpUpdateLoading] = 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) => {
try {
const config = await generateMikrotikConfig();
@@ -1802,6 +1819,15 @@ function FilterManager() {
Сохранить
+
>
)}