Skip to content

Commit

Permalink
fix: report the correct platform in client metadata
Browse files Browse the repository at this point in the history
This relatively large refactoring ultimately corrects the fact that
the platform was not always reported correctly in client metadata
during initial handshake. It also takes the steps to localize the
creation of that metadata to one place, and makes the metadata
consistent across legacy and unified topologies

NODE-2418
  • Loading branch information
mbroadst committed Jan 12, 2020
1 parent c528a66 commit 35d0274
Show file tree
Hide file tree
Showing 19 changed files with 143 additions and 194 deletions.
3 changes: 2 additions & 1 deletion lib/cmap/connection_pool.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ class ConnectionPool extends EventEmitter {
maxIdleTimeMS: typeof options.maxIdleTimeMS === 'number' ? options.maxIdleTimeMS : 0,
waitQueueTimeoutMS:
typeof options.waitQueueTimeoutMS === 'number' ? options.waitQueueTimeoutMS : 0,
autoEncrypter: options.autoEncrypter
autoEncrypter: options.autoEncrypter,
metadata: options.metadata
});

if (options.minSize > options.maxSize) {
Expand Down
4 changes: 2 additions & 2 deletions lib/core/connection/connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ const net = require('net');
const tls = require('tls');
const Connection = require('./connection');
const Query = require('./commands').Query;
const createClientInfo = require('../topologies/shared').createClientInfo;
const MongoError = require('../error').MongoError;
const MongoNetworkError = require('../error').MongoNetworkError;
const defaultAuthProviders = require('../auth/defaultAuthProviders').defaultAuthProviders;
const WIRE_CONSTANTS = require('../wireprotocol/constants');
const makeClientMetadata = require('../utils').makeClientMetadata;
const MAX_SUPPORTED_WIRE_VERSION = WIRE_CONSTANTS.MAX_SUPPORTED_WIRE_VERSION;
const MAX_SUPPORTED_SERVER_VERSION = WIRE_CONSTANTS.MAX_SUPPORTED_SERVER_VERSION;
const MIN_SUPPORTED_WIRE_VERSION = WIRE_CONSTANTS.MIN_SUPPORTED_WIRE_VERSION;
Expand Down Expand Up @@ -105,7 +105,7 @@ function performInitialHandshake(conn, options, _callback) {
const handshakeDoc = Object.assign(
{
ismaster: true,
client: createClientInfo(options),
client: options.metadata || makeClientMetadata(options),
compression: compressors
},
getSaslSupportedMechs(options)
Expand Down
3 changes: 0 additions & 3 deletions lib/core/sdam/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const ConnectionPool = require('../../cmap/connection_pool').ConnectionPool;
const MongoError = require('../error').MongoError;
const relayEvents = require('../utils').relayEvents;
const BSON = require('../connection/utils').retrieveBSON();
const createClientInfo = require('../topologies/shared').createClientInfo;
const Logger = require('../connection/logger');
const ServerDescription = require('./server_description').ServerDescription;
const ReadPreference = require('../topologies/read_preference');
Expand Down Expand Up @@ -99,8 +98,6 @@ class Server extends EventEmitter {
BSON.Symbol,
BSON.Timestamp
]),
// client metadata for the initial handshake
clientInfo: createClientInfo(options),
// the server state
state: STATE_CLOSED,
credentials: options.credentials,
Expand Down
19 changes: 10 additions & 9 deletions lib/core/sdam/topology.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ const createCompressionInfo = require('../topologies/shared').createCompressionI
const isRetryableError = require('../error').isRetryableError;
const isSDAMUnrecoverableError = require('../error').isSDAMUnrecoverableError;
const ClientSession = require('../sessions').ClientSession;
const createClientInfo = require('../topologies/shared').createClientInfo;
const MongoError = require('../error').MongoError;
const resolveClusterTime = require('../topologies/shared').resolveClusterTime;
const SrvPoller = require('./srv_polling').SrvPoller;
Expand All @@ -25,6 +24,7 @@ const makeStateMachine = require('../utils').makeStateMachine;
const eachAsync = require('../utils').eachAsync;
const emitDeprecationWarning = require('../../utils').emitDeprecationWarning;
const ServerSessionPool = require('../sessions').ServerSessionPool;
const makeClientMetadata = require('../utils').makeClientMetadata;

const common = require('./common');
const drainTimerQueue = common.drainTimerQueue;
Expand Down Expand Up @@ -119,6 +119,13 @@ class Topology extends EventEmitter {
}

options = Object.assign({}, common.TOPOLOGY_DEFAULTS, options);
options = Object.freeze(
Object.assign(options, {
metadata: makeClientMetadata(options),
compression: { compressors: createCompressionInfo(options) }
})
);

DEPRECATED_OPTIONS.forEach(optionName => {
if (options[optionName]) {
emitDeprecationWarning(
Expand Down Expand Up @@ -196,12 +203,6 @@ class Topology extends EventEmitter {
connectionTimers: new Set()
};

// amend options for server instance creation
this.s.options.compression = { compressors: createCompressionInfo(options) };

// add client info
this.s.clientInfo = createClientInfo(options);

if (options.srvHost) {
this.s.srvPoller =
options.srvPoller ||
Expand Down Expand Up @@ -705,8 +706,8 @@ class Topology extends EventEmitter {
return new CursorClass(topology, ns, cmd, options);
}

get clientInfo() {
return this.s.clientInfo;
get clientMetadata() {
return this.s.options.metadata;
}

isConnected() {
Expand Down
18 changes: 5 additions & 13 deletions lib/core/topologies/mongos.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@ const Logger = require('../connection/logger');
const retrieveBSON = require('../connection/utils').retrieveBSON;
const MongoError = require('../error').MongoError;
const Server = require('./server');
const clone = require('./shared').clone;
const diff = require('./shared').diff;
const cloneOptions = require('./shared').cloneOptions;
const createClientInfo = require('./shared').createClientInfo;
const SessionMixins = require('./shared').SessionMixins;
const isRetryableWritesSupported = require('./shared').isRetryableWritesSupported;
const relayEvents = require('../utils').relayEvents;
const isRetryableError = require('../error').isRetryableError;
const BSON = retrieveBSON();
const getMMAPError = require('./shared').getMMAPError;
const makeClientMetadata = require('../utils').makeClientMetadata;

/**
* @fileOverview The **Mongos** class is a class that represents a Mongos Proxy topology and is
Expand Down Expand Up @@ -116,7 +115,7 @@ var Mongos = function(seedlist, options) {

// Internal state
this.s = {
options: Object.assign({}, options),
options: Object.assign({ metadata: makeClientMetadata(options) }, options),
// BSON instance
bson:
options.bson ||
Expand Down Expand Up @@ -153,14 +152,9 @@ var Mongos = function(seedlist, options) {
// Are we running in debug mode
debug: typeof options.debug === 'boolean' ? options.debug : false,
// localThresholdMS
localThresholdMS: options.localThresholdMS || 15,
// Client info
clientInfo: createClientInfo(options)
localThresholdMS: options.localThresholdMS || 15
};

// Set the client info
this.s.options.clientInfo = createClientInfo(options);

// Log info warning if the socketTimeout < haInterval as it will cause
// a lot of recycled connections to happen.
if (
Expand Down Expand Up @@ -265,8 +259,7 @@ Mongos.prototype.connect = function(options) {
Object.assign({}, self.s.options, x, options, {
reconnect: false,
monitoring: false,
parent: self,
clientInfo: clone(self.s.clientInfo)
parent: self
})
);

Expand Down Expand Up @@ -607,8 +600,7 @@ function reconnectProxies(self, proxies, callback) {
port: parseInt(_server.name.split(':')[1], 10),
reconnect: false,
monitoring: false,
parent: self,
clientInfo: clone(self.s.clientInfo)
parent: self
})
);

Expand Down
15 changes: 5 additions & 10 deletions lib/core/topologies/replset.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,16 @@ const Logger = require('../connection/logger');
const MongoError = require('../error').MongoError;
const Server = require('./server');
const ReplSetState = require('./replset_state');
const clone = require('./shared').clone;
const Timeout = require('./shared').Timeout;
const Interval = require('./shared').Interval;
const createClientInfo = require('./shared').createClientInfo;
const SessionMixins = require('./shared').SessionMixins;
const isRetryableWritesSupported = require('./shared').isRetryableWritesSupported;
const relayEvents = require('../utils').relayEvents;
const isRetryableError = require('../error').isRetryableError;
const BSON = retrieveBSON();
const calculateDurationInMs = require('../utils').calculateDurationInMs;
const getMMAPError = require('./shared').getMMAPError;
const makeClientMetadata = require('../utils').makeClientMetadata;

//
// States
Expand Down Expand Up @@ -140,7 +139,7 @@ var ReplSet = function(seedlist, options) {

// Internal state
this.s = {
options: Object.assign({}, options),
options: Object.assign({ metadata: makeClientMetadata(options) }, options),
// BSON instance
bson:
options.bson ||
Expand Down Expand Up @@ -187,9 +186,7 @@ var ReplSet = function(seedlist, options) {
// Connect function options passed in
connectOptions: {},
// Are we running in debug mode
debug: typeof options.debug === 'boolean' ? options.debug : false,
// Client info
clientInfo: createClientInfo(options)
debug: typeof options.debug === 'boolean' ? options.debug : false
};

// Add handler for topology change
Expand Down Expand Up @@ -369,8 +366,7 @@ function connectNewServers(self, servers, callback) {
port: parseInt(_server.split(':')[1], 10),
reconnect: false,
monitoring: false,
parent: self,
clientInfo: clone(self.s.clientInfo)
parent: self
})
);

Expand Down Expand Up @@ -918,8 +914,7 @@ ReplSet.prototype.connect = function(options) {
Object.assign({}, self.s.options, x, options, {
reconnect: false,
monitoring: false,
parent: self,
clientInfo: clone(self.s.clientInfo)
parent: self
})
);
});
Expand Down
13 changes: 9 additions & 4 deletions lib/core/topologies/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ var inherits = require('util').inherits,
wireProtocol = require('../wireprotocol'),
CoreCursor = require('../cursor').CoreCursor,
sdam = require('./shared'),
createClientInfo = require('./shared').createClientInfo,
createCompressionInfo = require('./shared').createCompressionInfo,
resolveClusterTime = require('./shared').resolveClusterTime,
SessionMixins = require('./shared').SessionMixins,
relayEvents = require('../utils').relayEvents;

const collationNotSupported = require('../utils').collationNotSupported;
const makeClientMetadata = require('../utils').makeClientMetadata;

// Used for filtering out fields for loggin
var debugFields = [
Expand Down Expand Up @@ -120,7 +120,7 @@ var Server = function(options) {
// Internal state
this.s = {
// Options
options: options,
options: Object.assign({ metadata: makeClientMetadata(options) }, options),
// Logger
logger: Logger('Server', options),
// Factory overrides
Expand Down Expand Up @@ -175,8 +175,6 @@ var Server = function(options) {
this.initialConnect = true;
// Default type
this._type = 'server';
// Set the client info
this.clientInfo = createClientInfo(options);

// Max Stalleness values
// last time we updated the ismaster state
Expand Down Expand Up @@ -212,6 +210,13 @@ Object.defineProperty(Server.prototype, 'logicalSessionTimeoutMinutes', {
}
});

Object.defineProperty(Server.prototype, 'clientMetadata', {
enumerable: true,
get: function() {
return this.s.options.metadata;
}
});

// In single server deployments we track the clusterTime directly on the topology, however
// in Mongos and ReplSet deployments we instead need to delegate the clusterTime up to the
// tracking objects so we can ensure we are gossiping the maximum time received from the
Expand Down
60 changes: 0 additions & 60 deletions lib/core/topologies/shared.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
'use strict';

const os = require('os');
const ReadPreference = require('./read_preference');
const Buffer = require('safe-buffer').Buffer;
const TopologyType = require('../sdam/common').TopologyType;
const MongoError = require('../error').MongoError;

Expand All @@ -18,62 +15,6 @@ function emitSDAMEvent(self, event, description) {
}
}

// Get package.json variable
const driverVersion = require('../../../package.json').version;
const nodejsVersion = `'Node.js ${process.version}, ${os.endianness}`;
const type = os.type();
const name = process.platform;
const architecture = process.arch;
const release = os.release();

function createClientInfo(options) {
const clientInfo = options.clientInfo
? clone(options.clientInfo)
: {
driver: {
name: 'nodejs',
version: driverVersion
},
os: {
type: type,
name: name,
architecture: architecture,
version: release
}
};

if (options.useUnifiedTopology) {
clientInfo.platform = `${nodejsVersion} (${options.useUnifiedTopology ? 'unified' : 'legacy'})`;
}

// Do we have an application specific string
if (options.appname) {
// Cut at 128 bytes
var buffer = Buffer.from(options.appname);
// Return the truncated appname
var appname = buffer.length > 128 ? buffer.slice(0, 128).toString('utf8') : options.appname;
// Add to the clientInfo
clientInfo.application = { name: appname };
}

// support optionally provided wrapping driver info
if (options.driverInfo) {
if (options.driverInfo.name) {
clientInfo.driver.name = `${clientInfo.driver.name}|${options.driverInfo.name}`;
}

if (options.driverInfo.version) {
clientInfo.driver.version = `${clientInfo.driver.version}|${options.driverInfo.version}`;
}

if (options.driverInfo.platform) {
clientInfo.platform = `${clientInfo.platform}|${options.driverInfo.platform}`;
}
}

return clientInfo;
}

function createCompressionInfo(options) {
if (!options.compression || !options.compression.compressors) {
return [];
Expand Down Expand Up @@ -475,7 +416,6 @@ module.exports.getTopologyType = getTopologyType;
module.exports.emitServerDescriptionChanged = emitServerDescriptionChanged;
module.exports.emitTopologyDescriptionChanged = emitTopologyDescriptionChanged;
module.exports.cloneOptions = cloneOptions;
module.exports.createClientInfo = createClientInfo;
module.exports.createCompressionInfo = createCompressionInfo;
module.exports.clone = clone;
module.exports.diff = diff;
Expand Down
Loading

0 comments on commit 35d0274

Please sign in to comment.