First signs of life with MariaDB.

Ylian Saint-Hilaire committed Feb 2, 2020 at 12:37 UTC d28b5667b7d03e6bbb40d0f5f54187d3aea87336
4 files changed +210 -54
db.js
+206 -52
@@ -68,7 +68,12 @@ module.exports.CreateDB = function (parent, func) {
68 // TODO: Remove all meshes that dont have any links
69
70 // Remove all events, power events and SMBIOS data from the main collection. They are all in seperate collections now.
71 - if (obj.databaseType == 3) {
71 + if (obj.databaseType == 4) {
72 + // MariaDB
73 + obj.RemoveAllOfType('event', function () { });
74 + obj.RemoveAllOfType('power', function () { });
75 + obj.RemoveAllOfType('smbios', function () { });
76 + } else if (obj.databaseType == 3) {
77 // MongoDB
78 obj.file.deleteMany({ type: 'event' }, { multi: true });
79 obj.file.deleteMany({ type: 'power' }, { multi: true });
@@ -84,7 +89,10 @@ module.exports.CreateDB = function (parent, func) {
89 obj.GetAllType('mesh', function (err, docs) {
90 var meshlist = [];
91 if ((err == null) && (docs.length > 0)) { for (var i in docs) { meshlist.push(docs[i]._id); } }
87 - if (obj.databaseType == 3) {
92 + if (obj.databaseType == 4) {
93 + // MariaDB
94 + mariaDbQuery('DELETE FROM MeshCentral.Main WHERE (extra LIKE ("mesh/%") AND (extra NOT IN ?)', [meshlist], func);
95 + } else if (obj.databaseType == 3) {
96 // MongoDB
97 obj.file.deleteMany({ meshid: { $exists: true, $nin: meshlist } }, { multi: true });
98 } else {
@@ -315,7 +323,25 @@ module.exports.CreateDB = function (parent, func) {
323 obj.dbRecordsDecryptKey = parent.crypto.createHash('sha384').update(parent.args.dbrecordsdecryptkey).digest("raw").slice(0, 32);
324 }
325
318 - if (parent.args.mongodb) {
326 + if (parent.args.mariadb) {
327 + // Use MariaDB
328 + obj.databaseType = 4;
329 + Datastore = require('mariadb').createPool(parent.args.mariadb);
330 + //mariaDbQuery('DROP DATABASE MeshCentral', null, function (err, docs) { console.log('DROP'); }); return;
331 + mariaDbQuery('USE meshcentral', null, function (err, docs) {
332 + if (err == null) { setupFunctions(func); } else
333 + mariaDbBatchExec([
334 + 'CREATE DATABASE meshcentral',
335 + 'CREATE TABLE meshcentral.main (id VARCHAR(256) NOT NULL, type CHAR(32), domain CHAR(64), extra CHAR(255), extraex CHAR(255), doc JSON, PRIMARY KEY(id), CHECK (json_valid(doc)))',
336 + 'CREATE INDEX ndxtypedomainextra ON meshcentral.main (type, domain, extra)',
337 + 'CREATE INDEX ndxextra ON meshcentral.main (extra)',
338 + 'CREATE INDEX ndxextraex ON meshcentral.main (extraex)',
339 + 'CREATE TABLE meshcentral.serverstats (time DATETIME, expire DATETIME, doc JSON, PRIMARY KEY(time), CHECK (json_valid(doc)))',
340 + 'CREATE INDEX ndxserverstattime ON meshcentral.serverstats (time)',
341 + 'CREATE INDEX ndxserverstatexpire ON meshcentral.serverstats (expire)'
342 + ], function (err) { if (err != null) { console.log(err); } setupFunctions(func); });
343 + });
344 + } else if (parent.args.mongodb) {
345 // Use MongoDB
346 obj.databaseType = 3;
347 require('mongodb').MongoClient.connect(parent.args.mongodb, { useNewUrlParser: true, useUnifiedTopology: true }, function (err, client) {
@@ -401,18 +427,18 @@ module.exports.CreateDB = function (parent, func) {
427 for (var i in indexes) { indexesByName[indexes[i].name] = indexes[i]; indexCount++; }
428 if ((indexCount != 5) || (indexesByName['Username1'] == null) || (indexesByName['DomainNodeTime1'] == null) || (indexesByName['IdsAndTime1'] == null) || (indexesByName['ExpireTime1'] == null)) {
429 // Reset all indexes
404 - console.log('Resetting events indexes...');
430 + console.log("Resetting events indexes...");
431 obj.eventsfile.dropIndexes(function (err) {
432 obj.eventsfile.createIndex({ username: 1 }, { sparse: 1, name: 'Username1' });
433 obj.eventsfile.createIndex({ domain: 1, nodeid: 1, time: -1 }, { sparse: 1, name: 'DomainNodeTime1' });
434 obj.eventsfile.createIndex({ ids: 1, time: -1 }, { sparse: 1, name: 'IdsAndTime1' });
409 - obj.eventsfile.createIndex({ "time": 1 }, { expireAfterSeconds: expireEventsSeconds, name: 'ExpireTime1' });
435 + obj.eventsfile.createIndex({ 'time': 1 }, { expireAfterSeconds: expireEventsSeconds, name: 'ExpireTime1' });
436 });
437 } else if (indexesByName['ExpireTime1'].expireAfterSeconds != expireEventsSeconds) {
438 // Reset the timeout index
413 - console.log('Resetting events expire index...');
414 - obj.eventsfile.dropIndex("ExpireTime1", function (err) {
415 - obj.eventsfile.createIndex({ "time": 1 }, { expireAfterSeconds: expireEventsSeconds, name: 'ExpireTime1' });
439 + console.log("Resetting events expire index...");
440 + obj.eventsfile.dropIndex('ExpireTime1', function (err) {
441 + obj.eventsfile.createIndex({ 'time': 1 }, { expireAfterSeconds: expireEventsSeconds, name: 'ExpireTime1' });
442 });
443 }
444 });
@@ -425,18 +451,18 @@ module.exports.CreateDB = function (parent, func) {
451 for (var i in indexes) { indexesByName[indexes[i].name] = indexes[i]; indexCount++; }
452 if ((indexCount != 3) || (indexesByName['NodeIdAndTime1'] == null) || (indexesByName['ExpireTime1'] == null)) {
453 // Reset all indexes
428 - console.log('Resetting power events indexes...');
454 + console.log("Resetting power events indexes...");
455 obj.powerfile.dropIndexes(function (err) {
456 // Create all indexes
457 obj.powerfile.createIndex({ nodeid: 1, time: 1 }, { sparse: 1, name: 'NodeIdAndTime1' });
432 - obj.powerfile.createIndex({ "time": 1 }, { expireAfterSeconds: expirePowerEventsSeconds, name: 'ExpireTime1' });
458 + obj.powerfile.createIndex({ 'time': 1 }, { expireAfterSeconds: expirePowerEventsSeconds, name: 'ExpireTime1' });
459 });
460 } else if (indexesByName['ExpireTime1'].expireAfterSeconds != expirePowerEventsSeconds) {
461 // Reset the timeout index
436 - console.log('Resetting power events expire index...');
437 - obj.powerfile.dropIndex("ExpireTime1", function (err) {
462 + console.log("Resetting power events expire index...");
463 + obj.powerfile.dropIndex('ExpireTime1', function (err) {
464 // Reset the expire power events index
439 - obj.powerfile.createIndex({ "time": 1 }, { expireAfterSeconds: expirePowerEventsSeconds, name: 'ExpireTime1' });
465 + obj.powerfile.createIndex({ 'time': 1 }, { expireAfterSeconds: expirePowerEventsSeconds, name: 'ExpireTime1' });
466 });
467 }
468 });
@@ -452,18 +478,18 @@ module.exports.CreateDB = function (parent, func) {
478 for (var i in indexes) { indexesByName[indexes[i].name] = indexes[i]; indexCount++; }
479 if ((indexCount != 3) || (indexesByName['ExpireTime1'] == null)) {
480 // Reset all indexes
455 - console.log('Resetting server stats indexes...');
481 + console.log("Resetting server stats indexes...");
482 obj.serverstatsfile.dropIndexes(function (err) {
483 // Create all indexes
458 - obj.serverstatsfile.createIndex({ "time": 1 }, { expireAfterSeconds: expireServerStatsSeconds, name: 'ExpireTime1' });
459 - obj.serverstatsfile.createIndex({ "expire": 1 }, { expireAfterSeconds: 0, name: 'ExpireTime2' }); // Auto-expire events
484 + obj.serverstatsfile.createIndex({ 'time': 1 }, { expireAfterSeconds: expireServerStatsSeconds, name: 'ExpireTime1' });
485 + obj.serverstatsfile.createIndex({ 'expire': 1 }, { expireAfterSeconds: 0, name: 'ExpireTime2' }); // Auto-expire events
486 });
487 } else if (indexesByName['ExpireTime1'].expireAfterSeconds != expireServerStatsSeconds) {
488 // Reset the timeout index
463 - console.log('Resetting server stats expire index...');
464 - obj.serverstatsfile.dropIndex("ExpireTime1", function (err) {
489 + console.log("Resetting server stats expire index...");
490 + obj.serverstatsfile.dropIndex('ExpireTime1', function (err) {
491 // Reset the expire server stats index
466 - obj.serverstatsfile.createIndex({ "time": 1 }, { expireAfterSeconds: expireServerStatsSeconds, name: 'ExpireTime1' });
492 + obj.serverstatsfile.createIndex({ 'time': 1 }, { expireAfterSeconds: expireServerStatsSeconds, name: 'ExpireTime1' });
493 });
494 }
495 });
@@ -488,7 +514,7 @@ module.exports.CreateDB = function (parent, func) {
514 var indexesByName = {}, indexCount = 0;
515 for (var i in indexes) { indexesByName[indexes[i].name] = indexes[i]; indexCount++; }
516 if ((indexCount != 4) || (indexesByName['TypeDomainMesh1'] == null) || (indexesByName['Email1'] == null) || (indexesByName['Mesh1'] == null)) {
491 - console.log('Resetting main indexes...');
517 + console.log("Resetting main indexes...");
518 obj.file.dropIndexes(function (err) {
519 obj.file.createIndex({ type: 1, domain: 1, meshid: 1 }, { sparse: 1, name: 'TypeDomainMesh1' }); // Speeds up GetAllTypeNoTypeField() and GetAllTypeNoTypeFieldMeshFiltered()
520 obj.file.createIndex({ email: 1 }, { sparse: 1, name: 'Email1' }); // Speeds up GetUserWithEmail() and GetUserWithVerifiedEmail()
@@ -505,18 +531,18 @@ module.exports.CreateDB = function (parent, func) {
531 for (var i in indexes) { indexesByName[indexes[i].name] = indexes[i]; indexCount++; }
532 if ((indexCount != 5) || (indexesByName['Username1'] == null) || (indexesByName['DomainNodeTime1'] == null) || (indexesByName['IdsAndTime1'] == null) || (indexesByName['ExpireTime1'] == null)) {
533 // Reset all indexes
508 - console.log('Resetting events indexes...');
534 + console.log("Resetting events indexes...");
535 obj.eventsfile.dropIndexes(function (err) {
536 obj.eventsfile.createIndex({ username: 1 }, { sparse: 1, name: 'Username1' });
537 obj.eventsfile.createIndex({ domain: 1, nodeid: 1, time: -1 }, { sparse: 1, name: 'DomainNodeTime1' });
538 obj.eventsfile.createIndex({ ids: 1, time: -1 }, { sparse: 1, name: 'IdsAndTime1' });
513 - obj.eventsfile.createIndex({ "time": 1 }, { expireAfterSeconds: expireEventsSeconds, name: 'ExpireTime1' });
539 + obj.eventsfile.createIndex({ 'time': 1 }, { expireAfterSeconds: expireEventsSeconds, name: 'ExpireTime1' });
540 });
541 } else if (indexesByName['ExpireTime1'].expireAfterSeconds != expireEventsSeconds) {
542 // Reset the timeout index
517 - console.log('Resetting events expire index...');
518 - obj.eventsfile.dropIndex("ExpireTime1", function (err) {
519 - obj.eventsfile.createIndex({ "time": 1 }, { expireAfterSeconds: expireEventsSeconds, name: 'ExpireTime1' });
543 + console.log("Resetting events expire index...");
544 + obj.eventsfile.dropIndex('ExpireTime1', function (err) {
545 + obj.eventsfile.createIndex({ 'time': 1 }, { expireAfterSeconds: expireEventsSeconds, name: 'ExpireTime1' });
546 });
547 }
548 });
@@ -529,18 +555,18 @@ module.exports.CreateDB = function (parent, func) {
555 for (var i in indexes) { indexesByName[indexes[i].name] = indexes[i]; indexCount++; }
556 if ((indexCount != 3) || (indexesByName['NodeIdAndTime1'] == null) || (indexesByName['ExpireTime1'] == null)) {
557 // Reset all indexes
532 - console.log('Resetting power events indexes...');
558 + console.log("Resetting power events indexes...");
559 obj.powerfile.dropIndexes(function (err) {
560 // Create all indexes
561 obj.powerfile.createIndex({ nodeid: 1, time: 1 }, { sparse: 1, name: 'NodeIdAndTime1' });
536 - obj.powerfile.createIndex({ "time": 1 }, { expireAfterSeconds: expirePowerEventsSeconds, name: 'ExpireTime1' });
562 + obj.powerfile.createIndex({ 'time': 1 }, { expireAfterSeconds: expirePowerEventsSeconds, name: 'ExpireTime1' });
563 });
564 } else if (indexesByName['ExpireTime1'].expireAfterSeconds != expirePowerEventsSeconds) {
565 // Reset the timeout index
540 - console.log('Resetting power events expire index...');
541 - obj.powerfile.dropIndex("ExpireTime1", function (err) {
566 + console.log("Resetting power events expire index...");
567 + obj.powerfile.dropIndex('ExpireTime1', function (err) {
568 // Reset the expire power events index
543 - obj.powerfile.createIndex({ "time": 1 }, { expireAfterSeconds: expirePowerEventsSeconds, name: 'ExpireTime1' });
569 + obj.powerfile.createIndex({ 'time': 1 }, { expireAfterSeconds: expirePowerEventsSeconds, name: 'ExpireTime1' });
570 });
571 }
572 });
@@ -556,22 +582,22 @@ module.exports.CreateDB = function (parent, func) {
582 for (var i in indexes) { indexesByName[indexes[i].name] = indexes[i]; indexCount++; }
583 if ((indexCount != 3) || (indexesByName['ExpireTime1'] == null)) {
584 // Reset all indexes
559 - console.log('Resetting server stats indexes...');
585 + console.log("Resetting server stats indexes...");
586 obj.serverstatsfile.dropIndexes(function (err) {
587 // Create all indexes
562 - obj.serverstatsfile.createIndex({ "time": 1 }, { expireAfterSeconds: expireServerStatsSeconds, name: 'ExpireTime1' });
563 - obj.serverstatsfile.createIndex({ "expire": 1 }, { expireAfterSeconds: 0, name: 'ExpireTime2' }); // Auto-expire events
588 + obj.serverstatsfile.createIndex({ 'time': 1 }, { expireAfterSeconds: expireServerStatsSeconds, name: 'ExpireTime1' });
589 + obj.serverstatsfile.createIndex({ 'expire': 1 }, { expireAfterSeconds: 0, name: 'ExpireTime2' }); // Auto-expire events
590 });
591 } else if (indexesByName['ExpireTime1'].expireAfterSeconds != expireServerStatsSeconds) {
592 // Reset the timeout index
567 - console.log('Resetting server stats expire index...');
568 - obj.serverstatsfile.dropIndex("ExpireTime1", function (err) {
593 + console.log("Resetting server stats expire index...");
594 + obj.serverstatsfile.dropIndex('ExpireTime1', function (err) {
595 // Reset the expire server stats index
570 - obj.serverstatsfile.createIndex({ "time": 1 }, { expireAfterSeconds: expireServerStatsSeconds, name: 'ExpireTime1' });
596 + obj.serverstatsfile.createIndex({ 'time': 1 }, { expireAfterSeconds: expireServerStatsSeconds, name: 'ExpireTime1' });
597 });
598 }
599 });
574 -
600 +
601 // Setup plugin info collection
602 if (parent.config.settings != null) { obj.pluginsfile = db.collection('plugins'); }
603
@@ -640,7 +666,7 @@ module.exports.CreateDB = function (parent, func) {
666 obj.pluginsfile = new Datastore({ filename: parent.getConfigFilePath('meshcentral-plugins.db'), autoload: true });
667 obj.pluginsfile.persistence.setAutocompactionInterval(36000);
668 }
643 -
669 +
670 setupFunctions(func); // Completed setup of NeDB
671 }
672
@@ -648,13 +674,144 @@ module.exports.CreateDB = function (parent, func) {
674 function checkObjectNames(r, tag) {
675 if (typeof r != 'object') return;
676 for (var i in r) {
651 - if (i.indexOf('.') >= 0) { throw('BadDbName (' + tag + '): ' + JSON.stringify(r)); }
677 + if (i.indexOf('.') >= 0) { throw ('BadDbName (' + tag + '): ' + JSON.stringify(r)); }
678 checkObjectNames(r[i], tag);
679 }
680 }
681
682 + // Query the database
683 + function mariaDbQuery(query, args, func) {
684 + Datastore.getConnection()
685 + .then(function (conn) {
686 + conn.query(query, args)
687 + .then(function (rows) {
688 + conn.release();
689 + const docs = [];
690 + for (var i in rows) { if (rows[i].doc) { docs.push(performTypedRecordDecrypt(JSON.parse(rows[i].doc))); } }
691 + if (func) try { func(null, docs); } catch (ex) { console.log(ex); }
692 + })
693 + .catch(function (err) { conn.release(); if (func) try { func(err); } catch (ex) { console.log(ex); } });
694 + }).catch(function (err) { if (func) { try { func(err); } catch (ex) { console.log(ex); } } });
695 + }
696 +
697 + // Exec on the database
698 + function mariaDbExec(query, args, func) {
699 + Datastore.getConnection()
700 + .then(function (conn) {
701 + conn.query(query, args)
702 + .then(function (rows) {
703 + conn.release();
704 + if (func) try { func(null, rows[0]); } catch (ex) { console.log(ex); }
705 + })
706 + .catch(function (err) { conn.release(); if (func) try { func(err); } catch (ex) { console.log(ex); } });
707 + }).catch(function (err) { if (func) { try { func(err); } catch (ex) { console.log(ex); } } });
708 + }
709 +
710 + // Execute a batch of commands on the database
711 + function mariaDbBatchExec(queries, func) {
712 + Datastore.getConnection()
713 + .then(function (conn) {
714 + var Promises = [];
715 + for (var i in queries) { Promises.push(conn.query(queries[i])); }
716 + Promise.all(Promises)
717 + .then(function (rows) { conn.release(); if (func) { try { func(null); } catch (ex) { console.log(ex); } } })
718 + .catch(function (err) { conn.release(); if (func) { try { func(err); } catch (ex) { console.log(ex); } } });
719 + })
720 + .catch(function (err) { if (func) { try { func(err); } catch (ex) { console.log(ex); } } });
721 + }
722 +
723 function setupFunctions(func) {
657 - if (obj.databaseType == 3) {
724 + if (obj.databaseType == 4) {
725 + // Database actions on the main collection (MariaDB)
726 + obj.Set = function (value, func) {
727 + var extra = null, extraex = null;
728 + if (value.meshid) { extra = value.meshid; } else if (value.email) { extra = 'email/' + value.email; }
729 + if ((value.type == 'node') && (value.intelamt != null) && (value.intelamt.uuid != null)) { extraex = 'uuid/' + value.intelamt.uuid; }
730 + mariaDbQuery('REPLACE INTO meshcentral.main VALUE (?, ?, ?, ?, ?, ?)', [value._id, (value.type ? value.type : null), ((value.domain != null) ? value.domain : null), extra, extraex, JSON.stringify(performTypedRecordEncrypt(value))], func);
731 + }
732 + obj.Get = function (_id, func) { mariaDbQuery('SELECT doc FROM meshcentral.main WHERE id = ?', [_id], func); }
733 + obj.GetAll = function (func) { mariaDbQuery('SELECT domain, doc FROM meshcentral.main', null, func); }
734 + obj.GetHash = function (id, func) { mariaDbQuery('SELECT doc FROM meshcentral.main WHERE id = ?', [id], func); }
735 + obj.GetAllTypeNoTypeField = function (type, domain, func) { mariaDbQuery('SELECT doc FROM meshcentral.main WHERE type = ? AND domain = ?', [type, domain], function (err, docs) { for (var i in docs) { delete docs[i].type } func(err, docs); }); };
736 + obj.GetAllTypeNoTypeFieldMeshFiltered = function (meshes, domain, type, id, func) { if (id && (id != '')) { mariaDbQuery('SELECT doc FROM meshcentral.main WHERE id = ? AND type = ? AND domain = ? AND extra IN ?', [id, type, domain, meshes], function (err, docs) { for (var i in docs) { delete docs[i].type } func(err, docs); }); } else { mariaDbQuery('SELECT doc FROM meshcentral.main WHERE type = ? AND domain = ? AND extra IN ?', [type, domain, meshes], function (err, docs) { for (var i in docs) { delete docs[i].type } func(err, docs); }); } };
737 + obj.GetAllType = function (type, func) { mariaDbQuery('SELECT doc FROM meshcentral.main WHERE type = ?', [type], func); }
738 + obj.GetAllIdsOfType = function (ids, domain, type, func) { mariaDbQuery('SELECT doc FROM meshcentral.main WHERE id IN ? AND domain = ? AND type = ?', [ids, domain, type], func); }
739 + obj.GetUserWithEmail = function (domain, email, func) { mariaDbQuery('SELECT doc FROM meshcentral.main WHERE domain = ? AND extra = ?', [domain, 'email/' + email], func); }
740 + obj.GetUserWithVerifiedEmail = function (domain, email, func) { mariaDbQuery('SELECT doc FROM meshcentral.main WHERE domain = ? AND extra = ?', [domain, 'email/' + email], func); }
741 + obj.Remove = function (id, func) { mariaDbQuery('DELETE FROM meshcentral.main WHERE id = ?', [id], func); };
742 + obj.RemoveAll = function (func) { mariaDbQuery('DELETE FROM meshcentral.main', null, func); };
743 + obj.RemoveAllOfType = function (type, func) { mariaDbQuery('DELETE FROM meshcentral.main WHERE type = ?', [type], func); };
744 + obj.InsertMany = function (data, func) { var pendingOps = 0; for (var i in data) { pendingOps++; obj.Set(data[i], function () { if (--pendingOps == 0) { func(); } }); } };
745 + obj.RemoveMeshDocuments = function (id) { mariaDbQuery('DELETE FROM meshcentral.main WHERE extra = ?', [id], function () { mariaDbQuery('DELETE FROM meshcentral.main WHERE id = ?', ['nt' + id], func); } ); };
746 + obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if (docs.length == 1) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); };
747 + obj.DeleteDomain = function (domain, func) { mariaDbQuery('DELETE FROM meshcentral.main WHERE domain = ?', [domain], func); };
748 + obj.SetUser = function (user) { if (user.subscriptions != null) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); } else { obj.Set(user); } };
749 + obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } };
750 + obj.getLocalAmtNodes = function (func) { mariaDbQuery('SELECT doc FROM meshcentral.main WHERE (type = "node") AND (extraex IS NOT NULL)', null, function (err, docs) { var r = []; for (var i in docs) { if (docs[i].host != null) { r.push(docs[i]); } } func(err, r); }); };
751 + obj.getAmtUuidMeshNode = function (meshid, uuid, func) { mariaDbQuery('SELECT doc FROM meshcentral.main WHERE meshid = ? AND extraex = ?', [meshid, 'uuid/' + uuid], func); };
752 + obj.getAmtUuidNode = function (uuid, func) { mariaDbQuery('SELECT doc FROM meshcentral.main WHERE type = "node" AND extraex = ?', ['uuid/' + uuid], func); };
753 + obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { mariaDbExec('SELECT COUNT(id) FROM meshcentral.main WHERE domain = ? AND type = ?', [domainid, type], function (err, response) { func((response['COUNT(id)'] == null) || (response['COUNT(id)'] > max), response['COUNT(id)']) }); } }
754 +
755 + // Database actions on the events collection
756 + obj.GetAllEvents = function (func) { console.log('TODO:GetAllEvents'); };
757 + obj.StoreEvent = function (event) { console.log('TODO:StoreEvent'); };
758 + obj.GetEvents = function (ids, domain, func) { console.log('TODO:GetEvents'); };
759 + obj.GetEventsWithLimit = function (ids, domain, limit, func) { console.log('TODO:GetEventsWithLimit'); };
760 + obj.GetUserEvents = function (ids, domain, username, func) { console.log('TODO:GetUserEvents'); };
761 + obj.GetUserEventsWithLimit = function (ids, domain, username, limit, func) { console.log('TODO:GetUserEventsWithLimit'); };
762 + obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, func) { console.log('TODO:GetNodeEventsWithLimit'); };
763 + obj.GetNodeEventsSelfWithLimit = function (nodeid, domain, userid, limit, func) { console.log('TODO:GetNodeEventsSelfWithLimit'); };
764 + obj.RemoveAllEvents = function (domain) { console.log('TODO:RemoveAllEvents'); };
765 + obj.RemoveAllNodeEvents = function (domain, nodeid) { console.log('TODO:RemoveAllNodeEvents'); };
766 + obj.RemoveAllUserEvents = function (domain, userid) { console.log('TODO:RemoveAllUserEvents'); };
767 + obj.GetFailedLoginCount = function (username, domainid, lastlogin, func) { console.log('TODO:GetFailedLoginCount'); }
768 +
769 + // Database actions on the power collection
770 + obj.getAllPower = function (func) { console.log('TODO:getAllPower'); };
771 + obj.storePowerEvent = function (event, multiServer, func) { console.log('TODO:storePowerEvent'); };
772 + obj.getPowerTimeline = function (nodeid, func) { console.log('TODO:getPowerTimeline'); };
773 + obj.removeAllPowerEvents = function () { console.log('TODO:removeAllPowerEvents'); };
774 + obj.removeAllPowerEventsForNode = function (nodeid) { console.log('TODO:removeAllPowerEventsForNode'); };
775 +
776 + // Database actions on the SMBIOS collection
777 + obj.GetAllSMBIOS = function (func) { console.log('TODO:GetAllSMBIOS'); };
778 + obj.SetSMBIOS = function (smbios, func) { console.log('TODO:SetSMBIOS'); };
779 + obj.RemoveSMBIOS = function (id) { console.log('TODO:RemoveSMBIOS'); };
780 + obj.GetSMBIOS = function (id, func) { console.log('TODO:GetSMBIOS'); };
781 +
782 + // Database actions on the Server Stats collection
783 + obj.SetServerStats = function (data, func) { mariaDbQuery('REPLACE INTO meshcentral.serverstats VALUE (?, ?, ?)', [data.time, data.expire, JSON.stringify(data)], func); };
784 + obj.GetServerStats = function (hours, func) { var t = new Date(); t.setTime(t.getTime() - (60 * 60 * 1000 * hours)); mariaDbQuery('SELECT doc FROM meshcentral.main WHERE time < ?', [t], func); }; // TODO: Expire old entries
785 +
786 + // Read a configuration file from the database
787 + obj.getConfigFile = function (path, func) { obj.Get('cfile/' + path, func); }
788 +
789 + // Write a configuration file to the database
790 + obj.setConfigFile = function (path, data, func) { obj.Set({ _id: 'cfile/' + path, type: 'cfile', data: data.toString('base64') }, func); }
791 +
792 + // List all configuration files
793 + obj.listConfigFiles = function (func) { mariaDbQuery('SELECT doc FROM meshcentral.main WHERE type = "cfile" ORDER BY id', func); }
794 +
795 + // Get all configuration files
796 + obj.getAllConfigFiles = function (password, func) {
797 + obj.file.find({ type: 'cfile' }).toArray(function (err, docs) {
798 + if (err != null) { func(null); return; }
799 + var r = null;
800 + for (var i = 0; i < docs.length; i++) {
801 + var name = docs[i]._id.split('/')[1];
802 + var data = obj.decryptData(password, docs[i].data);
803 + if (data != null) { if (r == null) { r = {}; } r[name] = data; }
804 + }
805 + func(r);
806 + });
807 + }
808 +
809 + // Get database information
810 + obj.getDbStats = function (func) { console.log('TODO:getDbStats'); }
811 +
812 + // Plugin operations
813 + //if (parent.config.settings.plugins != null) {}
814 + } else if (obj.databaseType == 3) {
815 // Database actions on the main collection (MongoDB)
816 obj.Set = function (data, func) { obj.file.replaceOne({ _id: data._id }, performTypedRecordEncrypt(data), { upsert: true }, func); };
817 obj.Get = function (id, func) {
@@ -698,7 +855,7 @@ module.exports.CreateDB = function (parent, func) {
855 // https://docs.mongodb.com/manual/reference/method/db.collection.countDocuments/
856 //obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { obj.file.countDocuments({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max)); }); } }
857 obj.isMaxType = function (max, type, domainid, func) {
701 - if (obj.eventsfile.countDocuments) {
858 + if (obj.file.countDocuments) {
859 if (max == null) { func(false); } else { obj.file.countDocuments({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max), count); }); }
860 } else {
861 if (max == null) { func(false); } else { obj.file.count({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max), count); }); }
@@ -707,10 +864,7 @@ module.exports.CreateDB = function (parent, func) {
864
865 // Database actions on the events collection
866 obj.GetAllEvents = function (func) { obj.eventsfile.find({}).toArray(func); };
710 - obj.StoreEvent = function (event) {
711 - checkObjectNames(event, 'x5'); // DEBUG CHECKING
712 - obj.eventsfile.insertOne(event);
713 - };
867 + obj.StoreEvent = function (event) { obj.eventsfile.insertOne(event); };
868 obj.GetEvents = function (ids, domain, func) { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }).project({ type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).toArray(func); };
869 obj.GetEventsWithLimit = function (ids, domain, limit, func) { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }).project({ type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).toArray(func); };
870 obj.GetUserEvents = function (ids, domain, username, func) { obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { username: username }] }).project({ type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).toArray(func); };
@@ -772,11 +926,11 @@ module.exports.CreateDB = function (parent, func) {
926 obj.getDbStats = function (func) {
927 obj.stats = { c: 6 };
928 obj.getStats(function (r) { obj.stats.recordTypes = r; if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } })
775 - obj.file.stats().then(function (stats) { obj.stats[stats.ns] = { size: stats.size, count: stats.count, avgObjSize: stats.avgObjSize, capped: stats.capped }; if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } }, function () { if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } } );
776 - obj.eventsfile.stats().then(function (stats) { obj.stats[stats.ns] = { size: stats.size, count: stats.count, avgObjSize: stats.avgObjSize, capped: stats.capped }; if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } }, function () { if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } } );
777 - obj.powerfile.stats().then(function (stats) { obj.stats[stats.ns] = { size: stats.size, count: stats.count, avgObjSize: stats.avgObjSize, capped: stats.capped }; if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } }, function () { if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } } );
778 - obj.smbiosfile.stats().then(function (stats) { obj.stats[stats.ns] = { size: stats.size, count: stats.count, avgObjSize: stats.avgObjSize, capped: stats.capped }; if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } }, function () { if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } } );
779 - obj.serverstatsfile.stats().then(function (stats) { obj.stats[stats.ns] = { size: stats.size, count: stats.count, avgObjSize: stats.avgObjSize, capped: stats.capped }; if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } }, function () { if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } } );
929 + obj.file.stats().then(function (stats) { obj.stats[stats.ns] = { size: stats.size, count: stats.count, avgObjSize: stats.avgObjSize, capped: stats.capped }; if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } }, function () { if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } });
930 + obj.eventsfile.stats().then(function (stats) { obj.stats[stats.ns] = { size: stats.size, count: stats.count, avgObjSize: stats.avgObjSize, capped: stats.capped }; if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } }, function () { if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } });
931 + obj.powerfile.stats().then(function (stats) { obj.stats[stats.ns] = { size: stats.size, count: stats.count, avgObjSize: stats.avgObjSize, capped: stats.capped }; if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } }, function () { if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } });
932 + obj.smbiosfile.stats().then(function (stats) { obj.stats[stats.ns] = { size: stats.size, count: stats.count, avgObjSize: stats.avgObjSize, capped: stats.capped }; if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } }, function () { if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } });
933 + obj.serverstatsfile.stats().then(function (stats) { obj.stats[stats.ns] = { size: stats.size, count: stats.count, avgObjSize: stats.avgObjSize, capped: stats.capped }; if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } }, function () { if (--obj.stats.c == 0) { delete obj.stats.c; func(obj.stats); } });
934 }
935
936 // Plugin operations
@@ -788,7 +942,7 @@ module.exports.CreateDB = function (parent, func) {
942 obj.setPluginStatus = function (id, status, func) { id = require('mongodb').ObjectID(id); obj.pluginsfile.updateOne({ _id: id }, { $set: { status: status } }, func); };
943 obj.updatePlugin = function (id, args, func) { delete args._id; id = require('mongodb').ObjectID(id); obj.pluginsfile.updateOne({ _id: id }, { $set: args }, func); };
944 }
791 -
945 +
946 } else {
947 // Database actions on the main collection (NeDB and MongoJS)
948 obj.Set = function (data, func) { var xdata = performTypedRecordEncrypt(data); obj.file.update({ _id: xdata._id }, xdata, { upsert: true }, func); };
@@ -933,7 +1087,7 @@ module.exports.CreateDB = function (parent, func) {
1087 const newAutoBackupPath = parent.path.join(backupPath, newAutoBackupFile);
1088
1089 r += 'DB Name: ' + dbname + '\r\n';
936 - r += 'DB Type: ' + ['None','NeDB','MongoJS','MongoDB'][obj.databaseType] + '\r\n';
1090 + r += 'DB Type: ' + ['None', 'NeDB', 'MongoJS', 'MongoDB'][obj.databaseType] + '\r\n';
1091 r += 'BackupPath: ' + backupPath + '\r\n';
1092 r += 'newAutoBackupFile: ' + newAutoBackupFile + '\r\n';
1093 r += 'newAutoBackupPath: ' + newAutoBackupPath + '\r\n';
meshcentral.js
+2
@@ -816,6 +816,7 @@ function CreateMeshCentralServer(config, args) {
816 }
817
818 // Grad some of the values from the original config.json file if present.
819 + config2['mariadb'] = config['mariadb'];
820 config2['mongodb'] = config['mongodb'];
821 config2['mongodbcol'] = config['mongodbcol'];
822 config2['dbencryptkey'] = config['dbencryptkey'];
@@ -2319,6 +2320,7 @@ function mainStart() {
2320 if (config.letsencrypt != null) { if ((nodeVersion < 10) || (require('crypto').generateKeyPair == null)) { addServerWarning("Let's Encrypt support requires Node v10.12 or higher.", !args.launch); } else { modules.push('greenlock'); } } // Add Greenlock Module
2321 if (config.settings.mqtt != null) { modules.push('aedes'); } // Add MQTT Modules
2322 if (config.settings.mongodb != null) { modules.push('mongodb'); } // Add MongoDB, official driver.
2323 + if (config.settings.mariadb != null) { modules.push('mariadb'); } // Add MariaDB, official driver.
2324 if (config.settings.vault != null) { modules.push('node-vault'); } // Add official HashiCorp's Vault module.
2325 if (config.settings.plugins != null) { modules.push('semver'); } // Required for version compat testing and update checks
2326 if ((config.settings.plugins != null) && (config.settings.plugins.proxy != null)) { modules.push('https-proxy-agent'); } // Required for HTTP/HTTPS proxy support
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.4.8-h",
3 + "version": "0.4.8-i",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
webserver.js
+1 -1
@@ -2263,7 +2263,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2263
2264 // Rename the file
2265 obj.fs.rename(file.path, fpath, function (err) {
2266 - if (err && (err.code === 'EXDEV') && fs.copyFile) {
2266 + if (err && (err.code === 'EXDEV')) {
2267 // On some Linux, the rename will fail with a "EXDEV" error, do a copy+unlink instead.
2268 obj.common.copyFile(file.path, fpath, function (err) {
2269 obj.fs.unlink(file.path, function (err) {