diff options
Diffstat (limited to 'jstests/free_mon/libs')
| -rw-r--r-- | jstests/free_mon/libs/free_mon.js | 331 | ||||
| -rw-r--r-- | jstests/free_mon/libs/mock_http_common.py | 24 | ||||
| -rw-r--r-- | jstests/free_mon/libs/mock_http_control.py | 52 | ||||
| -rw-r--r-- | jstests/free_mon/libs/mock_http_server.py | 306 |
4 files changed, 0 insertions, 713 deletions
diff --git a/jstests/free_mon/libs/free_mon.js b/jstests/free_mon/libs/free_mon.js deleted file mode 100644 index 269f1e65306..00000000000 --- a/jstests/free_mon/libs/free_mon.js +++ /dev/null @@ -1,331 +0,0 @@ - -/** - * Control the Free Monitoring Mock Webserver. - */ - -// These faults must match the list of faults in mock_http_server.py, see the -// SUPPORTED_FAULT_TYPES list in mock_http_server.py -const FAULT_FAIL_REGISTER = "fail_register"; -const FAULT_INVALID_REGISTER = "invalid_register"; -const FAULT_HALT_METRICS_5 = "halt_metrics_5"; -const FAULT_PERMANENTLY_DELETE_AFTER_3 = "permanently_delete_after_3"; -const FAULT_RESEND_REGISTRATION_AT_3 = "resend_registration_at_3"; -const FAULT_RESEND_REGISTRATION_ONCE = "resend_registration_once"; - -const DISABLE_FAULTS = "disable_faults"; -const ENABLE_FAULTS = "enable_faults"; - -class FreeMonWebServer { - /** - * Create a new webserver. - * - * @param {string} fault_type - * @param {bool} disableFaultsOnStartup optionally disable fault on startup - */ - constructor(fault_type, disableFaultsOnStartup) { - this.python = "python3"; - this.disableFaultsOnStartup = disableFaultsOnStartup || false; - this.fault_type = fault_type; - - if (_isWindows()) { - this.python = "python.exe"; - } - - print("Using python interpreter: " + this.python); - this.web_server_py = "jstests/free_mon/libs/mock_http_server.py"; - this.control_py = "jstests/free_mon/libs/mock_http_control.py"; - - this.pid = undefined; - this.port = -1; - } - - /** - * Get the Port. - * - * @return {number} port number of http server - */ - getPort() { - return port; - } - - /** - * Get the URL. - * - * @return {string} url of http server - */ - getURL() { - return "http://localhost:" + this.port; - } - - /** - * Start the Mock HTTP Server. - */ - start() { - this.port = allocatePort(); - print("Mock Web server is listening on port: " + this.port); - - let args = [this.python, "-u", this.web_server_py, "--port=" + this.port]; - if (this.fault_type) { - args.push("--fault=" + this.fault_type); - if (this.disableFaultsOnStartup) { - args.push("--disable-faults"); - } - } - - clearRawMongoProgramOutput(); - - this.pid = _startMongoProgram({args: args}); - - assert(checkProgram(this.pid)); - - // Wait for the web server to start - assert.soon(function() { - return rawMongoProgramOutput().search("Mock Web Server Listening") !== -1; - }); - - print("Mock HTTP Server sucessfully started."); - } - - /** - * Stop the Mock HTTP Server. - */ - stop() { - stopMongoProgramByPid(this.pid); - } - - /** - * Query the HTTP server. - * - * @param {string} query type - * - * @return {object} Object representation of JSON from the server. - */ - query(query) { - const out_file = "out_" + this.port + ".txt"; - const python_command = this.python + " -u " + this.control_py + " --port=" + this.port + - " --query=" + query + " > " + out_file; - - let ret = 0; - if (_isWindows()) { - ret = runProgram('cmd.exe', '/c', python_command); - } else { - ret = runProgram('/bin/sh', '-c', python_command); - } - - assert.eq(ret, 0); - - const result = cat(out_file); - - try { - return JSON.parse(result); - } catch (e) { - jsTestLog("Failed to parse: " + result + "\n" + result); - throw e; - } - } - - /** - * Control the HTTP server. - * - * @param {string} query type - */ - control(query) { - const out_file = "out_" + this.port + ".txt"; - const python_command = this.python + " -u " + this.control_py + " --port=" + this.port + - " --query=" + query + " > " + out_file; - - let ret = 0; - if (_isWindows()) { - ret = runProgram('cmd.exe', '/c', python_command); - } else { - ret = runProgram('/bin/sh', '-c', python_command); - } - - assert.eq(ret, 0); - } - - /** - * Disable Faults - */ - disableFaults() { - this.control(DISABLE_FAULTS); - } - - /** - * Enable Faults - */ - enableFaults() { - this.control(ENABLE_FAULTS); - } - - /** - * Query the stats page for the HTTP server. - * - * @return {object} Object representation of JSON from the server. - */ - queryStats() { - return this.query("stats"); - } - - /** - * Wait for N register calls to be received by web server. - * - * @throws assert.soon() exception - */ - waitRegisters(count) { - const qs = this.queryStats.bind(this); - const port = this.port; - // Wait for registration to occur - assert.soon(function() { - const stats = qs(); - print("w" + port + "| waiting for registers >= (" + count + ") QS : " + tojson(stats)); - return stats.registers >= count; - }, "Failed to web server register", 60 * 1000); - } - - /** - * Wait for N metrics calls to be received by web server. - * - * @throws assert.soon() exception - */ - waitMetrics(count) { - const qs = this.queryStats.bind(this); - const port = this.port; - // Wait for metrics uploads to occur - assert.soon(function() { - const stats = qs(); - print("w" + port + "| waiting for metrics >= (" + count + ") QS : " + tojson(stats)); - return stats.metrics >= count; - }, "Failed to web server metrics", 60 * 1000); - } - - /** - * Wait for N fault calls to e received by web server. - * - * @throws assert.soon() exception - */ - waitFaults(count) { - const qs = this.queryStats.bind(this); - const port = this.port; - // Wait for faults to be triggered - assert.soon(function() { - const stats = qs(); - print("w" + port + "| waiting for faults >= (" + count + ") QS : " + tojson(stats)); - return stats.faults >= count; - }, "Failed to web server faults", 60 * 1000); - } -} - -/** - * Wait for registration information to be populated in the database. - * - * @param {object} conn - * @param {string} state - */ -function WaitForDiskState(conn, state) { - 'use strict'; - - const admin = conn.getDB("admin"); - - // Wait for registration to occur - assert.soon(function() { - const docs = admin.system.version.find({_id: "free_monitoring"}); - const da = docs.toArray(); - return da.length === 1 && da[0].state === state; - }, "Failed to disk state", 60 * 1000); -} - -/** - * Wait for registration information to be populated in the database. - * - * @param {object} conn - */ -function WaitForRegistration(conn) { - WaitForDiskState(conn, 'enabled'); -} - -/** - * Wait for unregistration information to be populated in the database. - * - * @param {object} conn - */ -function WaitForUnRegistration(conn) { - WaitForDiskState(conn, 'disabled'); -} - -/** - * Get registration document. - * - * @param {object} registration document - */ -function FreeMonGetRegistration(conn) { - 'use strict'; - - const admin = conn.getDB("admin"); - const docs = admin.system.version.find({_id: "free_monitoring"}); - const da = docs.toArray(); - return da[0]; -} - -/** - * Get current Free Monitoring Status via serverStatus. - * - * @param {object} serverStatus.freeMonitoring section - */ -function FreeMonGetServerStatus(conn) { - 'use strict'; - - const admin = conn.getDB("admin"); - return assert.commandWorked(admin.runCommand({serverStatus: 1})).freeMonitoring; -} - -/** - * Get current Free Monitoring Status via getFreeMonitoringStatus. - * - * @param {object} getFreeMonitoringStatus document - */ -function FreeMonGetStatus(conn) { - 'use strict'; - - const admin = conn.getDB("admin"); - return assert.commandWorked(admin.runCommand({getFreeMonitoringStatus: 1})); -} - -/** - * Wait for server status state - * - * @param {object} conn - * @param {string} state - */ -function WaitForFreeMonServerStatusState(conn, state) { - 'use strict'; - - // Wait for registration to occur - assert.soon( - function() { - let status = FreeMonGetServerStatus(conn).state; - return status === state; - }, - "Failed to find expected server status state: expected: '" + state + - "', actual: " + tojson(FreeMonGetServerStatus(conn)), - 20 * 1000); -} - -/** - * Validate Free Monitoring Replica Set consistency - * WARNING: Not valid if secondary is started with enableFreeMonitoring since it registers before it - * joins the replica set. - * - * @param {object} rst - */ -function ValidateFreeMonReplicaSet(rst) { - 'use strict'; - - const primary_status = FreeMonGetStatus(rst.getPrimary()); - const primary_url = primary_status.url; - const secondary_status = FreeMonGetStatus(rst.getSecondary()); - const secondary_url = secondary_status.url; - assert.eq(primary_url, - secondary_url, - `DUMP ${tojson(primary_status)} == ${tojson(secondary_status)}`); -} diff --git a/jstests/free_mon/libs/mock_http_common.py b/jstests/free_mon/libs/mock_http_common.py deleted file mode 100644 index 14cc6ba5a21..00000000000 --- a/jstests/free_mon/libs/mock_http_common.py +++ /dev/null @@ -1,24 +0,0 @@ -"""Common code for mock free monitoring http endpoint.""" -import json - -URL_PATH_STATS = "/stats" -URL_PATH_LAST_REGISTER = "/last_register" -URL_PATH_LAST_METRICS = "/last_metrics" -URL_DISABLE_FAULTS = "/disable_faults" -URL_ENABLE_FAULTS = "/enable_faults" - - -class Stats: - """Stats class shared between client and server.""" - - def __init__(self): - self.register_calls = 0 - self.metrics_calls = 0 - self.fault_calls = 0 - - def __repr__(self): - return json.dumps({ - 'metrics': self.metrics_calls, - 'registers': self.register_calls, - 'faults': self.fault_calls, - }) diff --git a/jstests/free_mon/libs/mock_http_control.py b/jstests/free_mon/libs/mock_http_control.py deleted file mode 100644 index 778450dd374..00000000000 --- a/jstests/free_mon/libs/mock_http_control.py +++ /dev/null @@ -1,52 +0,0 @@ -#! /usr/bin/env python3 -""" -Python script to interact with mock free monitoring HTTP server. -""" - -import argparse -import json -import logging -import sys -import urllib.request - -import mock_http_common - - -def main(): - """Main entry point.""" - parser = argparse.ArgumentParser(description='MongoDB Mock Free Monitoring Endpoint.') - - parser.add_argument('-p', '--port', type=int, default=8000, help="Port to listen on") - - parser.add_argument('-v', '--verbose', action='count', help="Enable verbose tracing") - - parser.add_argument('--query', type=str, help="Query endpoint <name>") - - args = parser.parse_args() - if args.verbose: - logging.basicConfig(level=logging.DEBUG) - - url_str = "http://localhost:" + str(args.port) - if args.query == "stats": - url_str += mock_http_common.URL_PATH_STATS - elif args.query == "last_register": - url_str += mock_http_common.URL_PATH_LAST_REGISTER - elif args.query == "last_metrics": - url_str += mock_http_common.URL_PATH_LAST_METRICS - elif args.query == "disable_faults": - url_str += mock_http_common.URL_DISABLE_FAULTS - elif args.query == "enable_faults": - url_str += mock_http_common.URL_ENABLE_FAULTS - else: - print("Unknown query type") - sys.exit(1) - - with urllib.request.urlopen(url_str) as f: - print(f.read().decode('utf-8')) - - sys.exit(0) - - -if __name__ == '__main__': - - main() diff --git a/jstests/free_mon/libs/mock_http_server.py b/jstests/free_mon/libs/mock_http_server.py deleted file mode 100644 index 7bfd8974c59..00000000000 --- a/jstests/free_mon/libs/mock_http_server.py +++ /dev/null @@ -1,306 +0,0 @@ -#! /usr/bin/env python3 -"""Mock Free Monitoring Endpoint.""" - -import argparse -import collections -import http.server -import json -import logging -import socketserver -import sys -import urllib.parse - -import bson -from bson.codec_options import CodecOptions -from bson.json_util import dumps -import mock_http_common - -# Pass this data out of band instead of storing it in FreeMonHandler since the -# BaseHTTPRequestHandler does not call the methods as object methods but as class methods. This -# means there is not self. -stats = mock_http_common.Stats() -last_metrics = None -last_register = None -disable_faults = False -fault_type = None -"""Fault which causes the server to return an HTTP failure on register.""" -FAULT_FAIL_REGISTER = "fail_register" -"""Fault which causes the server to return a response with a document with a bad version.""" -FAULT_INVALID_REGISTER = "invalid_register" -"""Fault which causes metrics to return halt after 5 metric uploads have occurred.""" -FAULT_HALT_METRICS_5 = "halt_metrics_5" -"""Fault which causes metrics to return permanentlyDelete = true after 3 uploads.""" -FAULT_PERMANENTLY_DELETE_AFTER_3 = "permanently_delete_after_3" -"""Fault which causes metrics to trigger resentRegistration at 3 uploads.""" -FAULT_RESEND_REGISTRATION_AT_3 = "resend_registration_at_3" -"""Fault which causes metrics to trigger resentRegistration once.""" -FAULT_RESEND_REGISTRATION_ONCE = "resend_registration_once" - -# List of supported fault types -SUPPORTED_FAULT_TYPES = [ - FAULT_FAIL_REGISTER, - FAULT_INVALID_REGISTER, - FAULT_HALT_METRICS_5, - FAULT_PERMANENTLY_DELETE_AFTER_3, - FAULT_RESEND_REGISTRATION_AT_3, - FAULT_RESEND_REGISTRATION_ONCE, -] - -# Supported POST URL types -URL_POST_REGISTER = '/register' -URL_POST_METRICS = '/metrics' - - -class FreeMonHandler(http.server.BaseHTTPRequestHandler): - """ - Handle requests from Free Monitoring and test commands - """ - - def do_GET(self): - """Serve a Test GET request.""" - parts = urllib.parse.urlsplit(self.path) - path = parts[2] - - if path == mock_http_common.URL_PATH_STATS: - self._do_stats() - elif path == mock_http_common.URL_PATH_LAST_REGISTER: - self._do_last_register() - elif path == mock_http_common.URL_PATH_LAST_METRICS: - self._do_last_metrics() - elif path == mock_http_common.URL_DISABLE_FAULTS: - self._do_disable_faults() - elif path == mock_http_common.URL_ENABLE_FAULTS: - self._do_enable_faults() - else: - self.send_response(http.HTTPStatus.NOT_FOUND) - self.end_headers() - self.wfile.write("Unknown URL".encode()) - - def do_POST(self): - """Serve a Free Monitoring POST request.""" - parts = urllib.parse.urlsplit(self.path) - path = parts[2] - - if path == URL_POST_REGISTER: - self._do_registration() - elif path == URL_POST_METRICS: - self._do_metrics() - else: - self.send_response(http.HTTPStatus.NOT_FOUND) - self.end_headers() - self.wfile.write("Unknown URL".encode()) - - def _send_header(self): - self.send_response(http.HTTPStatus.OK) - self.send_header("content-type", "application/octet-stream") - self.end_headers() - - def _do_registration(self): - global stats - global last_register - clen = int(self.headers.get('content-length')) - - stats.register_calls += 1 - - raw_input = self.rfile.read(clen) - decoded_doc = bson.BSON.decode(raw_input) - last_register = dumps(decoded_doc) - - if not disable_faults and fault_type == FAULT_FAIL_REGISTER: - stats.fault_calls += 1 - self.send_response(http.HTTPStatus.INTERNAL_SERVER_ERROR) - self.send_header("content-type", "application/octet-stream") - self.end_headers() - self.wfile.write("Internal Error of some sort.".encode()) - return - - if not disable_faults and fault_type == FAULT_INVALID_REGISTER: - stats.fault_calls += 1 - data = bson.BSON.encode({ - 'version': bson.int64.Int64(42), - 'haltMetricsUploading': False, - 'id': '', - 'informationalURL': 'http://www.example.com/123', - 'message': 'Welcome to the Mock Free Monitoring Endpoint', - 'reportingInterval': bson.int64.Int64(1), - }) - else: - reg_id = 'mock123_' + str(stats.register_calls) - if 'id' in decoded_doc: - reg_id = decoded_doc['id'] - - data = bson.BSON.encode({ - 'version': - bson.int64.Int64(1), - 'haltMetricsUploading': - False, - 'id': - reg_id, - 'informationalURL': - 'http://www.example.com/' + reg_id, - 'message': - 'Welcome to the Mock Free Monitoring Endpoint', - 'reportingInterval': - bson.int64.Int64(1), - 'userReminder': - """To see your monitoring data, navigate to the unique URL below. -Anyone you share the URL with will also be able to view this page. - -https://localhost:8080/someUUID6v5jLKTIZZklDvN5L8sZ - -You can disable monitoring at any time by running db.disableFreeMonitoring().""", - }) - - self._send_header() - - self.wfile.write(data) - - def _do_metrics(self): - global stats - global last_metrics - clen = int(self.headers.get('content-length')) - - stats.metrics_calls += 1 - - raw_input = self.rfile.read(clen) - decoded_doc = bson.BSON.decode(raw_input) - last_metrics = dumps(decoded_doc) - - if not disable_faults and \ - stats.metrics_calls > 5 and \ - fault_type == FAULT_HALT_METRICS_5: - stats.fault_calls += 1 - data = bson.BSON.encode({ - 'version': bson.int64.Int64(1), - 'haltMetricsUploading': True, - 'permanentlyDelete': False, - 'id': 'mock123', - 'reportingInterval': bson.int64.Int64(1), - 'message': 'Thanks for all the metrics', - }) - elif not disable_faults and \ - stats.metrics_calls > 3 and fault_type == FAULT_PERMANENTLY_DELETE_AFTER_3: - stats.fault_calls += 1 - data = bson.BSON.encode({ - 'version': bson.int64.Int64(1), - 'haltMetricsUploading': False, - 'permanentlyDelete': True, - 'id': 'mock123', - 'reportingInterval': bson.int64.Int64(1), - 'message': 'Thanks for all the metrics', - }) - elif not disable_faults and \ - stats.metrics_calls > 3 and \ - stats.fault_calls < 1 and fault_type == FAULT_RESEND_REGISTRATION_ONCE: - stats.fault_calls += 1 - data = bson.BSON.encode({ - 'version': bson.int64.Int64(2), - 'haltMetricsUploading': False, - 'permanentlyDelete': False, - 'id': 'mock123', - 'reportingInterval': bson.int64.Int64(1), - 'message': 'Thanks for all the metrics', - 'resendRegistration': True, - }) - elif not disable_faults and \ - stats.metrics_calls == 3 and fault_type == FAULT_RESEND_REGISTRATION_AT_3: - stats.fault_calls += 1 - data = bson.BSON.encode({ - 'version': bson.int64.Int64(2), - 'haltMetricsUploading': False, - 'permanentlyDelete': False, - 'id': 'mock123', - 'reportingInterval': bson.int64.Int64(1), - 'message': 'Thanks for all the metrics', - 'resendRegistration': True, - }) - else: - data = bson.BSON.encode({ - 'version': bson.int64.Int64(1), - 'haltMetricsUploading': False, - 'permanentlyDelete': False, - 'id': decoded_doc['id'], - 'reportingInterval': bson.int64.Int64(1), - 'message': 'Thanks for all the metrics', - }) - - # TODO: test what if header is sent first? - self._send_header() - - self.wfile.write(data) - - def _do_stats(self): - self._send_header() - - self.wfile.write(str(stats).encode('utf-8')) - - def _do_last_register(self): - self._send_header() - - self.wfile.write(str(last_register).encode('utf-8')) - - def _do_last_metrics(self): - self._send_header() - - self.wfile.write(str(last_metrics).encode('utf-8')) - - def _do_disable_faults(self): - global disable_faults - disable_faults = True - self._send_header() - - def _do_enable_faults(self): - global disable_faults - disable_faults = False - self._send_header() - - -def run(port, server_class=http.server.HTTPServer, handler_class=FreeMonHandler): - """Run web server.""" - server_address = ('', port) - - http.server.HTTPServer.protocol_version = "HTTP/1.1" - - httpd = server_class(server_address, handler_class) - - print("Mock Web Server Listening on %s" % (str(server_address))) - - httpd.serve_forever() - - -def main(): - """Main Method.""" - global fault_type - global disable_faults - - parser = argparse.ArgumentParser(description='MongoDB Mock Free Monitoring Endpoint.') - - parser.add_argument('-p', '--port', type=int, default=8000, help="Port to listen on") - - parser.add_argument('-v', '--verbose', action='count', help="Enable verbose tracing") - - parser.add_argument('--fault', type=str, help="Type of fault to inject") - - parser.add_argument('--disable-faults', action='store_true', help="Disable faults on startup") - - args = parser.parse_args() - if args.verbose: - logging.basicConfig(level=logging.DEBUG) - - if args.fault: - if args.fault not in SUPPORTED_FAULT_TYPES: - print("Unsupported fault type %s, supports types are %s" % (args.fault, - SUPPORTED_FAULT_TYPES)) - sys.exit(1) - - fault_type = args.fault - - if args.disable_faults: - disable_faults = True - - run(args.port) - - -if __name__ == '__main__': - - main() |
