From f3396801f81b18d4d639a550e0fe3886cb0e5d36 Mon Sep 17 00:00:00 2001 From: John Susek Date: Sun, 23 Sep 2018 20:52:06 -0500 Subject: [PATCH 01/20] Add search route for doing ES searches. --- src/handlers/search/get.js | 18 ++++++++++++++++++ src/routes/routes.js | 6 ++++++ 2 files changed, 24 insertions(+) create mode 100644 src/handlers/search/get.js diff --git a/src/handlers/search/get.js b/src/handlers/search/get.js new file mode 100644 index 00000000..d2eab689 --- /dev/null +++ b/src/handlers/search/get.js @@ -0,0 +1,18 @@ +import { getClient } from '../../common/elasticsearch_client'; + +export default function searchHandler(request, response) { + /** + * @type {ElastalertServer} + */ + var client = getClient(); + + client.search({ + index: request.params.index, + body: request.body + }).then(function(resp) { + response.send(resp); + }, function(error) { + response.send({ error }); + }); + +} diff --git a/src/routes/routes.js b/src/routes/routes.js index 5161560a..7a7fafd0 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -16,6 +16,7 @@ import configGetHandler from '../handlers/config/get'; import configPostHandler from '../handlers/config/post'; import metadataHandler from '../handlers/metadata/get'; import mappingHandler from '../handlers/mapping/get'; +import searchHandler from '../handlers/search/get'; /** * A server route. @@ -86,6 +87,11 @@ let routes = [ path: 'mapping/:index', method: ['GET'], handler: [mappingHandler] + }, + { + path: 'search/:index', + method: ['POST'], + handler: [searchHandler] } ]; From 766358d69e27d40740f18fc674c544c224f41c3a Mon Sep 17 00:00:00 2001 From: John Susek Date: Sun, 23 Sep 2018 21:00:49 -0500 Subject: [PATCH 02/20] Add server-sent events for tests. --- README.md | 8 +++++ src/controllers/test/index.js | 13 +++++++- src/handlers/test/stream.js | 59 +++++++++++++++++++++++++++++++++++ src/routes/routes.js | 9 +++++- 4 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 src/handlers/test/stream.js diff --git a/README.md b/README.md index de79e20d..3f60fbb7 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,10 @@ This server exposes the following REST API's: } ``` +- **GET `/test_stream`** + + This allows you to test a rule and get a [Server Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) event stream back. Pass params `rule` (yaml string) and `options` (JSON string) to start receiving events. + - **GET `/metadata/:type`** Returns metadata from elasticsearch related to elasalert's state. `:type` should be one of: elastalert_status, elastalert, elastalert_error, or silence. See [docs about the elastalert metadata index](https://elastalert.readthedocs.io/en/latest/elastalert_status.html). @@ -217,6 +221,10 @@ This server exposes the following REST API's: Returns field mapping from elasticsearch for a given index. +- **GET `/search/:index`** + + Performs elasticsearch query on behalf of the API. JSON body to this endpoint will become body of an ES search. + - **[WIP] GET `/config`** Gets the ElastAlert configuration from `config.yaml` in `elastalertPath` (from the config). diff --git a/src/controllers/test/index.js b/src/controllers/test/index.js index 053bb487..425bdaa8 100644 --- a/src/controllers/test/index.js +++ b/src/controllers/test/index.js @@ -19,7 +19,7 @@ export default class TestController { }); } - testRule(rule, options) { + testRule(rule, options, stream, response) { const self = this; let tempFileName = '~' + randomstring.generate() + '.temp'; let tempFilePath = path.join(self.testFolder, tempFileName); @@ -61,14 +61,25 @@ export default class TestController { }); testProcess.stdout.on('data', function (data) { + if (stream) { + response.write('event: result\ndata: ' + data.toString() + '\n\n'); + } stdoutLines.push(data.toString()); }); testProcess.stderr.on('data', function (data) { + if (stream) { + response.write('event: progress\ndata: ' + data.toString() + '\n\n'); + } stderrLines.push(data.toString()); }); testProcess.on('exit', function (statusCode) { + if (stream) { + response.write('event: done\ndata: DONE\n\n'); + response.end(); + } + if (statusCode === 0) { if (options.format === 'json') { resolve(stdoutLines.join('')); diff --git a/src/handlers/test/stream.js b/src/handlers/test/stream.js new file mode 100644 index 00000000..2f8d7a23 --- /dev/null +++ b/src/handlers/test/stream.js @@ -0,0 +1,59 @@ +import RouteLogger from '../../routes/route_logger'; +import {sendRequestError} from '../../common/errors/utils'; +import { RuleNotSendError, OptionsInvalidError} from '../../common/errors/test_request_errors'; +import Joi from 'joi'; + +let logger = new RouteLogger('/test_stream', 'POST'); + +const optionsSchema = Joi.object().keys({ + testType: Joi.string().valid('all', 'schemaOnly', 'countOnly').default('all'), + days: Joi.number().min(1).default(1), + alert: Joi.boolean().default(false), + format: Joi.string().default(''), + maxResults: Joi.number().default(0) +}).default(); + +function analyzeRequest(request) { + if (!request.query.rule) { + return new RuleNotSendError(); + } + + const validationResult = Joi.validate(JSON.parse(request.query.options), optionsSchema); + + if (validationResult.error) { + return new OptionsInvalidError(validationResult.error); + } + + return request.body; +} + +export default function testStreamGetHandler(request, response) { + /** + * @type {ElastalertServer} + */ + let server = request.app.get('server'); + let body = analyzeRequest(request); + + try { + var options = JSON.parse(request.query.options); + } catch (error) { + response.status(500).send(); + } + + if (body.error) { + logger.sendFailed(body.error); + sendRequestError(response, body.error); + } + + response.writeHead(200, { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive' + }); + + try { + server.testController.testRule(request.query.rule, options, true, response); + } catch (error) { + response.status(500).send(); + } +} diff --git a/src/routes/routes.js b/src/routes/routes.js index 7a7fafd0..23a2544c 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -12,6 +12,7 @@ import templateGetHandler from '../handlers/templates/id/get'; import templatePostHandler from '../handlers/templates/id/post'; import templateDeleteHandler from '../handlers/templates/id/delete'; import testPostHandler from '../handlers/test/post'; +import testStreamGetHandler from '../handlers/test/stream'; import configGetHandler from '../handlers/config/get'; import configPostHandler from '../handlers/config/post'; import metadataHandler from '../handlers/metadata/get'; @@ -68,7 +69,13 @@ let routes = [ path: 'test', method: 'POST', handler: testPostHandler - }, { + }, + { + path: 'test_stream', + method: 'GET', + handler: testStreamGetHandler + }, + { path: 'config', method: ['GET', 'POST'], handler: [configGetHandler, configPostHandler] From b3b73e975f27243d409eeeb60617dbdbdf989fed Mon Sep 17 00:00:00 2001 From: John Susek Date: Mon, 24 Sep 2018 10:04:54 -0500 Subject: [PATCH 03/20] Add vscode settings to gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e1b85a52..0030073a 100644 --- a/.gitignore +++ b/.gitignore @@ -74,3 +74,5 @@ lib/ *.pyc config/config.json package-lock.json + +.vscode From e84a3fa8fc79520eaddf701c220d3f92291bb9c9 Mon Sep 17 00:00:00 2001 From: John Susek Date: Fri, 28 Sep 2018 20:01:37 -0500 Subject: [PATCH 04/20] Add websocket support for testing rules. Add search endpoint for checking user queries before a test runs. --- README.md | 9 +++--- config/config.json | 1 + package.json | 3 +- src/common/websocket.js | 27 ++++++++++++++++ src/controllers/test/index.js | 38 +++++++++++++++------- src/elastalert_server.js | 22 ++++++++++++- src/handlers/test/stream.js | 59 ----------------------------------- src/routes/routes.js | 6 ---- 8 files changed, 82 insertions(+), 83 deletions(-) create mode 100644 src/common/websocket.js delete mode 100644 src/handlers/test/stream.js diff --git a/README.md b/README.md index 3f60fbb7..945a7959 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The most convenient way to run the ElastAlert server is by using our Docker cont To run the Docker image you will want to mount the volumes for configuration and rule files to keep them after container updates. In order to do that conveniently, please do: `git clone https://github.com/bitsensor/elastalert.git; cd elastalert` ```bash -docker run -d -p 3030:3030 \ +docker run -d -p 3030:3030 -p 3333:3333 \ -v `pwd`/config/elastalert.yaml:/opt/elastalert/config.yaml \ -v `pwd`/config/config.json:/opt/elastalert-server/config/config.json \ -v `pwd`/rules:/opt/elastalert/rules \ @@ -60,6 +60,7 @@ You can use the following config options: { "appName": "elastalert-server", // The name used by the logging framework. "port": 3030, // The port to bind to + "wsport": 3333, // The port to bind to for websockets "elastalertPath": "/opt/elastalert", // The path to the root ElastAlert folder. It's the folder that contains the `setup.py` script. "start": "2014-01-01T00:00:00", // Optional date to start querying from "end": "2016-01-01T00:00:00", // Optional date to stop querying at @@ -208,10 +209,10 @@ This server exposes the following REST API's: } } ``` - -- **GET `/test_stream`** - This allows you to test a rule and get a [Server Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) event stream back. Pass params `rule` (yaml string) and `options` (JSON string) to start receiving events. +- **WEBSOCKET `/test`** + + This allows you to test a rule and receive progress over a websocket. Send a message as JSON object (stringified) with two keys: `rule` (yaml string) and `options` (JSON object). You will receive progress messages over the socket as the test runs. - **GET `/metadata/:type`** diff --git a/config/config.json b/config/config.json index d3afcf46..371abd75 100644 --- a/config/config.json +++ b/config/config.json @@ -2,6 +2,7 @@ "appName": "elastalert-server", "port": 3030, "elastalertPath": "/opt/elastalert", + "wsport": 3333, "verbose": false, "es_debug": false, "debug": false, diff --git a/package.json b/package.json index 7f26ee66..b404f96c 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,8 @@ "raven": "^2.6.1", "request": "^2.85.0", "request-promise-native": "^1.0.5", - "tar": "^4.4.1" + "tar": "^4.4.1", + "ws": "^6.0.0" }, "devDependencies": { "eslint": "^4.17.0", diff --git a/src/common/websocket.js b/src/common/websocket.js new file mode 100644 index 00000000..af6f8a6a --- /dev/null +++ b/src/common/websocket.js @@ -0,0 +1,27 @@ +import WebSocket from 'ws'; + +export var wss = null; + +export function listen(port) { + wss = new WebSocket.Server({ port, path: '/test' }); + + wss.on('connection', ws => { + ws.isAlive = true; + ws.on('pong', () => { + ws.isAlive = true; + }); + }); + + return wss; +} + +// Keepalive in case clients lose connection during a long rule test. +// If client doesn't respond in 10s this will close the socket and +// therefore stop the elastalert test from continuing to run detached. +setInterval(() => { + wss.clients.forEach(ws => { + if (ws.isAlive === false) return ws.terminate(); + ws.isAlive = false; + ws.ping(() => {}); + }); +}, 10000); diff --git a/src/controllers/test/index.js b/src/controllers/test/index.js index 425bdaa8..0f9bdbb8 100644 --- a/src/controllers/test/index.js +++ b/src/controllers/test/index.js @@ -19,7 +19,7 @@ export default class TestController { }); } - testRule(rule, options, stream, response) { + testRule(rule, options, socket) { const self = this; let tempFileName = '~' + randomstring.generate() + '.temp'; let tempFilePath = path.join(self.testFolder, tempFileName); @@ -55,31 +55,41 @@ export default class TestController { break; } + try { let testProcess = spawn('python', processOptions, { cwd: self._elastalertPath }); + // When the websocket closes we kill the test process + // so it doesn't keep running detached + if (socket) { + socket.on('close', () => { + testProcess.kill(); + }); + } + testProcess.stdout.on('data', function (data) { - if (stream) { - response.write('event: result\ndata: ' + data.toString() + '\n\n'); + if (socket) { + socket.send(JSON.stringify({ + event: 'result', + data: data.toString() + })); } stdoutLines.push(data.toString()); }); testProcess.stderr.on('data', function (data) { - if (stream) { - response.write('event: progress\ndata: ' + data.toString() + '\n\n'); + if (socket) { + socket.send(JSON.stringify({ + event: 'progress', + data: data.toString() + })); } stderrLines.push(data.toString()); }); testProcess.on('exit', function (statusCode) { - if (stream) { - response.write('event: done\ndata: DONE\n\n'); - response.end(); - } - if (statusCode === 0) { if (options.format === 'json') { resolve(stdoutLines.join('')); @@ -88,8 +98,10 @@ export default class TestController { resolve(stdoutLines.join('\n')); } } else { - reject(stderrLines.join('\n')); - logger.error(stderrLines.join('\n')); + if (!socket) { + reject(stderrLines.join('\n')); + logger.error(stderrLines.join('\n')); + } } fileSystem.deleteFile(tempFilePath) @@ -106,6 +118,8 @@ export default class TestController { logger.error(`Failed to write file ${tempFileName} to ${self.testFolder} with error:`, error); reject(error); }); + }).catch((error) => { + logger.error('Failed to test rule with error:', error); }); } diff --git a/src/elastalert_server.js b/src/elastalert_server.js index 8db07e9d..aebe82b0 100644 --- a/src/elastalert_server.js +++ b/src/elastalert_server.js @@ -4,6 +4,7 @@ import Logger from './common/logger'; import config from './common/config'; import path from 'path'; import FileSystem from './common/file_system'; +import { listen } from './common/websocket'; import setupRouter from './routes/route_setup'; import ProcessController from './controllers/process'; import RulesController from './controllers/rules'; @@ -77,8 +78,27 @@ export default class ElastalertServer { self._fileSystemController.createDirectoryIfNotExists(self.getDataFolder()).catch(function (error) { logger.error('Error creating data folder with error:', error); }); - + logger.info('Server listening on port ' + config.get('port')); + + let wss = listen(config.get('wsport')); + + wss.on('connection', ws => { + ws.on('message', (data) => { + try { + data = JSON.parse(data); + if (data.rule) { + let rule = data.rule; + let options = data.options; + self._testController.testRule(rule, options, ws); + } + } catch (error) { + console.log(error); + } + }); + }); + + logger.info('Websocket listening on port 3333'); } catch (error) { logger.error('Starting server failed with error:', error); process.exit(1); diff --git a/src/handlers/test/stream.js b/src/handlers/test/stream.js deleted file mode 100644 index 2f8d7a23..00000000 --- a/src/handlers/test/stream.js +++ /dev/null @@ -1,59 +0,0 @@ -import RouteLogger from '../../routes/route_logger'; -import {sendRequestError} from '../../common/errors/utils'; -import { RuleNotSendError, OptionsInvalidError} from '../../common/errors/test_request_errors'; -import Joi from 'joi'; - -let logger = new RouteLogger('/test_stream', 'POST'); - -const optionsSchema = Joi.object().keys({ - testType: Joi.string().valid('all', 'schemaOnly', 'countOnly').default('all'), - days: Joi.number().min(1).default(1), - alert: Joi.boolean().default(false), - format: Joi.string().default(''), - maxResults: Joi.number().default(0) -}).default(); - -function analyzeRequest(request) { - if (!request.query.rule) { - return new RuleNotSendError(); - } - - const validationResult = Joi.validate(JSON.parse(request.query.options), optionsSchema); - - if (validationResult.error) { - return new OptionsInvalidError(validationResult.error); - } - - return request.body; -} - -export default function testStreamGetHandler(request, response) { - /** - * @type {ElastalertServer} - */ - let server = request.app.get('server'); - let body = analyzeRequest(request); - - try { - var options = JSON.parse(request.query.options); - } catch (error) { - response.status(500).send(); - } - - if (body.error) { - logger.sendFailed(body.error); - sendRequestError(response, body.error); - } - - response.writeHead(200, { - 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache', - 'Connection': 'keep-alive' - }); - - try { - server.testController.testRule(request.query.rule, options, true, response); - } catch (error) { - response.status(500).send(); - } -} diff --git a/src/routes/routes.js b/src/routes/routes.js index 23a2544c..e4fedecd 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -12,7 +12,6 @@ import templateGetHandler from '../handlers/templates/id/get'; import templatePostHandler from '../handlers/templates/id/post'; import templateDeleteHandler from '../handlers/templates/id/delete'; import testPostHandler from '../handlers/test/post'; -import testStreamGetHandler from '../handlers/test/stream'; import configGetHandler from '../handlers/config/get'; import configPostHandler from '../handlers/config/post'; import metadataHandler from '../handlers/metadata/get'; @@ -70,11 +69,6 @@ let routes = [ method: 'POST', handler: testPostHandler }, - { - path: 'test_stream', - method: 'GET', - handler: testStreamGetHandler - }, { path: 'config', method: ['GET', 'POST'], From 1fb05372542d1820f00690c3e3dcf86bfdbe4760 Mon Sep 17 00:00:00 2001 From: John Susek Date: Tue, 25 Sep 2018 09:31:44 -0500 Subject: [PATCH 05/20] Clean up temp file if user cancels test --- src/controllers/test/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/controllers/test/index.js b/src/controllers/test/index.js index 0f9bdbb8..2df0c6c7 100644 --- a/src/controllers/test/index.js +++ b/src/controllers/test/index.js @@ -66,6 +66,11 @@ export default class TestController { if (socket) { socket.on('close', () => { testProcess.kill(); + + fileSystem.deleteFile(tempFilePath) + .catch(function (error) { + logger.error(`Failed to delete temporary test file ${tempFilePath} with error:`, error); + }); }); } From 37111813007147436cab654c2509bb61d687ca81 Mon Sep 17 00:00:00 2001 From: John Susek Date: Fri, 28 Sep 2018 11:19:32 -0500 Subject: [PATCH 06/20] Escape and quote rule names when searching for elastalert metadata. --- src/handlers/metadata/get.js | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/handlers/metadata/get.js b/src/handlers/metadata/get.js index 36bd8eb3..229df943 100644 --- a/src/handlers/metadata/get.js +++ b/src/handlers/metadata/get.js @@ -2,12 +2,43 @@ import config from '../../common/config'; import { getClient } from '../../common/elasticsearch_client'; +function escapeLuceneSyntax(str) { + return [].map + .call(str, char => { + if ( + char === '/' || + char === '+' || + char === '-' || + char === '&' || + char === '|' || + char === '!' || + char === '(' || + char === ')' || + char === '{' || + char === '}' || + char === '[' || + char === ']' || + char === '^' || + char === '"' || + char === '~' || + char === '*' || + char === '?' || + char === ':' || + char === '\\' + ) { + return `\\${char}`; + } + return char; + }) + .join(''); +} + function getQueryString(request) { if (request.params.type === 'elastalert_error') { return '*:*'; } else { - return `rule_name:${request.query.rule_name || '*'}`; + return `rule_name:"${escapeLuceneSyntax(request.query.rule_name) || '*'}"`; } } From cefeff2542f3ec87c4c9972084e2799bbfb053fc Mon Sep 17 00:00:00 2001 From: John Susek Date: Fri, 28 Sep 2018 20:06:20 -0500 Subject: [PATCH 07/20] Update example configs --- config/config-hisoric-data-example.json | 7 ++++++- config/config-local-elastalert-installation.json | 7 ++++++- config/config.json | 4 ++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/config/config-hisoric-data-example.json b/config/config-hisoric-data-example.json index fd3b1f05..247da2f8 100644 --- a/config/config-hisoric-data-example.json +++ b/config/config-hisoric-data-example.json @@ -1,6 +1,7 @@ { "appName": "elastalert-server", "port": 3030, + "wsport": 3333, "elastalertPath": "/opt/elastalert", "start": "2014-01-01T00:00:00", "end": "2016-01-01T00:00:00", @@ -14,5 +15,9 @@ "templatesPath": { "relative": true, "path": "/rule_templates" - } + }, + "es_host": "elasticsearch", + "es_port": 9200, + "writeback_index": "elastalert_status" + } \ No newline at end of file diff --git a/config/config-local-elastalert-installation.json b/config/config-local-elastalert-installation.json index d92d71a8..c8e8e3fd 100644 --- a/config/config-local-elastalert-installation.json +++ b/config/config-local-elastalert-installation.json @@ -1,6 +1,7 @@ { "appName": "elastalert-server", "port": 3030, + "wsport": 3333, "elastalertPath": "/opt/elastalert", "verbose": false, "es_debug": false, @@ -12,5 +13,9 @@ "templatesPath": { "relative": false, "path": "/opt/elastalert/rule_templates" - } + }, + "es_host": "elasticsearch", + "es_port": 9200, + "writeback_index": "elastalert_status" + } \ No newline at end of file diff --git a/config/config.json b/config/config.json index 371abd75..0f4aecd2 100644 --- a/config/config.json +++ b/config/config.json @@ -1,8 +1,8 @@ { "appName": "elastalert-server", "port": 3030, - "elastalertPath": "/opt/elastalert", "wsport": 3333, + "elastalertPath": "/opt/elastalert", "verbose": false, "es_debug": false, "debug": false, @@ -14,7 +14,7 @@ "relative": true, "path": "/rule_templates" }, - "es_host": "localhost", + "es_host": "elasticsearch", "es_port": 9200, "writeback_index": "elastalert_status" } From b3e8925cad42b6780cf0f6e462c6b6358f2a9a60 Mon Sep 17 00:00:00 2001 From: Alvaro Olmedo Date: Thu, 7 Mar 2019 11:28:22 +0100 Subject: [PATCH 08/20] Fixing get config of index used to write back --- src/controllers/process/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/process/index.js b/src/controllers/process/index.js index 79ac0e24..1528a1cb 100644 --- a/src/controllers/process/index.js +++ b/src/controllers/process/index.js @@ -38,7 +38,7 @@ export default class ProcessController { // Create ElastAlert index if it doesn't exist yet logger.info('Creating index'); - var indexCreate = spawnSync('python', ['-m', 'elastalert.create_index', '--index', 'elastalert_status', '--old-index', ''], { + var indexCreate = spawnSync('python', ['-m', config.get('writeback_index'), '--index', 'elastalert_status', '--old-index', ''], { cwd: this._elastalertPath }); From 97dabb5df731d5845413566a76dfdfa584df099a Mon Sep 17 00:00:00 2001 From: Alvaro Olmedo Date: Thu, 7 Mar 2019 11:42:43 +0100 Subject: [PATCH 09/20] Typo fixed --- src/controllers/process/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/process/index.js b/src/controllers/process/index.js index 1528a1cb..69f259c7 100644 --- a/src/controllers/process/index.js +++ b/src/controllers/process/index.js @@ -38,7 +38,7 @@ export default class ProcessController { // Create ElastAlert index if it doesn't exist yet logger.info('Creating index'); - var indexCreate = spawnSync('python', ['-m', config.get('writeback_index'), '--index', 'elastalert_status', '--old-index', ''], { + var indexCreate = spawnSync('python', ['-m', 'elastalert.create_index', '--index', config.get('writeback_index'), '--old-index', ''], { cwd: this._elastalertPath }); From ad03913a1faf07b36e36297d67bfd10211ec494e Mon Sep 17 00:00:00 2001 From: Garrett Thornburg Date: Mon, 1 Apr 2019 10:56:09 -0400 Subject: [PATCH 10/20] Add a callback to the elastalert process to stop the server on exit --- src/controllers/process/index.js | 11 +++++++++++ src/elastalert_server.js | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/src/controllers/process/index.js b/src/controllers/process/index.js index 79ac0e24..2e5841b3 100644 --- a/src/controllers/process/index.js +++ b/src/controllers/process/index.js @@ -9,6 +9,7 @@ export default class ProcessController { constructor() { this._elastalertPath = config.get('elastalertPath'); + this._onExitCallbacks = []; this._status = Status.IDLE; /** @@ -18,6 +19,10 @@ export default class ProcessController { this._process = null; } + onExit(onExitCallback) { + this._onExitCallbacks.push(onExitCallback); + } + get status() { return this._status; } @@ -112,6 +117,12 @@ export default class ProcessController { this._status = Status.ERROR; } this._process = null; + + this._onExitCallbacks.map(function(onExitCallback) { + if (onExitCallback !== null) { + onExitCallback(); + } + }); }); // Set listener for ElastAlert error diff --git a/src/elastalert_server.js b/src/elastalert_server.js index 8db07e9d..ee7c20cf 100644 --- a/src/elastalert_server.js +++ b/src/elastalert_server.js @@ -69,6 +69,10 @@ export default class ElastalertServer { self._fileSystemController = new FileSystem(); self._processController = new ProcessController(); self._processController.start(); + self._processController.onExit(function() { + // If the elastalert process exits, we should stop the server. + process.exit(0); + }); self._rulesController = new RulesController(); self._templatesController = new TemplatesController(); From dce8fc1e28dd2752f1c8636080b57c7c6ff7789c Mon Sep 17 00:00:00 2001 From: Martijn Rondeel Date: Tue, 2 Apr 2019 11:56:41 +0200 Subject: [PATCH 11/20] Update ElastAlert to v0.1.39 --- Dockerfile | 2 +- Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1f83f624..c638b783 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM alpine:latest as py-ea -ARG ELASTALERT_VERSION=v0.1.38 +ARG ELASTALERT_VERSION=v0.1.39 ENV ELASTALERT_VERSION=${ELASTALERT_VERSION} # URL from which to download Elastalert. ARG ELASTALERT_URL=https://github.com/Yelp/elastalert/archive/$ELASTALERT_VERSION.zip diff --git a/Makefile b/Makefile index 78767ffa..82255fc0 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -v ?= v0.1.38 +v ?= v0.1.39 all: build From 671cac65d729a6c1ff7c1961ddb5bf9ac45cf6e0 Mon Sep 17 00:00:00 2001 From: Martijn Rondeel Date: Tue, 2 Apr 2019 13:07:52 +0200 Subject: [PATCH 12/20] Bump version to 2.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fff21598..aee8e84b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@bitsensor/elastalert", - "version": "1.0.0", + "version": "2.0.0", "description": "A server that runs ElastAlert and exposes REST API's for manipulating rules and alerts.", "license": "MIT", "main": "index.js", From 14e836feda45aba016efcc74a7f5415000305422 Mon Sep 17 00:00:00 2001 From: Martijn Rondeel Date: Tue, 2 Apr 2019 15:08:27 +0200 Subject: [PATCH 13/20] Set websocket port to default of 3333 --- src/common/config/schema.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/config/schema.js b/src/common/config/schema.js index fe757a4d..2d60e964 100644 --- a/src/common/config/schema.js +++ b/src/common/config/schema.js @@ -7,6 +7,7 @@ const schema = Joi.object().keys({ 'es_port': Joi.number().default(9200), 'writeback_index': Joi.string().default('elastalert_status'), 'port': Joi.number().default(3030), + 'wsport': Joi.number().default(3333), 'elastalertPath': Joi.string().default('/opt/elastalert'), 'rulesPath': Joi.object().keys({ 'relative': Joi.boolean().default(true), From f1c5069724a544244d9a287df76470aa4a0cdde3 Mon Sep 17 00:00:00 2001 From: Martijn Rondeel Date: Tue, 2 Apr 2019 15:09:37 +0200 Subject: [PATCH 14/20] Bump version to 2.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index aee8e84b..0ea6ac65 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@bitsensor/elastalert", - "version": "2.0.0", + "version": "2.0.1", "description": "A server that runs ElastAlert and exposes REST API's for manipulating rules and alerts.", "license": "MIT", "main": "index.js", From d7253d5518e36c04041c650cf930fd5b659cc5dd Mon Sep 17 00:00:00 2001 From: Martijn Rondeel Date: Fri, 19 Apr 2019 12:16:14 +0200 Subject: [PATCH 15/20] Update LICENSE.md --- LICENSE.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index ef020c3d..d8a65aa0 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,7 +1,7 @@ The 3-clause BSD license (Modified) =================================== -Copyright © 2018, BitSensor B.V. +Copyright © 2019, BitSensor B.V. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -14,9 +14,9 @@ modification, are permitted provided that the following conditions are met: * Neither the name of BitSensor, BitSensor B.V. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - However, those names can be used when explicitely stating the use of - the ElastAlert Server Plugin (which can be rephrased as the Alerting - Plugin). + However, those names can be used when explicitly stating the use of + the 'ElastAlert Server Plugin' (which can be rephrased as the 'Alerting + Plugin'). THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED From eb0d53e8c2b976393a9cd193030a3b85947ffd50 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Delpech Date: Tue, 16 Apr 2019 16:16:28 +0200 Subject: [PATCH 16/20] chore: run image as node user Run elastalert image as unpriviledged user --- Dockerfile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Dockerfile b/Dockerfile index c638b783..f1aee048 100644 --- a/Dockerfile +++ b/Dockerfile @@ -45,5 +45,12 @@ COPY config/config.json config/config.json COPY rule_templates/ /opt/elastalert/rule_templates COPY elastalert_modules/ /opt/elastalert/elastalert_modules +# Add default rules directory +# Set permission as unpriviledged user (1000:1000), compatible with Kubernetes +RUN mkdir -p /opt/elastalert/rules/ /opt/elastalert/server_data/tests/ \ + && chown -R node:node /opt + +USER node + EXPOSE 3030 ENTRYPOINT ["npm", "start"] From baf90a96a69c3438b56e9f3d35adae9d7ee1e853 Mon Sep 17 00:00:00 2001 From: Martijn Rondeel Date: Tue, 14 May 2019 09:58:58 +0200 Subject: [PATCH 17/20] Bump version to 3.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0ea6ac65..306f7b08 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@bitsensor/elastalert", - "version": "2.0.1", + "version": "3.0.0", "description": "A server that runs ElastAlert and exposes REST API's for manipulating rules and alerts.", "license": "MIT", "main": "index.js", From 5c3155c69da6c58d7259a69336d0b2fe69de517b Mon Sep 17 00:00:00 2001 From: Martijn Rondeel Date: Tue, 14 May 2019 10:00:39 +0200 Subject: [PATCH 18/20] Fix error when starting ElastAlert --- src/controllers/process/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/process/index.js b/src/controllers/process/index.js index 83e7f40d..6ad53432 100644 --- a/src/controllers/process/index.js +++ b/src/controllers/process/index.js @@ -48,10 +48,10 @@ export default class ProcessController { }); // Redirect stdin/stderr to logger - if (indexCreate.stdout.toString() !== '') { + if (indexCreate.stdout && indexCreate.stdout.toString() !== '') { logger.info(indexCreate.stdout.toString()); } - if (indexCreate.stderr.toString() !== '') { + if (indexCreate.stderr && indexCreate.stderr.toString() !== '') { logger.error(indexCreate.stderr.toString()); } From 3806188716970f7f2bac6c3f41c81c15062e3357 Mon Sep 17 00:00:00 2001 From: Martijn Rondeel Date: Tue, 14 May 2019 11:07:04 +0200 Subject: [PATCH 19/20] Bump version to 3.0.0-beta.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 306f7b08..b1150496 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@bitsensor/elastalert", - "version": "3.0.0", + "version": "3.0.0-beta.0", "description": "A server that runs ElastAlert and exposes REST API's for manipulating rules and alerts.", "license": "MIT", "main": "index.js", From 6720985ae59acbf1145189b6a44d74fbf45b415d Mon Sep 17 00:00:00 2001 From: Martijn Rondeel Date: Tue, 14 May 2019 11:07:24 +0200 Subject: [PATCH 20/20] Bump ElastAlert to v0.2.0b2 --- Dockerfile | 2 +- Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index c638b783..226d70df 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM alpine:latest as py-ea -ARG ELASTALERT_VERSION=v0.1.39 +ARG ELASTALERT_VERSION=v0.2.0b2 ENV ELASTALERT_VERSION=${ELASTALERT_VERSION} # URL from which to download Elastalert. ARG ELASTALERT_URL=https://github.com/Yelp/elastalert/archive/$ELASTALERT_VERSION.zip diff --git a/Makefile b/Makefile index 82255fc0..9a7610e0 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -v ?= v0.1.39 +v ?= v0.2.0b2 all: build