diff --git a/jstests/noPassthrough/traffic_recording/traffic_recording.js b/jstests/noPassthrough/traffic_recording/traffic_recording.js index 0b2f1d5bc49..91cfbaeffcd 100644 --- a/jstests/noPassthrough/traffic_recording/traffic_recording.js +++ b/jstests/noPassthrough/traffic_recording/traffic_recording.js @@ -216,3 +216,64 @@ function runTest(client, restartCommand) { removeFile(dirB); } } + +// Ensure startTrafficRecording validates startTime and endTime +{ + const path = MongoRunner.toRealDir("$dataDir/traffic_recording/"); + let recordingDir = path + "/recordings/"; + + removeFile(recordingDir); + mkdir(recordingDir); + + let m = MongoRunner.runMongod({auth: "", setParameter: {trafficRecordingDirectory: path, enableTestCommands: 1}}); + + let db = m.getDB("admin"); + + db.createUser({user: "admin", pwd: "pass", roles: jsTest.adminUserRoles}); + db.auth("admin", "pass"); + + const nowPlusDays = (days) => { + const now = new Date(); + const milliseconds = days * 24 * 60 * 60 * 1000; + return new Date(now.getTime() + milliseconds); + }; + + // No start or end time - allowed. + assert.commandWorked(db.runCommand({"startTrafficRecording": 1, "destination": "recordings"})); + assert.commandWorked(db.runCommand({"stopTrafficRecording": 1})); + + // start time < 1 day in the future, end time > start time && end time < 10 days in the future - + // allowed. + assert.commandWorked( + db.runCommand({ + "startTrafficRecording": 1, + "destination": "recordings", + startTime: nowPlusDays(0.5), + endTime: nowPlusDays(2), + }), + ); + // Cancelling early is permitted. + assert.commandWorked(db.runCommand({"stopTrafficRecording": 1})); + + const expectFailure = (params) => { + assert.commandFailedWithCode( + db.runCommand({"startTrafficRecording": 1, "destination": "recordings", ...params}), + ErrorCodes.BadValue, + ); + }; + + // Only start. + expectFailure({startTime: nowPlusDays(0.5)}); + // Only end. + expectFailure({endTime: nowPlusDays(2)}); + // Starts too late. + expectFailure({startTime: nowPlusDays(1.5), endTime: nowPlusDays(2)}); + // Ends too late. + expectFailure({startTime: nowPlusDays(0.5), endTime: nowPlusDays(20)}); + // Both. + expectFailure({startTime: nowPlusDays(1.5), endTime: nowPlusDays(20)}); + + MongoRunner.stopMongod(m, null, {user: "admin", pwd: "pass"}); + + removeFile(recordingDir); +} diff --git a/src/mongo/db/traffic_recorder.cpp b/src/mongo/db/traffic_recorder.cpp index fca041da60f..cee13670b1b 100644 --- a/src/mongo/db/traffic_recorder.cpp +++ b/src/mongo/db/traffic_recorder.cpp @@ -52,6 +52,7 @@ #include "mongo/stdx/thread.h" #include "mongo/util/assert_util.h" #include "mongo/util/decorable.h" +#include "mongo/util/duration.h" #include "mongo/util/net/hostandport.h" #include "mongo/util/producer_consumer_queue.h" #include "mongo/util/tick_source.h" @@ -300,6 +301,24 @@ std::shared_ptr TrafficRecorder::_makeRecording( } void TrafficRecorder::start(const StartTrafficRecording& options, ServiceContext* svcCtx) { + uassert(ErrorCodes::BadValue, + "startTime and endTime should both be provided, or neither", + options.getStartTime().has_value() == options.getEndTime().has_value()); + + if (options.getStartTime().has_value()) { + auto start = *options.getStartTime(); + auto end = *options.getEndTime(); + + uassert(ErrorCodes::BadValue, + "startTime should be in the future, and less than 1 day into the future", + start > Date_t::now() && start < (Date_t::now() + Days(1))); + + + uassert(ErrorCodes::BadValue, + "endTime should be after startTime, and less than 10 days into the future", + end > start && end < (Date_t::now() + Days(10))); + } + _prepare(options, svcCtx); _start(svcCtx); } diff --git a/src/mongo/db/traffic_recorder.idl b/src/mongo/db/traffic_recorder.idl index 4b214e5ba63..f3802cdf9c9 100644 --- a/src/mongo/db/traffic_recorder.idl +++ b/src/mongo/db/traffic_recorder.idl @@ -92,6 +92,14 @@ commands: description: "max additional memory the recording is allowed to use" default: 134217728 type: numBytes + startTime: + description: "Future time to start the recording" + optional: true + type: date + endTime: + description: "Future time to halt the recording" + optional: true + type: date stopTrafficRecording: description: "stop recording Command"