Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

upgrade mongoose from 5 to 8.8.4 #1676

Merged
merged 16 commits into from
Dec 16, 2024
Merged
1 change: 0 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ jobs:
strategy:
matrix:
node-version:
- 14.x
- 16.x
- 18.x
steps:
Expand Down
5 changes: 3 additions & 2 deletions CHANGES_NEXT_RELEASE
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
- Upgrade express de from 4.19.2 to 4.20.0
- Upgrade mongoose dep from 5.13.20 to 5.13.22
- Upgrade express dep from 4.19.2 to 4.20.0
- Upgrade mongodb devdep from 4.17.1 to 4.17.2
- Upgrade mongoose dep from 5.13.22 to 8.4.4 (solving vulnerability CVE-2024-53900) (#1674)
4 changes: 2 additions & 2 deletions lib/model/Command.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ const Command = new Schema({
creationDate: { type: Date, default: Date.now }
});

function load(db) {
module.exports.model = db.model('Command', Command);
function load() {
module.exports.model = mongoose.model('Command', Command);
module.exports.internalSchema = Command;
}

Expand Down
4 changes: 2 additions & 2 deletions lib/model/Device.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ const Device = new Schema({
payloadType: String
});

function load(db) {
module.exports.model = db.model('Device', Device);
function load() {
module.exports.model = mongoose.model('Device', Device);
module.exports.internalSchema = Device;
}

Expand Down
4 changes: 2 additions & 2 deletions lib/model/Group.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ const Group = new Schema({
payloadType: String
});

function load(db) {
function load() {
Group.index({ apikey: 1, resource: 1 }, { unique: true });
module.exports.model = db.model('Group', Group);
module.exports.model = mongoose.model('Group', Group);
module.exports.internalSchema = Group;
}

Expand Down
165 changes: 53 additions & 112 deletions lib/model/dbConn.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ const config = require('../commonConfig');
const constants = require('../constants');
const alarms = require('../services/common/alarmManagement');
const logger = require('logops');
const async = require('async');
const errors = require('../errors');
let defaultDb;
const DEFAULT_DB_NAME = 'iotagent';
Expand All @@ -40,103 +39,62 @@ const context = {
};

function loadModels() {
require('./Device').load(defaultDb);
require('./Group').load(defaultDb);
require('./Command').load(defaultDb);
require('./Device').load();
require('./Group').load();
require('./Command').load();
}

/**
* Creates a new connection to the Mongo DB.
*
* @this Reference to the dbConn module itself.
*/

function init(host, db, port, options, callback) {
/*jshint camelcase:false, validthis:true */
let url;
let retries = 0;
let lastError;
const maxRetries =
(config.getConfig().mongodb && config.getConfig().mongodb.retries) || constants.DEFAULT_MONGODB_RETRIES;
const maxRetries = config.getConfig().mongodb?.retries || constants.DEFAULT_MONGODB_RETRIES;

function addPort(item) {
return item + ':' + port;
}

function commaConcat(previous, current, currentIndex) {
if (currentIndex !== 0) {
previous += ',';
}

previous += current;

return previous;
return `${item}:${port}`;
}

url = 'mongodb://';

if (options.auth) {
url += options.auth.user + ':' + options.auth.password + '@';
url += `${encodeURIComponent(options.auth.user)}:${encodeURIComponent(options.auth.password)}@`;
}

const hosts = host.split(',').map(addPort).reduce(commaConcat, '');

url += hosts + '/' + db;
const hosts = host.split(',').map(addPort).join(',');
url += `${hosts}/${db}`;

if (options.extraArgs) {
if (options.extraArgs instanceof Object && Object.keys(options.extraArgs).length > 0) {
url += '?';
url += Object.entries(options.extraArgs)
.map(function ([k, v]) {
return encodeURIComponent(k) + '=' + encodeURIComponent(v);
})
.join('&');
const query = new URLSearchParams(options.extraArgs).toString();
if (query) {
url += `?${query}`;
}
delete options.extraArgs;
}

/* eslint-disable-next-line no-unused-vars */
function createConnectionHandler(error, results) {
if (defaultDb) {
logger.info(context, 'Successfully connected to MongoDB.');
module.exports.db = defaultDb;
loadModels();
} else {
logger.error(context, 'MONGODB-002: Error found after [%d] attempts: %s', retries, error || lastError);
}

callback(error);
}

function retryCheck() {
return !defaultDb && retries < maxRetries;
}

function connectionAttempt(url, options, callback) {
logger.info(context, 'Attempting to connect to MongoDB instance with url %j. Attempt %d', url, retries);
// FIXME: useNewUrlParser is no longer used in underlying mongodb driver 4.x
// (see https://github.com/mongodb/node-mongodb-native/blob/HEAD/etc/notes/CHANGES_4.0.0.md)
// but not sure if current mongoose version is still using mongodb 3.x internally
// probably mongodb-connectionoptions-test.js needs to be fixed if useNewUrlParser is removed at the end
options.useNewUrlParser = true;
options.useUnifiedTopology = true;
mongoose.set('useCreateIndex', true);
/* eslint-disable-next-line no-unused-vars */
const candidateDb = mongoose.createConnection(url, options, function (error, result) {
if (error) {
logger.error(context, 'MONGODB-001: Error trying to connect to MongoDB: %s', error);
lastError = error;
} else {
defaultDb = candidateDb;
function connectionAttempt(callback) {
logger.info(context, `Attempting to connect to MongoDB at ${url}. Attempt ${retries + 1}`);

mongoose
.connect(url, options)
.then(() => {
defaultDb = mongoose.connection;
logger.info(context, 'Successfully connected to MongoDB.');
loadModels();
defaultDb.on('error', function (error) {
logger.error(context, 'Mongo Driver error: %j', error);
lastError = error;
alarms.raise(constants.MONGO_ALARM, error);
});
/* eslint-disable-next-line no-unused-vars */
defaultDb.on('connecting', function (error) {
logger.debug(context, 'Mongo Driver connecting');
});

defaultDb.on('connected', function () {
logger.debug(context, 'Mongo Driver connected');
});
Expand All @@ -159,77 +117,60 @@ function init(host, db, port, options, callback) {
defaultDb.on('close', function () {
logger.debug(context, 'Mongo Driver close');
});
}

callback();
});
}

function tryCreateConnection(callback) {
const attempt = async.apply(connectionAttempt, url, options, callback);
const seconds =
(config.getConfig().mongodb && config.getConfig().mongodb.retryTime) ||
constants.DEFAULT_MONGODB_RETRY_TIME;

retries++;

if (retries === 1) {
logger.info(context, 'First connection attempt');
attempt();
} else {
logger.info(context, 'Waiting %d seconds before attempting again.', seconds);
setTimeout(attempt, seconds * 1000);
}
callback();
})
.catch((err) => {
logger.error(context, `MONGODB-001: Error trying to connect to MongoDB: ${err}`);
lastError = err;
retries++;
if (retries < maxRetries) {
const retryTime = config.getConfig().mongodb?.retryTime || constants.DEFAULT_MONGODB_RETRY_TIME;
logger.info(context, `Retrying in ${retryTime} seconds...`);
setTimeout(() => connectionAttempt(callback), retryTime * 1000);
} else {
logger.error(
context,
'MONGODB-002: Error to connect found after %d attempts: %s',
retries,
lastError
);
callback(err);
}
});
}

defaultDb = null;
async.whilst(retryCheck, tryCreateConnection, createConnectionHandler);
connectionAttempt(callback);
}

function configureDb(callback) {
/*jshint camelcase:false, validthis:true */
const currentConfig = config.getConfig();

if (currentConfig.deviceRegistry && currentConfig.deviceRegistry.type === 'mongodb') {
if (!currentConfig.mongodb || !currentConfig.mongodb.host) {
if (currentConfig.deviceRegistry?.type === 'mongodb') {
if (!currentConfig.mongodb?.host) {
logger.fatal(context, 'MONGODB-003: No host found for MongoDB driver.');
callback(new errors.BadConfiguration('No host found for MongoDB driver'));
} else {
let dbName = currentConfig.mongodb.db;
const dbName = currentConfig.mongodb.db || DEFAULT_DB_NAME;
const port = currentConfig.mongodb.port || 27017;
const options = {};

if (!currentConfig.mongodb.db) {
dbName = DEFAULT_DB_NAME;
}

if (currentConfig.mongodb.replicaSet) {
options.replicaSet = currentConfig.mongodb.replicaSet;
}

if (currentConfig.mongodb.ssl) {
options.ssl = currentConfig.mongodb.ssl;
}

if (currentConfig.mongodb.extraArgs) {
options.extraArgs = currentConfig.mongodb.extraArgs;
}
if (currentConfig.mongodb.replicaSet) options.replicaSet = currentConfig.mongodb.replicaSet;
if (currentConfig.mongodb.ssl) options.ssl = currentConfig.mongodb.ssl;
if (currentConfig.mongodb.extraArgs) options.extraArgs = currentConfig.mongodb.extraArgs;

if (currentConfig.mongodb.user && currentConfig.mongodb.password) {
options.auth = {};
options.auth.user = currentConfig.mongodb.user;
options.auth.password = currentConfig.mongodb.password;
// authSource only applies if auth is set
options.auth = {
user: currentConfig.mongodb.user,
password: currentConfig.mongodb.password
};
if (currentConfig.mongodb.authSource) {
// Overload extraArgs if it was set
options.extraArgs = {
...options.extraArgs,
authSource: currentConfig.mongodb.authSource
};
}
}

init(config.getConfig().mongodb.host, dbName, port, options, callback);
init(currentConfig.mongodb.host, dbName, port, options, callback);
}
} else {
callback();
Expand Down
Loading
Loading