diff --git a/SConstruct b/SConstruct index 388af8a998a..1f75cd522e9 100644 --- a/SConstruct +++ b/SConstruct @@ -434,14 +434,6 @@ add_option( nargs=0, ) -add_option( - 'enable-free-mon', - choices=["auto", "on", "off"], - default="auto", - help='Disable support for Free Monitoring to avoid HTTP client library dependencies', - type='choice', -) - add_option( 'enable-http-client', choices=["auto", "on", "off"], @@ -3306,7 +3298,6 @@ if has_ninja_module: # --- check system --- ssl_provider = None -free_monitoring = get_option("enable-free-mon") http_client = get_option("enable-http-client") @@ -3324,7 +3315,6 @@ env.AddMethod(isSanitizerEnabled, 'IsSanitizerEnabled') def doConfigure(myenv): global wiredtiger global ssl_provider - global free_monitoring global http_client # Check that the compilers work. @@ -5361,16 +5351,6 @@ def doConfigure(myenv): # ask each module to configure itself and the build environment. moduleconfig.configure_modules(mongo_modules, conf) - # Resolve --enable-free-mon - if free_monitoring == "auto": - if 'enterprise' not in conf.env['MONGO_MODULES']: - free_monitoring = "on" - else: - free_monitoring = "off" - - if free_monitoring == "on": - checkHTTPLib(required=True) - # Resolve --enable-http-client if http_client == "auto": if checkHTTPLib(): @@ -5381,12 +5361,6 @@ def doConfigure(myenv): elif http_client == "on": checkHTTPLib(required=True) - # Sanity check. - # We know that http_client was explicitly disabled here, - # because the free_monitoring check would have failed if no http lib were available. - if (free_monitoring == "on") and (http_client == "off"): - env.ConfError("FreeMonitoring requires an HTTP client which has been explicitly disabled") - if env['TARGET_ARCH'] == "ppc64le": # This checks for an altivec optimization we use in full text search. # Different versions of gcc appear to put output bytes in different @@ -6330,7 +6304,6 @@ version_parts = [int(x) for x in version_parts[:4]] Export([ 'debugBuild', 'endian', - 'free_monitoring', 'get_option', 'has_option', 'http_client', diff --git a/buildscripts/resmokeconfig/suites/free_monitoring.yml b/buildscripts/resmokeconfig/suites/free_monitoring.yml deleted file mode 100644 index 98fb2867c51..00000000000 --- a/buildscripts/resmokeconfig/suites/free_monitoring.yml +++ /dev/null @@ -1,10 +0,0 @@ -test_kind: js_test - -selector: - roots: - - jstests/free_mon/*.js - -executor: - config: - shell_options: - nodb: '' diff --git a/debian/mongod.1 b/debian/mongod.1 index 148fd617b22..c2792b9f6a3 100644 --- a/debian/mongod.1 +++ b/debian/mongod.1 @@ -857,75 +857,6 @@ For usage examples, see: \fBConvert Command\-Line Options to YAML\f1 .RE .RE -.SS FREE MONITORING -.PP -\fBmongod \-\-enableFreeMonitoring\f1 -.RS -.PP -Enables or disables \fBfree MongoDB Cloud monitoring\f1\&. \fB\-\-enableFreeMonitoring\f1\f1 accepts the following -values: -.RS -.IP \(bu 2 -.RS -.IP \(bu 4 -Value -.IP \(bu 4 -Description -.RE -.IP \(bu 2 -.RS -.IP \(bu 4 -\fBruntime\f1 -.IP \(bu 4 -Default. You can enable or disable free monitoring during -runtime. -.IP -To enable or disable free monitoring during runtime, see -\fBdb.enableFreeMonitoring()\f1\f1 and -\fBdb.disableFreeMonitoring()\f1\f1\&. -.IP -To enable or disable free monitoring during runtime when -running with access control, users must have required -privileges. See \fBdb.enableFreeMonitoring()\f1\f1 and -\fBdb.disableFreeMonitoring()\f1\f1 for details. -.RE -.IP \(bu 2 -.RS -.IP \(bu 4 -\fBon\f1 -.IP \(bu 4 -Enables free monitoring at startup; i.e. registers for free -monitoring. When enabled at startup, you cannot disable free -monitoring during runtime. -.RE -.IP \(bu 2 -.RS -.IP \(bu 4 -\fBoff\f1 -.IP \(bu 4 -Disables free monitoring at startup, regardless of whether -you have previously registered for free monitoring. When disabled at startup, -you cannot enable free monitoring during runtime. -.RE -.RE -.PP -Once enabled, the free monitoring state remains enabled until -explicitly disabled. That is, you do not need to re\-enable each time -you start the server. -.PP -For the corresponding configuration file setting, see -\fBcloud.monitoring.free.state\f1\f1\&. -.RE -.PP -\fBmongod \-\-freeMonitoringTag\f1 -.RS -.PP -Optional tag to describe environment context. The tag can be sent as -part of the \fBfree MongoDB Cloud monitoring\f1 registration at start up. -.PP -For the corresponding configuration file setting, see -\fBcloud.monitoring.free.tags\f1\f1\&. -.RE .SS LDAP AUTHENTICATION OR AUTHORIZATION OPTIONS .PP \fBmongod \-\-ldapServers\f1 @@ -1344,9 +1275,9 @@ anything preceeding the suffix into a regex capture group. { match: "(.+)@DBA.EXAMPLE.COM", ldapQuery: "ou=dba,dc=example,dc=com??one?(user={0})" - + } - + ]" .EE .PP diff --git a/docs/security_guide.md b/docs/security_guide.md index d929df9ed9c..798bf8c626e 100644 --- a/docs/security_guide.md +++ b/docs/security_guide.md @@ -3,6 +3,5 @@ - [Identity and Access Management](https://github.com/mongodb/mongo/blob/master/src/mongo/db/auth/README.md) - [TLS](https://github.com/mongodb/mongo/blob/master/src/mongo/util/net/README.md) - [FTDC](https://github.com/mongodb/mongo/blob/master/src/mongo/db/ftdc/README.md) -- [Free Monitoring](https://github.com/mongodb/mongo/blob/master/src/mongo/db/free_mon/README.md) - [LibFuzzer](https://github.com/mongodb/mongo/blob/master/docs/libfuzzer.md) - [SELinux](https://github.com/mongodb/mongodb-selinux/blob/master/README.md) diff --git a/docs/server-parameters.md b/docs/server-parameters.md index 758e1671cf4..a440164c0a7 100644 --- a/docs/server-parameters.md +++ b/docs/server-parameters.md @@ -148,13 +148,13 @@ inside the namespace defined by `globals.cpp_namespace`. Consider the following global: cpp_namespace: "mongo" cpp_includes: - - "mongo/db/free_mon/free_mon_mongod.h" + - "mongo/util/net/ssl_parameters.h" server_parameters: - cloudFreeMonitoringEndpointURL: + opensslCipherConfig: ... validator: - callback: "onValidateFreeMonEndpointURL" # The callback is declared in "free_mon_mongod.h" + callback: "validateOpensslCipherConfig" # The callback is declared in "ssl_parameters.h" ``` ### Specialized Server Parameters diff --git a/etc/evergreen.yml b/etc/evergreen.yml index c46c0ca64c5..76f3acb8451 100644 --- a/etc/evergreen.yml +++ b/etc/evergreen.yml @@ -319,7 +319,6 @@ buildvariants: - name: .clustered_collections - name: .misc_js - name: disk_wiredtiger - - name: free_monitoring - name: .jscore .common - name: jsCore_txns_large_txns_format - name: json_schema @@ -367,7 +366,6 @@ buildvariants: --opt=on -j$(grep -c ^processor /proc/cpuinfo) --variables-files=etc/scons/mongodbtoolchain_stable_gcc.vars - --enable-free-mon=on --enable-http-client=on --link-model=dynamic scons_cache_mode: all @@ -573,7 +571,6 @@ buildvariants: distros: - windows-vsCurrent-large - name: disk_wiredtiger - - name: free_monitoring - name: initial_sync_fuzzer_gen - name: fcv_upgrade_downgrade_replica_sets_jscore_passthrough_gen - name: fcv_upgrade_downgrade_sharding_jscore_passthrough_gen @@ -2089,7 +2086,6 @@ buildvariants: --sanitize=undefined --ssl --ocsp-stapling=off - --enable-free-mon=on -j$(grep -c ^processor /proc/cpuinfo) compile_variant: *rhel80-debug-ubsan-all-feature-flags # To force disable feature flags even on the all feature flags variant, please use this file: @@ -2156,7 +2152,6 @@ buildvariants: - name: .misc_js - name: .concurrency !.ubsan !.no_txns !.kill_terminate !.compute_mode - name: .encrypt - - name: free_monitoring - name: external_auth - name: external_auth_aws - name: external_auth_oidc @@ -2237,7 +2232,6 @@ buildvariants: - name: external_auth_aws - name: external_auth_oidc - name: .encrypt - - name: free_monitoring - name: generate_buildid_to_debug_symbols_mapping - name: initial_sync_fuzzer_gen - name: fcv_upgrade_downgrade_replica_sets_jscore_passthrough_gen @@ -2312,7 +2306,6 @@ buildvariants: --allocator=system --sanitize=thread --ssl - --enable-free-mon=on --use-libunwind=off --link-model=dynamic -j$(grep -c ^processor /proc/cpuinfo) diff --git a/etc/evergreen_yml_components/definitions.yml b/etc/evergreen_yml_components/definitions.yml index 295125765d7..978503c2667 100644 --- a/etc/evergreen_yml_components/definitions.yml +++ b/etc/evergreen_yml_components/definitions.yml @@ -3316,7 +3316,6 @@ tasks: targets: install-stitch-support install-stitch-support-debug install-stitch-support-dev task_compile_flags: >- --link-model=dynamic-sdk - --enable-free-mon=off --ssl=off --enable-http-client=off --modules= @@ -3348,7 +3347,6 @@ tasks: targets: install-stitch-support-test compiling_for_test: true task_compile_flags: >- - --enable-free-mon=off --ssl=off --enable-http-client=off --modules= @@ -3380,7 +3378,6 @@ tasks: targets: archive-mongo-crypt-dev task_compile_flags: >- --allocator=system - --enable-free-mon=off --enterprise-features=fle,search,vector_search --js-engine=none --link-model=dynamic-sdk @@ -3418,7 +3415,6 @@ tasks: --dbg=on --opt=off --allocator=system - --enable-free-mon=off --enterprise-features=fle,search,vector_search --js-engine=none --link-model=dynamic-sdk @@ -3456,7 +3452,6 @@ tasks: compiling_for_test: true task_compile_flags: >- --allocator=system - --enable-free-mon=off --enterprise-features=fle,search,vector_search --js-engine=none --link-model=static @@ -7020,15 +7015,6 @@ tasks: resmoke_args: --storageEngine=inMemory resmoke_jobs_max: 1 -- <<: *task_template - name: free_monitoring - tags: [] - commands: - - func: "do setup" - - func: "run tests" - vars: - resmoke_jobs_max: 1 - - <<: *task_template name: client_encrypt tags: ["ssl", "encrypt", "patch_build"] diff --git a/etc/evergreen_yml_components/variants/classic_engine.yml b/etc/evergreen_yml_components/variants/classic_engine.yml index 1ac4001e2d8..a9a43c5b96f 100644 --- a/etc/evergreen_yml_components/variants/classic_engine.yml +++ b/etc/evergreen_yml_components/variants/classic_engine.yml @@ -196,7 +196,6 @@ buildvariants: --sanitize=address --ssl --ocsp-stapling=off - --enable-free-mon=on -j$(grep -c ^processor /proc/cpuinfo) compile_variant: *rhel80-debug-asan-classic-engine test_flags: >- @@ -221,7 +220,6 @@ buildvariants: - name: .misc_js - name: .concurrency !.ubsan !.no_txns !.kill_terminate !.compute_mode - name: .encrypt - - name: free_monitoring - name: external_auth - name: external_auth_aws - name: external_auth_oidc @@ -281,7 +279,6 @@ buildvariants: --sanitize=undefined --ssl --ocsp-stapling=off - --enable-free-mon=on -j$(grep -c ^processor /proc/cpuinfo) test_flags: >- --mongodSetParameters="{internalQueryFrameworkControl: forceClassicEngine}" @@ -304,7 +301,6 @@ buildvariants: - name: .concurrency !.no_txns !.repl !.kill_terminate !.compute_mode - name: disk_wiredtiger - name: .encrypt - - name: free_monitoring - name: initial_sync_fuzzer_gen - name: compile_integration_and_test_parallel_stream_TG distros: diff --git a/etc/evergreen_yml_components/variants/compile_static_analysis.yml b/etc/evergreen_yml_components/variants/compile_static_analysis.yml index 6ac3b223498..88b0791e844 100644 --- a/etc/evergreen_yml_components/variants/compile_static_analysis.yml +++ b/etc/evergreen_yml_components/variants/compile_static_analysis.yml @@ -113,7 +113,6 @@ buildvariants: --opt=on -j$(grep -c ^processor /proc/cpuinfo) --variables-files=etc/scons/mongodbtoolchain_stable_gcc.vars - --enable-free-mon=on --enable-http-client=on --link-model=dynamic num_scons_link_jobs_available: 0.99 @@ -154,7 +153,6 @@ buildvariants: --ocsp-stapling=off -j$(grep -c ^processor /proc/cpuinfo) --link-model=dynamic - --enable-free-mon=on compile_variant: *linux-debug-aubsan-compile-required - <<: *linux-x86-dynamic-compile-params diff --git a/etc/evergreen_yml_components/variants/misc_release.yml b/etc/evergreen_yml_components/variants/misc_release.yml index 722007b0a0d..ca4cd1212f7 100644 --- a/etc/evergreen_yml_components/variants/misc_release.yml +++ b/etc/evergreen_yml_components/variants/misc_release.yml @@ -42,7 +42,6 @@ buildvariants: - name: .concurrency .common - name: concurrency_replication_causal_consistency_gen - name: disk_wiredtiger - - name: free_monitoring - name: .jscore .common - name: .jstestfuzz .common - name: libunwind_tests @@ -166,7 +165,6 @@ buildvariants: - amazon2-arm64-large - name: concurrency_replication_causal_consistency_gen - name: disk_wiredtiger - - name: free_monitoring - name: .jscore .common - name: .jstestfuzz .common - name: replica_sets_gen @@ -343,7 +341,6 @@ buildvariants: - amazon2023.0-large - name: concurrency_replication_causal_consistency_gen - name: disk_wiredtiger - - name: free_monitoring - name: .jscore .common - name: .jstestfuzz .common - name: replica_sets_gen @@ -504,7 +501,6 @@ buildvariants: - amazon2023.0-arm64-large - name: concurrency_replication_causal_consistency_gen - name: disk_wiredtiger - - name: free_monitoring - name: .jscore .common - name: .jstestfuzz .common - name: replica_sets_gen @@ -675,7 +671,6 @@ buildvariants: - name: .concurrency .common - name: concurrency_replication_causal_consistency_gen - name: disk_wiredtiger - - name: free_monitoring - name: .jscore .common !.decimal !.feature_flag_guarded - name: .jstestfuzz .common - name: multiversion_gen @@ -797,7 +792,6 @@ buildvariants: - name: .concurrency .common - name: concurrency_replication_causal_consistency_gen - name: disk_wiredtiger - - name: free_monitoring - name: .jscore .common !.decimal !.feature_flag_guarded - name: .jstestfuzz .common - name: multiversion_gen @@ -913,7 +907,6 @@ buildvariants: - rhel70 - name: concurrency_replication_causal_consistency_gen - name: disk_wiredtiger - - name: free_monitoring - name: .jscore .common - name: .jstestfuzz .common - name: multiversion_gen @@ -1024,7 +1017,6 @@ buildvariants: - rhel80-build - name: concurrency_replication_causal_consistency_gen - name: disk_wiredtiger - - name: free_monitoring - name: .jscore .common - name: .jstestfuzz .common - name: multiversion_gen @@ -1217,7 +1209,6 @@ buildvariants: - rhel82-arm64-large - name: concurrency_replication_causal_consistency_gen - name: disk_wiredtiger - - name: free_monitoring - name: .jscore .common - name: .jstestfuzz .common - name: replica_sets_gen @@ -1341,7 +1332,6 @@ buildvariants: - rhel90-build - name: concurrency_replication_causal_consistency_gen - name: disk_wiredtiger - - name: free_monitoring - name: .jscore .common - name: .jstestfuzz .common !.multiversion - name: replica_sets_gen @@ -1469,7 +1459,6 @@ buildvariants: - rhel90-arm64-large - name: concurrency_replication_causal_consistency_gen - name: disk_wiredtiger - - name: free_monitoring - name: .jscore .common - name: .jstestfuzz .common - name: replica_sets_gen @@ -1606,7 +1595,6 @@ buildvariants: - suse12-sp5-large - name: concurrency_replication_causal_consistency_gen - name: disk_wiredtiger - - name: free_monitoring - name: .jscore .common !.decimal !.feature_flag_guarded - name: .jstestfuzz .common - name: multiversion_gen @@ -1781,7 +1769,6 @@ buildvariants: - name: .concurrency .common - name: concurrency_replication_causal_consistency_gen - name: disk_wiredtiger - - name: free_monitoring - name: .jscore .common !.decimal !.feature_flag_guarded - name: .jstestfuzz .common - name: multiversion_gen @@ -1839,7 +1826,6 @@ buildvariants: - name: .concurrency .common - name: concurrency_replication_causal_consistency_gen - name: disk_wiredtiger - - name: free_monitoring - name: .jepsen distros: - ubuntu1804-build @@ -2038,7 +2024,6 @@ buildvariants: compile_variant: ubuntu1804-arm64 tasks: - name: compile_test_and_package_serial_no_unittests_TG - - name: free_monitoring - name: jsCore - name: replica_sets_jscore_passthrough - name: test_packages @@ -2086,7 +2071,6 @@ buildvariants: - name: .concurrency .common - name: concurrency_replication_causal_consistency_gen - name: disk_wiredtiger - - name: free_monitoring - name: .jscore .common - name: .jstestfuzz .common - name: libunwind_tests @@ -2143,7 +2127,6 @@ buildvariants: - name: .concurrency .common - name: concurrency_replication_causal_consistency_gen - name: disk_wiredtiger - - name: free_monitoring - name: .jscore .common - name: .jstestfuzz .common - name: libunwind_tests @@ -2390,7 +2373,6 @@ buildvariants: compile_variant: ubuntu2004-arm64 tasks: - name: compile_test_and_package_serial_no_unittests_TG - - name: free_monitoring - name: jsCore - name: replica_sets_jscore_passthrough - name: test_packages @@ -2483,7 +2465,6 @@ buildvariants: compile_variant: ubuntu2204-arm64 tasks: - name: compile_test_and_package_serial_no_unittests_TG - - name: free_monitoring - name: jsCore - name: replica_sets_jscore_passthrough - name: test_packages @@ -2536,7 +2517,6 @@ buildvariants: - windows-vsCurrent-large - name: .concurrency .common - name: disk_wiredtiger - - name: free_monitoring - name: .jscore .common !.auth !.feature_flag_guarded - name: json_schema - name: .jstestfuzz !.initsync !.flow_control !.stepdowns @@ -2666,7 +2646,6 @@ buildvariants: - name: .misc_js - name: .concurrency !.ubsan !.no_txns !.kill_terminate - name: disk_wiredtiger - - name: free_monitoring - name: initial_sync_fuzzer_gen - name: .jscore .common !.auth !.feature_flag_guarded - name: jsCore_txns_large_txns_format @@ -2719,7 +2698,6 @@ buildvariants: - name: .misc_js - name: .concurrency !.ubsan !.no_txns !.kill_terminate - name: disk_wiredtiger - - name: free_monitoring - name: initial_sync_fuzzer_gen - name: .jscore .common !.auth !.feature_flag_guarded - name: jsCore_txns_large_txns_format diff --git a/etc/evergreen_yml_components/variants/sanitizer.yml b/etc/evergreen_yml_components/variants/sanitizer.yml index 672453255e1..d3cf3fa554d 100644 --- a/etc/evergreen_yml_components/variants/sanitizer.yml +++ b/etc/evergreen_yml_components/variants/sanitizer.yml @@ -41,7 +41,6 @@ buildvariants: tasks: - name: compile_test_serial_TG - name: .aggfuzzer .common !.feature_flag_guarded - - name: free_monitoring - name: .jstestfuzz !.initsync - name: generate_buildid_to_debug_symbols_mapping @@ -67,7 +66,6 @@ buildvariants: --sanitize=address --ssl --ocsp-stapling=off - --enable-free-mon=on -j$(grep -c ^processor /proc/cpuinfo) test_flags: --excludeWithAnyTags=requires_fast_memory,requires_ocsp_stapling,requires_increased_memlock_limits multiversion_platform: rhel80 @@ -93,7 +91,6 @@ buildvariants: - name: .misc_js - name: .concurrency !.ubsan !.no_txns !.kill_terminate - name: .encrypt - - name: free_monitoring - name: external_auth - name: external_auth_aws - name: external_auth_oidc @@ -152,7 +149,6 @@ buildvariants: --sanitize=undefined --ssl --ocsp-stapling=off - --enable-free-mon=on -j$(grep -c ^processor /proc/cpuinfo) test_flags: --excludeWithAnyTags=requires_ocsp_stapling,requires_increased_memlock_limits multiversion_platform: rhel80 @@ -177,7 +173,6 @@ buildvariants: - name: .concurrency !.no_txns !.repl !.kill_terminate - name: disk_wiredtiger - name: .encrypt - - name: free_monitoring - name: initial_sync_fuzzer_gen - name: .jscore .common - name: jsCore_min_batch_repeat_queries_ese_gsm diff --git a/etc/system_perf.yml b/etc/system_perf.yml index 818503c64ea..b522ce0deca 100755 --- a/etc/system_perf.yml +++ b/etc/system_perf.yml @@ -1717,7 +1717,6 @@ buildvariants: --variables-files=etc/scons/mongodbtoolchain_stable_gcc.vars --use-diagnostic-latches=off --allocator=system - --enable-free-mon=off --enterprise-features=fle,search,vector_search --js-engine=none --link-model=dynamic-sdk diff --git a/jstests/auth/lib/commands_lib.js b/jstests/auth/lib/commands_lib.js index c0904fc21c9..2d3764b9be8 100644 --- a/jstests/auth/lib/commands_lib.js +++ b/jstests/auth/lib/commands_lib.js @@ -4896,16 +4896,6 @@ export const authCommandsLib = { {runOnDb: secondDbName, roles: {}} ] }, - { - testname: "getFreeMonitoringStatus", - skipSharded: true, - command: {getFreeMonitoringStatus: 1}, - testcases: [{ - runOnDb: adminDbName, - roles: {clusterMonitor: 1, clusterAdmin: 1, root: 1, __system: 1}, - privileges: [{resource: {cluster: true}, actions: ["checkFreeMonitoringStatus"]}] - }] - }, { testname: "getLog", command: {getLog: "*"}, diff --git a/jstests/core/views/views_all_commands.js b/jstests/core/views/views_all_commands.js index 93792681265..c162e07ff4c 100644 --- a/jstests/core/views/views_all_commands.js +++ b/jstests/core/views/views_all_commands.js @@ -423,7 +423,6 @@ let viewsCommandTests = { getCmdLineOpts: {skip: isUnrelated}, getDefaultRWConcern: {skip: isUnrelated}, getDiagnosticData: {skip: isUnrelated}, - getFreeMonitoringStatus: {skip: isUnrelated}, getLog: {skip: isUnrelated}, getMore: { setup: function(conn) { @@ -680,7 +679,6 @@ let viewsCommandTests = { setCommittedSnapshot: {skip: isAnInternalCommand}, setDefaultRWConcern: {skip: isUnrelated}, setFeatureCompatibilityVersion: {skip: isUnrelated}, - setFreeMonitoring: {skip: isUnrelated}, setProfilingFilterGlobally: {skip: isUnrelated}, setParameter: {skip: isUnrelated}, setShardVersion: {skip: isUnrelated}, diff --git a/jstests/free_mon/free_mon_announce.js b/jstests/free_mon/free_mon_announce.js deleted file mode 100644 index 61f88b95763..00000000000 --- a/jstests/free_mon/free_mon_announce.js +++ /dev/null @@ -1,26 +0,0 @@ -// Validate connect message display. -// -import { - FreeMonGetStatus, - FreeMonWebServer, - WaitForRegistration -} from "jstests/free_mon/libs/free_mon.js"; - -const mock_web = new FreeMonWebServer(); -mock_web.start(); - -const mongod = MongoRunner.runMongod({ - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), -}); -assert.neq(mongod, null, 'mongod not running'); -const admin = mongod.getDB('admin'); - -// state === 'enabled'. -admin.enableFreeMonitoring(); -WaitForRegistration(mongod); -const reminder = "To see your monitoring data"; -assert(FreeMonGetStatus(mongod).userReminder.includes(reminder), 'userReminder not found'); - -// Cleanup. -MongoRunner.stopMongod(mongod); -mock_web.stop(); diff --git a/jstests/free_mon/free_mon_disable.js b/jstests/free_mon/free_mon_disable.js deleted file mode 100644 index bba3ec5d97f..00000000000 --- a/jstests/free_mon/free_mon_disable.js +++ /dev/null @@ -1,35 +0,0 @@ -// Validate disable works -// -import { - FreeMonGetServerStatus, - FreeMonGetStatus, - FreeMonWebServer -} from "jstests/free_mon/libs/free_mon.js"; - -let mock_web = new FreeMonWebServer(); - -mock_web.start(); - -let options = { - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), - freeMonitoringTag: "foo", - verbose: 1, -}; - -const conn = MongoRunner.runMongod(options); -assert.neq(null, conn, 'mongod was unable to start up'); - -assert.commandWorked(conn.adminCommand({setFreeMonitoring: 1, action: "disable"})); - -const stats = mock_web.queryStats(); -print(tojson(stats)); - -assert.eq(stats.registers, 0); - -assert.eq(FreeMonGetStatus(conn).state, "disabled"); - -assert.eq(FreeMonGetServerStatus(conn).state, "disabled"); - -MongoRunner.stopMongod(conn); - -mock_web.stop(); diff --git a/jstests/free_mon/free_mon_http_down.js b/jstests/free_mon/free_mon_http_down.js deleted file mode 100644 index a6eef7ad2ed..00000000000 --- a/jstests/free_mon/free_mon_http_down.js +++ /dev/null @@ -1,32 +0,0 @@ -// Validate registration retries if the web server is down. -// -import { - FAULT_FAIL_REGISTER, - FreeMonGetServerStatus, - FreeMonWebServer -} from "jstests/free_mon/libs/free_mon.js"; - -let mock_web = new FreeMonWebServer(FAULT_FAIL_REGISTER); - -mock_web.start(); - -let options = { - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), - enableFreeMonitoring: "on", - verbose: 1, -}; - -const conn = MongoRunner.runMongod(options); -assert.neq(null, conn, 'mongod was unable to start up'); -const admin = conn.getDB('admin'); - -mock_web.waitRegisters(3); - -assert.soon(function() { - const freeMonStats = FreeMonGetServerStatus(conn); - return freeMonStats.registerErrors >= 3; -}, "Failed to wait for 3 register errors: " + FreeMonGetServerStatus(conn), 20 * 1000); - -MongoRunner.stopMongod(conn); - -mock_web.stop(); diff --git a/jstests/free_mon/free_mon_http_validate.js b/jstests/free_mon/free_mon_http_validate.js deleted file mode 100644 index 8c1f2e7fc9b..00000000000 --- a/jstests/free_mon/free_mon_http_validate.js +++ /dev/null @@ -1,31 +0,0 @@ -// Ensure free monitoring gives up if registration fails -// -import {FAULT_INVALID_REGISTER, FreeMonWebServer} from "jstests/free_mon/libs/free_mon.js"; - -let mock_web = new FreeMonWebServer(FAULT_INVALID_REGISTER); - -mock_web.start(); - -let options = { - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), - enableFreeMonitoring: "on", - verbose: 1, -}; - -const conn = MongoRunner.runMongod(options); -assert.neq(null, conn, 'mongod was unable to start up'); - -mock_web.waitRegisters(1); - -// Sleep for some more time in case free monitoring would still try to register -sleep(20 * 1000); - -// Ensure it only tried to register once since we gave it a bad response. -const stats = mock_web.queryStats(); -print(tojson(stats)); - -assert.eq(stats.registers, 1); - -MongoRunner.stopMongod(conn); - -mock_web.stop(); diff --git a/jstests/free_mon/free_mon_metrics_halt.js b/jstests/free_mon/free_mon_metrics_halt.js deleted file mode 100644 index 8daa25458e2..00000000000 --- a/jstests/free_mon/free_mon_metrics_halt.js +++ /dev/null @@ -1,29 +0,0 @@ -// Ensure free monitoring gives up if metrics returns halt -// -import { - FAULT_HALT_METRICS_5, - FreeMonWebServer, - WaitForUnRegistration -} from "jstests/free_mon/libs/free_mon.js"; - -let mock_web = new FreeMonWebServer(FAULT_HALT_METRICS_5); - -mock_web.start(); - -let options = { - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), - enableFreeMonitoring: "on", - verbose: 1, -}; - -const conn = MongoRunner.runMongod(options); -assert.neq(null, conn, 'mongod was unable to start up'); - -mock_web.waitMetrics(6); - -// It gets marked as disabled on halt -WaitForUnRegistration(conn); - -MongoRunner.stopMongod(conn); - -mock_web.stop(); diff --git a/jstests/free_mon/free_mon_metrics_perm_del.js b/jstests/free_mon/free_mon_metrics_perm_del.js deleted file mode 100644 index c2b11113e70..00000000000 --- a/jstests/free_mon/free_mon_metrics_perm_del.js +++ /dev/null @@ -1,35 +0,0 @@ -// Ensure free monitoring gives up if metrics returns permanently delete -// -import { - FAULT_PERMANENTLY_DELETE_AFTER_3, - FreeMonGetRegistration, - FreeMonWebServer -} from "jstests/free_mon/libs/free_mon.js"; - -let mock_web = new FreeMonWebServer(FAULT_PERMANENTLY_DELETE_AFTER_3); - -mock_web.start(); - -let options = { - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), - enableFreeMonitoring: "on", - verbose: 1, -}; - -const conn = MongoRunner.runMongod(options); -assert.neq(null, conn, 'mongod was unable to start up'); - -mock_web.waitMetrics(4); - -// Make sure the registration document gets removed -assert.soon( - function() { - const reg = FreeMonGetRegistration(conn); - return reg === undefined; - }, - "Failed to wait for free mon document to be removed: " + FreeMonGetRegistration(conn), - 20 * 1000); - -MongoRunner.stopMongod(conn); - -mock_web.stop(); diff --git a/jstests/free_mon/free_mon_register.js b/jstests/free_mon/free_mon_register.js deleted file mode 100644 index 62012232fac..00000000000 --- a/jstests/free_mon/free_mon_register.js +++ /dev/null @@ -1,49 +0,0 @@ -// Validate registration works -// -import {FreeMonWebServer, WaitForRegistration} from "jstests/free_mon/libs/free_mon.js"; - -const localTime = Date.now(); - -let mock_web = new FreeMonWebServer(); - -mock_web.start(); - -let options = { - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), - enableFreeMonitoring: "on", - freeMonitoringTag: "foo", - verbose: 1, -}; - -const conn = MongoRunner.runMongod(options); -assert.neq(null, conn, 'mongod was unable to start up'); - -WaitForRegistration(conn); - -const stats = mock_web.queryStats(); -print(tojson(stats)); - -assert.eq(stats.registers, 1); - -const last_register = mock_web.query("last_register"); -print(tojson(last_register)); - -assert.eq(last_register.version, 2); -assert.gt(new Date(last_register.localTime["$date"]), localTime); -assert.eq(last_register.payload.buildInfo.bits, 64); -assert.eq(last_register.payload.buildInfo.ok, 1); -assert.eq(last_register.payload.storageEngine.readOnly, false); -assert.eq(last_register.payload.isMaster.ok, 1); -assert.eq(last_register.tags, ["foo"]); - -mock_web.waitMetrics(2); - -const last_metrics = mock_web.query("last_metrics"); -print(tojson(last_metrics)); - -assert.eq(last_metrics.version, 2); -assert.gt(new Date(last_metrics.localTime["$date"]), localTime); - -MongoRunner.stopMongod(conn); - -mock_web.stop(); diff --git a/jstests/free_mon/free_mon_register_cmd.js b/jstests/free_mon/free_mon_register_cmd.js deleted file mode 100644 index f9ffc964de0..00000000000 --- a/jstests/free_mon/free_mon_register_cmd.js +++ /dev/null @@ -1,71 +0,0 @@ -// Validate registration works via a command. Validate it can be registered and unregistered -// -import { - FreeMonGetRegistration, - FreeMonGetStatus, - FreeMonWebServer, - WaitForFreeMonServerStatusState, -} from "jstests/free_mon/libs/free_mon.js"; - -let mock_web = new FreeMonWebServer(); - -mock_web.start(); - -let options = { - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), - verbose: 1, -}; - -const conn = MongoRunner.runMongod(options); -assert.neq(null, conn, 'mongod was unable to start up'); - -// Wait an arbitrary amount of time to allow the processor loop to start. -sleep(10 * 1000); - -// Then verify that no registrations happened since we haven't runtime enabled yed. -assert.eq('undecided', FreeMonGetStatus(conn).state, "Initial state should be 'undecided'"); -assert.eq(0, mock_web.queryStats().registers, "mongod registered without enabling free_mod"); - -assert.commandWorked(conn.adminCommand({setFreeMonitoring: 1, action: "enable"})); - -WaitForFreeMonServerStatusState(conn, 'enabled'); - -// The command should either timeout or suceed after registration is complete -const retStatus1 = FreeMonGetStatus(conn); -assert.eq(retStatus1.state, "enabled", tojson(retStatus1)); - -const stats = mock_web.queryStats(); -print(tojson(stats)); - -assert.eq(stats.registers, 1); - -const last_register = mock_web.query("last_register"); -print(tojson(last_register)); - -assert.eq(last_register.version, 2); -assert.eq(last_register.payload.buildInfo.bits, 64); -assert.eq(last_register.payload.buildInfo.ok, 1); -assert.eq(last_register.payload.storageEngine.readOnly, false); -assert.eq(last_register.payload.isMaster.ok, 1); - -mock_web.waitMetrics(2); - -const last_metrics = mock_web.query("last_metrics"); -print(tojson(last_metrics)); - -assert.eq(last_metrics.version, 2); - -assert.commandWorked(conn.adminCommand({setFreeMonitoring: 1, action: "disable"})); - -// Wait for unregistration to occur -assert.soon(function() { - const regDoc = FreeMonGetRegistration(conn); - return regDoc.state == "disabled"; -}, "Failed to unregister", 60 * 1000); - -const retStatus2 = FreeMonGetStatus(conn); -assert.eq(retStatus2.state, "disabled", tojson(retStatus1)); - -MongoRunner.stopMongod(conn); - -mock_web.stop(); diff --git a/jstests/free_mon/free_mon_register_off.js b/jstests/free_mon/free_mon_register_off.js deleted file mode 100644 index 5afd21d9cc1..00000000000 --- a/jstests/free_mon/free_mon_register_off.js +++ /dev/null @@ -1,36 +0,0 @@ -// Validate registration does work if free monitoring is disabled. -// -import {FreeMonWebServer} from "jstests/free_mon/libs/free_mon.js"; - -let mock_web = new FreeMonWebServer(); - -mock_web.start(); - -let options = { - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), - enableFreeMonitoring: "off", - verbose: 1, -}; - -const conn = MongoRunner.runMongod(options); -assert.neq(null, conn, 'mongod was unable to start up'); - -assert.commandFailed(conn.adminCommand({setFreeMonitoring: 1, action: "enable"})); - -// If it some time in case it actually started to process something. -sleep(10 * 1000); - -const retStatus1 = conn.adminCommand({getFreeMonitoringStatus: 1}); -assert.commandWorked(retStatus1); -assert.eq(retStatus1.state, "disabled", tojson(retStatus1)); - -const stats = mock_web.queryStats(); -print(tojson(stats)); - -assert.eq(stats.registers, 0); - -assert.commandFailed(conn.adminCommand({setFreeMonitoring: 1, action: "disable"})); - -MongoRunner.stopMongod(conn); - -mock_web.stop(); diff --git a/jstests/free_mon/free_mon_register_resend.js b/jstests/free_mon/free_mon_register_resend.js deleted file mode 100644 index 8356bdb04f6..00000000000 --- a/jstests/free_mon/free_mon_register_resend.js +++ /dev/null @@ -1,28 +0,0 @@ -// Validate resend registration works in a replica set -// -import { - FAULT_RESEND_REGISTRATION_ONCE, - FreeMonWebServer, - WaitForRegistration -} from "jstests/free_mon/libs/free_mon.js"; - -let mock_web = new FreeMonWebServer(FAULT_RESEND_REGISTRATION_ONCE); - -mock_web.start(); - -let options = { - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), - enableFreeMonitoring: "on", - verbose: 1, -}; - -const conn = MongoRunner.runMongod(options); -assert.neq(null, conn, 'mongod was unable to start up'); - -WaitForRegistration(conn); - -mock_web.waitRegisters(2); - -MongoRunner.stopMongod(conn); - -mock_web.stop(); diff --git a/jstests/free_mon/free_mon_rs_corrupt.js b/jstests/free_mon/free_mon_rs_corrupt.js deleted file mode 100644 index f7979565a21..00000000000 --- a/jstests/free_mon/free_mon_rs_corrupt.js +++ /dev/null @@ -1,33 +0,0 @@ -// Validate a user manipulating system.version for free monitoring does -// not crash mongod -import {FreeMonWebServer, WaitForRegistration} from "jstests/free_mon/libs/free_mon.js"; - -let mock_web = new FreeMonWebServer(); - -mock_web.start(); - -let options = { - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), - enableFreeMonitoring: "on", - verbose: 1, -}; - -const rst = new ReplSetTest({nodes: 2, nodeOptions: options}); -rst.startSet(); -rst.initiate(); -rst.awaitReplication(); - -WaitForRegistration(rst.getPrimary()); - -mock_web.waitRegisters(2); - -// For kicks, corrupt the free monitoring storage state to knock free mon offline -// and make sure the node does not crash -rst.getPrimary().getDB("admin").system.version.update({_id: "free_monitoring"}, - {$set: {version: 2}}); - -sleep(20 * 1000); - -rst.stopSet(); - -mock_web.stop(); diff --git a/jstests/free_mon/free_mon_rs_delete.js b/jstests/free_mon/free_mon_rs_delete.js deleted file mode 100644 index 37e7bc67dec..00000000000 --- a/jstests/free_mon/free_mon_rs_delete.js +++ /dev/null @@ -1,66 +0,0 @@ -// Validate a user deleting free monitoring in system.version does -// not crash mongod -import { - FreeMonWebServer, - WaitForFreeMonServerStatusState, - WaitForRegistration -} from "jstests/free_mon/libs/free_mon.js"; - -let mock_web = new FreeMonWebServer(); - -mock_web.start(); - -let options = { - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), - enableFreeMonitoring: "on", - verbose: 1, -}; - -const rst = new ReplSetTest({nodes: 2, nodeOptions: options}); -rst.startSet(); -rst.initiate(); -rst.awaitReplication(); - -WaitForRegistration(rst.getPrimary()); - -mock_web.waitRegisters(2); - -WaitForRegistration(rst.getPrimary()); -WaitForRegistration(rst.getSecondary()); - -const qs1 = mock_web.queryStats(); - -jsTestLog("Breaking Free Monitoring"); - -// For kicks, delete the free monitoring storage state to knock free mon offline -// and make sure the node does not crash -rst.getPrimary().getDB("admin").system.version.remove({_id: "free_monitoring"}); - -jsTestLog("Sleeping for 20s"); -sleep(20 * 1000); - -const qs2 = mock_web.queryStats(); - -// Make sure we are back to the initial state. -WaitForFreeMonServerStatusState(rst.getPrimary(), 'undecided'); -WaitForFreeMonServerStatusState(rst.getSecondary(), 'undecided'); - -// Verify free monitoring stops but tolerate one additional collection -assert.gte(qs1.metrics + 2, qs2.metrics); -// Tolerate an additional registration on the secondary side. We may delete the record on the -// primary before the secondary processes all pending registrations requests. -assert.lte(qs1.registers, qs2.registers); - -// Enable it again to be sure we can resume -assert.commandWorked(rst.getPrimary().adminCommand({setFreeMonitoring: 1, action: "enable"})); -WaitForRegistration(rst.getPrimary()); -WaitForRegistration(rst.getSecondary()); - -sleep(20 * 1000); - -WaitForRegistration(rst.getPrimary()); -WaitForRegistration(rst.getSecondary()); - -rst.stopSet(); - -mock_web.stop(); diff --git a/jstests/free_mon/free_mon_rs_halt.js b/jstests/free_mon/free_mon_rs_halt.js deleted file mode 100644 index 36cd272eb23..00000000000 --- a/jstests/free_mon/free_mon_rs_halt.js +++ /dev/null @@ -1,63 +0,0 @@ -// Validate that if the endpoint returns halt = true that free monitoring halts -import { - FAULT_HALT_METRICS_5, - FreeMonWebServer, - WaitForFreeMonServerStatusState, - WaitForRegistration, -} from "jstests/free_mon/libs/free_mon.js"; - -let mock_web = new FreeMonWebServer(FAULT_HALT_METRICS_5, true); - -mock_web.start(); - -let options = { - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), - enableFreeMonitoring: "on", - verbose: 1, -}; - -const rst = new ReplSetTest({nodes: 2, nodeOptions: options}); -rst.startSet(); -rst.initiate(); -rst.awaitReplication(); - -WaitForRegistration(rst.getPrimary()); - -mock_web.waitRegisters(2); - -WaitForFreeMonServerStatusState(rst.getPrimary(), 'enabled'); -WaitForFreeMonServerStatusState(rst.getSecondary(), 'enabled'); - -mock_web.enableFaults(); -mock_web.waitFaults(1); - -const qs1 = mock_web.queryStats(); - -sleep(20 * 1000); - -const qs2 = mock_web.queryStats(); - -// Verify free monitoring stops but tolerate one additional collection -assert.gte(qs1.metrics + 1, qs2.metrics); -assert.eq(qs1.registers, qs2.registers); - -// Halt causes us to disable free monitoring, not return it to initial state. -WaitForFreeMonServerStatusState(rst.getPrimary(), 'disabled'); -WaitForFreeMonServerStatusState(rst.getSecondary(), 'disabled'); - -// Disable the fault so we can re-enable again -mock_web.disableFaults(); - -// Enable it again to be sure we can resume -assert.commandWorked(rst.getPrimary().adminCommand({setFreeMonitoring: 1, action: "enable"})); -WaitForRegistration(rst.getPrimary()); -WaitForRegistration(rst.getSecondary()); - -sleep(20 * 1000); - -WaitForFreeMonServerStatusState(rst.getPrimary(), 'enabled'); -WaitForFreeMonServerStatusState(rst.getSecondary(), 'enabled'); - -rst.stopSet(); - -mock_web.stop(); diff --git a/jstests/free_mon/free_mon_rs_off.js b/jstests/free_mon/free_mon_rs_off.js deleted file mode 100644 index f5e80583f87..00000000000 --- a/jstests/free_mon/free_mon_rs_off.js +++ /dev/null @@ -1,34 +0,0 @@ -// Validate replica set starts up with free monitoring disabled -// -import {FreeMonWebServer} from "jstests/free_mon/libs/free_mon.js"; - -let mock_web = new FreeMonWebServer(); - -mock_web.start(); - -let options = { - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), - enableFreeMonitoring: "off", - verbose: 1, -}; - -const rst = new ReplSetTest({nodes: 2, nodeOptions: options}); - -rst.startSet(); -rst.initiate(); -rst.awaitReplication(); - -const retStatus1 = rst.getPrimary().adminCommand({getFreeMonitoringStatus: 1}); -assert.commandWorked(retStatus1); -assert.eq(retStatus1.state, "disabled", tojson(retStatus1)); - -const stats = mock_web.queryStats(); -print(tojson(stats)); - -assert.eq(stats.registers, 0); - -assert.commandFailed(rst.getPrimary().adminCommand({setFreeMonitoring: 1, action: "disable"})); - -rst.stopSet(); - -mock_web.stop(); diff --git a/jstests/free_mon/free_mon_rs_perm_del.js b/jstests/free_mon/free_mon_rs_perm_del.js deleted file mode 100644 index 17d62be13a3..00000000000 --- a/jstests/free_mon/free_mon_rs_perm_del.js +++ /dev/null @@ -1,56 +0,0 @@ -// Validate that if the endpoint says permanently delete that the state -// document is deleted and replicated properly -import { - FAULT_PERMANENTLY_DELETE_AFTER_3, - FreeMonWebServer, - WaitForFreeMonServerStatusState, - WaitForRegistration, -} from "jstests/free_mon/libs/free_mon.js"; - -let mock_web = new FreeMonWebServer(FAULT_PERMANENTLY_DELETE_AFTER_3, true); - -mock_web.start(); - -let options = { - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), - enableFreeMonitoring: "on", - verbose: 1, -}; - -const rst = new ReplSetTest({nodes: 2, nodeOptions: options}); -rst.startSet(); -rst.initiate(); -rst.awaitReplication(); - -WaitForRegistration(rst.getPrimary()); - -mock_web.waitRegisters(2); - -WaitForRegistration(rst.getPrimary()); -WaitForRegistration(rst.getSecondary()); - -mock_web.enableFaults(); -mock_web.waitFaults(1); - -sleep(20 * 1000); - -// Make sure we are back to the initial state. -WaitForFreeMonServerStatusState(rst.getPrimary(), 'undecided'); -WaitForFreeMonServerStatusState(rst.getSecondary(), 'undecided'); - -// Disable the fault so we can re-enable again -mock_web.disableFaults(); - -// Enable it again to be sure we can resume -assert.commandWorked(rst.getPrimary().adminCommand({setFreeMonitoring: 1, action: "enable"})); -WaitForRegistration(rst.getPrimary()); -WaitForRegistration(rst.getSecondary()); - -sleep(20 * 1000); - -WaitForFreeMonServerStatusState(rst.getPrimary(), 'enabled'); -WaitForFreeMonServerStatusState(rst.getSecondary(), 'enabled'); - -rst.stopSet(); - -mock_web.stop(); diff --git a/jstests/free_mon/free_mon_rs_register.js b/jstests/free_mon/free_mon_rs_register.js deleted file mode 100644 index a990ea82458..00000000000 --- a/jstests/free_mon/free_mon_rs_register.js +++ /dev/null @@ -1,105 +0,0 @@ -// Validate registration works in a replica set -// -import { - FreeMonWebServer, - ValidateFreeMonReplicaSet, - WaitForFreeMonServerStatusState, - WaitForRegistration, - WaitForUnRegistration, -} from "jstests/free_mon/libs/free_mon.js"; - -let mock_web = new FreeMonWebServer(); - -mock_web.start(); - -let options = { - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), - verbose: 1, -}; - -const rst = new ReplSetTest({nodes: 2, nodeOptions: options}); - -rst.startSet(); -rst.initiate(); -rst.awaitReplication(); - -sleep(10 * 1000); -assert.eq(0, mock_web.queryStats().registers, "mongod registered without enabling free_mod"); - -assert.commandWorked(rst.getPrimary().adminCommand({setFreeMonitoring: 1, action: "enable"})); -WaitForRegistration(rst.getPrimary()); - -mock_web.waitRegisters(2); - -WaitForRegistration(rst.getPrimary()); -WaitForRegistration(rst.getSecondary()); -ValidateFreeMonReplicaSet(rst); - -const last_register = mock_web.query("last_register"); -print(tojson(last_register)); - -assert.eq(last_register.version, 2); -assert.eq(last_register.payload.buildInfo.bits, 64); -assert.eq(last_register.payload.buildInfo.ok, 1); -assert.eq(last_register.payload.storageEngine.readOnly, false); -assert.eq(last_register.payload.isMaster.ok, 1); -assert.gte(last_register.payload.replSetGetConfig.config.version, 2); - -function isUUID(val) { - // Mock webserver gives us back unpacked BinData/UUID in the form: - //"$binary" : {"base64" : "2gzkSY3bTlu/k3bXfpPUKg==", "subType" : "04"} - if ((typeof val) !== 'object') { - return false; - } - const binary = val['$binary']; - const subType = binary['subType']; - const base64 = binary['base64']; - - // This number is the indentifier for a UUID. - // https://www.mongodb.com/docs/manual/reference/bson-types/#binary-data - if (subType !== '04') { - return false; - } - - // Validate base64 - return base64.match('^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$') !== - null; -} -assert.eq(isUUID(last_register.payload.uuid['local.oplog.rs']), true); - -// Restart the secondary -var s1 = rst.getSecondary(); -var s1Id = rst.getNodeId(s1); - -rst.stop(s1Id); -rst.waitForState(s1, ReplSetTest.State.DOWN); - -rst.restart(s1Id); - -mock_web.waitRegisters(3); - -// Now disable it -assert.commandWorked(rst.getPrimary().adminCommand({setFreeMonitoring: 1, action: "disable"})); - -WaitForUnRegistration(rst.getPrimary()); -WaitForUnRegistration(rst.getSecondary()); - -WaitForFreeMonServerStatusState(rst.getPrimary(), 'disabled'); -WaitForFreeMonServerStatusState(rst.getSecondary(), 'disabled'); - -// Restart the secondary with it disabled -var s1 = rst.getSecondary(); -var s1Id = rst.getNodeId(s1); - -rst.stop(s1Id); -rst.waitForState(s1, ReplSetTest.State.DOWN); - -rst.restart(s1Id); - -// Make sure it is disabled -WaitForFreeMonServerStatusState(rst.getPrimary(), 'disabled'); -WaitForFreeMonServerStatusState(rst.getSecondary(), 'disabled'); - -rst.stopSet(); - -mock_web.stop(); diff --git a/jstests/free_mon/free_mon_rs_resend.js b/jstests/free_mon/free_mon_rs_resend.js deleted file mode 100644 index 57f4772d811..00000000000 --- a/jstests/free_mon/free_mon_rs_resend.js +++ /dev/null @@ -1,69 +0,0 @@ -// Validate resend registration works in a replica set -// -import { - FAULT_RESEND_REGISTRATION_AT_3, - FAULT_RESEND_REGISTRATION_ONCE, - FreeMonWebServer, - ValidateFreeMonReplicaSet, - WaitForFreeMonServerStatusState, - WaitForRegistration, -} from "jstests/free_mon/libs/free_mon.js"; - -let mock_web = new FreeMonWebServer(FAULT_RESEND_REGISTRATION_AT_3); -let mock_web_sec = new FreeMonWebServer(FAULT_RESEND_REGISTRATION_ONCE, true); - -mock_web.start(); -mock_web_sec.start(); - -const rst = new ReplSetTest({ - name: "free_mon_rs_register", - nodes: [ - { - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), - verbose: 1, - }, - { - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web_sec.getURL(), - verbose: 1, - } - ] -}); - -rst.startSet(); -rst.initiate(); -rst.awaitReplication(); - -sleep(10 * 1000); -assert.eq(0, mock_web.queryStats().registers, "mongod registered without enabling free_mod"); -assert.eq(0, mock_web_sec.queryStats().registers, "mongod registered without enabling free_mod"); - -assert.commandWorked(rst.getPrimary().adminCommand({setFreeMonitoring: 1, action: "enable"})); -WaitForRegistration(rst.getPrimary()); - -mock_web.waitRegisters(1); -mock_web_sec.waitRegisters(1); - -WaitForFreeMonServerStatusState(rst.getPrimary(), 'enabled'); -WaitForFreeMonServerStatusState(rst.getSecondary(), 'enabled'); -ValidateFreeMonReplicaSet(rst); - -mock_web.waitRegisters(2); -mock_web_sec.waitRegisters(2); -mock_web_sec.disableFaults(); - -// Trigger resend on the secondary only -mock_web_sec.enableFaults(); -mock_web_sec.waitFaults(1); -mock_web_sec.waitRegisters(3); - -// Double check registers were as expected -const stats = mock_web.queryStats(); -assert.eq(stats.registers, 2); - -const stats_sec = mock_web_sec.queryStats(); -assert.gte(stats_sec.registers, 3); - -rst.stopSet(); - -mock_web.stop(); -mock_web_sec.stop(); diff --git a/jstests/free_mon/free_mon_server_status.js b/jstests/free_mon/free_mon_server_status.js deleted file mode 100644 index 9ad3ba06588..00000000000 --- a/jstests/free_mon/free_mon_server_status.js +++ /dev/null @@ -1,49 +0,0 @@ -// Validate serverStatus output. -// -import { - FreeMonWebServer, - WaitForFreeMonServerStatusState, - WaitForRegistration -} from "jstests/free_mon/libs/free_mon.js"; - -const mock_web = new FreeMonWebServer(); -mock_web.start(); - -const mongod = MongoRunner.runMongod({ - setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), -}); -assert.neq(mongod, null, 'mongod not running'); -const admin = mongod.getDB('admin'); - -const kRetryIntervalSecs = 1; -function freeMonStats() { - return assert.commandWorked(admin.runCommand({serverStatus: 1})).freeMonitoring; -} - -// Initial state. -assert.eq(freeMonStats().state, 'undecided'); - -admin.enableFreeMonitoring(); -WaitForRegistration(mongod); - -// Enabled. -const enabled = freeMonStats(); -assert.eq(enabled.state, 'enabled'); -assert.eq(enabled.retryIntervalSecs, kRetryIntervalSecs); -assert.eq(enabled.registerErrors, 0); -assert.eq(enabled.metricsErrors, 0); - -// Explicitly disabled. -admin.disableFreeMonitoring(); - -WaitForFreeMonServerStatusState(mongod, "disabled"); - -const disabled = freeMonStats(); -assert.eq(disabled.state, 'disabled'); -assert.eq(disabled.retryIntervalSecs, kRetryIntervalSecs); -assert.eq(disabled.registerErrors, 0); -assert.eq(disabled.metricsErrors, 0); - -// Cleanup. -MongoRunner.stopMongod(mongod); -mock_web.stop(); diff --git a/jstests/free_mon/libs/free_mon.js b/jstests/free_mon/libs/free_mon.js deleted file mode 100644 index 65d9f522678..00000000000 --- a/jstests/free_mon/libs/free_mon.js +++ /dev/null @@ -1,322 +0,0 @@ - -/** - * Control the Free Monitoring Mock Webserver. - */ - -import {getPython3Binary} from "jstests/libs/python.js"; - -// These faults must match the list of faults in mock_http_server.py, see the -// SUPPORTED_FAULT_TYPES list in mock_http_server.py -export const FAULT_FAIL_REGISTER = "fail_register"; - -export const FAULT_INVALID_REGISTER = "invalid_register"; -export const FAULT_HALT_METRICS_5 = "halt_metrics_5"; -export const FAULT_PERMANENTLY_DELETE_AFTER_3 = "permanently_delete_after_3"; -export const FAULT_RESEND_REGISTRATION_AT_3 = "resend_registration_at_3"; -export const FAULT_RESEND_REGISTRATION_ONCE = "resend_registration_once"; -export const DISABLE_FAULTS = "disable_faults"; -export const ENABLE_FAULTS = "enable_faults"; - -export class FreeMonWebServer { - /** - * Create a new webserver. - * - * @param {string} fault_type - * @param {bool} disableFaultsOnStartup optionally disable fault on startup - */ - constructor(fault_type, disableFaultsOnStartup) { - this.python = getPython3Binary(); - this.disableFaultsOnStartup = disableFaultsOnStartup || false; - this.fault_type = fault_type; - - 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 - */ -export function WaitForDiskState(conn, state) { - 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 - */ -export function WaitForRegistration(conn) { - WaitForDiskState(conn, 'enabled'); -} - -/** - * Wait for unregistration information to be populated in the database. - * - * @param {object} conn - */ -export function WaitForUnRegistration(conn) { - WaitForDiskState(conn, 'disabled'); -} - -/** - * Get registration document. - * - * @param {object} registration document - */ -export function FreeMonGetRegistration(conn) { - 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 - */ -export function FreeMonGetServerStatus(conn) { - const admin = conn.getDB("admin"); - return assert.commandWorked(admin.runCommand({serverStatus: 1})).freeMonitoring; -} - -/** - * Get current Free Monitoring Status via getFreeMonitoringStatus. - * - * @param {object} getFreeMonitoringStatus document - */ -export function FreeMonGetStatus(conn) { - const admin = conn.getDB("admin"); - const reply = assert.commandWorked(admin.runCommand({getFreeMonitoringStatus: 1})); - // FreeMonitoring has been deprecated and reports 'disabled' regardless of status. - assert.eq(reply.state, 'disabled', 'FreeMonitoring has been deprecated'); - - // Use the "true" state tucked into the 'debug' field if its available. - return reply.debug || reply; -} - -/** - * Wait for server status state - * - * @param {object} conn - * @param {string} state - */ -export function WaitForFreeMonServerStatusState(conn, state) { - // 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 - */ -export function ValidateFreeMonReplicaSet(rst) { - 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 ") - - 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() diff --git a/jstests/replsets/all_commands_downgrading_to_upgraded.js b/jstests/replsets/all_commands_downgrading_to_upgraded.js index 7a7fc02ff89..98cc2332052 100644 --- a/jstests/replsets/all_commands_downgrading_to_upgraded.js +++ b/jstests/replsets/all_commands_downgrading_to_upgraded.js @@ -777,11 +777,6 @@ const allCommands = { isAdminCommand: true, command: {getDiagnosticData: 1}, }, - getFreeMonitoringStatus: { - isAdminCommand: true, - command: {getFreeMonitoringStatus: 1}, - doesNotRunOnMongos: true, - }, getLog: { isAdminCommand: true, command: {getLog: "global"}, @@ -1402,9 +1397,6 @@ const allCommands = { }, setIndexCommitQuorum: {skip: requiresParallelShell}, setFeatureCompatibilityVersion: {skip: "is tested through this test"}, - setFreeMonitoring: { - skip: "requires cloudFreeMonitoringEndpointURL setup", - }, setProfilingFilterGlobally: { command: {setProfilingFilterGlobally: 1, filter: {nreturned: 0}}, expectFailure: true, diff --git a/jstests/replsets/db_reads_while_recovering_all_commands.js b/jstests/replsets/db_reads_while_recovering_all_commands.js index 4d43d93019a..ec57b122f74 100644 --- a/jstests/replsets/db_reads_while_recovering_all_commands.js +++ b/jstests/replsets/db_reads_while_recovering_all_commands.js @@ -273,7 +273,6 @@ const allCommands = { getDatabaseVersion: {skip: isNotAUserDataRead}, getDefaultRWConcern: {skip: isNotAUserDataRead}, getDiagnosticData: {skip: isNotAUserDataRead}, - getFreeMonitoringStatus: {skip: isNotAUserDataRead}, getLog: {skip: isNotAUserDataRead}, getMore: { command: {getMore: NumberLong(123), collection: collName}, @@ -396,7 +395,6 @@ const allCommands = { setDefaultRWConcern: {skip: isPrimaryOnly}, setIndexCommitQuorum: {skip: isPrimaryOnly}, setFeatureCompatibilityVersion: {skip: isPrimaryOnly}, - setFreeMonitoring: {skip: isPrimaryOnly}, setProfilingFilterGlobally: {skip: isNotAUserDataRead}, setParameter: {skip: isNotAUserDataRead}, setShardVersion: {skip: isNotAUserDataRead}, diff --git a/jstests/replsets/tenant_migration_concurrent_writes_on_donor_util.js b/jstests/replsets/tenant_migration_concurrent_writes_on_donor_util.js index 4d98f64e0a7..3461867e87e 100644 --- a/jstests/replsets/tenant_migration_concurrent_writes_on_donor_util.js +++ b/jstests/replsets/tenant_migration_concurrent_writes_on_donor_util.js @@ -526,7 +526,6 @@ export const TenantMigrationConcurrentWriteUtil = { getDatabaseVersion: {skip: isNotRunOnUserDatabase}, getDefaultRWConcern: {skip: isNotRunOnUserDatabase}, getDiagnosticData: {skip: isNotRunOnUserDatabase}, - getFreeMonitoringStatus: {skip: isNotRunOnUserDatabase}, getLog: {skip: isNotRunOnUserDatabase}, getMore: {skip: isNotWriteCommand}, getParameter: {skip: isNotRunOnUserDatabase}, @@ -653,7 +652,6 @@ export const TenantMigrationConcurrentWriteUtil = { setCommittedSnapshot: {skip: isNotRunOnUserDatabase}, setDefaultRWConcern: {skip: isNotRunOnUserDatabase}, setFeatureCompatibilityVersion: {skip: isNotRunOnUserDatabase}, - setFreeMonitoring: {skip: isNotRunOnUserDatabase}, setProfilingFilterGlobally: {skip: isNotRunOnUserDatabase}, setIndexCommitQuorum: {skip: isNotRunOnUserDatabase}, setParameter: {skip: isNotRunOnUserDatabase}, diff --git a/jstests/sharding/database_versioning_all_commands.js b/jstests/sharding/database_versioning_all_commands.js index 7e76faf2348..91874ae35f4 100644 --- a/jstests/sharding/database_versioning_all_commands.js +++ b/jstests/sharding/database_versioning_all_commands.js @@ -740,8 +740,6 @@ let testCases = { } }, setFeatureCompatibilityVersion: {skip: "not on a user database"}, - setFreeMonitoring: - {skip: "explicitly fails for mongos, primary mongod only", conditional: true}, setProfilingFilterGlobally: {skip: "executes locally on mongos (not sent to any remote node)"}, setParameter: {skip: "executes locally on mongos (not sent to any remote node)"}, setClusterParameter: {skip: "always targets the config server"}, diff --git a/jstests/sharding/libs/mongos_api_params_util.js b/jstests/sharding/libs/mongos_api_params_util.js index 52db12a7a4c..5f1b3ab14a6 100644 --- a/jstests/sharding/libs/mongos_api_params_util.js +++ b/jstests/sharding/libs/mongos_api_params_util.js @@ -1256,11 +1256,6 @@ export let MongosAPIParametersUtil = (function() { command: () => ({setFeatureCompatibilityVersion: latestFCV, confirm: true}) } }, - { - commandName: "setFreeMonitoring", - skip: "explicitly fails for mongos, primary mongod only", - conditional: true - }, { commandName: "setProfilingFilterGlobally", skip: "executes locally on mongos (not sent to any remote node)", diff --git a/jstests/sharding/read_write_concern_defaults_application.js b/jstests/sharding/read_write_concern_defaults_application.js index 202731153be..6c165ebe67d 100644 --- a/jstests/sharding/read_write_concern_defaults_application.js +++ b/jstests/sharding/read_write_concern_defaults_application.js @@ -530,7 +530,6 @@ let testCases = { getDatabaseVersion: {skip: "does not accept read or write concern"}, getDefaultRWConcern: {skip: "does not accept read or write concern"}, getDiagnosticData: {skip: "does not accept read or write concern"}, - getFreeMonitoringStatus: {skip: "does not accept read or write concern"}, getLog: {skip: "does not accept read or write concern"}, getMore: {skip: "does not accept read or write concern"}, getParameter: {skip: "does not accept read or write concern"}, @@ -745,7 +744,6 @@ let testCases = { setCommittedSnapshot: {skip: "internal command"}, setDefaultRWConcern: {skip: "special case (must run after all other commands)"}, setFeatureCompatibilityVersion: {skip: "does not accept read or write concern"}, - setFreeMonitoring: {skip: "does not accept read or write concern"}, setProfilingFilterGlobally: {skip: "does not accept read or write concern"}, setIndexCommitQuorum: {skip: "does not accept read or write concern"}, setParameter: {skip: "does not accept read or write concern"}, diff --git a/jstests/sharding/safe_secondary_reads_drop_recreate.js b/jstests/sharding/safe_secondary_reads_drop_recreate.js index e727d336e81..3b5347543af 100644 --- a/jstests/sharding/safe_secondary_reads_drop_recreate.js +++ b/jstests/sharding/safe_secondary_reads_drop_recreate.js @@ -359,7 +359,6 @@ let testCases = { setDefaultRWConcern: {skip: "primary only"}, setIndexCommitQuorum: {skip: "primary only"}, setFeatureCompatibilityVersion: {skip: "primary only"}, - setFreeMonitoring: {skip: "primary only"}, setProfilingFilterGlobally: {skip: "does not return user data"}, setParameter: {skip: "does not return user data"}, setShardVersion: {skip: "does not return user data"}, diff --git a/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js b/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js index 9f6d82c44a3..7ebd5bb0b25 100644 --- a/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js +++ b/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js @@ -417,7 +417,6 @@ let testCases = { setDefaultRWConcern: {skip: "primary only"}, setIndexCommitQuorum: {skip: "primary only"}, setFeatureCompatibilityVersion: {skip: "primary only"}, - setFreeMonitoring: {skip: "primary only"}, setProfilingFilterGlobally: {skip: "does not return user data"}, setParameter: {skip: "does not return user data"}, setShardVersion: {skip: "does not return user data"}, diff --git a/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js b/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js index c8b589508f7..6f9463f33a9 100644 --- a/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js +++ b/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js @@ -370,7 +370,6 @@ let testCases = { setDefaultRWConcern: {skip: "primary only"}, setIndexCommitQuorum: {skip: "primary only"}, setFeatureCompatibilityVersion: {skip: "primary only"}, - setFreeMonitoring: {skip: "primary only"}, setProfilingFilterGlobally: {skip: "does not return user data"}, setParameter: {skip: "does not return user data"}, setShardVersion: {skip: "does not return user data"}, diff --git a/src/mongo/base/error_codes.yml b/src/mongo/base/error_codes.yml index 53de55b50a6..2987bdc2e33 100644 --- a/src/mongo/base/error_codes.yml +++ b/src/mongo/base/error_codes.yml @@ -299,9 +299,9 @@ error_codes: - {code: 250,name: StaleChunkHistory,categories: [SnapshotError]} - {code: 251,name: NoSuchTransaction,categories: [VoteAbortError]} - {code: 252,name: ReentrancyNotAllowed} - - {code: 253,name: FreeMonHttpInFlight} - - {code: 254,name: FreeMonHttpTemporaryFailure} - - {code: 255,name: FreeMonHttpPermanentFailure} + # - {code: 253,name: FreeMonHttpInFlight} # Removed in 7.1 + # - {code: 254,name: FreeMonHttpTemporaryFailure} # Removed in 7.1 + # - {code: 255,name: FreeMonHttpPermanentFailure} # Removed in 7.1 - {code: 256,name: TransactionCommitted} - {code: 257,name: TransactionTooLarge} - {code: 258,name: UnknownFeatureCompatibilityVersion} diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index 916b5ac6f67..62cc15ccc9c 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -26,7 +26,6 @@ env.SConscript( 'concurrency', 'cst', 'exec', - 'free_mon', 'fts', 'ftdc', 'geo', @@ -2415,7 +2414,6 @@ env.Library( 'dbhelpers', 'exec/working_set', 'feature_compatibility_version_metrics', - 'free_mon/free_mon_mongod', 'ftdc/ftdc_mongod', 'fts/ftsmongod', 'index/index_access_method', @@ -2527,7 +2525,6 @@ env.Library( 'concurrency/flow_control_ticketholder', 'concurrency/lock_manager', 'fle_crud_mongod', - 'free_mon/free_mon_mongod', 'ftdc/ftdc_mongod', 'index/index_access_method', 'index_builds_coordinator_mongod', diff --git a/src/mongo/db/auth/action_type.idl b/src/mongo/db/auth/action_type.idl index a1cdc2f67ee..5e9ca0e5271 100644 --- a/src/mongo/db/auth/action_type.idl +++ b/src/mongo/db/auth/action_type.idl @@ -63,7 +63,7 @@ enums: changeOwnPassword : "changeOwnPassword" changeOwnCustomData : "changeOwnCustomData" changeStream : "changeStream" - checkFreeMonitoringStatus : "checkFreeMonitoringStatus" + checkFreeMonitoringStatus : "checkFreeMonitoringStatus" # Removed (backwards compatibility) checkMetadataConsistency : "checkMetadataConsistency" cleanupOrphaned : "cleanupOrphaned" clearJumboFlag : "clearJumboFlag" @@ -182,7 +182,7 @@ enums: setClusterParameter: "setClusterParameter" setDefaultRWConcern : "setDefaultRWConcern" setFeatureCompatibilityVersion : "setFeatureCompatibilityVersion" - setFreeMonitoring : "setFreeMonitoring" + setFreeMonitoring : "setFreeMonitoring" # Removed (backwards compatibility) setParameter : "setParameter" setUserWriteBlockMode: "setUserWriteBlockMode" shardCollection : "shardCollection" # ID only diff --git a/src/mongo/db/auth/builtin_roles.yml b/src/mongo/db/auth/builtin_roles.yml index de0797a015c..b31fb0d8452 100644 --- a/src/mongo/db/auth/builtin_roles.yml +++ b/src/mongo/db/auth/builtin_roles.yml @@ -245,7 +245,6 @@ roles: privileges: - matchType: cluster actions: &clusterMonitorRoleClusterActions - - checkFreeMonitoringStatus - connPoolStats - getCmdLineOpts - getDefaultRWConcern # clusterManager gets this also @@ -357,7 +356,6 @@ roles: - runTenantMigration - setDefaultRWConcern - setFeatureCompatibilityVersion - - setFreeMonitoring - setClusterParameter - getClusterParameter - setChangeStreamState diff --git a/src/mongo/db/free_mon/README.md b/src/mongo/db/free_mon/README.md deleted file mode 100644 index 55db27c037f..00000000000 --- a/src/mongo/db/free_mon/README.md +++ /dev/null @@ -1,130 +0,0 @@ -# Free Monitoring - -## Table of Contents - -- [Free Monitoring](#free-monitoring) - - [Table of Contents](#table-of-contents) - - [High Level Overview](#high-level-overview) - -## High Level Overview - -Free Monitoring is a way for MongoDB Community users to enable Cloud Monitoring on their database. -To use Free Monitoring, a customer must first register by issuing the command -`db.enableFreeMonitoring()`. - -The entire Free Monitoring subsystem is controlled by an object of type -[`FreeMonController`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_controller.h#L53). -The `FreeMonController` lives as a decoration on the `ServiceContext`. The `FreeMonController` has a -two collections of collectors - the -[`_registrationCollectors`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_controller.h#L197) -which collect data at registration time, and the -[`_metricCollectors`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_controller.h#L200) -which collect data periodically. It also owns a -[`FreeMonProcessor`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_processor.h#L304) -which under the hood contains a multi-producer priority queue, and a -[`FreeMonNetworkInterface`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_network.h#L40) -which is a way for the subsystem to send and receive packets to the cloud endpoint. - -When the server first starts, if Free Monitoring is enabled (using a command line parameter -`enableFreeMonitoring`), the FreeMonController is initialized on server startup through the mongod -main function which calls -[`startFreeMonitoring`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_mongod.cpp#L310). -This function creates the -[`FreeMonNetworkInterface`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_mongod.cpp#L322), -initializes the controller, determines the Registration type, and calls -[`start`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_mongod.cpp#L346-L348) -on the controller. The -[`start`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_controller.h#L59-L65) -function initializes the processor, creates a thread for it to run on, and performs registration if -the user has performed registration. - -If the user has not performed registration, the metrics collector begins collecting data. It stores -this data in a MetricsBuffer, capable of holding up to 10 data points. When the user performs -registration, a call to -[`registerServerStartup`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_controller.cpp#L79-L84) -is made, placing a -[`FreeMonMessageWithPayload`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_message.h#L255) -object in the processor's queue. A `FreeMonMessageWithPayload` is an expanded subclass of -[`FreeMonMessage`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_message.h#L146), -which represents a message sent to the -[`FreeMonProcessor`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_processor.h#L304) -actor to process and make a decision. For more reading on the actor model that the Free Monitoring -system is based on, see [here](https://en.wikipedia.org/wiki/Actor_model). A `FreeMonMessage` has -two significant properties, a type and a deadline. The type determines how the queue responds when -processing the message. The code for how the queue processes messages can be found -[here](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_processor.cpp#L156-L269). -The deadline determines the priority of the message in the queue. The deadline represents both the -waiting period the queue must take to process a message and a priority the queue uses to determine -the order in which messages are processed. For example, a message with a deadline of now can be -processed before something with a deadline of an hour from now. - -In the call to -[`registerServerStartup`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_controller.cpp#L79-L84), -a message of type `RegisterServer` is sent to the queue. Included with the message is a payload of -the registration type that the server should perform. The queue processes this message and calls -[`doServerRegister`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_processor.cpp#L324) -with the message object. The function processes the `RegistrationType` and if it is -`RegisterOnStart`, sends a `RegisterCommand` message to the queue. If the `RegistrationType` is -something else, we try to determine whether we are a primary or secondary in a replica set and send -a message depending on the state of free monitoring in the set. The full logic with comments is -[here](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_processor.cpp#L330-L367), -but know that it may create a `RegisterCommand` message to the queue in certain cases. The function -[`doServerRegister`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_processor.cpp#L328) -also creates a message of type `MetricsCollect` in the queue. - -When the queue processes the -[`RegisterCommand`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_processor.cpp#L173-L175) -message, it calls -[`doCommandRegister`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_processor.cpp#L406) -which uses the -[`FreeMonNetworkInterface`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_mongod.cpp#L322) -to send a message over the wire to the cloud endpoint. It also writes the registration state -(`FreeMonRegistrationStatus::kPending`) and registration information out to disk, calling -[`writeState`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_processor.cpp#L299), -which invokes functions on the -[`FreeMonStorage`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_storage.h#L43) -class. The job of the `FreeMonStorage` class is to provide an interface for different functions to -interact with the storage subsystem. Whenever a change is made to the registration state - -registration completes or registration is cancelled because of an endpoint error - the processor -writes this information out to disk. - -The queue also processes the first `MetricsCollect` command around this time. The queue reads the -Metrics collect method and calls -[`doMetricsCollect`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_processor.cpp#L714-L726) -which fires the `_metrics` collectors to collect and stores the data in a -[`MetricsBuffer`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_processor.h#L185-L225). -The buffer can hold 10 data points at a time, so if the data has not been synced to the cloud -endpoint by the time the 11th data point is collected, then the buffer will remove the last item -from the queue. The function -[`doMetricsCollect`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_processor.cpp#L724-L725) -creates another message of type `MetricsCollect` with a deadline of the specified -`_metricsGatherInterval` for collection. - -The way for a queue to trigger sending new metrics to the server is by sending a message of type -`MetricsSend`. This occurs on a few occasions - when registration information has been successfully -[sent to the cloud -endpoint](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_processor.cpp#L666), -when metrics information has [successfully been sent to the cloud -endpoint](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_processor.cpp#L865-L866), -and when metrics information has [failed to send to the -endpoint](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_processor.cpp#L886-L888). -In the first case, a message is created with a deadline of now. In the second case the message is -sent with a deadline that is tracked by the -[`MetricsRetryCounter`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_processor.h#L153-L183) -object. The retry object is used to track any failures the processor encountered when sending -metrics; if enough failures have occured in a row, then the processor stops sending the metrics. In -the third case, the `MetricsRetryCounter` object is incremented to indicate failure. If it has not -exceeded the retry limit, then the message is again sent with a deadline tracked by the retry -object. - -The last notable part of `FreeMonitoring` is the -[`FreeMonOpObserver`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_op_observer.h#L40). -This `OpObserver` watches the namespace where the free monitoring registration information is stored -(the `admin` database and the `system.version` collection) and sends a message to the processor if -there is a change to the document for the registration information. For example, if someone updates -the document, the OpObserver calls -[`notifyOnUpsert`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_controller.h#L133-L138) -in the controller, the controller queues a -[`NotifyOnUpsert`](https://github.com/mongodb/mongo/blob/r4.4.0/src/mongo/db/free_mon/free_mon_controller.cpp#L111) -command in the processor. When the processor reads that message, it reads the updated registration -state from disk and updates the free monitoring subsystem based on the new information. diff --git a/src/mongo/db/free_mon/SConscript b/src/mongo/db/free_mon/SConscript deleted file mode 100644 index 1d22c36ba80..00000000000 --- a/src/mongo/db/free_mon/SConscript +++ /dev/null @@ -1,87 +0,0 @@ -# -*- mode: python -*- -Import("env") -Import("free_monitoring") - -env = env.Clone() - -fmEnv = env.Clone() -fmEnv.InjectThirdParty(libraries=['snappy']) - -fmEnv.Library( - target='free_mon', - source=[ - 'free_mon_processor.cpp', - 'free_mon_queue.cpp', - 'free_mon_op_observer.cpp', - 'free_mon_storage.cpp', - 'free_mon_controller.cpp', - 'free_mon_protocol.idl', - 'free_mon_commands.idl', - 'free_mon_storage.idl', - ], - LIBDEPS=[ - '$BUILD_DIR/mongo/db/concurrency/lock_manager', - '$BUILD_DIR/mongo/db/dbhelpers', - '$BUILD_DIR/mongo/db/ftdc/ftdc', - '$BUILD_DIR/mongo/db/server_base', - '$BUILD_DIR/third_party/shim_snappy', - ], -) - -if free_monitoring == "on": - fmEnv.Library( - target='free_mon_mongod', - source=[ - 'free_mon_commands.cpp', - 'free_mon_mongod.cpp', - 'free_mon_mongod.idl', - 'free_mon_options.cpp', - 'free_mon_options.idl', - 'free_mon_status.cpp', - ], - LIBDEPS=[ - 'free_mon', - ], - LIBDEPS_PRIVATE=[ - '$BUILD_DIR/mongo/client/clientdriver_network', - '$BUILD_DIR/mongo/db/commands/server_status_core', - '$BUILD_DIR/mongo/db/ftdc/ftdc_server', - '$BUILD_DIR/mongo/util/concurrency/thread_pool', - '$BUILD_DIR/mongo/util/net/http_client', - '$BUILD_DIR/mongo/util/options_parser/options_parser', - ], - ) -else: - fmEnv.Library( - target='free_mon_mongod', - source=[ - 'free_mon_commands_stub.cpp', - 'free_mon_stub.cpp', - ], - LIBDEPS_PRIVATE=[ - '$BUILD_DIR/mongo/base', - '$BUILD_DIR/mongo/db/auth/auth', - '$BUILD_DIR/mongo/db/auth/authprivilege', - '$BUILD_DIR/mongo/db/commands', - 'free_mon', - ], - ) - -fmEnv.CppUnitTest( - target='db_free_mon_test', - source=[ - 'free_mon_controller_test.cpp', - 'free_mon_queue_test.cpp', - 'free_mon_storage_test.cpp', - ], - LIBDEPS=[ - '$BUILD_DIR/mongo/db/auth/authmocks', - '$BUILD_DIR/mongo/db/op_observer/op_observer', - '$BUILD_DIR/mongo/db/repl/replmocks', - '$BUILD_DIR/mongo/db/repl/storage_interface_impl', - '$BUILD_DIR/mongo/db/service_context_d_test_fixture', - '$BUILD_DIR/mongo/executor/thread_pool_task_executor_test_fixture', - '$BUILD_DIR/mongo/util/clock_source_mock', - 'free_mon', - ], -) diff --git a/src/mongo/db/free_mon/free_mon_commands.cpp b/src/mongo/db/free_mon/free_mon_commands.cpp deleted file mode 100644 index 3c3be470cf7..00000000000 --- a/src/mongo/db/free_mon/free_mon_commands.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include - -#include -#include -#include - -#include "mongo/base/error_codes.h" -#include "mongo/base/status.h" -#include "mongo/base/string_data.h" -#include "mongo/bson/bsonobj.h" -#include "mongo/bson/bsonobjbuilder.h" -#include "mongo/db/auth/action_type.h" -#include "mongo/db/auth/authorization_session.h" -#include "mongo/db/auth/resource_pattern.h" -#include "mongo/db/commands.h" -#include "mongo/db/database_name.h" -#include "mongo/db/free_mon/free_mon_commands_gen.h" -#include "mongo/db/free_mon/free_mon_controller.h" -#include "mongo/db/free_mon/free_mon_options.h" -#include "mongo/db/operation_context.h" -#include "mongo/db/service_context.h" -#include "mongo/idl/idl_parser.h" -#include "mongo/util/assert_util.h" -#include "mongo/util/duration.h" - -namespace mongo { - -namespace { - -const auto kRegisterSyncTimeout = Milliseconds{5000}; - -/** - * Indicates the current status of Free Monitoring. - */ -class GetFreeMonitoringStatusCommand : public BasicCommand { -public: - GetFreeMonitoringStatusCommand() : BasicCommand("getFreeMonitoringStatus") {} - - bool adminOnly() const override { - return true; - } - - AllowedOnSecondary secondaryAllowed(ServiceContext*) const final { - return AllowedOnSecondary::kAlways; - } - - bool supportsWriteConcern(const BSONObj& cmd) const final { - return false; - } - - std::string help() const final { - return "Indicates free monitoring status"; - } - - Status checkAuthForOperation(OperationContext* opCtx, - const DatabaseName& dbName, - const BSONObj&) const final { - if (!AuthorizationSession::get(opCtx->getClient()) - ->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(dbName.tenantId()), - ActionType::checkFreeMonitoringStatus)) { - return Status(ErrorCodes::Unauthorized, "Unauthorized"); - } - return Status::OK(); - } - - bool run(OperationContext* opCtx, - const DatabaseName&, - const BSONObj& cmdObj, - BSONObjBuilder& result) final { - // Command has no members, invoke the parser to confirm that. - IDLParserContext ctx("getFreeMonitoringStatus"); - GetFreeMonitoringStatus::parse(ctx, cmdObj); - - // FreeMonitoring has been deprecated and will be decomissioned. - // Report that FreeMon is disabled even if it's running to draw attention - // to the deprecation notice returned from the service. - result.append("state"_sd, "disabled"_sd); - - if (globalFreeMonParams.freeMonitoringState != EnableCloudStateEnum::kOff) { - // To aid discovery during deprecation period, add true state as context. - auto* controller = FreeMonController::get(opCtx->getServiceContext()); - if (controller) { - result.append( - "message"_sd, - "Free monitoring is deprecated, refer to 'debug' field for actual status"_sd); - BSONObjBuilder debug(result.subobjStart("debug"_sd)); - controller->getStatus(opCtx, &debug); - } - } - - return true; - } -} getFreeMonitoringStatusCommand; - -/** - * Enables or disables Free Monitoring service. - */ -class SetFreeMonitoringCommand : public BasicCommand { -public: - SetFreeMonitoringCommand() : BasicCommand("setFreeMonitoring") {} - - bool adminOnly() const override { - return true; - } - - AllowedOnSecondary secondaryAllowed(ServiceContext*) const final { - return AllowedOnSecondary::kNever; - } - - bool supportsWriteConcern(const BSONObj& cmd) const final { - return false; - } - - std::string help() const final { - return "enable or disable Free Monitoring"; - } - - Status checkAuthForOperation(OperationContext* opCtx, - const DatabaseName& dbName, - const BSONObj&) const final { - if (!AuthorizationSession::get(opCtx->getClient()) - ->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(dbName.tenantId()), - ActionType::setFreeMonitoring)) { - return Status(ErrorCodes::Unauthorized, "Unauthorized"); - } - return Status::OK(); - } - - bool run(OperationContext* opCtx, - const DatabaseName&, - const BSONObj& cmdObj, - BSONObjBuilder& result) final { - IDLParserContext ctx("setFreeMonitoring"); - auto cmd = SetFreeMonitoring::parse(ctx, cmdObj); - - auto* controller = FreeMonController::get(opCtx->getServiceContext()); - if (!controller) { - // Pending operation. - uasserted(50840, - "Free Monitoring has been disabled via the command-line and/or config file"); - } - - boost::optional optStatus = boost::none; - if (cmd.getAction() == SetFreeMonActionEnum::enable) { - optStatus = controller->registerServerCommand(kRegisterSyncTimeout); - } else { - optStatus = controller->unregisterServerCommand(kRegisterSyncTimeout); - } - - if (optStatus) { - // Completed within timeout. - uassertStatusOK(*optStatus); - } else { - // Pending operation. - } - return true; - } - -} setFreeMonitoringCmd; - -} // namespace -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_commands.idl b/src/mongo/db/free_mon/free_mon_commands.idl deleted file mode 100644 index ff2d83378b5..00000000000 --- a/src/mongo/db/free_mon/free_mon_commands.idl +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright (C) 2018-present MongoDB, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the Server Side Public License, version 1, -# as published by MongoDB, Inc. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# Server Side Public License for more details. -# -# You should have received a copy of the Server Side Public License -# along with this program. If not, see -# . -# -# As a special exception, the copyright holders give permission to link the -# code of portions of this program with the OpenSSL library under certain -# conditions as described in each individual source file and distribute -# linked combinations including the program with the OpenSSL library. You -# must comply with the Server Side Public License in all respects for -# all of the code used other than as permitted herein. If you modify file(s) -# with this exception, you may extend this exception to your version of the -# file(s), but you are not obligated to do so. If you do not wish to do so, -# delete this exception statement from your version. If you delete this -# exception statement from all source files in the program, then also delete -# it in the license file. -# -global: - cpp_namespace: "mongo" - - -imports: - - "mongo/db/basic_types.idl" - - -enums: - SetFreeMonAction: - description: "Action types" - type: string - values: - enable: "enable" - disable: "disable" - - -commands: - setFreeMonitoring: - description: "setFreeMonitoring Command" - command_name: setFreeMonitoring - namespace: ignored - api_version: "" - fields: - action: - description: "Action to take" - type: SetFreeMonAction - - getFreeMonitoringStatus: - description: "getFreeMonitoringStatus Command" - command_name: getFreeMonitoringStatus - namespace: ignored - api_version: "" - diff --git a/src/mongo/db/free_mon/free_mon_commands_stub.cpp b/src/mongo/db/free_mon/free_mon_commands_stub.cpp deleted file mode 100644 index d813003db7b..00000000000 --- a/src/mongo/db/free_mon/free_mon_commands_stub.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/platform/basic.h" - -#include "mongo/db/auth/authorization_session.h" -#include "mongo/db/commands.h" -#include "mongo/db/free_mon/free_mon_commands_gen.h" - -namespace mongo { - -namespace { - -/** - * Indicates the current status of Free Monitoring. - * - * Note that this file is only built when --enable-free-mon=off - * and it will return a static result of {status:"disabled"}. - */ -class GetFreeMonitoringStatusCommandStub : public BasicCommand { -public: - GetFreeMonitoringStatusCommandStub() : BasicCommand("getFreeMonitoringStatus") {} - - bool adminOnly() const override { - return true; - } - - AllowedOnSecondary secondaryAllowed(ServiceContext*) const final { - return AllowedOnSecondary::kAlways; - } - - bool supportsWriteConcern(const BSONObj& cmd) const final { - return false; - } - - std::string help() const final { - return "Indicates free monitoring status"; - } - - Status checkAuthForOperation(OperationContext* opCtx, - const DatabaseName& dbName, - const BSONObj&) const final { - if (!AuthorizationSession::get(opCtx->getClient()) - ->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(dbName.tenantId()), - ActionType::checkFreeMonitoringStatus)) { - return Status(ErrorCodes::Unauthorized, "Unauthorized"); - } - return Status::OK(); - } - - bool run(OperationContext* opCtx, - const DatabaseName&, - const BSONObj& cmdObj, - BSONObjBuilder& result) final { - // Command has no members, invoke the parser to confirm that. - IDLParserContext ctx("getFreeMonitoringStatus"); - GetFreeMonitoringStatus::parse(ctx, cmdObj); - - result.append("state", "disabled"); - result.append("message", - "Free Monitoring support is not available in this build of MongoDB"); - return true; - } -} getFreeMonitoringStatusCommand; - -} // namespace -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_controller.cpp b/src/mongo/db/free_mon/free_mon_controller.cpp deleted file mode 100644 index 4a110e0867a..00000000000 --- a/src/mongo/db/free_mon/free_mon_controller.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - - -#include -#include -#include -#include - -#include - -#include "mongo/db/free_mon/free_mon_controller.h" -#include "mongo/db/ftdc/collector.h" -#include "mongo/logv2/log.h" -#include "mongo/logv2/log_attr.h" -#include "mongo/logv2/log_component.h" -#include "mongo/util/assert_util_core.h" -#include "mongo/util/decorable.h" -#include "mongo/util/synchronized_value.h" - -#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kControl - - -namespace mongo { - -namespace { - -const auto getFreeMonController = - ServiceContext::declareDecoration>>(); - -} // namespace - -FreeMonController* FreeMonController::get(ServiceContext* serviceContext) { - return getFreeMonController(serviceContext)->get(); -} - -void FreeMonController::init(ServiceContext* serviceContext, - std::unique_ptr controller) { - auto fmcContainer = getFreeMonController(serviceContext).synchronize(); - // Since FreeMonController::get() provides raw pointers, the FreeMonController can only be - // set once without producing memory leaks. - invariant(!fmcContainer->get()); - fmcContainer = std::move(controller); -} - - -FreeMonNetworkInterface::~FreeMonNetworkInterface() = default; - -void FreeMonController::addRegistrationCollector( - std::unique_ptr collector) { - { - stdx::lock_guard lock(_mutex); - invariant(_state == State::kNotStarted); - - _registrationCollectors.add(std::move(collector)); - } -} - -void FreeMonController::addMetricsCollector(std::unique_ptr collector) { - { - stdx::lock_guard lock(_mutex); - invariant(_state == State::kNotStarted); - - _metricCollectors.add(std::move(collector)); - } -} - -void FreeMonController::registerServerStartup(RegistrationType registrationType, - std::vector& tags) { - _enqueue(FreeMonMessageWithPayload::createNow( - FreeMonMessageWithPayload::payload_type( - registrationType, tags))); -} - -boost::optional FreeMonController::registerServerCommand(Milliseconds timeout) { - auto msg = FreeMonRegisterCommandMessage::createNow({std::vector(), boost::none}); - _enqueue(msg); - - if (timeout > Milliseconds::min()) { - return msg->wait_for(timeout); - } - - return Status::OK(); -} - -boost::optional FreeMonController::unregisterServerCommand(Milliseconds timeout) { - auto msg = - FreeMonWaitableMessageWithPayload::createNow(true); - _enqueue(msg); - - if (timeout > Milliseconds::min()) { - return msg->wait_for(timeout); - } - - return Status::OK(); -} - -void FreeMonController::notifyOnUpsert(const BSONObj& doc) { - invariant(doc.isOwned()); - _enqueue(FreeMonMessageWithPayload::createNow(doc)); -} - - -void FreeMonController::notifyOnDelete() { - _enqueue(FreeMonMessage::createNow(FreeMonMessageType::NotifyOnDelete)); -} - - -void FreeMonController::notifyOnTransitionToPrimary() { - _enqueue(FreeMonMessage::createNow(FreeMonMessageType::OnTransitionToPrimary)); -} - -void FreeMonController::notifyOnRollback() { - _enqueue(FreeMonMessage::createNow(FreeMonMessageType::NotifyOnRollback)); -} - -void FreeMonController::_enqueue(std::shared_ptr msg) { - { - stdx::lock_guard lock(_mutex); - invariant(_state == State::kStarted); - } - - _processor->enqueue(std::move(msg)); -} - -void FreeMonController::start(RegistrationType registrationType, - std::vector& tags, - Seconds gatherMetricsInterval) { - { - stdx::lock_guard lock(_mutex); - - invariant(_state == State::kNotStarted); - } - - // Start the agent - _processor = std::make_shared(_registrationCollectors, - _metricCollectors, - _network.get(), - _useCrankForTest, - gatherMetricsInterval); - - _thread = stdx::thread([this] { _processor->run(); }); - - { - stdx::lock_guard lock(_mutex); - - invariant(_state == State::kNotStarted); - _state = State::kStarted; - } - - if (registrationType != RegistrationType::DoNotRegister) { - registerServerStartup(registrationType, tags); - } -} - -void FreeMonController::stop() { - // Stop the agent - LOGV2(20609, "Shutting down free monitoring"); - - { - stdx::lock_guard lock(_mutex); - - bool started = (_state == State::kStarted); - - invariant(_state == State::kNotStarted || _state == State::kStarted); - - if (!started) { - _state = State::kDone; - return; - } - - _state = State::kStopRequested; - - // Tell the processor to stop - _processor->stop(); - } - - _thread.join(); - - { - stdx::lock_guard lock(_mutex); - - _state = State::kDone; - } -} - -void FreeMonController::turnCrankForTest(size_t countMessagesToIgnore) { - { - stdx::lock_guard lock(_mutex); - invariant(_state == State::kStarted); - } - - LOGV2(20610, "Turning Crank", "count"_attr = countMessagesToIgnore); - - _processor->turnCrankForTest(countMessagesToIgnore); -} - -void FreeMonController::deprioritizeFirstMessageForTest(FreeMonMessageType type) { - { - stdx::lock_guard lock(_mutex); - invariant(_state == State::kStarted); - } - - LOGV2(5167901, "Deprioritize message", "type"_attr = static_cast(type)); - - _processor->deprioritizeFirstMessageForTest(type); -} - -void FreeMonController::getStatus(OperationContext* opCtx, BSONObjBuilder* status) { - { - stdx::lock_guard lock(_mutex); - - if (_state != State::kStarted) { - status->append("state", "disabled"); - return; - } - } - - _processor->getStatus(opCtx, status, FreeMonProcessor::FreeMonGetStatusEnum::kCommandStatus); -} - -void FreeMonController::getServerStatus(OperationContext* opCtx, BSONObjBuilder* status) { - { - stdx::lock_guard lock(_mutex); - - if (_state != State::kStarted) { - status->append("state", "disabled"); - return; - } - } - - _processor->getStatus(opCtx, status, FreeMonProcessor::FreeMonGetStatusEnum::kServerStatus); -} - -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_controller.h b/src/mongo/db/free_mon/free_mon_controller.h deleted file mode 100644 index 5ad1e054434..00000000000 --- a/src/mongo/db/free_mon/free_mon_controller.h +++ /dev/null @@ -1,227 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include "mongo/base/status.h" -#include "mongo/bson/bsonobj.h" -#include "mongo/bson/bsonobjbuilder.h" -#include "mongo/db/auth/validated_tenancy_scope.h" -#include "mongo/db/client.h" -#include "mongo/db/free_mon/free_mon_message.h" -#include "mongo/db/free_mon/free_mon_network.h" -#include "mongo/db/free_mon/free_mon_processor.h" -#include "mongo/db/ftdc/collector.h" -#include "mongo/db/service_context.h" -#include "mongo/platform/mutex.h" -#include "mongo/stdx/thread.h" -#include "mongo/util/duration.h" - -namespace mongo { - -/** - * Manages and control Free Monitoring. This is the entry point for non-free monitoring components - * into free-monitoring. - */ -class FreeMonController { -public: - explicit FreeMonController(std::unique_ptr network, - bool useCrankForTest = false) - : _network(std::move(network)), _useCrankForTest(useCrankForTest) {} - - /** - * Initializes free monitoring. - * Start free monitoring thread in the background. - */ - void start(RegistrationType registrationType, - std::vector& tags, - Seconds gatherMetricsInterval); - - /** - * Stops free monitoring thread. - */ - void stop(); - - /** - * Turn the crank of the message queue by ignoring deadlines for N messages. - */ - void turnCrankForTest(size_t countMessagesToIgnore); - - /** - * Deproritize the first message to force interleavings of messages. - */ - void deprioritizeFirstMessageForTest(FreeMonMessageType type); - - /** - * Add a metric collector to collect on registration - */ - void addRegistrationCollector(std::unique_ptr collector); - - /** - * Add a metric collector to collect periodically - */ - void addMetricsCollector(std::unique_ptr collector); - - /** - * Get the FreeMonController from ServiceContext. - */ - static FreeMonController* get(ServiceContext* serviceContext); - - /** - * Initialize the FreeMonController decoration in the ServiceContext. - */ - static void init(ServiceContext* serviceContext, std::unique_ptr controller); - - /** - * Start registration of mongod with remote service. - * - * Only sends one remote registration at a time. - * Returns after timeout if registrations is not complete. Registration continues though. - */ - void registerServerStartup(RegistrationType registrationType, std::vector& tags); - - /** - * Start registration of mongod with remote service. - * - * Only sends one remote registration at a time. - * Returns after timeout if registrations is not complete. Registration continues though. - * Update is synchronous with 10sec timeout - * kicks off register, and once register is done kicks off metrics upload - */ - boost::optional registerServerCommand(Milliseconds timeout); - - /** - * Stop registration of mongod with remote service. - * - * As with registerServerCommand() above, but undoes registration. - * On complettion of this command, no further metrics will be transmitted. - */ - boost::optional unregisterServerCommand(Milliseconds timeout); - - /** - * Populates an info blob for use by {getFreeMonitoringStatus: 1} - */ - void getStatus(OperationContext* opCtx, BSONObjBuilder* status); - - /** - * Populates an info blob for use by {serverStatus: 1} - */ - void getServerStatus(OperationContext* opCtx, BSONObjBuilder* status); - - /** - * Notify on upsert. - * - * Updates and inserts are treated as the same. - */ - void notifyOnUpsert(const BSONObj& doc); - - /** - * Notify on document delete or drop collection. - */ - void notifyOnDelete(); - - /** - * Notify that we local instance has become a primary. - */ - void notifyOnTransitionToPrimary(); - - /** - * Notify that storage has rolled back - */ - void notifyOnRollback(); - -private: - void _enqueue(std::shared_ptr msg); - -private: - /** - * Private enum to track state. - * - * +-----------------------------------------------------------+ - * | v - * +-------------+ +----------+ +----------------+ +-------+ - * | kNotStarted | --> | kStarted | --> | kStopRequested | --> | kDone | - * +-------------+ +----------+ +----------------+ +-------+ - */ - enum class State { - /** - * Initial state. Either start() or stop() can be called next. - */ - kNotStarted, - - /** - * start() has been called. stop() should be called next. - */ - kStarted, - - /** - * stop() has been called, and the background thread is in progress of shutting down - */ - kStopRequested, - - /** - * Controller has been stopped. - */ - kDone, - }; - - // Controller state - State _state{State::kNotStarted}; - - // Mutext to protect internal state - Mutex _mutex = MONGO_MAKE_LATCH("FreeMonController::_mutex"); - - // Set of registration collectors - FreeMonCollectorCollection _registrationCollectors; - - // Set of metric collectors - FreeMonCollectorCollection _metricCollectors; - - // Network interface - std::unique_ptr _network; - - // Background thead for agent - stdx::thread _thread; - - // Crank for test - bool _useCrankForTest; - - // Background agent - std::shared_ptr _processor; -}; - -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_controller_test.cpp b/src/mongo/db/free_mon/free_mon_controller_test.cpp deleted file mode 100644 index 66cecc38355..00000000000 --- a/src/mongo/db/free_mon/free_mon_controller_test.cpp +++ /dev/null @@ -1,1701 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - - -#include -// IWYU pragma: no_include "cxxabi.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mongo/base/data_range.h" -#include "mongo/base/data_type_validated.h" -#include "mongo/base/error_codes.h" -#include "mongo/base/status_with.h" -#include "mongo/base/string_data.h" -#include "mongo/bson/bsonelement.h" -#include "mongo/bson/bsonmisc.h" -#include "mongo/bson/bsonobjbuilder.h" -#include "mongo/db/catalog/collection_options.h" -#include "mongo/db/client.h" -#include "mongo/db/free_mon/free_mon_controller.h" -#include "mongo/db/free_mon/free_mon_op_observer.h" -#include "mongo/db/free_mon/free_mon_protocol_gen.h" -#include "mongo/db/free_mon/free_mon_storage.h" -#include "mongo/db/free_mon/free_mon_storage_gen.h" -#include "mongo/db/namespace_string.h" -#include "mongo/db/op_observer/op_observer.h" -#include "mongo/db/op_observer/op_observer_registry.h" -#include "mongo/db/operation_context.h" -#include "mongo/db/repl/member_state.h" -#include "mongo/db/repl/oplog.h" -#include "mongo/db/repl/replication_coordinator.h" -#include "mongo/db/repl/replication_coordinator_mock.h" -#include "mongo/db/repl/storage_interface.h" -#include "mongo/db/repl/storage_interface_impl.h" -#include "mongo/db/service_context.h" -#include "mongo/db/service_context_d_test_fixture.h" -#include "mongo/executor/network_interface_mock.h" -#include "mongo/executor/task_executor.h" -#include "mongo/executor/thread_pool_task_executor.h" -#include "mongo/executor/thread_pool_task_executor_test_fixture.h" -#include "mongo/idl/idl_parser.h" -#include "mongo/logv2/log.h" -#include "mongo/logv2/log_attr.h" -#include "mongo/logv2/log_component.h" -#include "mongo/platform/atomic_word.h" -#include "mongo/platform/random.h" -#include "mongo/rpc/object_check.h" // IWYU pragma: keep -#include "mongo/stdx/condition_variable.h" -#include "mongo/unittest/assert.h" -#include "mongo/unittest/bson_test_util.h" -#include "mongo/unittest/framework.h" -#include "mongo/util/assert_util.h" -#include "mongo/util/future.h" -#include "mongo/util/future_impl.h" -#include "mongo/util/uuid.h" - -#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kControl - - -namespace mongo { -namespace { - -auto makeRandom() { - auto seed = SecureRandom().nextInt64(); - LOGV2(24189, "PseudoRandom()", "seed"_attr = seed); - return PseudoRandom(seed); -} - -class FreeMonMetricsCollectorMock : public FreeMonCollectorInterface { -public: - ~FreeMonMetricsCollectorMock() { - // ASSERT_TRUE(_state == State::kStarted); - } - - void collect(OperationContext* opCtx, BSONObjBuilder& builder) final { - _state = State::kStarted; - - builder.append("mock", "some data"); - - { - stdx::lock_guard lck(_mutex); - - ++_counter; - - if (_counter == _wait) { - _condvar.notify_all(); - } - } - } - - std::string name() const final { - return "mock"; - } - - void setSignalOnCount(int c) { - _wait = c; - } - - std::uint32_t count() { - stdx::lock_guard lck(_mutex); - return _counter; - } - - void wait() { - stdx::unique_lock lck(_mutex); - while (_counter < _wait) { - _condvar.wait(lck); - } - } - -private: - /** - * Private enum to ensure caller uses class correctly. - */ - enum class State { - kNotStarted, - kStarted, - }; - - // state - State _state{State::kNotStarted}; - - std::uint32_t _counter{0}; - - Mutex _mutex = MONGO_MAKE_LATCH("FreeMonMetricsCollectorMock::_mutex"); - stdx::condition_variable _condvar; - std::uint32_t _wait{0}; -}; - -BSONArray decompressMetrics(ConstDataRange cdr) { - std::string outBuffer; - snappy::Uncompress(cdr.data(), cdr.length(), &outBuffer); - - ConstDataRange raw(outBuffer.data(), outBuffer.data() + outBuffer.size()); - auto swObj = raw.readNoThrow>(); - ASSERT_OK(swObj.getStatus()); - - return BSONArray(swObj.getValue().val["data"].Obj().getOwned()); -} - -/** - * Countdown latch that propagates a message. - */ -template -class CountdownLatchResult { -public: - CountdownLatchResult(uint32_t count) : _count(count) {} - - /** - * Set the count of events to wait for. - */ - void reset(uint32_t count) { - stdx::lock_guard lock(_mutex); - ASSERT_EQ(_count, 0UL); - ASSERT_GT(count, 0UL); - - _count = count; - _payload = T(); - } - - /** - * Set the payload and signal waiter. - */ - void set(T payload) { - stdx::lock_guard lock(_mutex); - - if (_count > 0) { - --_count; - if (_count == 0) { - _payload = std::move(payload); - _condvar.notify_one(); - } - } - } - - /** - * Waits for duration until N events have occured. - * - * Returns boost::none on timeout. - */ - boost::optional wait_for(Milliseconds duration) { - stdx::unique_lock lock(_mutex); - - if (!_condvar.wait_for( - lock, duration.toSystemDuration(), [this]() { return _count == 0; })) { - return {}; - } - - return _payload; - } - -private: - // Condition variable to signal consumer - stdx::condition_variable _condvar; - - // Lock for condition variable and to protect state - Mutex _mutex = MONGO_MAKE_LATCH("CountdownLatchResult::_mutex"); - - // Count to wait fore - uint32_t _count; - - // Provided payload - T _payload; -}; - -class FreeMonNetworkInterfaceMock final : public FreeMonNetworkInterface { -public: - struct Options { - // If sync = true, then execute the callback immediately and the subsequent future chain - // This allows us to ensure the follow up functions to a network request are executed - // before anything else is processed by FreeMonProcessor - bool doSync{false}; - - // Faults to inject for registration - bool failRegisterHttp{false}; - bool invalidRegister{false}; - bool haltRegister{false}; - - // Faults to inject for metrics - bool haltMetrics{false}; - bool fail2MetricsUploads{false}; - bool permanentlyDeleteAfter3{false}; - - bool resendRegistrationAfter3{false}; - }; - - explicit FreeMonNetworkInterfaceMock(executor::ThreadPoolTaskExecutor* threadPool, - Options options) - : _threadPool(threadPool), _options(options), _countdownMetrics(0) {} - - Future sendRegistrationAsync( - const FreeMonRegistrationRequest& req) final { - LOGV2(20611, "Sending Registration ..."); - - _registers.addAndFetch(1); - - auto pf = makePromiseFuture(); - if (_options.doSync) { - pf.promise.setFrom(doRegister(req)); - } else { - auto swSchedule = _threadPool->scheduleWork( - [sharedPromise = std::move(pf.promise), req, this]( - const executor::TaskExecutor::CallbackArgs& cbArgs) mutable { - sharedPromise.setWith([&] { return doRegister(req); }); - }); - - ASSERT_OK(swSchedule.getStatus()); - } - - return std::move(pf.future); - } - - StatusWith doRegister(const FreeMonRegistrationRequest& req) { - - if (_options.failRegisterHttp) { - return Status(ErrorCodes::FreeMonHttpTemporaryFailure, "Mock failure"); - } - - auto resp = FreeMonRegistrationResponse(); - resp.setVersion(1); - - if (_options.invalidRegister) { - resp.setVersion(42); - } - - resp.setId("regId123"); - - if (_options.haltRegister) { - resp.setHaltMetricsUploading(true); - } - - resp.setReportingInterval(1); - - return resp; - } - - - Future sendMetricsAsync(const FreeMonMetricsRequest& req) final { - LOGV2(20612, "Sending Metrics ..."); - - _metrics.addAndFetch(1); - - auto pf = makePromiseFuture(); - if (_options.doSync) { - pf.promise.setFrom(doMetrics(req)); - } else { - auto swSchedule = _threadPool->scheduleWork( - [sharedPromise = std::move(pf.promise), req, this]( - const executor::TaskExecutor::CallbackArgs& cbArgs) mutable { - sharedPromise.setWith([&] { return doMetrics(req); }); - }); - - ASSERT_OK(swSchedule.getStatus()); - } - - return std::move(pf.future); - } - - StatusWith doMetrics(const FreeMonMetricsRequest& req) { - auto cdr = req.getMetrics(); - - { - stdx::lock_guard lock(_metricsLock); - auto metrics = decompressMetrics(cdr); - _lastMetrics = metrics; - _countdownMetrics.set(metrics); - } - - if (_options.fail2MetricsUploads && _metrics.loadRelaxed() < 3) { - return Status(ErrorCodes::FreeMonHttpTemporaryFailure, "Mock failure"); - } - - auto resp = FreeMonMetricsResponse(); - resp.setVersion(1); - resp.setReportingInterval(1); - - resp.setId("metricsId456"_sd); - - if (_options.haltMetrics) { - resp.setHaltMetricsUploading(true); - } - - if (_options.permanentlyDeleteAfter3 && _metrics.loadRelaxed() > 3) { - resp.setPermanentlyDelete(true); - } - - if (_options.resendRegistrationAfter3 && _metrics.loadRelaxed() == 3) { - resp.setResendRegistration(true); - } - - return resp; - } - - int32_t getRegistersCalls() const { - return _registers.load(); - } - - int32_t getMetricsCalls() const { - return _metrics.load(); - } - - boost::optional waitMetricsCalls(uint32_t count, Milliseconds wait) { - _countdownMetrics.reset(count); - return _countdownMetrics.wait_for(wait); - } - - BSONArray getLastMetrics() { - stdx::lock_guard lock(_metricsLock); - return _lastMetrics; - } - - -private: - AtomicWord _registers; - AtomicWord _metrics; - - executor::ThreadPoolTaskExecutor* _threadPool; - - Mutex _metricsLock = MONGO_MAKE_LATCH("FreeMonNetworkInterfaceMock::_metricsLock"); - BSONArray _lastMetrics; - - Options _options; - - CountdownLatchResult _countdownMetrics; -}; - -class FreeMonControllerTest : public ServiceContextMongoDTest { - -protected: - void setUp() override; - void tearDown() override; - -protected: - /** - * Looks up the current ReplicationCoordinator. - * The result is cast to a ReplicationCoordinatorMock to provide access to test features. - */ - repl::ReplicationCoordinatorMock* _getReplCoord() const; - - ServiceContext::UniqueOperationContext _opCtx; - - executor::NetworkInterfaceMock* _mockNetwork{nullptr}; - - std::unique_ptr _mockThreadPool; -}; - -void FreeMonControllerTest::setUp() { - ServiceContextMongoDTest::setUp(); - auto service = getServiceContext(); - - repl::ReplicationCoordinator::set(service, - std::make_unique(service)); - - // Set up a NetworkInterfaceMock. Note, unlike NetworkInterfaceASIO, which has its own pool of - // threads, tasks in the NetworkInterfaceMock must be carried out synchronously by the (single) - // thread the unit test is running on. - auto netForFixedTaskExecutor = std::make_unique(); - _mockNetwork = netForFixedTaskExecutor.get(); - - // Set up a ThreadPoolTaskExecutor. Note, for local tasks this TaskExecutor uses a - // ThreadPoolMock, and for remote tasks it uses the NetworkInterfaceMock created above. However, - // note that the ThreadPoolMock uses the NetworkInterfaceMock's threads to run tasks, which is - // again just the (single) thread the unit test is running on. Therefore, all tasks, local and - // remote, must be carried out synchronously by the test thread. - _mockThreadPool = makeThreadPoolTestExecutor(std::move(netForFixedTaskExecutor)); - - _mockThreadPool->startup(); - - _opCtx = cc().makeOperationContext(); - - //_storage = std::make_unique(); - repl::StorageInterface::set(service, std::make_unique()); - - // Transition to PRIMARY so that the server can accept writes. - ASSERT_OK(_getReplCoord()->setFollowerMode(repl::MemberState::RS_PRIMARY)); - - repl::createOplog(_opCtx.get()); - - // Create collection with one document. - CollectionOptions collectionOptions; - collectionOptions.uuid = UUID::gen(); - - auto statusCC = repl::StorageInterface::get(service)->createCollection( - _opCtx.get(), - NamespaceString::createNamespaceString_forTest("admin", "system.version"), - collectionOptions); - ASSERT_OK(statusCC); -} - -void FreeMonControllerTest::tearDown() { - _opCtx = {}; - ServiceContextMongoDTest::tearDown(); -} - -repl::ReplicationCoordinatorMock* FreeMonControllerTest::_getReplCoord() const { - auto replCoord = repl::ReplicationCoordinator::get(_opCtx.get()); - ASSERT(replCoord) << "No ReplicationCoordinator installed"; - auto replCoordMock = dynamic_cast(replCoord); - ASSERT(replCoordMock) << "Unexpected type for installed ReplicationCoordinator"; - return replCoordMock; -} - -#define ASSERT_RANGE(target, lower, upper) \ - { \ - auto __x = counter.getNextDuration(); \ - ASSERT_GTE(__x, target + lower); \ - ASSERT_LTE(__x, target + upper); \ - } - - -// Positive: Ensure deadlines sort properly -TEST(FreeMonRetryTest, TestRegistration) { - auto random = makeRandom(); - RegistrationRetryCounter counter(random); - counter.reset(); - - ASSERT_EQ(counter.getNextDuration(), Seconds(1)); - ASSERT_EQ(counter.getNextDuration(), Seconds(1)); - - for (int j = 0; j < 3; j++) { - // Fail requests - for (int i = 1; i <= 10; ++i) { - ASSERT_TRUE(counter.incrementError()); - - int64_t base = pow(2, i); - ASSERT_RANGE(Seconds(base), Seconds(2), Seconds(10)); - } - - ASSERT_TRUE(counter.incrementError()); - ASSERT_RANGE(Seconds(1024), Seconds(60), Seconds(120)); - ASSERT_TRUE(counter.incrementError()); - ASSERT_RANGE(Seconds(1024), Seconds(60), Seconds(120)); - - counter.reset(); - } - - // Validate max timeout - - auto characterizeJitter = [](Seconds jitter1, Seconds jitter2) { - static constexpr size_t kStage1Retries = 10; - static constexpr auto kTMax = Days{2}; - auto t = Seconds(0); - auto base = Seconds(1); - size_t i = 0; - for (; t < kTMax; ++i) { - if (i < kStage1Retries) { - base *= 2; - t += base + jitter1; - } else { - t += base + jitter2; - } - } - return i; - }; - // If jitter is small as possible, we'd expect trueMax increments before false. - const auto trueMax = characterizeJitter(Seconds{2}, Seconds{60}); - // If jitter is large as possible, we'd expect trueMin increments before false. - const auto trueMin = characterizeJitter(Seconds{9}, Seconds{119}); - - // LOGV2(20613, "trueMin:{trueMin}", "trueMin"_attr = trueMin); - // LOGV2(20614, "trueMax:{trueMax}", "trueMax"_attr = trueMax); - - for (int j = 0; j < 30; j++) { - // std::cout << "j: " << j << "\n"; - // Fail requests - size_t trueCount = 0; - while (counter.incrementError()) { - ++trueCount; - } - ASSERT_GTE(trueCount, trueMin); - ASSERT_LTE(trueCount, trueMax); - counter.reset(); - } -} - -// Positive: Ensure deadlines sort properly -TEST(FreeMonRetryTest, TestMetrics) { - auto random = makeRandom(); - MetricsRetryCounter counter(random); - counter.reset(); - - ASSERT_EQ(counter.getNextDuration(), Seconds(1)); - ASSERT_EQ(counter.getNextDuration(), Seconds(1)); - - int32_t minTime = 1; - for (int j = 0; j < 3; j++) { - // Fail requests - for (int i = 0; i <= 6; ++i) { - ASSERT_TRUE(counter.incrementError()); - - int64_t base = pow(2, i); - ASSERT_RANGE(Seconds(base), Seconds(minTime / 2), Seconds(minTime)); - } - - ASSERT_TRUE(counter.incrementError()); - ASSERT_RANGE(Seconds(64), Seconds(minTime / 2), Seconds(minTime)); - ASSERT_TRUE(counter.incrementError()); - ASSERT_RANGE(Seconds(64), Seconds(minTime / 2), Seconds(minTime)); - - counter.reset(); - } - - // Validate max timeout - static size_t expectation = [] { - // There's technically a jitter in the MetricsRetryCounter but its default - // magnitude rounds to 0, so we make an exact expectation. - size_t iters = 0; - static constexpr auto kDurationMax = Days{7}; - auto t = Seconds{0}; - auto base = Seconds{1}; - for (; t < kDurationMax; ++iters) { - if (iters < 6) - base *= 2; - t += base; - } - return iters; - }(); - - for (int j = 0; j < 30; j++) { - // Fail requests - int iters = 0; - while (counter.incrementError()) { - ++iters; - } - ASSERT_EQ(iters, expectation); - counter.reset(); - } -} - -// Positive: Ensure the response is validated correctly -TEST(FreeMonProcessorTest, TestRegistrationResponseValidation) { - ASSERT_OK(FreeMonProcessor::validateRegistrationResponse(FreeMonRegistrationResponse::parse( - IDLParserContext("foo"), - BSON("version" << 1LL << "haltMetricsUploading" << false << "id" - << "mock123" - << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << 1LL)))); - - // max reporting interval - ASSERT_OK(FreeMonProcessor::validateRegistrationResponse(FreeMonRegistrationResponse::parse( - IDLParserContext("foo"), - BSON("version" << 1LL << "haltMetricsUploading" << false << "id" - << "mock123" - << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << 30 * 60 * 60 * 24LL)))); - - // Positive: version 2 - ASSERT_OK(FreeMonProcessor::validateRegistrationResponse(FreeMonRegistrationResponse::parse( - IDLParserContext("foo"), - BSON("version" << 2LL << "haltMetricsUploading" << false << "id" - << "mock123" - << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << 1LL)))); - - // Positive: empty registration id string - ASSERT_OK(FreeMonProcessor::validateRegistrationResponse(FreeMonRegistrationResponse::parse( - IDLParserContext("foo"), - BSON("version" << 1LL << "haltMetricsUploading" << false << "id" - << "" - << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << 1LL)))); - - // Negative: bad protocol version - ASSERT_NOT_OK(FreeMonProcessor::validateRegistrationResponse(FreeMonRegistrationResponse::parse( - IDLParserContext("foo"), - BSON("version" << 42LL << "haltMetricsUploading" << false << "id" - << "mock123" - << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << 1LL)))); - - // Negative: halt uploading - ASSERT_NOT_OK(FreeMonProcessor::validateRegistrationResponse(FreeMonRegistrationResponse::parse( - IDLParserContext("foo"), - BSON("version" << 1LL << "haltMetricsUploading" << true << "id" - << "mock123" - << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << 1LL)))); - - // Negative: large registartation id - ASSERT_NOT_OK(FreeMonProcessor::validateRegistrationResponse(FreeMonRegistrationResponse::parse( - IDLParserContext("foo"), - BSON("version" << 1LL << "haltMetricsUploading" << false << "id" << std::string(5000, 'a') - << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << 1LL)))); - - // Negative: large URL - ASSERT_NOT_OK(FreeMonProcessor::validateRegistrationResponse(FreeMonRegistrationResponse::parse( - IDLParserContext("foo"), - BSON("version" << 1LL << "haltMetricsUploading" << false << "id" - << "mock123" - << "informationalURL" << std::string(5000, 'b') << "message" - << "msg456" - << "reportingInterval" << 1LL)))); - - // Negative: large message - ASSERT_NOT_OK(FreeMonProcessor::validateRegistrationResponse(FreeMonRegistrationResponse::parse( - IDLParserContext("foo"), - BSON("version" << 1LL << "haltMetricsUploading" << false << "id" - << "mock123" - << "informationalURL" - << "http://www.example.com/123" - << "message" << std::string(5000, 'c') << "reportingInterval" << 1LL)))); - - // Negative: too small a reporting interval - ASSERT_NOT_OK(FreeMonProcessor::validateRegistrationResponse(FreeMonRegistrationResponse::parse( - IDLParserContext("foo"), - BSON("version" << 1LL << "haltMetricsUploading" << false << "id" - << "mock123" - << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << 0LL)))); - - // Negative: too large a reporting interval - ASSERT_NOT_OK(FreeMonProcessor::validateRegistrationResponse(FreeMonRegistrationResponse::parse( - IDLParserContext("foo"), - BSON("version" << 1LL << "haltMetricsUploading" << false << "id" - << "mock123" - << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << (60LL * 60 * 24 * 30 + 1LL))))); -} - - -// Positive: Ensure the response is validated correctly -TEST(FreeMonProcessorTest, TestMetricsResponseValidation) { - ASSERT_OK(FreeMonProcessor::validateMetricsResponse( - FreeMonMetricsResponse::parse(IDLParserContext("foo"), - - BSON("version" << 1LL << "haltMetricsUploading" << false - << "permanentlyDelete" << false << "id" - << "mock123" - << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << 1LL)))); - - // Positive: Support version 2 - ASSERT_OK(FreeMonProcessor::validateMetricsResponse( - FreeMonMetricsResponse::parse(IDLParserContext("foo"), - - BSON("version" << 2LL << "haltMetricsUploading" << false - << "permanentlyDelete" << false << "id" - << "mock123" - << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << 1LL)))); - - // Positive: Add resendRegistration - ASSERT_OK(FreeMonProcessor::validateMetricsResponse(FreeMonMetricsResponse::parse( - IDLParserContext("foo"), - - BSON("version" << 2LL << "haltMetricsUploading" << false << "permanentlyDelete" << false - << "id" - << "mock123" - << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << 1LL << "resendRegistration" << true)))); - - - // Positive: max reporting interval - ASSERT_OK(FreeMonProcessor::validateMetricsResponse(FreeMonMetricsResponse::parse( - IDLParserContext("foo"), - - BSON("version" << 1LL << "haltMetricsUploading" << false << "permanentlyDelete" << false - << "id" - << "mock123" - << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << 60 * 60 * 24 * 30LL)))); - - // Negative: bad protocol version - ASSERT_NOT_OK(FreeMonProcessor::validateMetricsResponse( - FreeMonMetricsResponse::parse(IDLParserContext("foo"), - BSON("version" << 42LL << "haltMetricsUploading" << false - << "permanentlyDelete" << false << "id" - << "mock123" - << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << 1LL)))); - - // Negative: halt uploading - ASSERT_NOT_OK(FreeMonProcessor::validateMetricsResponse( - FreeMonMetricsResponse::parse(IDLParserContext("foo"), - BSON("version" << 1LL << "haltMetricsUploading" << true - << "permanentlyDelete" << false << "id" - << "mock123" - << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << 1LL)))); - - // Negative: large registartation id - ASSERT_NOT_OK(FreeMonProcessor::validateMetricsResponse(FreeMonMetricsResponse::parse( - IDLParserContext("foo"), - BSON("version" << 1LL << "haltMetricsUploading" << false << "permanentlyDelete" << false - << "id" << std::string(5000, 'a') << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << 1LL)))); - - // Negative: large URL - ASSERT_NOT_OK(FreeMonProcessor::validateMetricsResponse(FreeMonMetricsResponse::parse( - IDLParserContext("foo"), - BSON("version" << 1LL << "haltMetricsUploading" << false - - << "permanentlyDelete" << false << "id" - << "mock123" - << "informationalURL" << std::string(5000, 'b') << "message" - << "msg456" - << "reportingInterval" << 1LL)))); - - // Negative: large message - ASSERT_NOT_OK(FreeMonProcessor::validateMetricsResponse(FreeMonMetricsResponse::parse( - IDLParserContext("foo"), - BSON("version" << 1LL << "haltMetricsUploading" << false << "permanentlyDelete" << false - << "id" - << "mock123" - << "informationalURL" - << "http://www.example.com/123" - << "message" << std::string(5000, 'c') << "reportingInterval" << 1LL)))); - - // Negative: too small a reporting interval - ASSERT_NOT_OK(FreeMonProcessor::validateMetricsResponse( - FreeMonMetricsResponse::parse(IDLParserContext("foo"), - BSON("version" << 1LL << "haltMetricsUploading" << false - << "permanentlyDelete" << false << "id" - << "mock123" - << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << 0LL)))); - - // Negative: too large a reporting interval - ASSERT_NOT_OK(FreeMonProcessor::validateMetricsResponse(FreeMonMetricsResponse::parse( - IDLParserContext("foo"), - BSON("version" << 1LL << "haltMetricsUploading" << false << "permanentlyDelete" << false - << "id" - << "mock123" - << "informationalURL" - << "http://www.example.com/123" - << "message" - << "msg456" - << "reportingInterval" << (60LL * 60 * 24 * 30 + 1LL))))); -} - -/** - * Fluent class that encapsulates how many turns of a crank is needed to do a particular operation. - * - * All commands take 1 turn except registerCommand and metricsSend since these have a HTTP send an - * HTTP receive. - */ -class Turner { -public: - Turner() = default; - - Turner& registerServer() { - return inc(1, 1); - } - - Turner& registerCommand(size_t count = 1) { - return inc(2, count); - } - - Turner& unRegisterCommand() { - return inc(1, 1); - } - - Turner& collect(size_t count = 1) { - return inc(1, count); - } - - Turner& metricsSend(size_t count = 1) { - return inc(2, count); - } - - Turner& onTransitionToPrimary() { - return inc(1, 1); - } - - Turner& notifyUpsert() { - return inc(1, 1); - } - - Turner& notifyDelete() { - return inc(1, 1); - } - - Turner& notifyOnRollback() { - return inc(1, 1); - } - - operator size_t() { - return _count; - } - -private: - Turner& inc(size_t perOperatioCost, size_t numberOfOperations) { - _count += (perOperatioCost * numberOfOperations); - return *this; - } - -private: - size_t _count; -}; - -/** - * Utility class to manage controller setup and lifecycle for testing. - */ -struct ControllerHolder { - ControllerHolder(executor::ThreadPoolTaskExecutor* pool, - FreeMonNetworkInterfaceMock::Options opts, - bool useCrankForTest = true) { - auto registerCollectorUnique = std::make_unique(); - auto metricsCollectorUnique = std::make_unique(); - - // If we want to manually turn the crank the queue, we must process the messages - // synchronously - if (useCrankForTest) { - opts.doSync = true; - } - - ASSERT_EQ(opts.doSync, useCrankForTest); - - auto networkUnique = - std::unique_ptr(new FreeMonNetworkInterfaceMock(pool, opts)); - network = static_cast(networkUnique.get()); - controller = std::make_unique(std::move(networkUnique), useCrankForTest); - - registerCollector = registerCollectorUnique.get(); - metricsCollector = metricsCollectorUnique.get(); - - controller->addRegistrationCollector(std::move(registerCollectorUnique)); - controller->addMetricsCollector(std::move(metricsCollectorUnique)); - } - - ~ControllerHolder() { - controller->stop(); - } - - void start(RegistrationType registrationType) { - std::vector tags; - controller->start(registrationType, tags, Seconds(1)); - } - - - FreeMonController* operator->() { - return controller.get(); - } - - FreeMonMetricsCollectorMock* registerCollector; - FreeMonMetricsCollectorMock* metricsCollector; - FreeMonNetworkInterfaceMock* network; - - std::unique_ptr controller; -}; - -// Positive: Test Register works -TEST_F(FreeMonControllerTest, TestRegister) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - controller.start(RegistrationType::DoNotRegister); - - auto optionalStatus = controller->registerServerCommand(Milliseconds::min()); - ASSERT(optionalStatus); - ASSERT_OK(*optionalStatus); - - controller->turnCrankForTest(Turner().registerCommand()); - - ASSERT_TRUE(!FreeMonStorage::read(_opCtx.get()).value().getRegistrationId().empty()); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_GTE(controller.metricsCollector->count(), 0UL); -} - -// Negatve: Test Register times out if network stack drops messages -TEST_F(FreeMonControllerTest, TestRegisterTimeout) { - - FreeMonNetworkInterfaceMock::Options opts; - opts.failRegisterHttp = true; - - ControllerHolder controller(_mockThreadPool.get(), opts); - - controller.start(RegistrationType::DoNotRegister); - - auto optionalStatus = controller->registerServerCommand(Milliseconds::min()); - ASSERT(optionalStatus); - ASSERT_OK(*optionalStatus); - controller->turnCrankForTest(Turner().registerCommand(2)); - - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).value().getState() == StorageStateEnum::pending); - ASSERT_GTE(controller.network->getRegistersCalls(), 2); - ASSERT_GTE(controller.registerCollector->count(), 2UL); -} - -// Negatve: Test Register fails if the registration is wrong -TEST_F(FreeMonControllerTest, TestRegisterFail) { - - FreeMonNetworkInterfaceMock::Options opts; - opts.invalidRegister = true; - ControllerHolder controller(_mockThreadPool.get(), opts); - - controller.start(RegistrationType::DoNotRegister); - - auto optionalStatus = controller->registerServerCommand(Milliseconds::min()); - ASSERT(optionalStatus); - ASSERT_OK(*optionalStatus); - controller->turnCrankForTest(Turner().registerCommand(1)); - - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).value().getState() == - StorageStateEnum::disabled); - ASSERT_EQ(controller.network->getRegistersCalls(), 1); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); -} - -// Positive: Ensure registration halts -TEST_F(FreeMonControllerTest, TestRegisterHalts) { - - FreeMonNetworkInterfaceMock::Options opts; - opts.haltRegister = true; - ControllerHolder controller(_mockThreadPool.get(), opts); - - controller.start(RegistrationType::DoNotRegister); - - auto optionalStatus = controller->registerServerCommand(Milliseconds::min()); - ASSERT(optionalStatus); - ASSERT_OK(*optionalStatus); - controller->turnCrankForTest(Turner().registerCommand()); - - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).value().getState() == - StorageStateEnum::disabled); - ASSERT_EQ(controller.network->getRegistersCalls(), 1); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); -} - -// Positive: Test Metrics works on server register -TEST_F(FreeMonControllerTest, TestMetrics) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - controller.start(RegistrationType::RegisterOnStart); - - controller->turnCrankForTest( - Turner().registerServer().registerCommand().collect(2).metricsSend()); - - ASSERT_TRUE(!FreeMonStorage::read(_opCtx.get()).value().getRegistrationId().empty()); - - ASSERT_GTE(controller.network->getRegistersCalls(), 1); - ASSERT_GTE(controller.network->getMetricsCalls(), 1); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_GTE(controller.metricsCollector->count(), 1UL); -} - - -// Positive: Test Metrics is collected but no registration happens on empty storage -TEST_F(FreeMonControllerTest, TestMetricsWithEmptyStorage) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - controller->turnCrankForTest(Turner().registerServer().collect(4)); - - ASSERT_GTE(controller.network->getRegistersCalls(), 0); - ASSERT_GTE(controller.network->getMetricsCalls(), 0); - - ASSERT_EQ(controller.registerCollector->count(), 0UL); - ASSERT_GTE(controller.metricsCollector->count(), 4UL); -} - -FreeMonStorageState initStorage(StorageStateEnum e) { - FreeMonStorageState storage; - storage.setVersion(1UL); - - storage.setRegistrationId("Foo"); - storage.setState(e); - storage.setInformationalURL("http://www.example.com"); - storage.setMessage("Hello World"); - storage.setUserReminder(""); - return storage; -} - -// Positive: Test Metrics is collected and implicit registration happens when storage is initialized -TEST_F(FreeMonControllerTest, TestMetricsWithEnabledStorage) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - FreeMonStorage::replace(_opCtx.get(), initStorage(StorageStateEnum::enabled)); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - controller->turnCrankForTest( - Turner().registerServer().registerCommand().collect(2).metricsSend()); - - ASSERT_TRUE(!FreeMonStorage::read(_opCtx.get()).value().getRegistrationId().empty()); - - ASSERT_GTE(controller.network->getRegistersCalls(), 1); - ASSERT_GTE(controller.network->getMetricsCalls(), 1); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_GTE(controller.metricsCollector->count(), 1UL); -} - -// Positive: Test Metrics is collected but no registration happens on disabled storage -TEST_F(FreeMonControllerTest, TestMetricsWithDisabledStorage) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - FreeMonStorage::replace(_opCtx.get(), initStorage(StorageStateEnum::disabled)); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - controller->turnCrankForTest(Turner().registerServer().collect(4)); - - ASSERT_GTE(controller.network->getRegistersCalls(), 0); - ASSERT_GTE(controller.network->getMetricsCalls(), 0); - - ASSERT_EQ(controller.registerCollector->count(), 0UL); - ASSERT_GTE(controller.metricsCollector->count(), 4UL); -} - - -// Positive: Test Metrics is collected but no registration happens on disabled storage until user -// registers -TEST_F(FreeMonControllerTest, TestMetricsWithDisabledStorageThenRegister) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - FreeMonStorage::replace(_opCtx.get(), initStorage(StorageStateEnum::disabled)); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - controller->turnCrankForTest(Turner().registerServer().metricsSend().collect(4)); - - auto optionalStatus = controller->registerServerCommand(Milliseconds::min()); - ASSERT(optionalStatus); - ASSERT_OK(*optionalStatus); - - controller->turnCrankForTest(Turner().registerCommand().metricsSend().collect(2).metricsSend()); - - ASSERT_GTE(controller.network->getRegistersCalls(), 1); - ASSERT_GTE(controller.network->getMetricsCalls(), 1); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_GTE(controller.metricsCollector->count(), 4UL + 2UL); -} - -// Positive: Test Metrics is collected but no registration happens, then register, then Unregister, -// and finally register again -TEST_F(FreeMonControllerTest, TestMetricsWithDisabledStorageThenRegisterAndReregister) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - FreeMonStorage::replace(_opCtx.get(), initStorage(StorageStateEnum::disabled)); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - controller->turnCrankForTest(Turner().registerServer().metricsSend().collect(4)); - - auto optionalStatus = controller->registerServerCommand(Milliseconds::min()); - ASSERT(optionalStatus); - ASSERT_OK(*optionalStatus); - - controller->turnCrankForTest(Turner().registerCommand().collect(2).metricsSend()); - - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get())->getState() == StorageStateEnum::enabled); - - optionalStatus = controller->unregisterServerCommand(Milliseconds::min()); - ASSERT(optionalStatus); - ASSERT_OK(*optionalStatus); - - controller->turnCrankForTest(Turner().unRegisterCommand().collect(3)); - - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get())->getState() == StorageStateEnum::disabled); - - optionalStatus = controller->registerServerCommand(Milliseconds::min()); - ASSERT(optionalStatus); - ASSERT_OK(*optionalStatus); - - controller->turnCrankForTest(Turner().registerCommand().metricsSend().collect(2).metricsSend()); - - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get())->getState() == StorageStateEnum::enabled); - - ASSERT_GTE(controller.network->getRegistersCalls(), 2); - ASSERT_GTE(controller.network->getMetricsCalls(), 1); - - ASSERT_EQ(controller.registerCollector->count(), 2UL); - ASSERT_GTE(controller.metricsCollector->count(), 4UL + 3UL + 2UL); -} - -// Positive: Test DeRegister cancels a register that is in the middle of retrying -TEST_F(FreeMonControllerTest, TestMetricsUnregisterCancelsRegister) { - FreeMonNetworkInterfaceMock::Options opts; - opts.failRegisterHttp = true; - ControllerHolder controller(_mockThreadPool.get(), opts); - - controller.start(RegistrationType::DoNotRegister); - - auto optionalStatus = controller->registerServerCommand(Milliseconds::min()); - ASSERT(optionalStatus); - ASSERT_OK(*optionalStatus); - controller->turnCrankForTest(Turner().registerCommand(2)); - - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).value().getState() == StorageStateEnum::pending); - - ASSERT_GTE(controller.network->getRegistersCalls(), 2); - ASSERT_GTE(controller.registerCollector->count(), 2UL); - - optionalStatus = controller->unregisterServerCommand(Milliseconds::min()); - ASSERT(optionalStatus); - ASSERT_OK(*optionalStatus); - - controller->turnCrankForTest(Turner().unRegisterCommand()); - - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).value().getState() == - StorageStateEnum::disabled); - - ASSERT_GTE(controller.network->getRegistersCalls(), 2); - ASSERT_GTE(controller.registerCollector->count(), 2UL); -} - -// Positive: Test Metrics halts -TEST_F(FreeMonControllerTest, TestMetricsHalt) { - FreeMonNetworkInterfaceMock::Options opts; - opts.haltMetrics = true; - ControllerHolder controller(_mockThreadPool.get(), opts); - - controller.start(RegistrationType::RegisterOnStart); - - controller->turnCrankForTest( - Turner().registerServer().registerCommand().metricsSend().collect(4).metricsSend()); - - ASSERT_TRUE(!FreeMonStorage::read(_opCtx.get()).value().getRegistrationId().empty()); - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).value().getState() == - StorageStateEnum::disabled); - - ASSERT_GTE(controller.network->getRegistersCalls(), 1); - ASSERT_GTE(controller.network->getMetricsCalls(), 1); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_GTE(controller.metricsCollector->count(), 4UL); -} - - -// Positive: Test Metrics permanently deletes if requested -TEST_F(FreeMonControllerTest, TestMetricsPermanentlyDelete) { - FreeMonNetworkInterfaceMock::Options opts; - opts.permanentlyDeleteAfter3 = true; - ControllerHolder controller(_mockThreadPool.get(), opts); - - controller.start(RegistrationType::RegisterOnStart); - - controller->turnCrankForTest( - Turner().registerServer().registerCommand().collect(5).metricsSend(4)); - - ASSERT_FALSE(FreeMonStorage::read(_opCtx.get()).has_value()); - - ASSERT_GTE(controller.network->getRegistersCalls(), 1); - ASSERT_GTE(controller.network->getMetricsCalls(), 3); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_GTE(controller.metricsCollector->count(), 3UL); -} - -// Positive: ensure registration id rotates -TEST_F(FreeMonControllerTest, TestRegistrationIdRotatesAfterRegistration) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - FreeMonStorage::replace(_opCtx.get(), initStorage(StorageStateEnum::enabled)); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - controller->turnCrankForTest(Turner().registerServer().registerCommand().collect(2)); - - // Ensure registration rotated the id - ASSERT_EQ(FreeMonStorage::read(_opCtx.get())->getRegistrationId(), "regId123"); - - controller->turnCrankForTest(Turner().metricsSend().collect()); - - // Ensure metrics rotated the id - ASSERT_EQ(FreeMonStorage::read(_opCtx.get())->getRegistrationId(), "metricsId456"); - - ASSERT_GTE(controller.network->getRegistersCalls(), 1); - ASSERT_GTE(controller.network->getMetricsCalls(), 1); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_GTE(controller.metricsCollector->count(), 1UL); -} - -// Positive: ensure pre-registration metrics batching occurs -// Positive: ensure we only get two metrics each time -TEST_F(FreeMonControllerTest, TestPreRegistrationMetricBatching) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - - controller->turnCrankForTest(Turner().registerServer().collect(4)); - - auto optionalStatus = controller->registerServerCommand(Milliseconds::min()); - ASSERT(optionalStatus); - ASSERT_OK(*optionalStatus); - - controller->turnCrankForTest(Turner().registerCommand().metricsSend()); - - // Ensure we sent all the metrics batched before registration - ASSERT_EQ(controller.network->getLastMetrics().nFields(), 4); - - controller->turnCrankForTest(Turner().metricsSend().collect(1)); - - // Ensure we only send 2 metrics in the normal happy case - ASSERT_EQ(controller.network->getLastMetrics().nFields(), 2); -} - -// Positive: resend registration in metrics response -TEST_F(FreeMonControllerTest, TestResendRegistration) { - FreeMonNetworkInterfaceMock::Options opts; - opts.resendRegistrationAfter3 = true; - - ControllerHolder controller(_mockThreadPool.get(), opts); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - - auto optionalStatus = controller->registerServerCommand(Milliseconds::min()); - ASSERT(optionalStatus); - ASSERT_OK(*optionalStatus); - - controller->turnCrankForTest(Turner().registerServer().registerCommand().collect(2)); - - ASSERT_TRUE(!FreeMonStorage::read(_opCtx.get()).value().getRegistrationId().empty()); - - controller->turnCrankForTest( - Turner().metricsSend(3).collect(3).registerCommand().metricsSend(1)); - - ASSERT_EQ(controller.registerCollector->count(), 2UL); - ASSERT_GTE(controller.metricsCollector->count(), 4UL); -} - -#if 0 -// Negative: Test metrics buffers on failure, and retries and ensure 2 metrics occurs after a blip -// of an error -// Note: this test operates in real-time because it needs to test multiple retries matched with -// metrics collection. -TEST_F(FreeMonControllerTest, TestMetricBatchingOnErrorRealtime) { - FreeMonNetworkInterfaceMock::Options opts; - opts.fail2MetricsUploads = true; - ControllerHolder controller(_mockThreadPool.get(), opts, false); - - controller.start(RegistrationType::RegisterOnStart); - - // Ensure the second upload sends 1 samples - ASSERT_TRUE(controller.network->waitMetricsCalls(2, Seconds(5)).is_initialized()); - ASSERT_EQ(controller.network->getLastMetrics().nFields(), 2); - - // Ensure the third upload sends 3 samples because first failed - ASSERT_TRUE(controller.network->waitMetricsCalls(1, Seconds(5)).is_initialized()); - ASSERT_EQ(controller.network->getLastMetrics().nFields(), 4); - - // Ensure the fourth upload sends 2 samples - ASSERT_TRUE(controller.network->waitMetricsCalls(1, Seconds(5)).is_initialized()); - ASSERT_EQ(controller.network->getLastMetrics().nFields(), 2); -} -#endif - -class FreeMonControllerRSTest : public FreeMonControllerTest { -private: - void setUp() final; - void tearDown() final; -}; - -void FreeMonControllerRSTest::setUp() { - FreeMonControllerTest::setUp(); - auto service = getServiceContext(); - - // Set up an OpObserver to exercise repl integration - auto opObserver = std::make_unique(); - auto opObserverRegistry = dynamic_cast(service->getOpObserver()); - opObserverRegistry->addObserver(std::move(opObserver)); -} - -void FreeMonControllerRSTest::tearDown() { - FreeMonControllerTest::tearDown(); -} - -// Positive: Transition to primary -TEST_F(FreeMonControllerRSTest, TransitionToPrimary) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - // Now become a secondary, then primary, and see what happens when we become primary - ASSERT_OK(_getReplCoord()->setFollowerMode(repl::MemberState::RS_SECONDARY)); - ASSERT_OK(_getReplCoord()->setFollowerMode(repl::MemberState::RS_PRIMARY)); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - - controller->turnCrankForTest(Turner().registerServer().collect(2)); - - controller->notifyOnTransitionToPrimary(); - - controller->turnCrankForTest(Turner().onTransitionToPrimary().registerCommand()); - - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).has_value()); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_GTE(controller.metricsCollector->count(), 2UL); -} - -// Positive: Test metrics works on secondary -TEST_F(FreeMonControllerRSTest, StartupOnSecondary) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - FreeMonStorage::replace(_opCtx.get(), initStorage(StorageStateEnum::enabled)); - - // Now become a secondary, then primary, and see what happens when we become primary - ASSERT_OK(_getReplCoord()->setFollowerMode(repl::MemberState::RS_SECONDARY)); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - - controller->turnCrankForTest(Turner().registerServer().registerCommand().collect()); - - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).has_value()); - - // Validate the new registration id was not written - ASSERT_EQ(FreeMonStorage::read(_opCtx.get())->getRegistrationId(), "Foo"); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_GTE(controller.metricsCollector->count(), 1UL); -} - -// Positive: Test registration occurs on replicated insert from primary -TEST_F(FreeMonControllerRSTest, SecondaryStartOnInsert) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - // Now become a secondary - ASSERT_OK(_getReplCoord()->setFollowerMode(repl::MemberState::RS_SECONDARY)); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - - controller->turnCrankForTest(Turner().registerServer().collect(2)); - - controller->notifyOnUpsert(initStorage(StorageStateEnum::enabled).toBSON()); - - controller->turnCrankForTest(Turner().notifyUpsert().registerCommand().collect()); - - ASSERT_FALSE(FreeMonStorage::read(_opCtx.get()).has_value()); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_GTE(controller.metricsCollector->count(), 2UL); -} - -// Positive: Test registration occurs on replicated update from primary -TEST_F(FreeMonControllerRSTest, SecondaryStartOnUpdate) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - FreeMonStorage::replace(_opCtx.get(), initStorage(StorageStateEnum::pending)); - - // Now become a secondary - ASSERT_OK(_getReplCoord()->setFollowerMode(repl::MemberState::RS_SECONDARY)); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - - controller->turnCrankForTest(Turner().registerServer().collect(2)); - - controller->notifyOnUpsert(initStorage(StorageStateEnum::enabled).toBSON()); - - controller->turnCrankForTest(Turner().notifyUpsert().registerCommand().collect()); - - // Since there is no local write, it remains pending - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).value().getState() == StorageStateEnum::pending); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_GTE(controller.metricsCollector->count(), 2UL); -} - -// Positive: Test Metrics works on secondary after opObserver de-register -TEST_F(FreeMonControllerRSTest, SecondaryStopOnDeRegister) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - FreeMonStorage::replace(_opCtx.get(), initStorage(StorageStateEnum::enabled)); - - // Now become a secondary - ASSERT_OK(_getReplCoord()->setFollowerMode(repl::MemberState::RS_SECONDARY)); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - - controller->turnCrankForTest(Turner().registerServer().registerCommand().collect(1)); - - ASSERT_EQ(controller.metricsCollector->count(), 1UL); - - controller->notifyOnUpsert(initStorage(StorageStateEnum::disabled).toBSON()); - - controller->turnCrankForTest(Turner().notifyUpsert().collect().metricsSend()); - - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).has_value()); - - // Since there is no local write, it remains enabled - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).value().getState() == StorageStateEnum::enabled); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_EQ(controller.metricsCollector->count(), 2UL); -} - -// Negative: Tricky: Primary becomes secondary during registration -TEST_F(FreeMonControllerRSTest, StepdownDuringRegistration) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - - auto optionalStatus = controller->registerServerCommand(Milliseconds::min()); - ASSERT(optionalStatus); - ASSERT_OK(*optionalStatus); - - controller->turnCrankForTest(Turner().registerServer() + 1); - - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).value().getState() == StorageStateEnum::pending); - - // Now become a secondary - ASSERT_OK(_getReplCoord()->setFollowerMode(repl::MemberState::RS_SECONDARY)); - - // Finish registration - controller->turnCrankForTest(1); - controller->turnCrankForTest(Turner().metricsSend().collect(2)); - - // Registration cannot write back to the local store so remain in pending - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).value().getState() == StorageStateEnum::pending); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_EQ(controller.metricsCollector->count(), 2UL); -} - -// Negative: Tricky: Primary becomes secondary during metrics send -TEST_F(FreeMonControllerRSTest, StepdownDuringMetricsSend) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - - auto optionalStatus = controller->registerServerCommand(Milliseconds::min()); - ASSERT(optionalStatus); - ASSERT_OK(*optionalStatus); - - controller->turnCrankForTest(Turner().registerServer().registerCommand().collect()); - - // Finish registration - controller->turnCrankForTest(Turner().collect(1) + 1); - - // Now become a secondary - ASSERT_OK(_getReplCoord()->setFollowerMode(repl::MemberState::RS_SECONDARY)); - - // Finish send - controller->turnCrankForTest(1); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_EQ(controller.metricsCollector->count(), 2UL); -} - -// Positive: Test Metrics works on secondary after opObserver delete of document -TEST_F(FreeMonControllerRSTest, SecondaryStopOnDocumentDrop) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - FreeMonStorage::replace(_opCtx.get(), initStorage(StorageStateEnum::enabled)); - - // Now become a secondary - ASSERT_OK(_getReplCoord()->setFollowerMode(repl::MemberState::RS_SECONDARY)); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - - controller->turnCrankForTest(Turner().registerServer().registerCommand().collect(1)); - - ASSERT_EQ(controller.metricsCollector->count(), 1UL); - - controller->notifyOnDelete(); - - // There is a race condition where sometimes metrics send sneaks in - controller->turnCrankForTest(Turner().notifyDelete().collect(3)); - - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).has_value()); - - // Since there is no local write, it remains enabled - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).value().getState() == StorageStateEnum::enabled); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_GTE(controller.metricsCollector->count(), 2UL); -} - - -// Positive: Test Metrics works on secondary after opObserver delete of document between metrics -// send and metrics async complete -TEST_F(FreeMonControllerRSTest, SecondaryStopOnDocumentDropDuringCollect) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - FreeMonStorage::replace(_opCtx.get(), initStorage(StorageStateEnum::enabled)); - - // Now become a secondary - ASSERT_OK(_getReplCoord()->setFollowerMode(repl::MemberState::RS_SECONDARY)); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - - controller->turnCrankForTest(Turner().registerServer().registerCommand().collect(1)); - - ASSERT_EQ(controller.metricsCollector->count(), 1UL); - - // Crank the metrics send but not the complete - controller->turnCrankForTest(Turner().collect(1)); - - controller->notifyOnDelete(); - - // Move the notify delete above the async metrics complete - controller->deprioritizeFirstMessageForTest(FreeMonMessageType::AsyncMetricsComplete); - - // There is a race condition where sometimes metrics send sneaks in - // Crank the notifyDelete and the async metrics complete. - controller->turnCrankForTest(Turner().notifyDelete().collect(1)); - - controller->turnCrankForTest(Turner().metricsSend().collect(2)); - - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).has_value()); - - // Since there is no local write, it remains enabled - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).value().getState() == StorageStateEnum::enabled); - - BSONObjBuilder builder; - controller->getServerStatus(_opCtx.get(), &builder); - auto obj = builder.obj(); - ASSERT_BSONOBJ_EQ(BSON("state" - << "undecided"), - obj); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_EQ(controller.metricsCollector->count(), 5UL); -} - - -// Negative: Test nice shutdown on bad update -TEST_F(FreeMonControllerRSTest, SecondaryStartOnBadUpdate) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - FreeMonStorage::replace(_opCtx.get(), initStorage(StorageStateEnum::enabled)); - - // Now become a secondary - ASSERT_OK(_getReplCoord()->setFollowerMode(repl::MemberState::RS_SECONDARY)); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - - controller->turnCrankForTest( - Turner().registerServer().registerCommand().metricsSend().collect(2)); - - controller->notifyOnUpsert(BSON("version" << 2LL)); - - controller->turnCrankForTest(Turner().notifyUpsert()); - - // Since there is no local write, it remains enabled - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).value().getState() == StorageStateEnum::enabled); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_EQ(controller.metricsCollector->count(), 2UL); -} - -// Positive: On rollback, start registration if needed -TEST_F(FreeMonControllerRSTest, SecondaryRollbackStopMetrics) { - ControllerHolder controller(_mockThreadPool.get(), FreeMonNetworkInterfaceMock::Options()); - - FreeMonStorage::replace(_opCtx.get(), initStorage(StorageStateEnum::disabled)); - - // Now become a secondary - ASSERT_OK(_getReplCoord()->setFollowerMode(repl::MemberState::RS_SECONDARY)); - - controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); - - controller->turnCrankForTest(Turner().registerServer().collect(2)); - - ASSERT_EQ(controller.metricsCollector->count(), 2UL); - - // Simulate a rollback by writing out of band - // Cheat a little by flipping to primary to allow the write to succeed - ASSERT_OK(_getReplCoord()->setFollowerMode(repl::MemberState::RS_PRIMARY)); - FreeMonStorage::replace(_opCtx.get(), initStorage(StorageStateEnum::enabled)); - ASSERT_OK(_getReplCoord()->setFollowerMode(repl::MemberState::RS_SECONDARY)); - - controller->notifyOnRollback(); - - controller->turnCrankForTest( - Turner().notifyOnRollback().registerCommand().metricsSend().collect(2).metricsSend()); - - // Since there is no local write, it remains enabled - ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).value().getState() == StorageStateEnum::enabled); - - ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_EQ(controller.metricsCollector->count(), 4UL); -} - -// TODO: tricky - OnUpser - disable - OnDelete - make sure registration halts -// TODO: tricky - OnDelete - make sure registration halts - -// TODO: Integration: Tricky - secondary as marked via command line - enableCloudFreeMOnitorig = -// false but a primary replicates a change to enable it - -// TODO: test SSL??? - - -// TODO: Positive: ensure optional fields are rotated - -} // namespace -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_message.h b/src/mongo/db/free_mon/free_mon_message.h deleted file mode 100644 index 2f8bab042c6..00000000000 --- a/src/mongo/db/free_mon/free_mon_message.h +++ /dev/null @@ -1,413 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include -#include - -#include "mongo/db/free_mon/free_mon_protocol_gen.h" -#include "mongo/platform/mutex.h" -#include "mongo/stdx/condition_variable.h" -#include "mongo/util/duration.h" -#include "mongo/util/time_support.h" - -namespace mongo { - -/** - * Message types for free monitoring. - * - * Some are generated internally by FreeMonProcessor to handle async HTTP requests. - */ -enum class FreeMonMessageType { - /** - * Register server from command-line/config. - */ - RegisterServer, - - /** - * Register server from server command. - */ - RegisterCommand, - - /** - * Internal: Generated when an async registration HTTP request completes succesfully. - */ - AsyncRegisterComplete, - - /** - * Internal: Generated when an async registration HTTP request completes with an error. - */ - AsyncRegisterFail, - - /** - * Unregister server from server command. - */ - UnregisterCommand, - - /** - * Internal: Collect metrics and buffer them in-memory - */ - MetricsCollect, - - /** - * Internal: Send metrics to the cloud endpoint by beginning an async HTTP request. - */ - MetricsSend, - - /** - * Internal: Generated when an async metrics HTTP request completes succesfully. - */ - AsyncMetricsComplete, - - /** - * Internal: Generated when an async metrics HTTP request completes with an error. - */ - AsyncMetricsFail, - - /** - * Notify that the node has been made a primary replica. - */ - OnTransitionToPrimary, - - /** - * Notify that storage has received an insert or update. - */ - NotifyOnUpsert, - - /** - * Notify that storage has received a delete or drop collection. - */ - NotifyOnDelete, - - /** - * Notify that storage has been rolled back. - */ - NotifyOnRollback, -}; - -/** - * Supported types of registration that occur on server startup. - */ -enum class RegistrationType { - /** - * Do not register on start because it was not configured via commandline/config file. - */ - DoNotRegister, - - /** - * Register immediately on start since we are a standalone. - */ - RegisterOnStart, - - /** - * Register after transition to becoming primary because we are in a replica set, - * and Free Monitoring has been explicitly enabled. - */ - RegisterAfterOnTransitionToPrimary, - - /** - * As above, but only if we have been runtime enabled. - */ - RegisterAfterOnTransitionToPrimaryIfEnabled, -}; - -/** - * Message class that encapsulate a message to the FreeMonMessageProcessor - * - * Has a type and a deadline for when to start processing the message. - */ -class FreeMonMessage { -public: - virtual ~FreeMonMessage(); - - /** - * Create a message that should processed immediately. - */ - static std::shared_ptr createNow(FreeMonMessageType type) { - return std::make_shared(type, Date_t()); - } - - /** - * Create a message that should processed after the specified deadline. - */ - static std::shared_ptr createWithDeadline(FreeMonMessageType type, - Date_t deadline) { - return std::make_shared(type, deadline); - } - - FreeMonMessage(const FreeMonMessage&) = delete; - FreeMonMessage(FreeMonMessage&&) = default; - - /** - * Get the type of message. - */ - FreeMonMessageType getType() const { - return _type; - } - - /** - * Get the deadline for the message. - */ - Date_t getDeadline() const { - return _deadline; - } - - /** - * Get the unique message id for FIFO ordering messages with the same deadline. - */ - uint64_t getId() const { - return _id; - } - - /** - * Set the unique message id. - */ - void setId(uint64_t id) { - _id = id; - } - -public: - FreeMonMessage(FreeMonMessageType type, Date_t deadline) : _type(type), _deadline(deadline) {} - -private: - // Type of message - FreeMonMessageType _type; - - // Deadline for when to process message - Date_t _deadline; - - // Process-wide unique message id to ensure messages with the same deadlines are processed in - // FIFO order. - uint64_t _id{0}; -}; - - -/** - * Most messages have a simple payload, and this template ensures we create type-safe messages for - * each message type without copy-pasting repeatedly. - */ -template -struct FreeMonPayloadForMessage { - using payload_type = void; -}; - -template <> -struct FreeMonPayloadForMessage { - using payload_type = FreeMonRegistrationResponse; -}; - -template <> -struct FreeMonPayloadForMessage { - using payload_type = std::pair>; -}; - -template <> -struct FreeMonPayloadForMessage { - using payload_type = Status; -}; - -template <> -struct FreeMonPayloadForMessage { - using payload_type = FreeMonMetricsResponse; -}; - -template <> -struct FreeMonPayloadForMessage { - using payload_type = Status; -}; - -template <> -struct FreeMonPayloadForMessage { - using payload_type = BSONObj; -}; - -/** - * Message with a generic payload based on the type of message. - */ -template -class FreeMonMessageWithPayload : public FreeMonMessage { -public: - using payload_type = typename FreeMonPayloadForMessage::payload_type; - - /** - * Create a message that should processed immediately. - */ - static std::shared_ptr createNow(payload_type t) { - return std::make_shared(t, Date_t{}); - } - - /** - * Get message payload. - */ - const payload_type& getPayload() const { - return _t; - } - -public: - FreeMonMessageWithPayload(payload_type t, Date_t deadline) - : FreeMonMessage(typeT, deadline), _t(std::move(t)) {} - -private: - // Message payload - payload_type _t; -}; - -/** - * Single-shot class that encapsulates a Status and allows a caller to wait for a time. - * - * Basically, a single producer, single consumer queue with one event. - */ -class WaitableResult { -public: - WaitableResult() : _status(Status::OK()) {} - - /** - * Set Status and signal waiter. - */ - void set(Status status) { - stdx::lock_guard lock(_mutex); - - invariant(!_set); - if (!_set) { - _set = true; - _status = std::move(status); - _condvar.notify_one(); - } - } - - /** - * Waits for duration until status has been set. - * - * Returns boost::none on timeout. - */ - boost::optional wait_for(Milliseconds duration) { - stdx::unique_lock lock(_mutex); - - if (!_condvar.wait_for(lock, duration.toSystemDuration(), [this]() { return _set; })) { - return {}; - } - - return _status; - } - -private: - // Condition variable to signal consumer - stdx::condition_variable _condvar; - - // Lock for condition variable and to protect state - Mutex _mutex = MONGO_MAKE_LATCH("WaitableResult::_mutex"); - - // Indicates whether _status has been set - bool _set{false}; - - // Provided status - Status _status; -}; - -/** - * For the messages that the caller needs to wait on, this provides a mechanism to wait on messages - * to be processed. - */ -template -struct FreeMonWaitablePayloadForMessage { - using payload_type = void; -}; - -template <> -struct FreeMonWaitablePayloadForMessage { - using payload_type = std::pair, boost::optional>; -}; - -template <> -struct FreeMonWaitablePayloadForMessage { - // The parameter is unused but most not be void. - using payload_type = bool; -}; - -/** - * Message with a generic payload based on the type of message. - */ -template -class FreeMonWaitableMessageWithPayload : public FreeMonMessage { -public: - using payload_type = typename FreeMonWaitablePayloadForMessage::payload_type; - - /** - * Create a message that should processed immediately. - */ - static std::shared_ptr createNow(payload_type t) { - return std::make_shared(t, Date_t()); - } - - /** - * Create a message that should processed immediately. - */ - static std::shared_ptr createWithDeadline(payload_type t, - Date_t deadline) { - return std::make_shared(t, deadline); - } - /** - * Get message payload. - */ - const payload_type& getPayload() const { - return _t; - } - - /** - * Set Status and signal waiter. - */ - void setStatus(Status status) { - _waitable.set(std::move(status)); - } - - /** - * Waits for duration until status has been set. - * - * Returns boost::none on timeout. - */ - boost::optional wait_for(Milliseconds duration) { - return _waitable.wait_for(duration); - } - -public: - FreeMonWaitableMessageWithPayload(payload_type t, Date_t deadline) - : FreeMonMessage(typeT, deadline), _t(std::move(t)) {} - -private: - // Message payload - payload_type _t; - - // WaitaleResult to notify caller - WaitableResult _waitable{}; -}; - -using FreeMonRegisterCommandMessage = - FreeMonWaitableMessageWithPayload; -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_mongod.cpp b/src/mongo/db/free_mon/free_mon_mongod.cpp deleted file mode 100644 index fbd5daa150d..00000000000 --- a/src/mongo/db/free_mon/free_mon_mongod.cpp +++ /dev/null @@ -1,394 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "mongo/base/data_builder.h" -#include "mongo/base/data_range.h" -#include "mongo/base/data_type_validated.h" -#include "mongo/base/error_codes.h" -#include "mongo/base/status.h" -#include "mongo/bson/bsonelement.h" -#include "mongo/bson/bsonmisc.h" -#include "mongo/bson/bsonobj.h" -#include "mongo/bson/bsonobjbuilder.h" -#include "mongo/db/catalog/collection_catalog.h" -#include "mongo/db/client.h" -#include "mongo/db/free_mon/free_mon_controller.h" -#include "mongo/db/free_mon/free_mon_message.h" -#include "mongo/db/free_mon/free_mon_mongod.h" -#include "mongo/db/free_mon/free_mon_mongod_gen.h" -#include "mongo/db/free_mon/free_mon_network.h" -#include "mongo/db/free_mon/free_mon_op_observer.h" -#include "mongo/db/free_mon/free_mon_options.h" -#include "mongo/db/free_mon/free_mon_processor.h" -#include "mongo/db/free_mon/free_mon_protocol_gen.h" -#include "mongo/db/free_mon/free_mon_storage.h" -#include "mongo/db/ftdc/ftdc_server.h" -#include "mongo/db/namespace_string.h" -#include "mongo/db/op_observer/op_observer.h" -#include "mongo/db/operation_context.h" -#include "mongo/db/repl/replication_coordinator.h" -#include "mongo/db/service_context.h" -#include "mongo/executor/network_interface_factory.h" -#include "mongo/executor/task_executor.h" -#include "mongo/executor/thread_pool_task_executor.h" -#include "mongo/idl/idl_parser.h" -#include "mongo/rpc/object_check.h" // IWYU pragma: keep -#include "mongo/util/assert_util.h" -#include "mongo/util/concurrency/thread_pool.h" -#include "mongo/util/duration.h" -#include "mongo/util/future.h" -#include "mongo/util/net/http_client.h" -#include "mongo/util/testing_proctor.h" -#include "mongo/util/uuid.h" - -#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kControl - - -namespace mongo { - -namespace { - -constexpr Seconds kDefaultMetricsGatherInterval(60); - -auto makeTaskExecutor(ServiceContext* /*serviceContext*/) { - ThreadPool::Options tpOptions; - tpOptions.poolName = "FreeMonHTTP"; - tpOptions.maxThreads = 2; - tpOptions.onCreateThread = [](const std::string& threadName) { - Client::initThread(threadName.c_str()); - - // TODO(SERVER-74659): Please revisit if this thread could be made killable. - stdx::lock_guard lk(cc()); - cc().setSystemOperationUnkillableByStepdown(lk); - }; - return std::make_unique( - std::make_unique(tpOptions), executor::makeNetworkInterface("FreeMonNet")); -} - -class FreeMonNetworkHttp final : public FreeMonNetworkInterface { -public: - explicit FreeMonNetworkHttp(ServiceContext* serviceContext) { - _executor = makeTaskExecutor(serviceContext); - _executor->startup(); - _client = HttpClient::create(); - _client->allowInsecureHTTP(TestingProctor::instance().isEnabled()); - _client->setHeaders({"Content-Type: application/octet-stream", - "Accept: application/octet-stream", - "Expect:"}); - } - - Future sendRegistrationAsync( - const FreeMonRegistrationRequest& req) override { - BSONObj reqObj = req.toBSON(); - auto data = std::make_shared>( - reqObj.objdata(), reqObj.objdata() + reqObj.objsize()); - - return post("/register", data).then([](DataBuilder&& blob) { - if (!blob.size()) { - uasserted(ErrorCodes::FreeMonHttpTemporaryFailure, "Empty response received"); - } - - auto blobSize = blob.size(); - auto blobData = blob.release(); - ConstDataRange cdr(blobData.get(), blobSize); - BSONObj respObj = cdr.read>(); - - auto resp = FreeMonRegistrationResponse::parse(IDLParserContext("response"), respObj); - - return resp; - }); - } - - Future sendMetricsAsync(const FreeMonMetricsRequest& req) override { - BSONObj reqObj = req.toBSON(); - auto data = std::make_shared>( - reqObj.objdata(), reqObj.objdata() + reqObj.objsize()); - - return post("/metrics", data).then([](DataBuilder&& blob) { - if (!blob.size()) { - uasserted(ErrorCodes::FreeMonHttpTemporaryFailure, "Empty response received"); - } - - auto blobSize = blob.size(); - auto blobData = blob.release(); - ConstDataRange cdr(blobData.get(), blobSize); - - BSONObj respObj = cdr.read>(); - - auto resp = FreeMonMetricsResponse::parse(IDLParserContext("response"), respObj); - - return resp; - }); - } - -private: - Future post(StringData path, - std::shared_ptr> data) const { - auto pf = makePromiseFuture(); - std::string url(FreeMonEndpointURL + path.toString()); - - auto status = _executor->scheduleWork( - [promise = std::move(pf.promise), url = std::move(url), data = std::move(data), this]( - const executor::TaskExecutor::CallbackArgs& cbArgs) mutable { - ConstDataRange cdr(data->data(), data->size()); - try { - auto result = this->_client->post(url, cdr); - promise.emplaceValue(std::move(result)); - } catch (...) { - promise.setError(exceptionToStatus()); - } - }); - - uassertStatusOK(status); - return std::move(pf.future); - } - -private: - std::unique_ptr _client; - std::unique_ptr _executor; -}; - -/** - * Collect the mms-automation state document from local.clustermanager during registration. - */ -class FreeMonLocalClusterManagerCollector : public FreeMonCollectorInterface { -public: - std::string name() const final { - return "clustermanager"; - } - - void collect(OperationContext* opCtx, BSONObjBuilder& builder) { - auto optionalObj = FreeMonStorage::readClusterManagerState(opCtx); - if (optionalObj.is_initialized()) { - builder.appendElements(optionalObj.get()); - } - } -}; - -/** - * Get the "storageEngine" section of "serverStatus" during registration. - */ -class FreeMonLocalStorageEngineStatusCollector : public FTDCSimpleInternalCommandCollector { -public: - FreeMonLocalStorageEngineStatusCollector() - : FTDCSimpleInternalCommandCollector( - "serverStatus", - "serverStatus", - "", - // Try to filter server status to make it cheaper to collect. Harmless if we gather - // extra - BSON("serverStatus" << 1 << "storageEngine" << true << "extra_info" << false - << "opLatencies" << false << "opcountersRepl" << false - << "opcounters" << false << "transactions" << false - << "connections" << false << "network" << false << "tcMalloc" - << false << "network" << false << "wiredTiger" << false - << "sharding" << false << "metrics" << false)) {} - - std::string name() const final { - return "storageEngine"; - } - - void collect(OperationContext* opCtx, BSONObjBuilder& builder) { - BSONObjBuilder localBuilder; - - FTDCSimpleInternalCommandCollector::collect(opCtx, localBuilder); - - BSONObj obj = localBuilder.obj(); - - builder.appendElements(obj["storageEngine"].Obj()); - } -}; - -/** - * Collect the UUIDs associated with the named collections (if available). - */ -class FreeMonNamespaceUUIDCollector : public FreeMonCollectorInterface { -public: - FreeMonNamespaceUUIDCollector(std::set namespaces) - : _namespaces(std::move(namespaces)) {} - - std::string name() const final { - return "uuid"; - } - - void collect(OperationContext* opCtx, BSONObjBuilder& builder) { - auto catalog = CollectionCatalog::get(opCtx); - for (auto& nss : _namespaces) { - auto optUUID = catalog->lookupUUIDByNSS(opCtx, nss); - if (optUUID) { - // Always include tenant id in nss for FTDC collector. - builder << toStringForLogging(nss) << optUUID.get(); - } - } - } - -private: - std::set _namespaces; -}; - -} // namespace - -Status onValidateFreeMonEndpointURL(StringData str, const boost::optional&) { - // Check for http, not https here because testEnabled may not be set yet - if (!str.startsWith("http"_sd) != 0) { - return Status(ErrorCodes::BadValue, - "cloudFreeMonitoringEndpointURL only supports http:// URLs"); - } - - return Status::OK(); -} - -void registerCollectors(FreeMonController* controller) { - // These are collected only at registration - // - // CmdBuildInfo - controller->addRegistrationCollector(std::make_unique( - "buildInfo", "buildInfo", "", BSON("buildInfo" << 1))); - - // HostInfoCmd - controller->addRegistrationCollector(std::make_unique( - "hostInfo", "hostInfo", "", BSON("hostInfo" << 1))); - - // Add storageEngine section from serverStatus - controller->addRegistrationCollector( - std::make_unique()); - - // Gather one document from local.clustermanager - controller->addRegistrationCollector(std::make_unique()); - - // These are periodically for metrics upload - // - controller->addMetricsCollector(std::make_unique( - "getDiagnosticData", "diagnosticData", "", BSON("getDiagnosticData" << 1))); - - // These are collected at registration and as metrics periodically - // - if (repl::ReplicationCoordinator::get(getGlobalServiceContext())->getSettings().isReplSet()) { - // CmdReplSetGetConfig - controller->addRegistrationCollector(std::make_unique( - "replSetGetConfig", "replSetGetConfig", "", BSON("replSetGetConfig" << 1))); - - controller->addMetricsCollector(std::make_unique( - "replSetGetConfig", "replSetGetConfig", "", BSON("replSetGetConfig" << 1))); - - // Collect UUID for certain collections. - std::set namespaces({NamespaceString::kRsOplogNamespace}); - controller->addRegistrationCollector( - std::make_unique(namespaces)); - controller->addMetricsCollector( - std::make_unique(namespaces)); - } - - controller->addRegistrationCollector(std::make_unique( - "isMaster", "isMaster", "", BSON("isMaster" << 1))); - - controller->addMetricsCollector(std::make_unique( - "isMaster", "isMaster", "", BSON("isMaster" << 1))); -} - -void startFreeMonitoring(ServiceContext* serviceContext) { - if (globalFreeMonParams.freeMonitoringState == EnableCloudStateEnum::kOff) { - return; - } - - if (!TestingProctor::instance().isEnabled()) { - uassert(50774, - "ExportedFreeMonEndpointURL only supports https:// URLs", - FreeMonEndpointURL.compare(0, 5, "https") == 0); - } - - auto network = std::unique_ptr(new FreeMonNetworkHttp(serviceContext)); - - auto controller = std::make_unique(std::move(network)); - - auto controllerPtr = controller.get(); - - registerCollectors(controller.get()); - - // Install the new controller - FreeMonController::init(getGlobalServiceContext(), std::move(controller)); - - RegistrationType registrationType = RegistrationType::DoNotRegister; - if (globalFreeMonParams.freeMonitoringState == EnableCloudStateEnum::kOn) { - // If replication is enabled, we may need to register on becoming primary - if (repl::ReplicationCoordinator::get(getGlobalServiceContext()) - ->getSettings() - .isReplSet()) { - registrationType = RegistrationType::RegisterAfterOnTransitionToPrimary; - } else { - registrationType = RegistrationType::RegisterOnStart; - } - } else if (globalFreeMonParams.freeMonitoringState == EnableCloudStateEnum::kRuntime) { - registrationType = RegistrationType::RegisterAfterOnTransitionToPrimaryIfEnabled; - } - - controllerPtr->start(registrationType, - globalFreeMonParams.freeMonitoringTags, - Seconds(kDefaultMetricsGatherInterval)); -} - -void stopFreeMonitoring() { - if (globalFreeMonParams.freeMonitoringState == EnableCloudStateEnum::kOff) { - return; - } - - auto controller = FreeMonController::get(getGlobalServiceContext()); - - if (controller != nullptr) { - controller->stop(); - } -} - -void notifyFreeMonitoringOnTransitionToPrimary() { - auto controller = FreeMonController::get(getGlobalServiceContext()); - - if (controller != nullptr) { - controller->notifyOnTransitionToPrimary(); - } -} - -void setupFreeMonitoringOpObserver(OpObserverRegistry* registry) { - registry->addObserver(std::make_unique()); -} - -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_mongod.h b/src/mongo/db/free_mon/free_mon_mongod.h deleted file mode 100644 index 32f0269a911..00000000000 --- a/src/mongo/db/free_mon/free_mon_mongod.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include -#include -#include - -#include "mongo/base/status.h" -#include "mongo/base/string_data.h" -#include "mongo/db/op_observer/op_observer_registry.h" -#include "mongo/db/service_context.h" -#include "mongo/db/tenant_id.h" - -namespace mongo { - -/** - * Start Free Monitoring - * Starts 1 thread. - */ -void startFreeMonitoring(ServiceContext* serviceContext); - -/** - * Stop Free Monitoring - */ -void stopFreeMonitoring(); - -/** - * Notify free monitoring about a replica set member becoming primary - */ -void notifyFreeMonitoringOnTransitionToPrimary(); - -/** - * Setup Free Monitoring OpObserver. - * - * Called before free monitoring is started. - */ -void setupFreeMonitoringOpObserver(OpObserverRegistry* registry); - -Status onValidateFreeMonEndpointURL(StringData str, const boost::optional&); - - -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_mongod.idl b/src/mongo/db/free_mon/free_mon_mongod.idl deleted file mode 100644 index cf944a6cc1b..00000000000 --- a/src/mongo/db/free_mon/free_mon_mongod.idl +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (C) 2018-present MongoDB, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the Server Side Public License, version 1, -# as published by MongoDB, Inc. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# Server Side Public License for more details. -# -# You should have received a copy of the Server Side Public License -# along with this program. If not, see -# . -# -# As a special exception, the copyright holders give permission to link the -# code of portions of this program with the OpenSSL library under certain -# conditions as described in each individual source file and distribute -# linked combinations including the program with the OpenSSL library. You -# must comply with the Server Side Public License in all respects for -# all of the code used other than as permitted herein. If you modify file(s) -# with this exception, you may extend this exception to your version of the -# file(s), but you are not obligated to do so. If you do not wish to do so, -# delete this exception statement from your version. If you delete this -# exception statement from all source files in the program, then also delete -# it in the license file. -# - -global: - cpp_namespace: "mongo" - cpp_includes: - - "mongo/db/free_mon/free_mon_mongod.h" - -imports: - - "mongo/db/basic_types.idl" - -server_parameters: - - cloudFreeMonitoringEndpointURL: - description: "Suppress logging of warnings when non-SSL connections are accepted in preferSSL mode" - set_at: startup - default: "https://cloud.mongodb.com/freemonitoring/mongo" - cpp_vartype: std::string - cpp_varname: FreeMonEndpointURL - validator: - callback: "onValidateFreeMonEndpointURL" - diff --git a/src/mongo/db/free_mon/free_mon_network.h b/src/mongo/db/free_mon/free_mon_network.h deleted file mode 100644 index 2bf1ff66b91..00000000000 --- a/src/mongo/db/free_mon/free_mon_network.h +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include "mongo/db/free_mon/free_mon_protocol_gen.h" -#include "mongo/util/future.h" - -namespace mongo { - -/** - * Makes HTTPS calls to cloud endpoint. - */ -class FreeMonNetworkInterface { -public: - virtual ~FreeMonNetworkInterface(); - - /** - * POSTs FreeMonRegistrationRequest to endpoint. - * - * Returns a FreeMonRegistrationResponse or throws an error on non-HTTP 200. - */ - virtual Future sendRegistrationAsync( - const FreeMonRegistrationRequest& req) = 0; - - /** - * POSTs FreeMonMetricsRequest to endpoint. - * - * Returns a FreeMonMetricsResponse or throws an error on non-HTTP 200. - */ - virtual Future sendMetricsAsync(const FreeMonMetricsRequest& req) = 0; -}; -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_op_observer.cpp b/src/mongo/db/free_mon/free_mon_op_observer.cpp deleted file mode 100644 index e56a39d67cd..00000000000 --- a/src/mongo/db/free_mon/free_mon_op_observer.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include -#include - -#include "mongo/base/string_data.h" -#include "mongo/bson/bsonelement.h" -#include "mongo/db/free_mon/free_mon_controller.h" -#include "mongo/db/free_mon/free_mon_op_observer.h" -#include "mongo/db/free_mon/free_mon_storage.h" -#include "mongo/db/operation_context.h" -#include "mongo/db/repl/member_state.h" -#include "mongo/db/repl/replication_coordinator.h" -#include "mongo/util/decorable.h" - -namespace mongo { -namespace { - -bool isStandaloneOrPrimary(OperationContext* opCtx) { - auto replCoord = repl::ReplicationCoordinator::get(opCtx); - const bool isReplSet = replCoord->getSettings().isReplSet(); - return !isReplSet || - (repl::ReplicationCoordinator::get(opCtx)->getMemberState() == - repl::MemberState::RS_PRIMARY); -} - -const auto getFreeMonDeleteState = OplogDeleteEntryArgs::declareDecoration(); - -} // namespace - -FreeMonOpObserver::FreeMonOpObserver() = default; - -FreeMonOpObserver::~FreeMonOpObserver() = default; - -repl::OpTime FreeMonOpObserver::onDropCollection(OperationContext* opCtx, - const NamespaceString& collectionName, - const UUID& uuid, - std::uint64_t numRecords, - const CollectionDropType dropType, - bool markFromMigrate) { - if (collectionName == NamespaceString::kServerConfigurationNamespace) { - auto controller = FreeMonController::get(opCtx->getServiceContext()); - - if (controller != nullptr) { - controller->notifyOnDelete(); - } - } - - return {}; -} - -void FreeMonOpObserver::onInserts(OperationContext* opCtx, - const CollectionPtr& coll, - std::vector::const_iterator begin, - std::vector::const_iterator end, - std::vector fromMigrate, - bool defaultFromMigrate, - OpStateAccumulator* opAccumulator) { - if (coll->ns() != NamespaceString::kServerConfigurationNamespace) { - return; - } - - if (isStandaloneOrPrimary(opCtx)) { - return; - } - - for (auto it = begin; it != end; ++it) { - const auto& insertedDoc = it->doc; - - if (auto idElem = insertedDoc["_id"]) { - if (idElem.str() == FreeMonStorage::kFreeMonDocIdKey) { - auto controller = FreeMonController::get(opCtx->getServiceContext()); - - if (controller != nullptr) { - controller->notifyOnUpsert(insertedDoc.getOwned()); - } - } - } - } -} - -void FreeMonOpObserver::onUpdate(OperationContext* opCtx, - const OplogUpdateEntryArgs& args, - OpStateAccumulator* opAccumulator) { - if (args.coll->ns() != NamespaceString::kServerConfigurationNamespace) { - return; - } - - if (isStandaloneOrPrimary(opCtx)) { - return; - } - - if (args.updateArgs->updatedDoc["_id"].str() == FreeMonStorage::kFreeMonDocIdKey) { - auto controller = FreeMonController::get(opCtx->getServiceContext()); - - if (controller != nullptr) { - controller->notifyOnUpsert(args.updateArgs->updatedDoc.getOwned()); - } - } -} - -void FreeMonOpObserver::aboutToDelete(OperationContext* opCtx, - const CollectionPtr& coll, - const BSONObj& doc, - OplogDeleteEntryArgs* args, - OpStateAccumulator* opAccumulator) { - - bool isFreeMonDoc = (coll->ns() == NamespaceString::kServerConfigurationNamespace) && - (doc["_id"].str() == FreeMonStorage::kFreeMonDocIdKey); - - // Set a flag that indicates whether the document to be delete is the free monitoring state - // document - getFreeMonDeleteState(args) = isFreeMonDoc; -} - -void FreeMonOpObserver::onDelete(OperationContext* opCtx, - const CollectionPtr& coll, - StmtId stmtId, - const OplogDeleteEntryArgs& args, - OpStateAccumulator* opAccumulator) { - if (coll->ns() != NamespaceString::kServerConfigurationNamespace) { - return; - } - - if (isStandaloneOrPrimary(opCtx)) { - return; - } - - if (getFreeMonDeleteState(args) == true) { - auto controller = FreeMonController::get(opCtx->getServiceContext()); - - if (controller != nullptr) { - controller->notifyOnDelete(); - } - } -} - -void FreeMonOpObserver::onReplicationRollback(OperationContext* opCtx, - const RollbackObserverInfo& rbInfo) { - // Invalidate any in-memory auth data if necessary. - const auto& rollbackNamespaces = rbInfo.rollbackNamespaces; - if (rollbackNamespaces.count(NamespaceString::kServerConfigurationNamespace) == 1) { - auto controller = FreeMonController::get(opCtx->getServiceContext()); - - if (controller != nullptr) { - controller->notifyOnRollback(); - } - } -} - - -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_op_observer.h b/src/mongo/db/free_mon/free_mon_op_observer.h deleted file mode 100644 index d9097c651fb..00000000000 --- a/src/mongo/db/free_mon/free_mon_op_observer.h +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include -#include - -#include "mongo/bson/bsonobj.h" -#include "mongo/db/catalog/collection.h" -#include "mongo/db/namespace_string.h" -#include "mongo/db/op_observer/op_observer.h" -#include "mongo/db/op_observer/op_observer_noop.h" -#include "mongo/db/operation_context.h" -#include "mongo/db/repl/oplog.h" -#include "mongo/db/repl/optime.h" -#include "mongo/db/session/logical_session_id.h" -#include "mongo/util/uuid.h" - -namespace mongo { - -/** - * OpObserver for Free Monitoring. Observes all secondary replication traffic and filters down to - * relevant entries for free monitoring. - */ -class FreeMonOpObserver final : public OpObserverNoop { - FreeMonOpObserver(const FreeMonOpObserver&) = delete; - FreeMonOpObserver& operator=(const FreeMonOpObserver&) = delete; - -public: - FreeMonOpObserver(); - ~FreeMonOpObserver(); - - NamespaceFilters getNamespaceFilters() const final { - return {NamespaceFilter::kSystem, NamespaceFilter::kSystem}; - } - - void onInserts(OperationContext* opCtx, - const CollectionPtr& coll, - std::vector::const_iterator begin, - std::vector::const_iterator end, - std::vector fromMigrate, - bool defaultFromMigrate, - OpStateAccumulator* opAccumulator = nullptr) final; - - void onUpdate(OperationContext* opCtx, - const OplogUpdateEntryArgs& args, - OpStateAccumulator* opAccumulator = nullptr) final; - - void aboutToDelete(OperationContext* opCtx, - const CollectionPtr& coll, - const BSONObj& doc, - OplogDeleteEntryArgs* args, - OpStateAccumulator* opAccumulator = nullptr) final; - - void onDelete(OperationContext* opCtx, - const CollectionPtr& coll, - StmtId stmtId, - const OplogDeleteEntryArgs& args, - OpStateAccumulator* opAccumulator = nullptr) final; - - repl::OpTime onDropCollection(OperationContext* opCtx, - const NamespaceString& collectionName, - const UUID& uuid, - std::uint64_t numRecords, - CollectionDropType dropType, - bool markFromMigrate) final; - - void onReplicationRollback(OperationContext* opCtx, const RollbackObserverInfo& rbInfo) final; -}; - -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_options.cpp b/src/mongo/db/free_mon/free_mon_options.cpp deleted file mode 100644 index b66434d95aa..00000000000 --- a/src/mongo/db/free_mon/free_mon_options.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - - -#include - -#include "mongo/base/error_codes.h" -#include "mongo/base/initializer.h" -#include "mongo/base/status.h" -#include "mongo/base/status_with.h" -#include "mongo/base/string_data.h" -#include "mongo/db/free_mon/free_mon_options.h" -#include "mongo/util/assert_util.h" -#include "mongo/util/options_parser/environment.h" -#include "mongo/util/options_parser/startup_option_init.h" -#include "mongo/util/options_parser/startup_options.h" -#include "mongo/util/options_parser/value.h" - -#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kFTDC - - -namespace mongo { - -FreeMonParams globalFreeMonParams; - -namespace moe = mongo::optionenvironment; - -namespace { - -constexpr StringData kEnableCloudState_on = "on"_sd; -constexpr StringData kEnableCloudState_off = "off"_sd; -constexpr StringData kEnableCloudState_runtime = "runtime"_sd; - -StatusWith EnableCloudState_parse(StringData value) { - if (value == kEnableCloudState_on) { - return EnableCloudStateEnum::kOn; - } - if (value == kEnableCloudState_off) { - return EnableCloudStateEnum::kOff; - } - if (value == kEnableCloudState_runtime) { - return EnableCloudStateEnum::kRuntime; - } - - return Status(ErrorCodes::InvalidOptions, "Unrecognized state"); -} - -Status storeFreeMonitoringOptions(const moe::Environment& params) { - - if (params.count("cloud.monitoring.free.state")) { - auto swState = - EnableCloudState_parse(params["cloud.monitoring.free.state"].as()); - if (!swState.isOK()) { - return swState.getStatus(); - } - globalFreeMonParams.freeMonitoringState = swState.getValue(); - } - - if (params.count("cloud.monitoring.free.tags")) { - globalFreeMonParams.freeMonitoringTags = - params["cloud.monitoring.free.tags"].as>(); - } - - return Status::OK(); -} - -MONGO_STARTUP_OPTIONS_STORE(FreeMonitoringOptions)(InitializerContext*) { - uassertStatusOK(storeFreeMonitoringOptions(moe::startupOptionsParsed)); -} - -} // namespace -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_options.h b/src/mongo/db/free_mon/free_mon_options.h deleted file mode 100644 index 79f458fb28f..00000000000 --- a/src/mongo/db/free_mon/free_mon_options.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include -#include -#include - -namespace mongo { - -/** - * Free Moniting Command line choices - */ -enum class EnableCloudStateEnum : std::int32_t { - kOn, - kOff, - kRuntime, -}; - -/** - * Free Monitoring configuration options - */ -struct FreeMonParams { - std::vector freeMonitoringTags; - EnableCloudStateEnum freeMonitoringState = EnableCloudStateEnum::kRuntime; -}; - -extern FreeMonParams globalFreeMonParams; - -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_options.idl b/src/mongo/db/free_mon/free_mon_options.idl deleted file mode 100644 index 906f6b20a0f..00000000000 --- a/src/mongo/db/free_mon/free_mon_options.idl +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (C) 2018-present MongoDB, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the Server Side Public License, version 1, -# as published by MongoDB, Inc. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# Server Side Public License for more details. -# -# You should have received a copy of the Server Side Public License -# along with this program. If not, see -# . -# -# As a special exception, the copyright holders give permission to link the -# code of portions of this program with the OpenSSL library under certain -# conditions as described in each individual source file and distribute -# linked combinations including the program with the OpenSSL library. You -# must comply with the Server Side Public License in all respects for -# all of the code used other than as permitted herein. If you modify file(s) -# with this exception, you may extend this exception to your version of the -# file(s), but you are not obligated to do so. If you do not wish to do so, -# delete this exception statement from your version. If you delete this -# exception statement from all source files in the program, then also delete -# it in the license file. -# - -global: - cpp_namespace: "mongo" - configs: - section: "Free Monitoring Options" - source: [ yaml, cli] - -imports: - - "mongo/db/basic_types.idl" - -configs: - # Command Line: --enableFreeMonitoring= - # YAML Name: cloud.monitoring.free= - cloud.monitoring.free.state: - description: "Enable Cloud Free Monitoring (on|runtime|off)" - short_name: enableFreeMonitoring - arg_vartype: String - - # Command Line: --enableFreeMonitoringTag=array - # YAML Name: cloud.monitoring.free.tag=array - cloud.monitoring.free.tags: - description: "Cloud Free Monitoring Tags" - short_name: freeMonitoringTag - arg_vartype: StringVector diff --git a/src/mongo/db/free_mon/free_mon_processor.cpp b/src/mongo/db/free_mon/free_mon_processor.cpp deleted file mode 100644 index 72554ac5ef0..00000000000 --- a/src/mongo/db/free_mon/free_mon_processor.cpp +++ /dev/null @@ -1,1048 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "mongo/base/checked_cast.h" -#include "mongo/base/data_range.h" -#include "mongo/base/error_codes.h" -#include "mongo/base/status.h" -#include "mongo/base/string_data.h" -#include "mongo/bson/bsonobj.h" -#include "mongo/db/free_mon/free_mon_processor.h" -#include "mongo/db/free_mon/free_mon_storage.h" -#include "mongo/db/operation_context.h" -#include "mongo/db/service_context.h" -#include "mongo/idl/idl_parser.h" -#include "mongo/logv2/log.h" -#include "mongo/logv2/log_attr.h" -#include "mongo/logv2/log_component.h" -#include "mongo/util/assert_util.h" -#include "mongo/util/future_impl.h" -#include "mongo/util/str.h" - -#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kControl - - -namespace mongo { - -namespace { - -constexpr auto kMinProtocolVersion = 1; -constexpr auto kMaxProtocolVersion = 2; -constexpr auto kStorageVersion = 1; - -constexpr auto kRegistrationIdMaxLength = 4096; -constexpr auto kInformationalURLMaxLength = 4096; -constexpr auto kInformationalMessageMaxLength = 4096; -constexpr auto kUserReminderMaxLength = 4096; - -constexpr auto kReportingIntervalSecondsMin = 1; -constexpr auto kReportingIntervalSecondsMax = 30 * 60 * 60 * 24; - -constexpr auto kMetricsRequestArrayElement = "data"_sd; - -int64_t randomJitter(PseudoRandom& random, int64_t min, int64_t max) { - dassert(max > min); - return (std::abs(random.nextInt64()) % (max - min)) + min; -} - -} // namespace - -void RegistrationRetryCounter::reset() { - _current = _min; - _base = _min; - _retryCount = 0; - _total = Hours(0); -} - -bool RegistrationRetryCounter::incrementError() { - if (_retryCount < kStage1RetryCountMax) { - _base = 2 * _base; - _current = _base + Seconds(randomJitter(_random, kStage1JitterMin, kStage1JitterMax)); - ++_retryCount; - } else { - _current = _base + Seconds(randomJitter(_random, kStage2JitterMin, kStage2JitterMax)); - } - - _total += _current; - - if (_total > kStage2DurationMax) { - return false; - } - - return true; -} - -void MetricsRetryCounter::reset() { - _current = _min; - _base = _min; - _retryCount = 0; - _total = Hours(0); -} - -bool MetricsRetryCounter::incrementError() { - _base = static_cast(pow(2, std::min(6, static_cast(_retryCount)))) * _min; - _current = _base + Seconds(randomJitter(_random, _min.count() / 2, _min.count())); - ++_retryCount; - - _total += _current; - - if (_total > kDurationMax) { - return false; - } - - return true; -} - -FreeMonProcessor::FreeMonProcessor(FreeMonCollectorCollection& registration, - FreeMonCollectorCollection& metrics, - FreeMonNetworkInterface* network, - bool useCrankForTest, - Seconds metricsGatherInterval) - : _registration(registration), - _metrics(metrics), - _network(network), - _random(Date_t::now().asInt64()), - _registrationRetry(RegistrationRetryCounter(_random)), - _metricsRetry(MetricsRetryCounter(_random)), - _metricsGatherInterval(metricsGatherInterval), - _queue(useCrankForTest) { - _registrationRetry->reset(); - _metricsRetry->reset(); -} - -void FreeMonProcessor::enqueue(std::shared_ptr msg) { - _queue.enqueue(std::move(msg)); -} - -void FreeMonProcessor::stop() { - _queue.stop(); -} - -void FreeMonProcessor::turnCrankForTest(size_t countMessagesToIgnore) { - _countdown.reset(countMessagesToIgnore); - - _queue.turnCrankForTest(countMessagesToIgnore); - - _countdown.wait(); -} - -void FreeMonProcessor::deprioritizeFirstMessageForTest(FreeMonMessageType type) { - _queue.deprioritizeFirstMessageForTest(type); -} - -void FreeMonProcessor::run() { - try { - - Client::initThread("FreeMonProcessor"); - Client* client = &cc(); - - // TODO(SERVER-74659): Please revisit if this thread could be made killable. - { - stdx::lock_guard lk(*client); - client->setSystemOperationUnkillableByStepdown(lk); - } - - while (true) { - auto item = _queue.dequeue(client->getServiceContext()->getPreciseClockSource()); - if (!item.has_value()) { - // Shutdown was triggered - return; - } - - auto msg = item.value(); - - // Do work here - switch (msg->getType()) { - case FreeMonMessageType::RegisterCommand: { - doCommandRegister(client, msg); - break; - } - case FreeMonMessageType::RegisterServer: { - doServerRegister( - client, - checked_cast< - FreeMonMessageWithPayload*>( - msg.get())); - break; - } - case FreeMonMessageType::UnregisterCommand: { - doCommandUnregister(client, - checked_cast*>(msg.get())); - break; - } - case FreeMonMessageType::AsyncRegisterComplete: { - doAsyncRegisterComplete( - client, - checked_cast< - FreeMonMessageWithPayload*>( - msg.get())); - break; - } - case FreeMonMessageType::AsyncRegisterFail: { - doAsyncRegisterFail( - client, - checked_cast< - FreeMonMessageWithPayload*>( - msg.get())); - break; - } - case FreeMonMessageType::MetricsCollect: { - doMetricsCollect(client); - break; - } - case FreeMonMessageType::MetricsSend: { - doMetricsSend(client); - break; - } - case FreeMonMessageType::AsyncMetricsComplete: { - doAsyncMetricsComplete( - client, - checked_cast< - FreeMonMessageWithPayload*>( - msg.get())); - break; - } - case FreeMonMessageType::AsyncMetricsFail: { - doAsyncMetricsFail( - client, - checked_cast< - FreeMonMessageWithPayload*>( - msg.get())); - break; - } - case FreeMonMessageType::OnTransitionToPrimary: { - doOnTransitionToPrimary(client); - break; - } - case FreeMonMessageType::NotifyOnUpsert: { - doNotifyOnUpsert( - client, - checked_cast< - FreeMonMessageWithPayload*>( - msg.get())); - break; - } - case FreeMonMessageType::NotifyOnDelete: { - doNotifyOnDelete(client); - break; - } - case FreeMonMessageType::NotifyOnRollback: { - doNotifyOnRollback(client); - break; - } - default: - MONGO_UNREACHABLE; - } - - // Record that we have finished processing the message for testing purposes. - _countdown.countDown(); - } - } catch (...) { - // Stop the queue - _queue.stop(); - - LOGV2_WARNING(20619, - "Uncaught exception in '{error}' in free monitoring subsystem. " - "Shutting down the free monitoring subsystem.", - "Uncaught exception in free monitoring subsystem. " - "Shutting down the free monitoring subsystem.", - "error"_attr = exceptionToStatus()); - } -} - -void FreeMonProcessor::readState(OperationContext* opCtx, bool updateInMemory) { - auto state = FreeMonStorage::read(opCtx); - - _lastReadState = state; - - if (state.has_value()) { - invariant(state.value().getVersion() == kStorageVersion); - - if (updateInMemory) { - _state = state.value(); - } - } else if (!state.has_value()) { - // Default the state - auto state = _state.synchronize(); - state->setVersion(kStorageVersion); - state->setState(StorageStateEnum::disabled); - state->setRegistrationId(""); - state->setInformationalURL(""); - state->setMessage(""); - state->setUserReminder(""); - } -} - -void FreeMonProcessor::readState(Client* client, bool updateInMemory) { - auto opCtx = client->makeOperationContext(); - readState(opCtx.get(), updateInMemory); -} - -void FreeMonProcessor::writeState(Client* client) { - - // Do a compare and swap - // Verify the document is the same as the one on disk, if it is the same, then do the update - // If the local document is different, then oh-well we do nothing, and wait until the next round - - // Has our in-memory state changed, if so consider writing - if (_lastReadState != _state.get()) { - - // The read and write are bound the same operation context - { - auto optCtx = client->makeOperationContext(); - - auto state = FreeMonStorage::read(optCtx.get()); - - // If our in-memory copy matches the last read, then write it to disk - if (state == _lastReadState) { - FreeMonStorage::replace(optCtx.get(), _state.get()); - - _lastReadState = boost::make_optional(_state.get()); - } - } - } -} - -void FreeMonProcessor::doServerRegister( - Client* client, const FreeMonMessageWithPayload* msg) { - - // Enqueue the first metrics gather first so we have something to send on intial registration - enqueue(FreeMonMessage::createNow(FreeMonMessageType::MetricsCollect)); - - // If we are asked to register now, then kick off a registration request - const auto regType = msg->getPayload().first; - if (regType == RegistrationType::RegisterOnStart) { - enqueue(FreeMonRegisterCommandMessage::createNow({msg->getPayload().second, boost::none})); - } else { - invariant((regType == RegistrationType::RegisterAfterOnTransitionToPrimary) || - (regType == RegistrationType::RegisterAfterOnTransitionToPrimaryIfEnabled)); - // Check if we need to wait to become primary: - // If the 'admin.system.version' has content, do not wait and just re-register - // If the collection is empty, wait until we become primary - // If we become secondary, OpObserver hooks will tell us our registration id - - auto optCtx = client->makeOperationContext(); - - // Check if there is an existing document - auto state = FreeMonStorage::read(optCtx.get()); - - // If there is no document, we may be: - // 1. in a replica set and may need to register after becoming primary since we cannot - // record the registration id until after becoming primary - // 2. a standalone which has never been registered - // - if (!state.has_value()) { - _registerOnTransitionToPrimary = regType; - } else { - // We are standalone or secondary, if we have a registration id, then send a - // registration notification, else wait for the user to register us. - if (state.value().getState() == StorageStateEnum::enabled) { - enqueue(FreeMonRegisterCommandMessage::createNow( - {msg->getPayload().second, boost::none})); - } - } - - // Ensure we read the state once. - // This is important on a disabled secondary so that the in-memory state knows we are - // disabled. - readState(optCtx.get()); - } -} - -namespace { -template -std::unique_ptr> doAsyncCallback(FreeMonProcessor* proc, - Future future, - std::function onSuccess, - std::function onErrorFunc) { - - // Grab a weak_ptr to be sure that FreeMonProcessor is alive during the callback - std::weak_ptr wpProc(proc->shared_from_this()); - - auto spError = std::make_shared(false); - - return std::make_unique>(std::move(future) - .onError([=](Status s) { - *(spError.get()) = true; - if (auto spProc = wpProc.lock()) { - onErrorFunc(s); - } - - return T(); - }) - .then([=](const auto& resp) { - // If we hit an error, then do not call onSuccess - if (*(spError.get()) == true) { - return; - } - - // Use a shared pointer here because the callback - // could return after we disappear - if (auto spProc = wpProc.lock()) { - onSuccess(resp); - } - })); -} -} // namespace - -void FreeMonProcessor::doCommandRegister(Client* client, - std::shared_ptr sharedMsg) { - auto msg = checked_cast(sharedMsg.get()); - - if (_futureRegistrationResponse) { - msg->setStatus(Status(ErrorCodes::FreeMonHttpInFlight, - "Free Monitoring Registration request in-flight already")); - return; - } - - _pendingRegisters.push_back(sharedMsg); - - readState(client); - - FreeMonRegistrationRequest req; - - if (msg->getPayload().second) { - req.setId(StringData(msg->getPayload().second.value())); - } else { - auto regid = _state->getRegistrationId(); - if (!regid.empty()) { - req.setId(regid); - } - } - - req.setVersion(kMaxProtocolVersion); - - req.setLocalTime(client->getServiceContext()->getPreciseClockSource()->now()); - - if (!msg->getPayload().first.empty()) { - // Cache the tags for subsequent retries - _tags = msg->getPayload().first; - } - - if (!_tags.empty()) { - req.setTags(transformVector(msg->getPayload().first)); - } - - // Collect the data - auto collect = _registration.collect(client); - - req.setPayload(std::get<0>(collect)); - - // Record that the registration is pending - _state->setState(StorageStateEnum::pending); - _registrationStatus = FreeMonRegistrationStatus::kPending; - - writeState(client); - - // Send the async request - _futureRegistrationResponse = doAsyncCallback( - this, - _network->sendRegistrationAsync(req), - [this](const auto& resp) { - this->enqueue( - FreeMonMessageWithPayload::createNow( - resp)); - }, - [this](Status s) { - this->enqueue( - FreeMonMessageWithPayload::createNow(s)); - }); -} - -Status FreeMonProcessor::validateRegistrationResponse(const FreeMonRegistrationResponse& resp) { - // Any validation failure stops registration from proceeding to upload - if (!(resp.getVersion() >= kMinProtocolVersion && resp.getVersion() <= kMaxProtocolVersion)) { - return Status(ErrorCodes::FreeMonHttpPermanentFailure, - str::stream() - << "Unexpected registration response protocol version, expected (" - << kMinProtocolVersion << ", " << kMaxProtocolVersion << "), received '" - << resp.getVersion() << "'"); - } - - if (resp.getId().size() >= kRegistrationIdMaxLength) { - return Status(ErrorCodes::FreeMonHttpPermanentFailure, - str::stream() << "Id is '" << resp.getId().size() - << "' bytes in length, maximum allowed length is '" - << kRegistrationIdMaxLength << "'"); - } - - if (resp.getInformationalURL().size() >= kInformationalURLMaxLength) { - return Status(ErrorCodes::FreeMonHttpPermanentFailure, - str::stream() << "InformationURL is '" << resp.getInformationalURL().size() - << "' bytes in length, maximum allowed length is '" - << kInformationalURLMaxLength << "'"); - } - - if (resp.getMessage().size() >= kInformationalMessageMaxLength) { - return Status(ErrorCodes::FreeMonHttpPermanentFailure, - str::stream() << "Message is '" << resp.getMessage().size() - << "' bytes in length, maximum allowed length is '" - << kInformationalMessageMaxLength << "'"); - } - - if (resp.getUserReminder().has_value() && - resp.getUserReminder().value().size() >= kUserReminderMaxLength) { - return Status(ErrorCodes::FreeMonHttpPermanentFailure, - str::stream() << "UserReminder is '" << resp.getUserReminder().value().size() - << "' bytes in length, maximum allowed length is '" - << kUserReminderMaxLength << "'"); - } - - if (resp.getReportingInterval() < kReportingIntervalSecondsMin || - resp.getReportingInterval() > kReportingIntervalSecondsMax) { - return Status(ErrorCodes::FreeMonHttpPermanentFailure, - str::stream() << "Reporting Interval '" << resp.getReportingInterval() - << "' must be in the range [" << kReportingIntervalSecondsMin - << "," << kReportingIntervalSecondsMax << "]"); - } - - // Did cloud ask us to stop uploading? - if (resp.getHaltMetricsUploading()) { - return Status(ErrorCodes::FreeMonHttpPermanentFailure, - str::stream() << "Halting metrics upload due to response"); - } - - return Status::OK(); -} - - -void FreeMonProcessor::notifyPendingRegisters(const Status s) { - for (auto&& pendingRegister : _pendingRegisters) { - (checked_cast(pendingRegister.get()))->setStatus(s); - } - _pendingRegisters.clear(); -} - - -Status FreeMonProcessor::validateMetricsResponse(const FreeMonMetricsResponse& resp) { - // Any validation failure stops registration from proceeding to upload - if (!(resp.getVersion() >= kMinProtocolVersion && resp.getVersion() <= kMaxProtocolVersion)) { - return Status(ErrorCodes::FreeMonHttpPermanentFailure, - str::stream() << "Unexpected metrics response protocol version, expected (" - << kMinProtocolVersion << ", " << kMaxProtocolVersion - << "), received '" << resp.getVersion() << "'"); - } - - if (resp.getId().has_value() && resp.getId().value().size() >= kRegistrationIdMaxLength) { - return Status(ErrorCodes::FreeMonHttpPermanentFailure, - str::stream() << "Id is '" << resp.getId().value().size() - << "' bytes in length, maximum allowed length is '" - << kRegistrationIdMaxLength << "'"); - } - - if (resp.getInformationalURL().has_value() && - resp.getInformationalURL().value().size() >= kInformationalURLMaxLength) { - return Status(ErrorCodes::FreeMonHttpPermanentFailure, - str::stream() - << "InformationURL is '" << resp.getInformationalURL().value().size() - << "' bytes in length, maximum allowed length is '" - << kInformationalURLMaxLength << "'"); - } - - if (resp.getMessage().has_value() && - resp.getMessage().value().size() >= kInformationalMessageMaxLength) { - return Status(ErrorCodes::FreeMonHttpPermanentFailure, - str::stream() << "Message is '" << resp.getMessage().value().size() - << "' bytes in length, maximum allowed length is '" - << kInformationalMessageMaxLength << "'"); - } - - if (resp.getUserReminder().has_value() && - resp.getUserReminder().value().size() >= kUserReminderMaxLength) { - return Status(ErrorCodes::FreeMonHttpPermanentFailure, - str::stream() << "UserReminder is '" << resp.getUserReminder().value().size() - << "' bytes in length, maximum allowed length is '" - << kUserReminderMaxLength << "'"); - } - - if (resp.getReportingInterval() < kReportingIntervalSecondsMin || - resp.getReportingInterval() > kReportingIntervalSecondsMax) { - return Status(ErrorCodes::FreeMonHttpPermanentFailure, - str::stream() << "Reporting Interval '" << resp.getReportingInterval() - << "' must be in the range [" << kReportingIntervalSecondsMin - << "," << kReportingIntervalSecondsMax << "]"); - } - - // Did cloud ask us to stop uploading? - if (resp.getHaltMetricsUploading()) { - return Status(ErrorCodes::FreeMonHttpPermanentFailure, - str::stream() << "Halting metrics upload due to response"); - } - - return Status::OK(); -} - - -void FreeMonProcessor::doAsyncRegisterComplete( - Client* client, - const FreeMonMessageWithPayload* msg) { - - // Our request is no longer in-progress so delete it - _futureRegistrationResponse.reset(); - - if (_registrationStatus != FreeMonRegistrationStatus::kPending) { - notifyPendingRegisters(Status(ErrorCodes::BadValue, "Registration was canceled")); - - return; - } - - auto& resp = msg->getPayload(); - - Status s = validateRegistrationResponse(resp); - if (!s.isOK()) { - LOGV2_WARNING(20620, - "Free Monitoring registration halted due to {error}", - "Free Monitoring registration halted due to error", - "error"_attr = s); - - // Disable on any error - _state->setState(StorageStateEnum::disabled); - _registrationStatus = FreeMonRegistrationStatus::kDisabled; - - // Persist state - writeState(client); - - notifyPendingRegisters(s); - - // If validation fails, we do not retry - return; - } - - // Update in-memory state - _registrationRetry->setMin(Seconds(resp.getReportingInterval())); - _metricsGatherInterval = Seconds(resp.getReportingInterval()); - - { - auto state = _state.synchronize(); - state->setRegistrationId(resp.getId()); - - if (resp.getUserReminder().has_value()) { - state->setUserReminder(resp.getUserReminder().value()); - } else { - state->setUserReminder(""); - } - - state->setMessage(resp.getMessage()); - state->setInformationalURL(resp.getInformationalURL()); - - state->setState(StorageStateEnum::enabled); - } - - _registrationStatus = FreeMonRegistrationStatus::kEnabled; - - // Persist state - writeState(client); - - // Reset retry counter - _registrationRetry->reset(); - - // Notify waiters - notifyPendingRegisters(Status::OK()); - - LOGV2(20615, - "Free Monitoring is Enabled. Frequency: {interval} seconds", - "Free Monitoring is Enabled", - "interval"_attr = resp.getReportingInterval()); - - // Enqueue next metrics upload immediately to deliver a good experience - enqueue(FreeMonMessage::createNow(FreeMonMessageType::MetricsSend)); -} - -void FreeMonProcessor::doAsyncRegisterFail( - Client* client, const FreeMonMessageWithPayload* msg) { - - // Our request is no longer in-progress so delete it - _futureRegistrationResponse.reset(); - - if (_registrationStatus != FreeMonRegistrationStatus::kPending) { - notifyPendingRegisters(Status(ErrorCodes::BadValue, "Registration was canceled")); - - return; - } - - if (!_registrationRetry->incrementError()) { - // We have exceeded our retry - LOGV2_WARNING(20621, "Free Monitoring is abandoning registration after excess retries"); - return; - } - - LOGV2_DEBUG(20616, - 1, - "Free Monitoring Registration Failed with status '{error}', retrying in {interval}", - "Free Monitoring Registration Failed, will retry after interval", - "error"_attr = msg->getPayload(), - "interval"_attr = _registrationRetry->getNextDuration()); - - // Enqueue a register retry - enqueue(FreeMonRegisterCommandMessage::createWithDeadline( - {_tags, boost::none}, _registrationRetry->getNextDeadline(client))); -} - -void FreeMonProcessor::doCommandUnregister( - Client* client, FreeMonWaitableMessageWithPayload* msg) { - // Treat this request as idempotent - readState(client); - - _state->setState(StorageStateEnum::disabled); - _registrationStatus = FreeMonRegistrationStatus::kDisabled; - - writeState(client); - - LOGV2(20617, "Free Monitoring is Disabled"); - - msg->setStatus(Status::OK()); -} - -void FreeMonProcessor::doMetricsCollect(Client* client) { - // Collect the time at the beginning so the time to collect does not affect the schedule - Date_t now = client->getServiceContext()->getPreciseClockSource()->now(); - - // Collect the data - auto collect = _metrics.collect(client); - - _metricsBuffer.push(std::get<0>(collect)); - - // Enqueue the next metrics collect based on when we started processing the last collection. - enqueue(FreeMonMessage::createWithDeadline(FreeMonMessageType::MetricsCollect, - now + _metricsGatherInterval)); -} - -std::string compressMetrics(MetricsBuffer& buffer) { - BSONObjBuilder builder; - - { - BSONArrayBuilder arrayBuilder(builder.subarrayStart(kMetricsRequestArrayElement)); - - for (const auto& obj : buffer) { - arrayBuilder.append(obj); - } - } - - BSONObj obj = builder.done(); - - std::string outBuffer; - snappy::Compress(obj.objdata(), obj.objsize(), &outBuffer); - - return outBuffer; -} - -void FreeMonProcessor::doMetricsSend(Client* client) { - // We want to read state from disk in case we asked to stop but otherwise - // use the in-memory state. It is important not to treat disk state as authoritative - // on secondaries. - readState(client, false); - - // Only continue metrics send if the local disk state (in-case user deleted local document) - // and in-memory status both say to continue. - if (_registrationStatus != FreeMonRegistrationStatus::kEnabled || - _state->getState() != StorageStateEnum::enabled) { - // If we are recently disabled, then stop sending metrics - return; - } - - // Build outbound request - FreeMonMetricsRequest req; - - req.setVersion(kMaxProtocolVersion); - req.setLocalTime(client->getServiceContext()->getPreciseClockSource()->now()); - req.setEncoding(MetricsEncodingEnum::snappy); - - req.setId(_state->getRegistrationId()); - - // Get the buffered metrics - auto metrics = compressMetrics(_metricsBuffer); - req.setMetrics(ConstDataRange(metrics.data(), metrics.size())); - - _lastMetricsSend = Date_t::now(); - - // Send the async request - doAsyncCallback( - this, - _network->sendMetricsAsync(req), - [this](const auto& resp) { - this->enqueue( - FreeMonMessageWithPayload::createNow( - resp)); - }, - [this](Status s) { - this->enqueue( - FreeMonMessageWithPayload::createNow(s)); - }); -} - -void FreeMonProcessor::doAsyncMetricsComplete( - Client* client, - const FreeMonMessageWithPayload* msg) { - - // If we have disabled the store between the metrics send message and the metrcs complete - // message then it means that we need to stop processing metrics on this instance. We ignore the - // message entirely including an errors as the disabling of the store takes priority. - if (_lastReadState == boost::none) { - return; - } - - auto& resp = msg->getPayload(); - - Status s = validateMetricsResponse(resp); - if (!s.isOK()) { - LOGV2_WARNING(20622, - "Free Monitoring metrics uploading halted due to {error}", - "Free Monitoring metrics uploading halted due to error", - "error"_attr = s); - - // Disable free monitoring on validation errors - _state->setState(StorageStateEnum::disabled); - _registrationStatus = FreeMonRegistrationStatus::kDisabled; - - writeState(client); - - // If validation fails, we do not retry - return; - } - - // If cloud said delete, not just halt, so erase state - if (resp.getPermanentlyDelete() == true) { - auto opCtxUnique = client->makeOperationContext(); - FreeMonStorage::deleteState(opCtxUnique.get()); - - _state->setState(StorageStateEnum::pending); - _registrationStatus = FreeMonRegistrationStatus::kDisabled; - - // Clear out the in-memory state - _lastReadState = boost::none; - - return; - } - - // Update in-memory state of buffered metrics - // TODO: do we reset only the metrics we send or all pending on success? - - _metricsBuffer.reset(); - - { - auto state = _state.synchronize(); - - if (resp.getId().has_value()) { - state->setRegistrationId(resp.getId().value()); - } - - if (resp.getUserReminder().has_value()) { - state->setUserReminder(resp.getUserReminder().value()); - } - - if (resp.getInformationalURL().has_value()) { - state->setInformationalURL(resp.getInformationalURL().value()); - } - - if (resp.getMessage().has_value()) { - state->setMessage(resp.getMessage().value()); - } - } - - // Persist state - writeState(client); - - // Reset retry counter - _metricsGatherInterval = Seconds(resp.getReportingInterval()); - _metricsRetry->setMin(Seconds(resp.getReportingInterval())); - _metricsRetry->reset(); - - if (resp.getResendRegistration().has_value() && resp.getResendRegistration()) { - enqueue(FreeMonRegisterCommandMessage::createNow({_tags, boost::none})); - } else { - // Enqueue next metrics upload - enqueue(FreeMonMessage::createWithDeadline(FreeMonMessageType::MetricsSend, - _metricsRetry->getNextDeadline(client))); - } -} - -void FreeMonProcessor::doAsyncMetricsFail( - Client* client, const FreeMonMessageWithPayload* msg) { - - if (!_metricsRetry->incrementError()) { - // We have exceeded our retry - LOGV2_WARNING(20623, "Free Monitoring is abandoning metrics upload after excess retries"); - return; - } - - LOGV2_DEBUG(20618, - 1, - "Free Monitoring Metrics upload failed with status {error}, retrying in {interval}", - "Free Monitoring Metrics upload failed, will retry after interval", - "error"_attr = msg->getPayload(), - "interval"_attr = _metricsRetry->getNextDuration()); - - // Enqueue next metrics upload - enqueue(FreeMonMessage::createWithDeadline(FreeMonMessageType::MetricsSend, - _metricsRetry->getNextDeadline(client))); -} - -void FreeMonProcessor::getStatus(OperationContext* opCtx, - BSONObjBuilder* status, - FreeMonGetStatusEnum mode) { - if (!_lastReadState.get()) { - // _state gets initialized by readState() regardless, - // use _lastReadState to differential "undecided" from default. - status->append("state", "undecided"); - return; - } - - if (mode == FreeMonGetStatusEnum::kServerStatus) { - status->append("state", StorageState_serializer(_state->getState())); - status->append("retryIntervalSecs", - durationCount(_metricsRetry->getNextDuration())); - auto lastMetricsSend = _lastMetricsSend.get(); - if (lastMetricsSend) { - status->append("lastRunTime", lastMetricsSend->toString()); - } - status->append("registerErrors", static_cast(_registrationRetry->getCount())); - status->append("metricsErrors", static_cast(_metricsRetry->getCount())); - } else { - auto state = _state.synchronize(); - status->append("state", StorageState_serializer(state->getState())); - status->append("message", state->getMessage()); - status->append("url", state->getInformationalURL()); - status->append("userReminder", state->getUserReminder()); - } -} - -void FreeMonProcessor::doOnTransitionToPrimary(Client* client) { - if (_registerOnTransitionToPrimary == RegistrationType::RegisterAfterOnTransitionToPrimary) { - enqueue( - FreeMonRegisterCommandMessage::createNow({std::vector(), boost::none})); - - } else if (_registerOnTransitionToPrimary == - RegistrationType::RegisterAfterOnTransitionToPrimaryIfEnabled) { - readState(client); - if (_state->getState() == StorageStateEnum::enabled) { - enqueue(FreeMonRegisterCommandMessage::createNow( - {std::vector(), boost::none})); - } - } - - // On transition to primary once - _registerOnTransitionToPrimary = RegistrationType::DoNotRegister; -} - -void FreeMonProcessor::processInMemoryStateChange(const FreeMonStorageState& originalState, - const FreeMonStorageState& newState) { - // Are we transition from disabled -> enabled? - if (originalState.getState() != newState.getState()) { - if (originalState.getState() != StorageStateEnum::enabled && - newState.getState() == StorageStateEnum::enabled) { - - // Secondary needs to start registration - enqueue(FreeMonRegisterCommandMessage::createNow( - {std::vector(), newState.getRegistrationId().toString()})); - } - } -} - -void FreeMonProcessor::doNotifyOnUpsert( - Client* client, const FreeMonMessageWithPayload* msg) { - try { - const BSONObj& doc = msg->getPayload(); - auto newState = FreeMonStorageState::parse(IDLParserContext("free_mon_storage"), doc); - - // Likely, the update changed something - if (newState != _state) { - uassert(50839, - str::stream() << "Unexpected free monitoring storage version " - << newState.getVersion(), - newState.getVersion() == kStorageVersion); - - processInMemoryStateChange(_state.get(), newState); - - // Note: enabled -> disabled is handled implicitly by register and send metrics checks - // after _state is updated below - - // Copy the fields - _state = newState; - } - - } catch (...) { - - // Stop the queue - _queue.stop(); - - LOGV2_WARNING(20624, - "Uncaught exception in '{exception}' in free monitoring op observer. " - "Shutting down the free monitoring subsystem.", - "exception"_attr = exceptionToStatus()); - } -} - -void FreeMonProcessor::doNotifyOnDelete(Client* client) { - // The config document was either deleted or the entire collection was dropped, we treat them - // the same and stop free monitoring. We continue collecting though. - - // So we mark the internal state as disabled which stop registration and metrics send - _state->setState(StorageStateEnum::pending); - _registrationStatus = FreeMonRegistrationStatus::kDisabled; - - // Clear out the in-memory state - _lastReadState = boost::none; -} - -void FreeMonProcessor::doNotifyOnRollback(Client* client) { - // We have rolled back, the state on disk reflects our new reality - // We should re-read the disk state and proceed. - - // copy the in-memory state - auto originalState = _state.get(); - - // Re-read state from disk - readState(client); - - auto newState = _state.get(); - - if (newState != originalState) { - processInMemoryStateChange(originalState, newState); - } -} - - -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_processor.h b/src/mongo/db/free_mon/free_mon_processor.h deleted file mode 100644 index a31f1fbb0a3..00000000000 --- a/src/mongo/db/free_mon/free_mon_processor.h +++ /dev/null @@ -1,541 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ -#pragma once - -#include -#include -#include -#include -#include -// IWYU pragma: no_include "cxxabi.h" -#include -#include -#include -#include -#include -#include -#include - -#include "mongo/base/status.h" -#include "mongo/bson/bsonobj.h" -#include "mongo/bson/bsonobjbuilder.h" -#include "mongo/db/client.h" -#include "mongo/db/free_mon/free_mon_message.h" -#include "mongo/db/free_mon/free_mon_network.h" -#include "mongo/db/free_mon/free_mon_processor.h" -#include "mongo/db/free_mon/free_mon_protocol_gen.h" -#include "mongo/db/free_mon/free_mon_queue.h" -#include "mongo/db/free_mon/free_mon_storage_gen.h" -#include "mongo/db/ftdc/collector.h" -#include "mongo/db/service_context.h" -#include "mongo/platform/mutex.h" -#include "mongo/platform/random.h" -#include "mongo/stdx/condition_variable.h" -#include "mongo/util/assert_util_core.h" -#include "mongo/util/clock_source.h" -#include "mongo/util/duration.h" -#include "mongo/util/future.h" -#include "mongo/util/synchronized_value.h" -#include "mongo/util/time_support.h" - -namespace mongo { -using FreeMonCollectorInterface = FTDCCollectorInterface; -using FreeMonCollectorCollection = FTDCCollectorCollection; - - -/** - * Reponsible for tracking when to send the next retry after errors are encountered. - */ -class RetryCounter { - const int64_t kMax = 60 * 60 * 24; - -public: - RetryCounter() : _min(1), _max(kMax) {} - virtual ~RetryCounter() = default; - - /** - * Set Minimum rety interval - */ - void setMin(Seconds s) { - _min = s; - reset(); - } - - /** - * Reset the retry interval, typically occurs after a succesfull message is sent. - */ - virtual void reset() = 0; - - /** - * Increment the error count and compute the next interval. - */ - virtual bool incrementError() = 0; - - /** - * Get the next retry duration. - */ - Seconds getNextDuration() const { - dassert(_current != Seconds(0)); - return _current; - } - - /** - * Get the next retry deadline - */ - Date_t getNextDeadline(Client* client) const { - return client->getServiceContext()->getPreciseClockSource()->now() + _current; - } - -protected: - // Current retry interval - Seconds _current; - - // Minimum retry interval - Seconds _min; - - // Maximum retry interval - Seconds _max; -}; - -/** - * Manage retries for registrations - */ -class RegistrationRetryCounter : public RetryCounter { -public: - explicit RegistrationRetryCounter(PseudoRandom& random) : _random(random) {} - - void reset() final; - - bool incrementError() final; - - size_t getCount() const { - return _retryCount; - } - -private: - // Random number generator for jitter - PseudoRandom& _random; - - // Retry count for stage 1 retry - size_t _retryCount{0}; - - // Total Seconds we have retried for - Seconds _total; - - // Last retry interval without jitter - Seconds _base; - - // Max Retry count - const size_t kStage1RetryCountMax{10}; - - const size_t kStage1JitterMin{2}; - const size_t kStage1JitterMax{10}; - - const Hours kStage2DurationMax{48}; - - const size_t kStage2JitterMin{60}; - const size_t kStage2JitterMax{120}; -}; - -/** - * Manage retries for metrics - */ -class MetricsRetryCounter : public RetryCounter { -public: - explicit MetricsRetryCounter(PseudoRandom& random) : _random(random) {} - - void reset() final; - - bool incrementError() final; - - size_t getCount() const { - return _retryCount; - } - -private: - // Random number generator for jitter - PseudoRandom& _random; - - // Retry count for stage 1 retry - size_t _retryCount{0}; - - // Total Seconds we have retried for - Seconds _total; - - // Last retry interval without jitter - Seconds _base; - - // Max Duration - const Hours kDurationMax{7 * 24}; -}; - -/** - * Simple bounded buffer of metrics to upload. - */ -class MetricsBuffer { -public: - using container_type = std::deque; - - /** - * Add a metric to the buffer. Oldest metric will be discarded if buffer is at capacity. - */ - void push(BSONObj obj) { - if (_queue.size() == kMaxElements) { - _queue.pop_front(); - } - - _queue.push_back(obj); - } - - /** - * Flush the buffer down to kMinElements entries. The last entries are held for cloud. - */ - void reset() { - while (_queue.size() > kMinElements) { - _queue.pop_front(); - } - } - - container_type::iterator begin() { - return _queue.begin(); - } - container_type::iterator end() { - return _queue.end(); - } - -private: - // Bounded queue of metrics - container_type _queue; - - const size_t kMinElements = 1; - const size_t kMaxElements = 10; -}; - -/** - * Countdown latch for test support in FreeMonProcessor so that a crank can be turned manually. - */ -class FreeMonCountdownLatch { -public: - explicit FreeMonCountdownLatch() : _count(0) {} - - /** - * Reset countdown latch wait for N events. - */ - void reset(uint32_t count) { - stdx::lock_guard lock(_mutex); - dassert(_count == 0); - dassert(count > 0); - _count = count; - } - - /** - * Count down an event. - */ - void countDown() { - stdx::lock_guard lock(_mutex); - - if (_count > 0) { - --_count; - if (_count == 0) { - _condvar.notify_one(); - } - } - } - - /** - * Wait until the N events specified in reset have occured. - */ - void wait() { - stdx::unique_lock lock(_mutex); - _condvar.wait(lock, [&] { return _count == 0; }); - } - -private: - // mutex to break count and cond var - Mutex _mutex = MONGO_MAKE_LATCH("FreeMonCountdownLatch::_mutex"); - - // cond var to signal and wait on - stdx::condition_variable _condvar; - - // count of events to wait for - size_t _count; -}; - -/** - * In-memory registration status - * - * Ensures primaries and secondaries register separately - */ -enum class FreeMonRegistrationStatus { - /** - * Free monitoring is not enabled - default state. - */ - kDisabled, - - /** - * Registration in progress. - */ - kPending, - - /** - * Free Monitoring is enabled. - */ - kEnabled, -}; - -/** - * Process in an Agent in a Agent/Message Passing model. - * - * Messages are given to it by enqueue, and the Processor processes messages with run(). - */ -class FreeMonProcessor : public std::enable_shared_from_this { -public: - FreeMonProcessor(FreeMonCollectorCollection& registration, - FreeMonCollectorCollection& metrics, - FreeMonNetworkInterface* network, - bool useCrankForTest, - Seconds metricsGatherInterval); - - /** - * Enqueue a message to process - */ - void enqueue(std::shared_ptr msg); - - /** - * Stop processing messages. - */ - void stop(); - - /** - * Turn the crank of the message queue by ignoring deadlines for N messages. - */ - void turnCrankForTest(size_t countMessagesToIgnore); - - /** - * Deproritize the first message to force interleavings of messages. - */ - void deprioritizeFirstMessageForTest(FreeMonMessageType type); - - /** - * Processes messages forever - */ - void run(); - - /** - * Validate the registration response. Public for unit testing. - */ - static Status validateRegistrationResponse(const FreeMonRegistrationResponse& resp); - - /** - * Validate the metrics response. Public for unit testing. - */ - static Status validateMetricsResponse(const FreeMonMetricsResponse& resp); - -private: - /** - * Read the state from the database. - * - * Checks if the storage document has been delete locally or does not exist. If it is missing, - * generates a default disable state. - * - * If updateInMemory is true, update the state in memory with the state from disk. If false, do - * not update the state in memory from disk but instead treat the state in memory as - * authoritative. The is important for secondaries which may be in a different state for - * regsistration then there primary. - */ - void readState(OperationContext* opCtx, bool updateInMemory = true); - - /** - * Create a short-lived opCtx and read the state from the database. - */ - void readState(Client* client, bool updateInMemory = true); - - /** - * Write the state to disk if there are any changes. - */ - void writeState(Client* client); - - /** - * Process a registration from a command. - */ - void doCommandRegister(Client* client, std::shared_ptr sharedMsg); - - /** - * Process a registration from configuration. - */ - void doServerRegister(Client* client, - const FreeMonMessageWithPayload* msg); - - /** - * Process unregistration from a command. - */ - void doCommandUnregister( - Client* client, - FreeMonWaitableMessageWithPayload* msg); - - /** - * Process a successful HTTP request. - */ - void doAsyncRegisterComplete( - Client* client, - const FreeMonMessageWithPayload* msg); - - /** - * Process an unsuccessful HTTP request. - */ - void doAsyncRegisterFail( - Client* client, - const FreeMonMessageWithPayload* msg); - - /** - * Notify any command registers that are waiting. - */ - void notifyPendingRegisters(Status s); - - /** - * Upload collected metrics. - */ - void doMetricsCollect(Client* client); - - /** - * Upload gathered metrics. - */ - void doMetricsSend(Client* client); - - /** - * Process a successful HTTP request. - */ - void doAsyncMetricsComplete( - Client* client, - const FreeMonMessageWithPayload* msg); - - /** - * Process an unsuccessful HTTP request. - */ - void doAsyncMetricsFail( - Client* client, const FreeMonMessageWithPayload* msg); - - /** - * Process a change to become a replica set primary - */ - void doOnTransitionToPrimary(Client* client); - - /** - * Process a notification that storage has received insert or update. - */ - void doNotifyOnUpsert(Client* client, - const FreeMonMessageWithPayload* msg); - - /** - * Process a notification that storage has received delete or drop collection. - */ - void doNotifyOnDelete(Client* client); - - - /** - * Process a notification that storage has rolled back. - */ - void doNotifyOnRollback(Client* client); - - /** - * Process a in-memory state transition of state. - */ - void processInMemoryStateChange(const FreeMonStorageState& originalState, - const FreeMonStorageState& newState); - -protected: - friend class FreeMonController; - - enum FreeMonGetStatusEnum { - kServerStatus, - kCommandStatus, - }; - - /** - * Populate results for getFreeMonitoringStatus or serverStatus commands. - */ - void getStatus(OperationContext* opCtx, BSONObjBuilder* status, FreeMonGetStatusEnum mode); - -private: - // Collection of collectors to send on registration - FreeMonCollectorCollection& _registration; - - // Collection of collectors to send on each metrics call - FreeMonCollectorCollection& _metrics; - - // HTTP Network interface - FreeMonNetworkInterface* _network; - - // Random number generator for retries - PseudoRandom _random; - - // Registration Retry logic - synchronized_value _registrationRetry; - - // Metrics Retry logic - synchronized_value _metricsRetry; - - // Interval for gathering metrics - Seconds _metricsGatherInterval; - - // Buffer of metrics to upload - MetricsBuffer _metricsBuffer; - - // When did we last send a metrics batch? - synchronized_value> _lastMetricsSend; - - // List of tags from server configuration registration - std::vector _tags; - - // In-flight registration response - std::unique_ptr> _futureRegistrationResponse; - - // List of command registers waiting to be told about registration - std::vector> _pendingRegisters; - - // Last read storage state - synchronized_value> _lastReadState; - - // When we change to primary, do we register? - RegistrationType _registerOnTransitionToPrimary{RegistrationType::DoNotRegister}; - - // Pending update to disk - synchronized_value _state; - - // In-memory registration status - FreeMonRegistrationStatus _registrationStatus{FreeMonRegistrationStatus::kDisabled}; - - // Countdown launch to support manual cranking - FreeMonCountdownLatch _countdown; - - // Message queue - FreeMonMessageQueue _queue; -}; - -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_protocol.idl b/src/mongo/db/free_mon/free_mon_protocol.idl deleted file mode 100644 index 7f24df4b085..00000000000 --- a/src/mongo/db/free_mon/free_mon_protocol.idl +++ /dev/null @@ -1,149 +0,0 @@ -# Copyright (C) 2018-present MongoDB, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the Server Side Public License, version 1, -# as published by MongoDB, Inc. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# Server Side Public License for more details. -# -# You should have received a copy of the Server Side Public License -# along with this program. If not, see -# . -# -# As a special exception, the copyright holders give permission to link the -# code of portions of this program with the OpenSSL library under certain -# conditions as described in each individual source file and distribute -# linked combinations including the program with the OpenSSL library. You -# must comply with the Server Side Public License in all respects for -# all of the code used other than as permitted herein. If you modify file(s) -# with this exception, you may extend this exception to your version of the -# file(s), but you are not obligated to do so. If you do not wish to do so, -# delete this exception statement from your version. If you delete this -# exception statement from all source files in the program, then also delete -# it in the license file. -# -global: - cpp_namespace: "mongo" - -imports: - - "mongo/db/basic_types.idl" - - -enums: - MetricsEncoding: - description: "Metrics Encoding Methods" - type: string - values: - snappy: "snappy" - - -structs: - FreeMonRegistrationRequest: - description: "Registration Request to Cloud Server" - fields: - version: - description: "Protocol version, initial version is 1" - type: long - payload: - description: "Payload of registration information" - type: object - id: - description: "Existing Registration Id" - type: string - optional: true - localTime: - description: "Local time at registration send" - type: date - tags: - description: "Tags" - type: array - optional: true - - FreeMonRegistrationResponse: - description: "Registration Response from Cloud Server" - fields: - version: - description: "Protocol version, initial version is 1" - type: long - haltMetricsUploading: - description: "True indicates it should not proceed to metrics uploading" - type: bool - id: - description: "Existing Registration Id" - type: string - informationalURL: - description: "Informational HTTP web page for metrics" - type: string - message: - description: "Informational message for shell to display to user" - type: string - reportingInterval: - description: "Metrics Reporting interval in seconds" - type: long - userReminder: - description: "Informational message to display to user to remind them about the service" - type: string - optional: true - - - FreeMonMetricsRequest: - description: "Metrics Request to Cloud Server" - fields: - version: - description: "Protocol version, initial version is 1" - type: long - id: - description: "Registration Id" - type: string - localTime: - description: "Local time at metrics send" - type: date - encoding: - description: "Compression Encoding" - type: MetricsEncoding - metrics: - description: "Metrics Blob" - type: bindata_generic - - # History - # ------- - # Version 2 - added resendRegistration bool - # - FreeMonMetricsResponse: - description: "Metrics Response from Cloud Server" - fields: - version: - description: "Protocol version, initial version is 1" - type: long - haltMetricsUploading: - description: "True indicates it should not proceed to metrics uploading" - type: bool - permanentlyDelete: - description: "True indicates it permanently delete the local state" - type: bool - reportingInterval: - description: "Metrics Reporting interval in seconds" - type: long - id: - description: "Existing Registration Id" - type: string - optional: true - message: - description: "Informational message for shell to display to user" - type: string - optional: true - informationalURL: - description: "Informational HTTP web page for metrics" - type: string - optional: true - userReminder: - description: "Message to display to user to remind them about service" - type: string - optional: true - resendRegistration: - description: "If true, resend registration to server" - type: bool - optional: true diff --git a/src/mongo/db/free_mon/free_mon_queue.cpp b/src/mongo/db/free_mon/free_mon_queue.cpp deleted file mode 100644 index 322257bf8d3..00000000000 --- a/src/mongo/db/free_mon/free_mon_queue.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include -#include -#include -// IWYU pragma: no_include "cxxabi.h" -#include -#include -#include - -#include "mongo/base/status.h" -#include "mongo/db/free_mon/free_mon_queue.h" -#include "mongo/util/assert_util.h" -#include "mongo/util/concurrency/idle_thread_block.h" -#include "mongo/util/duration.h" - -namespace mongo { - -std::shared_ptr FreeMonPriorityQueue::top() const { - return _vector.front(); -} - -void FreeMonPriorityQueue::pop() { - std::pop_heap(_vector.begin(), _vector.end(), _comp); - _vector.pop_back(); -} - -void FreeMonPriorityQueue::push(std::shared_ptr item) { - _vector.push_back(item); - std::push_heap(_vector.begin(), _vector.end(), _comp); -} - -void FreeMonPriorityQueue::eraseByType(FreeMonMessageType type) { - - while (true) { - auto it = std::find_if(_vector.begin(), _vector.end(), [type](const auto& item) { - return item->getType() == type; - }); - - if (it == _vector.end()) { - break; - } - - _vector.erase(it); - } - - std::make_heap(_vector.begin(), _vector.end(), _comp); -} - - -FreeMonMessage::~FreeMonMessage() {} - -void FreeMonMessageQueue::enqueue(std::shared_ptr msg) { - { - stdx::lock_guard lock(_mutex); - - // If we were stopped, drop messages - if (_stop) { - return; - } - - ++_counter; - msg->setId(_counter); - - if (msg->getType() == FreeMonMessageType::MetricsSend) { - _queue.eraseByType(FreeMonMessageType::MetricsSend); - } - - _queue.push(msg); - - // Signal the dequeue - _condvar.notify_one(); - } -} - -void FreeMonMessageQueue::deprioritizeFirstMessageForTest(FreeMonMessageType type) { - { - stdx::lock_guard lock(_mutex); - - auto item = _queue.top(); - uassert(5167902, "Wrong message type", item->getType() == type); - - _queue.pop(); - - ++_counter; - item->setId(_counter); - _queue.push(item); - } -} - -boost::optional> FreeMonMessageQueue::dequeue( - ClockSource* clockSource) { - { - stdx::unique_lock lock(_mutex); - if (_stop) { - return {}; - } - - while (true) { - Date_t deadlineCV = Date_t::max(); - if (_useCrank) { - if (!_queue.empty() && _countMessagesIgnored < _countMessagesToIgnore) { - // For testing purposes, ignore the deadline - deadlineCV = Date_t(); - } else { - deadlineCV = clockSource->now() + Hours(1); - } - } else { - if (!_queue.empty()) { - deadlineCV = _queue.top()->getDeadline(); - } else { - deadlineCV = clockSource->now() + Hours(24); - } - } - - MONGO_IDLE_THREAD_BLOCK; - - _condvar.wait_until(lock, deadlineCV.toSystemTimePoint(), [this, clockSource]() { - if (_stop) { - return true; - } - - if (this->_queue.empty()) { - return false; - } - - // Always wake in test mode - if (_useCrank) { - if (_countMessagesIgnored < _countMessagesToIgnore) { - return true; - } else { - dassert(_countMessagesIgnored == _countMessagesToIgnore); - return false; - } - } - - auto deadlineMessage = this->_queue.top()->getDeadline(); - if (deadlineMessage <= Date_t()) { - return true; - } - - auto now = clockSource->now(); - - bool check = deadlineMessage < now; - return check; - }); - - if (_stop) { - return {}; - } - - // We were woken-up by a message being enqueue, go back to sleep and wait until crank is - // installed and turned. - if (_useCrank) { - if (_countMessagesIgnored == _countMessagesToIgnore) { - continue; - } - - dassert(_countMessagesIgnored <= _countMessagesToIgnore); - } - - // If the queue is not empty, return the message - // otherwise we need to go back to sleep in the hope we get a message. - if (!_queue.empty()) { - break; - } else if (_useCrank) { - dassert(0, "Was asked to wait for more messages then available"); - } - } - - _countMessagesIgnored++; - if (_useCrank && _countMessagesIgnored == _countMessagesToIgnore && _waitable) { - _waitable->set(Status::OK()); - } - - auto item = _queue.top(); - _queue.pop(); - return item; - } -} - -void FreeMonMessageQueue::stop() { - { - stdx::lock_guard lock(_mutex); - - // We can be stopped twice in some situations: - // 1. Stop on unexpected error - // 2. Stop on clean shutdown - if (_stop == false) { - _stop = true; - _condvar.notify_one(); - } - } -} - -void FreeMonMessageQueue::turnCrankForTest(size_t countMessagesToIgnore) { - invariant(_useCrank); - - { - stdx::lock_guard lock(_mutex); - - _waitable = std::make_unique(); - - _countMessagesIgnored = 0; - _countMessagesToIgnore = countMessagesToIgnore; - - _condvar.notify_one(); - } - - //_waitable->wait_for(Seconds(10)); -} -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_queue.h b/src/mongo/db/free_mon/free_mon_queue.h deleted file mode 100644 index 0311d5f79b8..00000000000 --- a/src/mongo/db/free_mon/free_mon_queue.h +++ /dev/null @@ -1,172 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mongo/db/free_mon/free_mon_message.h" -#include "mongo/platform/mutex.h" -#include "mongo/stdx/condition_variable.h" -#include "mongo/util/clock_source.h" -#include "mongo/util/time_support.h" - -namespace mongo { - -/** - * Comparator for FreeMonMessage that will sort smallest deadlines at the beginning of a priority - * queue. The std::priority_queue is a max-heap. - */ -struct FreeMonMessageGreater { - bool operator()(const std::shared_ptr& left, - const std::shared_ptr& right) const { - if (left->getDeadline() > right->getDeadline()) { - return true; - } - - if (left->getDeadline() == right->getDeadline()) { - return left->getId() > right->getId(); - } - - return false; - } -}; - -/** - * Priority Queue with ability to remove items by filter. - */ -class FreeMonPriorityQueue { -public: - bool empty() const { - return _vector.empty(); - } - - /** - * Return the message at the top of the priority queue. - */ - std::shared_ptr top() const; - - /** - * Pop the message at the top of the priority queue. - */ - void pop(); - - /** - * Push a message into the priority queue. - */ - void push(std::shared_ptr item); - - /** - * Erase messages of a given type from the queue. - */ - void eraseByType(FreeMonMessageType type); - -private: - // Using shared_ptr because std::pop_heap does not support move-only types - std::vector> _vector; - FreeMonMessageGreater _comp; -}; - -/** - * A multi-producer, single-consumer queue with deadlines. - * - * The smallest deadline sorts first. Messages with deadlines can be use as a timer mechanism. - */ -class FreeMonMessageQueue { -public: - FreeMonMessageQueue(bool useCrankForTest = false) : _useCrank(useCrankForTest) {} - - /** - * Enqueue a message and wake consumer if needed. - * - * Messages are dropped if the queue has been stopped. - */ - void enqueue(std::shared_ptr msg); - - /** - * Deque a message from the queue. - * - * Waits for a message to arrive. Returns boost::none if the queue has been stopped. - */ - boost::optional> dequeue(ClockSource* clockSource); - - /** - * Stop the queue. - */ - void stop(); - - /** - * Turn the crank of the message queue by ignoring deadlines for N messages. - */ - void turnCrankForTest(size_t countMessagesToIgnore); - - /** - * Deproritize the first message to force interleavings of messages. - */ - void deprioritizeFirstMessageForTest(FreeMonMessageType type); - -private: - // Condition variable to signal consumer - stdx::condition_variable _condvar; - - // Lock for condition variable and to protect state - Mutex _mutex = MONGO_MAKE_LATCH("FreeMonMessageQueue::_mutex"); - - // Indicates whether queue has been stopped. - bool _stop{false}; - - // Priority queue of messages with shortest deadline first - FreeMonPriorityQueue _queue; - - // Use manual crank to process messages in-order instead of based on deadlines. - bool _useCrank{false}; - - // Stamp each message with a unique counter. This ensures that if two messages are queued with - // the same deadline, FIFO is achieved. - uint64_t _counter{0}; - - // Number of messages to ignore - size_t _countMessagesToIgnore{0}; - - // Number of messages that have been ignored - size_t _countMessagesIgnored{0}; - - // Waitable result for testing - std::unique_ptr _waitable; -}; - - -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_queue_test.cpp b/src/mongo/db/free_mon/free_mon_queue_test.cpp deleted file mode 100644 index 7903a94dc82..00000000000 --- a/src/mongo/db/free_mon/free_mon_queue_test.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include -#include - -#include - -#include "mongo/base/status_with.h" -#include "mongo/base/string_data.h" -#include "mongo/db/client.h" -#include "mongo/db/free_mon/free_mon_message.h" -#include "mongo/db/free_mon/free_mon_queue.h" -#include "mongo/db/operation_context.h" -#include "mongo/db/service_context.h" -#include "mongo/db/service_context_d_test_fixture.h" -#include "mongo/executor/network_interface_mock.h" -#include "mongo/executor/task_executor.h" -#include "mongo/executor/thread_pool_task_executor.h" -#include "mongo/executor/thread_pool_task_executor_test_fixture.h" -#include "mongo/unittest/assert.h" -#include "mongo/unittest/barrier.h" -#include "mongo/unittest/framework.h" -#include "mongo/util/duration.h" -#include "mongo/util/time_support.h" - -namespace mongo { -namespace { - -class FreeMonQueueTest : public ServiceContextMongoDTest { -private: - void setUp() final; - void tearDown() final; - -protected: - ServiceContext::UniqueOperationContext _opCtx; - - executor::NetworkInterfaceMock* _mockNetwork{nullptr}; - - std::unique_ptr _mockThreadPool; -}; - -void FreeMonQueueTest::setUp() { - ServiceContextMongoDTest::setUp(); - - // Set up a NetworkInterfaceMock. Note, unlike NetworkInterfaceASIO, which has its own pool of - // threads, tasks in the NetworkInterfaceMock must be carried out synchronously by the (single) - // thread the unit test is running on. - auto netForFixedTaskExecutor = std::make_unique(); - _mockNetwork = netForFixedTaskExecutor.get(); - - // Set up a ThreadPoolTaskExecutor. Note, for local tasks this TaskExecutor uses a - // ThreadPoolMock, and for remote tasks it uses the NetworkInterfaceMock created above. However, - // note that the ThreadPoolMock uses the NetworkInterfaceMock's threads to run tasks, which is - // again just the (single) thread the unit test is running on. Therefore, all tasks, local and - // remote, must be carried out synchronously by the test thread. - _mockThreadPool = makeThreadPoolTestExecutor(std::move(netForFixedTaskExecutor)); - - _mockThreadPool->startup(); - - _opCtx = cc().makeOperationContext(); -} - -void FreeMonQueueTest::tearDown() { - _opCtx = {}; - - ServiceContextMongoDTest::tearDown(); -} - -// Postive: Can we enqueue and dequeue one item -TEST_F(FreeMonQueueTest, TestBasic) { - FreeMonMessageQueue queue; - - queue.enqueue(FreeMonMessage::createNow(FreeMonMessageType::RegisterServer)); - - auto item = queue.dequeue(_opCtx.get()->getServiceContext()->getPreciseClockSource()); - - ASSERT(item.value()->getType() == FreeMonMessageType::RegisterServer); -} - -Date_t fromNow(int millis) { - return getGlobalServiceContext()->getPreciseClockSource()->now() + Milliseconds(millis); -} - -// Positive: Ensure deadlines sort properly -TEST_F(FreeMonQueueTest, TestDeadlinePriority) { - FreeMonMessageQueue queue; - - queue.enqueue( - FreeMonMessage::createWithDeadline(FreeMonMessageType::RegisterServer, fromNow(5000))); - queue.enqueue( - FreeMonMessage::createWithDeadline(FreeMonMessageType::RegisterCommand, fromNow(50))); - - auto item = queue.dequeue(_opCtx.get()->getServiceContext()->getPreciseClockSource()).value(); - ASSERT(item->getType() == FreeMonMessageType::RegisterCommand); - - item = queue.dequeue(_opCtx.get()->getServiceContext()->getPreciseClockSource()).value(); - ASSERT(item->getType() == FreeMonMessageType::RegisterServer); -} - -// Positive: Ensure deadlines sort properly when they have the same deadlines -TEST_F(FreeMonQueueTest, TestFIFO) { - FreeMonMessageQueue queue; - - queue.enqueue(FreeMonMessage::createWithDeadline(FreeMonMessageType::RegisterServer, Date_t())); - queue.enqueue( - FreeMonMessage::createWithDeadline(FreeMonMessageType::AsyncRegisterComplete, Date_t())); - queue.enqueue( - FreeMonMessage::createWithDeadline(FreeMonMessageType::RegisterCommand, Date_t())); - - auto item = queue.dequeue(_opCtx.get()->getServiceContext()->getPreciseClockSource()).value(); - ASSERT(item->getType() == FreeMonMessageType::RegisterServer); - - item = queue.dequeue(_opCtx.get()->getServiceContext()->getPreciseClockSource()).value(); - ASSERT(item->getType() == FreeMonMessageType::AsyncRegisterComplete); - - item = queue.dequeue(_opCtx.get()->getServiceContext()->getPreciseClockSource()).value(); - ASSERT(item->getType() == FreeMonMessageType::RegisterCommand); -} - - -// Positive: Test Queue Stop -TEST_F(FreeMonQueueTest, TestQueueStop) { - FreeMonMessageQueue queue; - - queue.enqueue( - FreeMonMessage::createWithDeadline(FreeMonMessageType::RegisterServer, fromNow(50000))); - - unittest::Barrier barrier(2); - - auto swSchedule = - _mockThreadPool->scheduleWork([&](const executor::TaskExecutor::CallbackArgs& cbArgs) { - barrier.countDownAndWait(); - - // Try to dequeue from a stopped task queue - auto item = queue.dequeue(_opCtx.get()->getServiceContext()->getPreciseClockSource()); - ASSERT_FALSE(item.has_value()); - }); - - ASSERT_OK(swSchedule.getStatus()); - - // Stop the queue - queue.stop(); - - // Let our worker thread proceed - barrier.countDownAndWait(); - - _mockThreadPool->shutdown(); - _mockThreadPool->join(); -} - -} // namespace -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_status.cpp b/src/mongo/db/free_mon/free_mon_status.cpp deleted file mode 100644 index 138b581e1ea..00000000000 --- a/src/mongo/db/free_mon/free_mon_status.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include - -#include "mongo/base/error_codes.h" -#include "mongo/base/status.h" -#include "mongo/base/string_data.h" -#include "mongo/bson/bsonelement.h" -#include "mongo/bson/bsonmisc.h" -#include "mongo/bson/bsonobj.h" -#include "mongo/bson/bsonobjbuilder.h" -#include "mongo/db/auth/action_type.h" -#include "mongo/db/auth/authorization_session.h" -#include "mongo/db/auth/resource_pattern.h" -#include "mongo/db/commands/server_status.h" -#include "mongo/db/free_mon/free_mon_controller.h" -#include "mongo/db/free_mon/free_mon_options.h" -#include "mongo/db/operation_context.h" - -namespace mongo { -namespace { - -class FreeMonServerStatus : public ServerStatusSection { -public: - FreeMonServerStatus() : ServerStatusSection("freeMonitoring") {} - - bool includeByDefault() const final { - return true; - } - - Status checkAuthForOperation(OperationContext* opCtx) const override { - auto* as = AuthorizationSession::get(opCtx->getClient()); - if (!as->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(as->getUserTenantId()), - ActionType::checkFreeMonitoringStatus)) { - return {ErrorCodes::Unauthorized, "unauthorized"}; - } - - return Status::OK(); - } - - BSONObj generateSection(OperationContext* opCtx, const BSONElement& configElement) const final { - if (globalFreeMonParams.freeMonitoringState == EnableCloudStateEnum::kOff) { - return BSON("state" - << "disabled"); - } - - auto* controller = FreeMonController::get(opCtx->getServiceContext()); - if (!controller) { - return BSON("state" - << "disabled"); - } - - BSONObjBuilder builder; - controller->getServerStatus(opCtx, &builder); - return builder.obj(); - } -} freeMonServerStatus; - -} // namespace -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_storage.cpp b/src/mongo/db/free_mon/free_mon_storage.cpp deleted file mode 100644 index 9f11973c8d3..00000000000 --- a/src/mongo/db/free_mon/free_mon_storage.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/db/free_mon/free_mon_storage.h" - -#include -#include - -#include - -#include "mongo/base/error_codes.h" -#include "mongo/base/status.h" -#include "mongo/base/status_with.h" -#include "mongo/base/string_data.h" -#include "mongo/bson/bsonelement.h" -#include "mongo/bson/bsonmisc.h" -#include "mongo/bson/bsonobjbuilder.h" -#include "mongo/db/catalog_raii.h" -#include "mongo/db/concurrency/lock_manager_defs.h" -#include "mongo/db/db_raii.h" -#include "mongo/db/namespace_string.h" -#include "mongo/db/operation_context.h" -#include "mongo/db/repl/replication_coordinator.h" -#include "mongo/db/repl/storage_interface.h" -#include "mongo/db/storage/recovery_unit.h" -#include "mongo/idl/idl_parser.h" -#include "mongo/util/assert_util.h" - -namespace mongo { - -constexpr StringData FreeMonStorage::kFreeMonDocIdKey; - -boost::optional FreeMonStorage::read(OperationContext* opCtx) { - BSONObj deleteKey = BSON("_id" << kFreeMonDocIdKey); - BSONElement elementKey = deleteKey.firstElement(); - - auto storageInterface = repl::StorageInterface::get(opCtx); - - // Ensure we read without a timestamp. - invariant(RecoveryUnit::ReadSource::kNoTimestamp == - opCtx->recoveryUnit()->getTimestampReadSource()); - - AutoGetCollectionForRead autoRead(opCtx, NamespaceString::kServerConfigurationNamespace); - - auto swObj = storageInterface->findById( - opCtx, NamespaceString::kServerConfigurationNamespace, elementKey); - if (!swObj.isOK()) { - if (swObj.getStatus() == ErrorCodes::NoSuchKey || - swObj.getStatus() == ErrorCodes::NamespaceNotFound) { - return {}; - } - - uassertStatusOK(swObj.getStatus()); - } - - return FreeMonStorageState::parse(IDLParserContext("FreeMonStorage"), swObj.getValue()); -} - -void FreeMonStorage::replace(OperationContext* opCtx, const FreeMonStorageState& doc) { - BSONObj deleteKey = BSON("_id" << kFreeMonDocIdKey); - BSONElement elementKey = deleteKey.firstElement(); - - BSONObj obj = doc.toBSON(); - - auto storageInterface = repl::StorageInterface::get(opCtx); - AutoGetCollection autoWrite(opCtx, NamespaceString::kServerConfigurationNamespace, MODE_IX); - - if (repl::ReplicationCoordinator::get(opCtx)->canAcceptWritesFor( - opCtx, NamespaceString::kServerConfigurationNamespace)) { - auto swObj = storageInterface->upsertById( - opCtx, NamespaceString::kServerConfigurationNamespace, elementKey, obj); - if (!swObj.isOK()) { - uassertStatusOK(swObj); - } - } -} - -void FreeMonStorage::deleteState(OperationContext* opCtx) { - BSONObj deleteKey = BSON("_id" << kFreeMonDocIdKey); - BSONElement elementKey = deleteKey.firstElement(); - - auto storageInterface = repl::StorageInterface::get(opCtx); - AutoGetCollection autoWrite(opCtx, NamespaceString::kServerConfigurationNamespace, MODE_IX); - - if (repl::ReplicationCoordinator::get(opCtx)->canAcceptWritesFor( - opCtx, NamespaceString::kServerConfigurationNamespace)) { - - auto swObj = storageInterface->deleteById( - opCtx, NamespaceString::kServerConfigurationNamespace, elementKey); - if (!swObj.isOK()) { - // Ignore errors about no document - if (swObj.getStatus() == ErrorCodes::NoSuchKey) { - return; - } - - uassertStatusOK(swObj); - } - } -} - -boost::optional FreeMonStorage::readClusterManagerState(OperationContext* opCtx) { - auto storageInterface = repl::StorageInterface::get(opCtx); - - AutoGetCollectionForRead autoRead(opCtx, NamespaceString::kServerConfigurationNamespace); - - auto swObj = - storageInterface->findSingleton(opCtx, NamespaceString::kLocalClusterManagerNamespace); - if (!swObj.isOK()) { - // Ignore errors about not-finding documents or having too many documents - if (swObj.getStatus() == ErrorCodes::NamespaceNotFound || - swObj.getStatus() == ErrorCodes::CollectionIsEmpty || - swObj.getStatus() == ErrorCodes::TooManyMatchingDocuments) { - return {}; - } - - uassertStatusOK(swObj.getStatus()); - } - - return swObj.getValue(); -} - -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_storage.h b/src/mongo/db/free_mon/free_mon_storage.h deleted file mode 100644 index 0e251d50768..00000000000 --- a/src/mongo/db/free_mon/free_mon_storage.h +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include -#include - -#include "mongo/base/string_data.h" -#include "mongo/bson/bsonobj.h" -#include "mongo/db/free_mon/free_mon_storage_gen.h" -#include "mongo/db/operation_context.h" - -namespace mongo { - -/** - * Storage tier for Free Monitoring. Provides access to storage engine. - */ -class FreeMonStorage { -public: - /** - * The _id value in admin.system.version. - */ - static constexpr auto kFreeMonDocIdKey = "free_monitoring"_sd; - - /** - * Reads document from disk if it exists. - */ - static boost::optional read(OperationContext* opCtx); - - /** - * Replaces document on disk with contents of document. Creates document if it does not exist. - */ - static void replace(OperationContext* opCtx, const FreeMonStorageState& doc); - - /** - * Deletes document on disk if it exists. - */ - static void deleteState(OperationContext* opCtx); - - /** - * Reads the singelton document from local.clustermanager. - * - * Returns nothing if there are more then one document or it does not exist. - */ - static boost::optional readClusterManagerState(OperationContext* opCtx); -}; - -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_storage.idl b/src/mongo/db/free_mon/free_mon_storage.idl deleted file mode 100644 index 59876b5aae4..00000000000 --- a/src/mongo/db/free_mon/free_mon_storage.idl +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright (C) 2018-present MongoDB, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the Server Side Public License, version 1, -# as published by MongoDB, Inc. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# Server Side Public License for more details. -# -# You should have received a copy of the Server Side Public License -# along with this program. If not, see -# . -# -# As a special exception, the copyright holders give permission to link the -# code of portions of this program with the OpenSSL library under certain -# conditions as described in each individual source file and distribute -# linked combinations including the program with the OpenSSL library. You -# must comply with the Server Side Public License in all respects for -# all of the code used other than as permitted herein. If you modify file(s) -# with this exception, you may extend this exception to your version of the -# file(s), but you are not obligated to do so. If you do not wish to do so, -# delete this exception statement from your version. If you delete this -# exception statement from all source files in the program, then also delete -# it in the license file. -# -global: - cpp_namespace: "mongo" - -imports: - - "mongo/db/basic_types.idl" - -enums: - StorageState: - description: "Action types" - type: string - values: - disabled: disabled - enabled: enabled - pending: pending - -structs: - FreeMonStorageState: - description: "Persisted document in admin.system.version" - strict: false - generate_comparison_operators: true - fields: - _id: - description: "Key of the Free Monitoring singleton document" - type: "string" - default: '"free_monitoring"' - version: - description: "Storage version, initial version is 1" - type: long - state: - description: "Indicates whether it is disabled or enabled" - type: StorageState - default: disabled - registrationId: - description: "Registration Id" - type: string - informationalURL: - description: "Informational HTTP web page for metrics" - type: string - message: - description: "Informational message for shell to display to user" - type: string - userReminder: - description: "Message to display to user to remind them about service" - type: string - diff --git a/src/mongo/db/free_mon/free_mon_storage_test.cpp b/src/mongo/db/free_mon/free_mon_storage_test.cpp deleted file mode 100644 index 8a6cc2c1451..00000000000 --- a/src/mongo/db/free_mon/free_mon_storage_test.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include -#include -#include -#include - -#include - -#include "mongo/base/string_data.h" -#include "mongo/bson/bsonelement.h" -#include "mongo/bson/bsonmisc.h" -#include "mongo/bson/bsonobjbuilder.h" -#include "mongo/db/catalog/collection_options.h" -#include "mongo/db/client.h" -#include "mongo/db/concurrency/d_concurrency.h" -#include "mongo/db/concurrency/lock_manager_defs.h" -#include "mongo/db/free_mon/free_mon_storage.h" -#include "mongo/db/namespace_string.h" -#include "mongo/db/repl/member_state.h" -#include "mongo/db/repl/oplog.h" -#include "mongo/db/repl/replication_coordinator.h" -#include "mongo/db/repl/replication_coordinator_mock.h" -#include "mongo/db/repl/storage_interface.h" -#include "mongo/db/repl/storage_interface_impl.h" -#include "mongo/db/service_context.h" -#include "mongo/db/service_context_d_test_fixture.h" -#include "mongo/executor/network_interface_mock.h" -#include "mongo/executor/thread_pool_task_executor.h" -#include "mongo/idl/idl_parser.h" -#include "mongo/unittest/assert.h" -#include "mongo/unittest/framework.h" -#include "mongo/util/uuid.h" - -namespace mongo { -namespace { - -class FreeMonStorageTest : public ServiceContextMongoDTest { -private: - void setUp() final; - void tearDown() final; - -protected: - /** - * Looks up the current ReplicationCoordinator. - * The result is cast to a ReplicationCoordinatorMock to provide access to test features. - */ - repl::ReplicationCoordinatorMock* _getReplCoord() const; - - ServiceContext::UniqueOperationContext _opCtx; - - executor::NetworkInterfaceMock* _mockNetwork{nullptr}; - - std::unique_ptr _mockThreadPool; - - repl::StorageInterface* _storage{nullptr}; -}; - -void FreeMonStorageTest::setUp() { - ServiceContextMongoDTest::setUp(); - auto service = getServiceContext(); - - repl::ReplicationCoordinator::set(service, - std::make_unique(service)); - - _opCtx = cc().makeOperationContext(); - - repl::StorageInterface::set(service, std::make_unique()); - _storage = repl::StorageInterface::get(service); - - // Transition to PRIMARY so that the server can accept writes. - ASSERT_OK(_getReplCoord()->setFollowerMode(repl::MemberState::RS_PRIMARY)); - - repl::createOplog(_opCtx.get()); -} - -void FreeMonStorageTest::tearDown() { - _opCtx = {}; - ServiceContextMongoDTest::tearDown(); -} - -repl::ReplicationCoordinatorMock* FreeMonStorageTest::_getReplCoord() const { - auto replCoord = repl::ReplicationCoordinator::get(_opCtx.get()); - ASSERT(replCoord) << "No ReplicationCoordinator installed"; - auto replCoordMock = dynamic_cast(replCoord); - ASSERT(replCoordMock) << "Unexpected type for installed ReplicationCoordinator"; - return replCoordMock; -} - -// Positive: Test Storage works -TEST_F(FreeMonStorageTest, TestStorage) { - - // Validate no collection works - { - auto emptyDoc = FreeMonStorage::read(_opCtx.get()); - ASSERT_FALSE(emptyDoc.has_value()); - } - - // Create collection with one document. - CollectionOptions collectionOptions; - collectionOptions.uuid = UUID::gen(); - auto statusCC = _storage->createCollection( - _opCtx.get(), - NamespaceString::createNamespaceString_forTest("admin", "system.version"), - collectionOptions); - ASSERT_OK(statusCC); - - - FreeMonStorageState initialState = - FreeMonStorageState::parse(IDLParserContext("foo"), - BSON("version" << 1LL << "state" - << "enabled" - << "registrationId" - << "1234" - << "informationalURL" - << "http://example.com" - << "message" - << "hello" - << "userReminder" - << "")); - - { - auto emptyDoc = FreeMonStorage::read(_opCtx.get()); - ASSERT_FALSE(emptyDoc.has_value()); - } - - FreeMonStorage::replace(_opCtx.get(), initialState); - - { - auto persistedDoc = FreeMonStorage::read(_opCtx.get()); - - ASSERT_TRUE(persistedDoc.has_value()); - - ASSERT_TRUE(persistedDoc == initialState); - } - - FreeMonStorage::deleteState(_opCtx.get()); - - { - auto emptyDoc = FreeMonStorage::read(_opCtx.get()); - ASSERT_FALSE(emptyDoc.has_value()); - } - - // Verfiy delete of nothing succeeds - FreeMonStorage::deleteState(_opCtx.get()); -} - - -// Positive: Test Storage works on a secondary -TEST_F(FreeMonStorageTest, TestSecondary) { - - // Create collection with one document. - CollectionOptions collectionOptions; - collectionOptions.uuid = UUID::gen(); - auto statusCC = _storage->createCollection( - _opCtx.get(), - NamespaceString::createNamespaceString_forTest("admin", "system.version"), - collectionOptions); - ASSERT_OK(statusCC); - - - FreeMonStorageState initialState = - FreeMonStorageState::parse(IDLParserContext("foo"), - BSON("version" << 1LL << "state" - << "enabled" - << "registrationId" - << "1234" - << "informationalURL" - << "http://example.com" - << "message" - << "hello" - << "userReminder" - << "")); - - FreeMonStorage::replace(_opCtx.get(), initialState); - - { - auto persistedDoc = FreeMonStorage::read(_opCtx.get()); - - ASSERT_TRUE(persistedDoc.has_value()); - - ASSERT_TRUE(persistedDoc == initialState); - } - - // Now become a secondary - ASSERT_OK(_getReplCoord()->setFollowerMode(repl::MemberState::RS_SECONDARY)); - - FreeMonStorageState updatedState = - FreeMonStorageState::parse(IDLParserContext("foo"), - BSON("version" << 2LL << "state" - << "enabled" - << "registrationId" - << "1234" - << "informationalURL" - << "http://example.com" - << "message" - << "hello" - << "userReminder" - << "")); - - - { - auto persistedDoc = FreeMonStorage::read(_opCtx.get()); - - ASSERT_TRUE(persistedDoc.has_value()); - - ASSERT_TRUE(persistedDoc == initialState); - } - - FreeMonStorage::deleteState(_opCtx.get()); - - { - auto persistedDoc = FreeMonStorage::read(_opCtx.get()); - ASSERT_TRUE(persistedDoc.has_value()); - } - - // Verfiy delete of nothing succeeds - FreeMonStorage::deleteState(_opCtx.get()); -} - -void insertDoc(OperationContext* optCtx, const NamespaceString nss, StringData id) { - auto storageInterface = repl::StorageInterface::get(optCtx); - - Lock::DBLock dblk(optCtx, nss.dbName(), MODE_IX); - Lock::CollectionLock lk(optCtx, nss, MODE_IX); - - BSONObj fakeDoc = BSON("_id" << id); - BSONElement elementKey = fakeDoc.firstElement(); - - ASSERT_OK(storageInterface->upsertById(optCtx, nss, elementKey, fakeDoc)); -} - -// Positive: Test local.clustermanager -TEST_F(FreeMonStorageTest, TestClusterManagerStorage) { - const NamespaceString localClusterManagerNss = - NamespaceString::createNamespaceString_forTest("local.clustermanager"); - - // Verify read of non-existent collection works - ASSERT_FALSE(FreeMonStorage::readClusterManagerState(_opCtx.get()).has_value()); - - CollectionOptions collectionOptions; - collectionOptions.uuid = UUID::gen(); - auto statusCC = - _storage->createCollection(_opCtx.get(), localClusterManagerNss, collectionOptions); - ASSERT_OK(statusCC); - - // Verify read of empty collection works - ASSERT_FALSE(FreeMonStorage::readClusterManagerState(_opCtx.get()).has_value()); - - insertDoc(_opCtx.get(), localClusterManagerNss, "foo1"); - - // Verify read of singleton collection works - ASSERT_TRUE(FreeMonStorage::readClusterManagerState(_opCtx.get()).has_value()); - - insertDoc(_opCtx.get(), localClusterManagerNss, "bar1"); - - // Verify read of two doc collection fails - ASSERT_FALSE(FreeMonStorage::readClusterManagerState(_opCtx.get()).has_value()); -} -} // namespace -} // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_stub.cpp b/src/mongo/db/free_mon/free_mon_stub.cpp deleted file mode 100644 index af50d7ce7df..00000000000 --- a/src/mongo/db/free_mon/free_mon_stub.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/db/free_mon/free_mon_mongod.h" - -#include "mongo/db/service_context.h" - -namespace mongo { - -void startFreeMonitoring(ServiceContext* serviceContext) {} - -void stopFreeMonitoring() {} - -void notifyFreeMonitoringOnTransitionToPrimary(){}; - -void setupFreeMonitoringOpObserver(OpObserverRegistry* registry) {} - -} // namespace mongo diff --git a/src/mongo/db/mongod_main.cpp b/src/mongo/db/mongod_main.cpp index 526e4432f35..f67e54df129 100644 --- a/src/mongo/db/mongod_main.cpp +++ b/src/mongo/db/mongod_main.cpp @@ -105,7 +105,6 @@ #include "mongo/db/dbdirectclient.h" #include "mongo/db/feature_flag.h" #include "mongo/db/fle_crud.h" -#include "mongo/db/free_mon/free_mon_mongod.h" #include "mongo/db/ftdc/ftdc_mongod.h" #include "mongo/db/ftdc/util.h" #include "mongo/db/global_settings.h" @@ -822,8 +821,6 @@ ExitCode _initAndListen(ServiceContext* serviceContext, int listenPort) { logStartup(startupOpCtx.get()); } - startFreeMonitoring(serviceContext); - if (serverGlobalParams.clusterRole.has(ClusterRole::ConfigServer)) { initializeGlobalShardingStateForConfigServerIfNeeded(startupOpCtx.get()); @@ -1400,8 +1397,6 @@ void setUpObservers(ServiceContext* serviceContext) { opObserverRegistry->addObserver(std::make_unique()); opObserverRegistry->addObserver(std::make_unique()); - setupFreeMonitoringOpObserver(opObserverRegistry.get()); - if (audit::opObserverRegistrar) { audit::opObserverRegistrar(opObserverRegistry.get()); } @@ -1695,9 +1690,6 @@ void shutdownTask(const ShutdownTaskArgs& shutdownArgs) { } } - LOGV2(4784925, "Shutting down free monitoring"); - stopFreeMonitoring(); - if (auto* healthLog = HealthLogInterface::get(serviceContext)) { LOGV2(4784927, "Shutting down the HealthLog"); healthLog->shutdown(); diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript index a66872bb5c5..3c8e8cabe5c 100644 --- a/src/mongo/db/repl/SConscript +++ b/src/mongo/db/repl/SConscript @@ -1582,7 +1582,6 @@ env.Library( '$BUILD_DIR/mongo/db/change_stream_serverless_helpers', '$BUILD_DIR/mongo/db/cloner', '$BUILD_DIR/mongo/db/concurrency/lock_manager', - '$BUILD_DIR/mongo/db/free_mon/free_mon_mongod', '$BUILD_DIR/mongo/db/not_primary_error_tracker', '$BUILD_DIR/mongo/db/op_observer/op_observer', '$BUILD_DIR/mongo/db/query/query_stats/query_stats', diff --git a/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp b/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp index 11ce410a9f2..58b77447de2 100644 --- a/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp @@ -66,7 +66,6 @@ #include "mongo/db/database_name.h" #include "mongo/db/dbhelpers.h" #include "mongo/db/feature_flag.h" -#include "mongo/db/free_mon/free_mon_mongod.h" #include "mongo/db/index_builds_coordinator.h" #include "mongo/db/logical_time.h" #include "mongo/db/logical_time_validator.h" @@ -571,8 +570,6 @@ OpTime ReplicationCoordinatorExternalStateImpl::onTransitionToPrimary(OperationC IndexBuildsCoordinator::get(opCtx)->onStepUp(opCtx); - notifyFreeMonitoringOnTransitionToPrimary(); - // It is only necessary to check the system indexes on the first transition to primary. // On subsequent transitions to primary the indexes will have already been created. static std::once_flag verifySystemIndexesOnce; diff --git a/src/mongo/s/commands/SConscript b/src/mongo/s/commands/SConscript index 40b8f991474..60bf1a5e4be 100644 --- a/src/mongo/s/commands/SConscript +++ b/src/mongo/s/commands/SConscript @@ -98,7 +98,6 @@ env.Library( 'cluster_set_allow_migrations_cmd.cpp', 'cluster_set_cluster_parameter_cmd.cpp', 'cluster_set_feature_compatibility_version_cmd.cpp', - 'cluster_set_free_monitoring_cmd.cpp' if get_option("enable-free-mon") == 'on' else [], 'cluster_set_index_commit_quorum_cmd.cpp', 'cluster_set_user_write_block_mode_command.cpp', 'cluster_shard_collection_cmd.cpp', diff --git a/src/mongo/s/commands/cluster_set_free_monitoring_cmd.cpp b/src/mongo/s/commands/cluster_set_free_monitoring_cmd.cpp deleted file mode 100644 index 8bb5514a3f7..00000000000 --- a/src/mongo/s/commands/cluster_set_free_monitoring_cmd.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/platform/basic.h" - -#include "mongo/db/auth/authorization_session.h" -#include "mongo/db/commands.h" - -namespace mongo { -namespace { - -class ClusterSetFreeMonitoring : public BasicCommand { -public: - ClusterSetFreeMonitoring() : BasicCommand("setFreeMonitoring") {} - - AllowedOnSecondary secondaryAllowed(ServiceContext*) const final { - return AllowedOnSecondary::kNever; - } - - bool supportsWriteConcern(const BSONObj& cmd) const final { - return false; - } - - std::string help() const final { - return "setFreeMonitoring command must be run against mongod instances"; - } - - Status checkAuthForOperation(OperationContext* opCtx, - const DatabaseName& dbName, - const BSONObj&) const final { - if (!AuthorizationSession::get(opCtx->getClient()) - ->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(dbName.tenantId()), - ActionType::setFreeMonitoring)) { - return Status(ErrorCodes::Unauthorized, "Unauthorized"); - } - return Status::OK(); - } - - bool run(OperationContext* opCtx, - const DatabaseName&, - const BSONObj& cmdObj, - BSONObjBuilder& result) final { - uasserted(ErrorCodes::CommandFailed, help()); - return true; - } - -} clusterSetFreeMonitoring; - -} // namespace -} // namespace mongo diff --git a/src/mongo/shell/db.js b/src/mongo/shell/db.js index 5ed58e7d633..a0613714499 100644 --- a/src/mongo/shell/db.js +++ b/src/mongo/shell/db.js @@ -1661,57 +1661,6 @@ DB.prototype.watch = function(pipeline, options) { return this._runAggregate({aggregate: 1, pipeline: pipeline}, aggOptions); }; -DB.prototype.getFreeMonitoringStatus = function() { - 'use strict'; - return assert.commandWorked(this.adminCommand({getFreeMonitoringStatus: 1})); -}; - -DB.prototype.enableFreeMonitoring = function() { - 'use strict'; - let reply, isPrimary; - if (this.getMongo().getApiParameters().apiVersion) { - reply = this.hello(); - isPrimary = reply.isWritablePrimary; - } else { - reply = this.isMaster(); - isPrimary = reply.ismaster; - } - - if (!isPrimary) { - print("ERROR: db.enableFreeMonitoring() may only be run on a primary"); - return; - } - - assert.commandWorked(this.adminCommand({setFreeMonitoring: 1, action: 'enable'})); - - const cmd = this.adminCommand({getFreeMonitoringStatus: 1}); - if (!cmd.ok && (cmd.code == ErrorCodes.Unauthorized)) { - // Edge case: It's technically possible that a user can change free-mon state, - // but is not allowed to inspect it. - print("Successfully initiated free monitoring, but unable to determine status " + - "as you lack the 'checkFreeMonitoringStatus' privilege."); - return; - } - assert.commandWorked(cmd); - - if (cmd.state !== 'enabled') { - const url = this.adminCommand({'getParameter': 1, 'cloudFreeMonitoringEndpointURL': 1}) - .cloudFreeMonitoringEndpointURL; - - print("Unable to get immediate response from the Cloud Monitoring service. We will" + - "continue to retry in the background. Please check your firewall " + - "settings to ensure that mongod can communicate with \"" + url + "\""); - return; - } - - print(tojson(cmd)); -}; - -DB.prototype.disableFreeMonitoring = function() { - 'use strict'; - assert.commandWorked(this.adminCommand({setFreeMonitoring: 1, action: 'disable'})); -}; - // Writing `this.hasOwnProperty` would cause DB.prototype.getCollection() to be called since the // DB's getProperty() handler in C++ takes precedence when a property isn't defined on the DB // instance directly. The "hasOwnProperty" property is defined on Object.prototype, so we must diff --git a/src/mongo/shell/mongo_main.cpp b/src/mongo/shell/mongo_main.cpp index 0cfb708824d..3146a69b2cd 100644 --- a/src/mongo/shell/mongo_main.cpp +++ b/src/mongo/shell/mongo_main.cpp @@ -1076,12 +1076,6 @@ int mongo_main(int argc, char* argv[]) { true, false); - scope->exec("shellHelper( 'show', 'freeMonitoring' )", - "(freeMonitoring)", - false, - true, - false); - scope->exec("shellHelper( 'show', 'automationNotices' )", "(automationnotices)", false, diff --git a/src/mongo/shell/utils.js b/src/mongo/shell/utils.js index 59f6d7b17b2..2aa66de29d2 100644 --- a/src/mongo/shell/utils.js +++ b/src/mongo/shell/utils.js @@ -1192,52 +1192,6 @@ shellHelper.show = function(what) { } } - if (what == "freeMonitoring") { - var dbDeclared, ex; - try { - // !!db essentially casts db to a boolean - // Will throw a reference exception if db hasn't been declared. - dbDeclared = !!globalThis.db; - } catch (ex) { - dbDeclared = false; - } - - if (dbDeclared) { - const freemonStatus = globalThis.db.adminCommand({getFreeMonitoringStatus: 1}); - - if (freemonStatus.ok) { - if (freemonStatus.state == 'enabled' && - freemonStatus.hasOwnProperty('userReminder')) { - print("---"); - print(freemonStatus.userReminder); - print("---"); - } else if (freemonStatus.state === 'undecided') { - print( - "---\n" + messageIndent + - "Enable MongoDB's free cloud-based monitoring service, which will then receive and display\n" + - messageIndent + - "metrics about your deployment (disk utilization, CPU, operation statistics, etc).\n" + - "\n" + messageIndent + - "The monitoring data will be available on a MongoDB website with a unique URL accessible to you\n" + - messageIndent + - "and anyone you share the URL with. MongoDB may use this information to make product\n" + - messageIndent + - "improvements and to suggest MongoDB products and deployment options to you.\n" + - "\n" + messageIndent + - "To enable free monitoring, run the following command: db.enableFreeMonitoring()\n" + - messageIndent + - "To permanently disable this reminder, run the following command: db.disableFreeMonitoring()\n" + - "---\n"); - } - } - - return ""; - } else { - print("Cannot show freeMonitoring, \"db\" is not set"); - return ""; - } - } - if (what == "nonGenuineMongoDBCheck") { let matchesKnownImposterSignature = false;