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) {