From 91f0d03f2a873a2b72ec162914266b0ab685e3e6 Mon Sep 17 00:00:00 2001 From: Massimo Candela Date: Tue, 26 May 2020 14:50:16 +0200 Subject: [PATCH] proxy support (#234) Introduced proxy support Co-authored-by: Florian Domain --- .travis.yml | 13 ++- AUTHORS | 1 + README.md | 1 + build.sh | 4 - config.yml.example | 8 ++ docs/configuration.md | 5 + docs/http-proxy.md | 34 ++++++ docs/prefixes.md | 1 + index.js | 7 +- package-lock.json | 67 ++++++++++-- package.json | 6 +- src/connectors/connector.js | 7 ++ src/connectors/connectorRIS.js | 10 +- src/connectors/connectorSwUpdates.js | 5 +- src/env.js | 9 +- src/generatePrefixesList.js | 8 +- src/monitors/monitor.js | 7 ++ src/processMonitors/uptime.js | 5 + src/processMonitors/uptimeHealthcheck.js | 3 +- src/reports/report.js | 6 ++ src/reports/reportAlerta.js | 5 +- src/reports/reportHTTP.js | 3 +- src/reports/reportWebex.js | 6 +- src/{ => utils}/fileLogger.js | 6 +- src/{ => utils}/lossyBuffer.js | 0 src/{ => utils}/pubSub.js | 0 src/worker.js | 2 +- tests/config.test.yml | 2 + tests/proxy_tests/config.proxy.test.yml | 55 ++++++++++ tests/proxy_tests/test_proxy.sh | 12 +++ tests/proxy_tests/tests.js | 125 +++++++++++++++++++++++ 31 files changed, 381 insertions(+), 42 deletions(-) create mode 100644 docs/http-proxy.md rename src/{ => utils}/fileLogger.js (97%) rename src/{ => utils}/lossyBuffer.js (100%) rename src/{ => utils}/pubSub.js (100%) create mode 100644 tests/proxy_tests/config.proxy.test.yml create mode 100755 tests/proxy_tests/test_proxy.sh create mode 100644 tests/proxy_tests/tests.js diff --git a/.travis.yml b/.travis.yml index 83da795..dcb538a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,18 @@ language: node_js node_js: - - 10 + - 12 + +jobs: + include: + - stage: "Tests without proxy" + name: "Tests without proxy" + script: npm run test + - stage: "Tests with proxy" + name: "Tests with proxy" + script: npm run test-proxy cache: - yarn: true + npm: true directories: - node_modules diff --git a/AUTHORS b/AUTHORS index bfd34bf..f65c226 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,6 +13,7 @@ If this list is not up to date, please contact NTT or one of the authors. Damian Zaremba, Fastly Mircea Ulinic, DigitalOcean Alan Haynes, Harbin Clinic + Florian Domain, Criteo A special THANK YOU goes to: diff --git a/README.md b/README.md index c28827d..ca7b794 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ Read the documentation below for more options. - [reportHTTP](docs/configuration.md#reporthttp) - [Process/Uptime monitoring](docs/process-monitors.md) - [Notification user groups](docs/usergroups.md) + - [HTTP/HTTPS proxy](docs/http-proxy.md) - [More information for developers](docs/develop.md) - [All npm commands](docs/develop.md#all-npm-commands) - [Git flow](docs/release-process.md#git-flow) diff --git a/build.sh b/build.sh index e82506d..0743726 100755 --- a/build.sh +++ b/build.sh @@ -5,10 +5,6 @@ mkdir bin npm run babel . -- --ignore node_modules --out-dir build -cp config.yml.example build/config.yml - -cp package.json build/package.json - cd build npm install --silent diff --git a/config.yml.example b/config.yml.example index 52335e1..c969636 100644 --- a/config.yml.example +++ b/config.yml.example @@ -4,6 +4,7 @@ connectors: params: carefulSubscription: true url: wss://ris-live.ripe.net/v1/ws/ + noProxy: false perMessageDeflate: true subscription: moreSpecific: true @@ -102,6 +103,7 @@ reports: # - misconfiguration # - rpki # params: +# noProxy: false # showPaths: 0 # Amount of AS_PATHs to report in the alert # colors: # hijack: '#d60b1c' @@ -154,6 +156,7 @@ reports: # - misconfiguration # - rpki # params: +# noProxy: false # severity: # hijack: critical # newprefix: informational @@ -176,6 +179,7 @@ reports: # - misconfiguration # - rpki # params: +# noProxy: false # hooks: # default: _YOUR_WEBEX_WEBHOOK_URL_ @@ -246,6 +250,10 @@ checkForUpdatesAtBoot: true monitoredPrefixesFiles: - prefixes.yml +############################ +# HTTP proxy setting: +# Allow to run BGPalerter behind an HTTP(S) proxy +# httpProxy: http://username:password@127.0.0.1:9000 ############################ diff --git a/docs/configuration.md b/docs/configuration.md index a4b1549..e7777bb 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -16,6 +16,7 @@ The following are common parameters which it is possible to specify in the confi |logging.maxRetainedFiles| Indicates the maximum amount of log files retained. When this threshold is passed, files are deleted. | An integer | 10 | Yes | |checkForUpdatesAtBoot| Indicates if at each booth the application should check for updates. If an update is available, a notification will be sent to the default group. If you restart the process often (e.g. debugging, experimenting etc.) set this to false to avoid notifications. Anyway, BGPalerter checks for updates every 10 days.| A boolean | true | Yes | |processMonitors| A list of modules allowing various ways to check for the status of BGPalerter (e.g. API, heartbeat). See [here](process-monitors.md) for more information. | | | No | +|httpProxy| Defines the HTTP/HTTPS proxy server to be used by BGPalerter and its submodules (reporters/connectors/monitors). See [here](http-proxy.md) for more information. | A string | http://username:password@proxy.example.org:8080 | No | The following are advanced parameters, please don't touch them if you are not doing research/experiments. @@ -79,6 +80,7 @@ Each monitor declaration is composed of: | channel | The name of the channel that will be used by the monitor to dispatch messages. If the inserted name doesn't correspond to an already existent channel, a new channel is created.| |name| The name associated to the monitor. Multiple monitors with the same implementation can be loaded with different names. This name will be used to annotate messages in order track from where they are coming from.| |params| A dictionary of parameters that can be useful for the functioning of the monitor. Different monitors with the same implementation can be initialized with different parameters. | +|params.noProxy| If there is a global proxy configuration (see [here](http-proxy.md)), this parameter if set to true allows the single module to bypass the proxy. | Each report declaration is composed of: @@ -86,6 +88,7 @@ Each report declaration is composed of: |---|---| | file | Name of the file containing the report implementation. Report implementations are in the `reports` directory. | |params| A dictionary of parameters that can be useful for the functioning of the report. It is common to have group declarations among the parameters. Different reports with the same implementation can be initialized with different parameters. | +|params.noProxy| If there is a global proxy configuration (see [here](http-proxy.md)), this parameter if set to true allows the single module to bypass the proxy. | |channels| A [list](docs/prefixes.md#array) of channels the monitor will listen (never write). Different reports with the same implementation can be initialized with a different list of channels to listen.| @@ -95,8 +98,10 @@ Each connector is composed of: |---|---| |file|Name of the file containing the connector implementation. Report implementations are in the `connectors` directory. | |params| A dictionary of parameters that can be useful for the functioning of the connector. E.g. the data source url, password, socket options| +|params.noProxy| If there is a global proxy configuration (see [here](http-proxy.md)), this parameter if set to true allows the single module to bypass the proxy. | |name| The name that will be used to identify this connector and to annotate logs and messages. | + > Connectors will always send the BGP updates to all the channels. The BGP updates have all the same format. diff --git a/docs/http-proxy.md b/docs/http-proxy.md new file mode 100644 index 0000000..02f4fb5 --- /dev/null +++ b/docs/http-proxy.md @@ -0,0 +1,34 @@ +# Run BGPalerter behind a proxy +BGPalerter can be run in a production environment requiring to access external resources via an HTTP/HTTPS proxy. +To enable this setting, in `config.yml` uncomment the following line and set the correct proxy URL: + +```yaml +httpProxy: http://username:password@proxy.example.org:8080 +``` +This will enable the proxy globally on all HTTP/HTTPS/WebSocket traffic generated by BGPalerter. + +## Bypass proxy for specific BGPalerter modules + +While the global configuration will send all requests to the proxy, you can specify which modules are able to bypass the proxy. +This is useful for example if you want to not proxy requests to internal apps or networks. +This can be set per module (i.e reporter/connector/monitor) by adding the `noProxy: true` parameter to the desired module(s) in `config.yml`. +For instance, the configuration below allows you to bypass your proxy server for your traffic towards an Alerta dashboard. + + +```yaml + - file: reportAlerta + channels: + - hijack + - newprefix + - visibility + - path + - misconfiguration + - rpki + params: + noProxy: true + severity: + hijack: critical + newprefix: informational + visibility: debug + path: trace +``` \ No newline at end of file diff --git a/docs/prefixes.md b/docs/prefixes.md index 31d1977..c3e2b71 100644 --- a/docs/prefixes.md +++ b/docs/prefixes.md @@ -22,6 +22,7 @@ Below the list of possible parameters. **Remember to prepend them with a `--` in | -l | A file containing the prefixes for which the list will be generated | A text file having a prefix for each line | prefixes.txt | No (one among -a, -p, -l is required) | | -s | A list of ASns to be monitored. See [monitorASns](#monitorASns) for more information | A comma separated list of integer | 2914,3333 | No | | -m | Monitor all ASns which are origin of at least one of the monitored prefixes. This option is the same of `-s` except that the list of ASns is automatically generated by detecting the origin AS of all the monitored prefixes. See [monitorASns](#monitorASns) for more information | Nothing | | No | +| -x | HTTP/HTTPS proxy server to use | A string | http://username:password@proxy.example.org:8080 | No | ## Prefixes list fields diff --git a/index.js b/index.js index 42a62dd..310a107 100644 --- a/index.js +++ b/index.js @@ -71,6 +71,10 @@ const params = yargs .nargs('m', 0) .describe('m', 'Automatically generate list of monitored ASes (options.monitorASns) from prefix origins.') + .alias('x', 'proxy') + .nargs('x', 1) + .describe('x', 'HTTP/HTTPS proxy to use') + .demandOption(['o']); }) .example('$0 generate -a 2914 -o prefixes.yml', 'Generate prefixes for AS2914') @@ -114,7 +118,8 @@ switch(params._[0]) { (params.e || "").split(","), params.i || false, prefixes, - monitoredASes + monitoredASes, + params.x || null ); break; diff --git a/package-lock.json b/package-lock.json index 03b1bba..5abae5c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2087,6 +2087,35 @@ "https-proxy-agent": "^4.0.0", "lru_map": "^0.3.3", "tslib": "^1.9.3" + }, + "dependencies": { + "agent-base": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", + "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==" + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "https-proxy-agent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", + "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "requires": { + "agent-base": "5", + "debug": "4" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } } }, "@sentry/types": { @@ -2130,9 +2159,27 @@ "dev": true }, "agent-base": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", - "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==" + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz", + "integrity": "sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==", + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } }, "ajv": { "version": "6.12.2", @@ -4386,11 +4433,11 @@ } }, "https-proxy-agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", - "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", "requires": { - "agent-base": "5", + "agent-base": "6", "debug": "4" }, "dependencies": { @@ -6376,9 +6423,9 @@ "dev": true }, "pstree.remy": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz", - "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true }, "pump": { diff --git a/package.json b/package.json index 685d3f4..fd2054a 100644 --- a/package.json +++ b/package.json @@ -6,11 +6,12 @@ "bin": "index.js", "repository": { "type": "git", - "url": "git+https://github.com/massimocandela/rpki-validator.git" + "url": "git+https://github.com/nttgin/BGPalerter.git" }, "scripts": { "babel": "./node_modules/.bin/babel", - "test": "./node_modules/.bin/mocha --exit tests --require @babel/register", + "test": "./node_modules/.bin/mocha --exit tests/*.js --require @babel/register", + "test-proxy": "tests/proxy_tests/test_proxy.sh", "build": "./build.sh", "watch-and-serve": "nodemon -e yml,js,json,txt --inspect --exec babel-node index.js", "serve": "babel-node index.js", @@ -39,6 +40,7 @@ "axios": "^0.19.2", "batch-promises": "^0.0.3", "brembo": "^2.0.3", + "https-proxy-agent": "^5.0.0", "inquirer": "^7.1.0", "ip-address": "^6.3.0", "ip-sub": "^1.0.7", diff --git a/src/connectors/connector.js b/src/connectors/connector.js index 3f9ba10..d0c2a0a 100644 --- a/src/connectors/connector.js +++ b/src/connectors/connector.js @@ -31,6 +31,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import axios from "axios"; + export default class Connector { constructor(name, params, env){ @@ -44,6 +46,11 @@ export default class Connector { this.connectCallback = null; this.errorCallback = null; this.disconnectCallback = null; + + if (!this.params.noProxy && env.agent) { + axios.defaults.httpsAgent = env.agent; + } + this.axios = axios; } connect = () => diff --git a/src/connectors/connectorRIS.js b/src/connectors/connectorRIS.js index 9d4a59d..adfaf8f 100644 --- a/src/connectors/connectorRIS.js +++ b/src/connectors/connectorRIS.js @@ -45,6 +45,7 @@ export default class ConnectorRIS extends Connector{ this.pingInterval = 5000; this._defaultReconnectTimeout = 10000; this.reconnectTimeout = this._defaultReconnectTimeout; + this.agent = env.agent; setInterval(this._ping, this.pingInterval); @@ -87,9 +88,14 @@ export default class ConnectorRIS extends Connector{ connect = () => new Promise((resolve, reject) => { try { - this.ws = new WebSocket(this.url, { + const wsOptions = { perMessageDeflate: this.params.perMessageDeflate - }); + }; + if (!this.params.noProxy && this.agent) { + console.log("Using proxy"); + wsOptions.agent = this.agent; + } + this.ws = new WebSocket(this.url, wsOptions); this.ws.on('message', this._messageToJson); this.ws.on('close', (error) => { diff --git a/src/connectors/connectorSwUpdates.js b/src/connectors/connectorSwUpdates.js index 6ccc5f5..8448efe 100644 --- a/src/connectors/connectorSwUpdates.js +++ b/src/connectors/connectorSwUpdates.js @@ -31,7 +31,6 @@ */ import Connector from "./connector"; -import axios from "axios"; import semver from "semver"; export default class ConnectorSwUpdates extends Connector{ @@ -46,7 +45,7 @@ export default class ConnectorSwUpdates extends Connector{ }); _checkForUpdates = () => { - return axios({ + return this.axios({ responseType: "json", url: "https://raw.githubusercontent.com/nttgin/BGPalerter/master/package.json" }) @@ -71,7 +70,7 @@ export default class ConnectorSwUpdates extends Connector{ subscribe = (input) => new Promise((resolve, reject) => { if (this.config.checkForUpdatesAtBoot){ - this._checkForUpdates(); + setTimeout(this._checkForUpdates, 1000); } setInterval(this._checkForUpdates, 1000 * 3600 * 24 * 5); // Check every 5 days resolve(true); diff --git a/src/env.js b/src/env.js index 30d1188..13b4543 100644 --- a/src/env.js +++ b/src/env.js @@ -33,11 +33,12 @@ import yaml from "js-yaml"; import fs from "fs"; import path from "path"; -import PubSub from './pubSub'; -import FileLogger from './fileLogger'; +import PubSub from './utils/pubSub'; +import FileLogger from './utils/fileLogger'; import Input from "./inputs/inputYml"; import {version} from '../package.json'; import axios from 'axios'; +import url from 'url'; const defaultConfigFilePath = path.resolve(process.cwd(), 'config.yml'); const vector = { @@ -258,6 +259,10 @@ config.connectors = config.connectors }); +if (config.httpProxy) { + const HttpsProxyAgent = require("https-proxy-agent"); + vector.agent = new HttpsProxyAgent(url.parse(config.httpProxy)); +} const input = new Input(config); diff --git a/src/generatePrefixesList.js b/src/generatePrefixesList.js index 2daeab7..388e144 100644 --- a/src/generatePrefixesList.js +++ b/src/generatePrefixesList.js @@ -1,14 +1,20 @@ import axios from "axios"; +import url from "url"; import brembo from "brembo"; import yaml from "js-yaml"; import fs from "fs"; const batchPromises = require('batch-promises'); -module.exports = function generatePrefixes(asnList, outputFile, exclude, excludeDelegated, prefixes, monitoredASes) { +module.exports = function generatePrefixes(asnList, outputFile, exclude, excludeDelegated, prefixes, monitoredASes, httpProxy) { const generateList = {}; const allOrigins = {}; let someNotValidatedPrefixes = false; + if (httpProxy) { + const HttpsProxyAgent = require("https-proxy-agent"); + axios.defaults.httpsAgent = new HttpsProxyAgent(url.parse(httpProxy)); + } + if (!asnList && !prefixes) { throw new Error("You need to specify at least an AS number or a list of prefixes."); } diff --git a/src/monitors/monitor.js b/src/monitors/monitor.js index e350b2d..b5e5f58 100644 --- a/src/monitors/monitor.js +++ b/src/monitors/monitor.js @@ -31,6 +31,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import axios from "axios"; + export default class Monitor { constructor(name, channel, params, env) { @@ -44,6 +46,11 @@ export default class Monitor { this.channel = channel; this.monitored = []; + if (!this.params.noProxy && env.agent) { + axios.defaults.httpsAgent = env.agent; + } + this.axios = axios; + this.alerts = {}; // Dictionary containing the alerts . The id is the "group" key of the alert. this.sent = {}; // Dictionary containing the last sent unix timestamp of each group this.truncated = {}; // Dictionary containing if the alerts Array for "id" is truncated according to maxDataSamples diff --git a/src/processMonitors/uptime.js b/src/processMonitors/uptime.js index b4f8145..c6a5a0e 100644 --- a/src/processMonitors/uptime.js +++ b/src/processMonitors/uptime.js @@ -30,11 +30,16 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import axios from "axios"; +import env from "../env"; + export default class Uptime { constructor(connectors, params){ this.connectors = connectors; this.params = params; + axios.defaults.httpsAgent = env.agent; + this.axios = axios; }; diff --git a/src/processMonitors/uptimeHealthcheck.js b/src/processMonitors/uptimeHealthcheck.js index ab47b8f..b2d1d10 100644 --- a/src/processMonitors/uptimeHealthcheck.js +++ b/src/processMonitors/uptimeHealthcheck.js @@ -31,7 +31,6 @@ */ import Uptime from "./uptime"; -import axios from "axios"; import env from "../env"; export default class UptimeHealthcheck extends Uptime { @@ -57,7 +56,7 @@ export default class UptimeHealthcheck extends Uptime { query.data = status; } - axios(query) + this.axios(query) .catch(error => { env.logger.log({ level: 'error', diff --git a/src/reports/report.js b/src/reports/report.js index e30c3f3..b413909 100644 --- a/src/reports/report.js +++ b/src/reports/report.js @@ -33,6 +33,7 @@ import moment from "moment"; import brembo from "brembo"; +import axios from "axios"; export default class Report { @@ -48,6 +49,11 @@ export default class Report { return this.report(message, content); }); } + + if (!this.params.noProxy && env.agent) { + axios.defaults.httpsAgent = env.agent; + } + this.axios = axios; } getBGPlayLink = (prefix, start, end, instant = null, rrcs = [0,1,2,5,6,7,10,11,13,14,15,16,18,20]) => { diff --git a/src/reports/reportAlerta.js b/src/reports/reportAlerta.js index 1116f63..9bba1d0 100644 --- a/src/reports/reportAlerta.js +++ b/src/reports/reportAlerta.js @@ -31,7 +31,6 @@ */ import Report from "./report"; -import axios from "axios"; export default class ReportAlerta extends Report { @@ -40,7 +39,7 @@ export default class ReportAlerta extends Report { this.environment = env.config.environment; this.enabled = true; - if (!this.params.urls || !Object.keys(this.params.urls).length){ + if (!this.params.urls || !Object.keys(this.params.urls).length) { this.logger.log({ level: 'error', message: "Alerta reporting is not enabled: no group is defined" @@ -85,7 +84,7 @@ export default class ReportAlerta extends Report { this.params.resourceTemplates["default"] || this.params.resource_templates["default"]; - axios({ + this.axios({ url: url + "/alert", method: "POST", headers: this.headers, diff --git a/src/reports/reportHTTP.js b/src/reports/reportHTTP.js index 6743313..8aea6f0 100644 --- a/src/reports/reportHTTP.js +++ b/src/reports/reportHTTP.js @@ -31,7 +31,6 @@ */ import Report from "./report"; -import axios from "axios"; export default class ReportHTTP extends Report { @@ -74,7 +73,7 @@ export default class ReportHTTP extends Report { const blob = this._getMessage(channel, content); - axios({ + this.axios({ url: url, method: "POST", headers: this.headers, diff --git a/src/reports/reportWebex.js b/src/reports/reportWebex.js index dd8efe5..1acd104 100644 --- a/src/reports/reportWebex.js +++ b/src/reports/reportWebex.js @@ -31,7 +31,6 @@ */ import Report from "./report"; -import axios from "axios"; export default class ReportWebex extends Report { @@ -54,17 +53,16 @@ export default class ReportWebex extends Report { }); } } - } _sendWebexMessage = (url, message, content) => { - axios({ + this.axios({ url: url, method: "POST", resposnseType: "json", data: { - markdown: `**${message}**: ${content.message}` + markdown: `**${message}**: ${content.message}` } }) .catch((error) => { diff --git a/src/fileLogger.js b/src/utils/fileLogger.js similarity index 97% rename from src/fileLogger.js rename to src/utils/fileLogger.js index 82e69ee..4417702 100644 --- a/src/fileLogger.js +++ b/src/utils/fileLogger.js @@ -1,5 +1,5 @@ -var fs = require('fs'); -var moment = require('moment'); +const fs = require('fs'); +const moment = require('moment'); const zlib = require('zlib'); export default class FileLogger { @@ -7,7 +7,7 @@ export default class FileLogger { constructor(params) { this.format = params.format || this.defaultFormat; - this.logRotatePattern = params.logRotatePattern; + this.logRotatePattern = params.logRotatePattern || "YYYY-MM-DD"; this.filename = params.filename; this.directory = params.directory; this.levels = params.levels || ['error', 'info', 'verbose']; diff --git a/src/lossyBuffer.js b/src/utils/lossyBuffer.js similarity index 100% rename from src/lossyBuffer.js rename to src/utils/lossyBuffer.js diff --git a/src/pubSub.js b/src/utils/pubSub.js similarity index 100% rename from src/pubSub.js rename to src/utils/pubSub.js diff --git a/src/worker.js b/src/worker.js index 9d6c23c..76fa3a4 100644 --- a/src/worker.js +++ b/src/worker.js @@ -31,7 +31,7 @@ */ import Consumer from "./consumer"; -import LossyBuffer from "./lossyBuffer"; +import LossyBuffer from "./utils/lossyBuffer"; import ConnectorFactory from "./connectorFactory"; import cluster from "cluster"; import fs from "fs"; diff --git a/tests/config.test.yml b/tests/config.test.yml index 667d78f..b3bbe5d 100644 --- a/tests/config.test.yml +++ b/tests/config.test.yml @@ -6,6 +6,8 @@ connectors: params: testType: withdrawal +#httpProxy: http://104.41.6.112:80 + monitors: - file: monitorHijack channel: hijack diff --git a/tests/proxy_tests/config.proxy.test.yml b/tests/proxy_tests/config.proxy.test.yml new file mode 100644 index 0000000..29e042c --- /dev/null +++ b/tests/proxy_tests/config.proxy.test.yml @@ -0,0 +1,55 @@ +environment: test + +connectors: + - file: connectorRIS + name: ris + params: + carefulSubscription: true + url: wss://ris-live.ripe.net/v1/ws/ + perMessageDeflate: true + subscription: + moreSpecific: true + type: UPDATE + host: + socketOptions: + includeRaw: false + +monitors: + + +reports: + +httpProxy: http://localhost:8001 + + +# The file containing the monitored prefixes. Please see monitored_prefixes_test.yml for an example +# This is an array (use new lines and dashes!) +monitoredPrefixesFiles: + - tests/prefixes.test.yml + + +checkForUpdatesAtBoot: true + +processMonitors: + - file: uptimeApi + params: + useStatusCodes: true + host: null + port: 8012 + + +logging: + directory: logs + logRotatePattern: YYYY-MM-DD # Whenever the pattern changes, a new file is created and the old one rotated + backlogSize: 1 + maxRetainedFiles: 10 + maxFileSizeMB: 15 + compressOnRotation: true + +notificationIntervalSeconds: 1800 +alertOnlyOnce: false +fadeOffSeconds: 10 +checkFadeOffGroupsSeconds: 2 +pidFile: bgpalerter.pid +multiProcess: false +maxMessagesPerSecond: 6000 \ No newline at end of file diff --git a/tests/proxy_tests/test_proxy.sh b/tests/proxy_tests/test_proxy.sh new file mode 100755 index 0000000..d641a4b --- /dev/null +++ b/tests/proxy_tests/test_proxy.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# Install anyproxy +npm install -g anyproxy +# Run anyproxy in background and store its PID +nohup anyproxy --port 8001 & +ANYPROXY_PID=$! +# Run tests suite +./node_modules/.bin/mocha --exit tests/proxy_tests/*.js --require @babel/register +# Terminate anyproxy process +kill $ANYPROXY_PID +exit 0 \ No newline at end of file diff --git a/tests/proxy_tests/tests.js b/tests/proxy_tests/tests.js new file mode 100644 index 0000000..f1a72fb --- /dev/null +++ b/tests/proxy_tests/tests.js @@ -0,0 +1,125 @@ +/* + * BSD 3-Clause License + * + * Copyright (c) 2019, NTT Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +var chai = require("chai"); +var chaiSubset = require('chai-subset'); +chai.use(chaiSubset); +var expect = chai.expect; +var axios = require('axios'); + +var asyncTimeout = 30000; +global.EXTERNAL_VERSION_FOR_TEST = "0.0.1"; +global.EXTERNAL_CONFIG_FILE = "tests/proxy_tests/config.proxy.test.yml"; + +describe("Composition", function() { + + describe("Software updates check", function () { + it("new version detected with proxy", function (done) { + + var worker = require("../../index"); + var pubSub = worker.pubSub; + + pubSub.subscribe("software-update", function (type, message) { + expect(type).to.equal("software-update"); + done(); + }); + }).timeout(asyncTimeout); + }); + + describe("Configuration loader", function () { + var worker = require("../../index"); + var config = worker.config; + + it("config structure - proxy config loaded", function () { + expect(config).to.have + .keys([ + "alertOnlyOnce", + "checkFadeOffGroupsSeconds", + "checkForUpdatesAtBoot", + "connectors", + "environment", + "fadeOffSeconds", + "httpProxy", + "logging", + "maxMessagesPerSecond", + "monitoredPrefixesFiles", + "monitors", + "multiProcess", + "notificationIntervalSeconds", + "pidFile", + "processMonitors", + "reports" + ]); + expect(config.connectors[0]).to.have + .property('class') + }); + + }); + + describe("Uptime Monitor", function() { + + var worker = require("../../index"); + var config = worker.config; + + it("uptime config", function () { + expect(config.processMonitors[0]).to + .containSubset({ + params: { + useStatusCodes: true, + host: null, + port: 8012 + } + }); + }); + + it("RIS connected with proxy", function (done) { + + const port = config.processMonitors[0].params.port; + + axios({ + method: 'get', + responseType: 'json', + url: `http://localhost:${port}/status` + }) + .then(data => { + expect(data.status).to.equal(200); + expect(data.data.warning).to.equal(false); + done(); + }) + .catch(error => { + console.log(error); + }); + + }).timeout(asyncTimeout); + }); + +}); \ No newline at end of file