Early work on Postgres SQL support.
Ylian Saint-Hilaire committed
Nov 2, 2021 at 19:44 UTC
97bd723e4e47af6a3f16802ee5a81746434d1121
4 files changed
+70
-10
MeshCentralServer.njsproj
+8
@@ -645,6 +645,7 @@
645
<Folder Include="typings\globals\is-plain-object\" />
646
<Folder Include="typings\globals\jsbn\" />
647
<Folder Include="typings\globals\klaw\" />
648
+ <Folder Include="typings\globals\load-json-file\" />
649
<Folder Include="typings\globals\localforage\" />
650
<Folder Include="typings\globals\lru-cache\" />
651
<Folder Include="typings\globals\marked\" />
@@ -655,10 +656,13 @@
656
<Folder Include="typings\globals\object-assign\" />
657
<Folder Include="typings\globals\once\" />
658
<Folder Include="typings\globals\passport\" />
659
+ <Folder Include="typings\globals\pg-pool\" />
660
+ <Folder Include="typings\globals\split2\" />
661
<Folder Include="typings\globals\sprintf-js\" />
662
<Folder Include="typings\globals\type-check\" />
663
<Folder Include="typings\globals\underscore\" />
664
<Folder Include="typings\globals\uuid\" />
665
+ <Folder Include="typings\globals\window-size\" />
666
<Folder Include="views\" />
667
</ItemGroup>
668
<ItemGroup>
@@ -681,6 +685,7 @@
685
<TypeScriptCompile Include="typings\globals\is-plain-object\index.d.ts" />
686
<TypeScriptCompile Include="typings\globals\jsbn\index.d.ts" />
687
<TypeScriptCompile Include="typings\globals\klaw\index.d.ts" />
688
+ <TypeScriptCompile Include="typings\globals\load-json-file\index.d.ts" />
689
<TypeScriptCompile Include="typings\globals\localforage\index.d.ts" />
690
<TypeScriptCompile Include="typings\globals\lru-cache\index.d.ts" />
691
<TypeScriptCompile Include="typings\globals\marked\index.d.ts" />
@@ -691,10 +696,13 @@
696
<TypeScriptCompile Include="typings\globals\object-assign\index.d.ts" />
697
<TypeScriptCompile Include="typings\globals\once\index.d.ts" />
698
<TypeScriptCompile Include="typings\globals\passport\index.d.ts" />
699
+ <TypeScriptCompile Include="typings\globals\pg-pool\index.d.ts" />
700
+ <TypeScriptCompile Include="typings\globals\split2\index.d.ts" />
701
<TypeScriptCompile Include="typings\globals\sprintf-js\index.d.ts" />
702
<TypeScriptCompile Include="typings\globals\type-check\index.d.ts" />
703
<TypeScriptCompile Include="typings\globals\underscore\index.d.ts" />
704
<TypeScriptCompile Include="typings\globals\uuid\index.d.ts" />
705
+ <TypeScriptCompile Include="typings\globals\window-size\index.d.ts" />
706
<TypeScriptCompile Include="typings\index.d.ts" />
707
</ItemGroup>
708
<Import Project="$(MSBuildToolsPath)\Microsoft.Common.targets" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
db.js
+45
-8
@@ -230,7 +230,7 @@ module.exports.CreateDB = function (parent, func) {
230
// TODO: Remove all meshes that dont have any links
231
232
// Remove all events, power events and SMBIOS data from the main collection. They are all in seperate collections now.
233
- if ((obj.databaseType == 4) || (obj.databaseType == 5)) {
233
+ if ((obj.databaseType == 4) || (obj.databaseType == 5) || (obj.databaseType == 6)) {
234
// MariaDB or MySQL
235
obj.RemoveAllOfType('event', function () { });
236
obj.RemoveAllOfType('power', function () { });
@@ -640,6 +640,43 @@ module.exports.CreateDB = function (parent, func) {
640
});
641
setTimeout(function () { tempDatastore.end(); }, 2000);
642
}
643
+ } else if (parent.args.postgres) {
644
+ // Postgres SQL
645
+ var connectinArgs = parent.args.postgres;
646
+ var dbname = (connectinArgs.database != null) ? connectinArgs.database : 'meshcentral';
647
+ obj.databaseType = 6;
648
+ const pgtools = require('pgtools');
649
+ pgtools.createdb(connectinArgs, dbname, function (err, res) {
650
+ const { Pool, Client } = require('pg');
651
+ connectinArgs.database = dbname;
652
+ Datastore = new Client(connectinArgs);
653
+ Datastore.connect()
654
+ parent.debug('db', 'Checking tables...');
655
+ sqlDbBatchExec([
656
+ 'CREATE TABLE IF NOT EXISTS main (id VARCHAR(256) PRIMARY KEY NOT NULL, type CHAR(32), domain CHAR(64), extra CHAR(255), extraex CHAR(255), doc JSON)',
657
+ 'CREATE TABLE IF NOT EXISTS events(id SERIAL PRIMARY KEY, time TIMESTAMP, domain CHAR(64), action CHAR(255), nodeid CHAR(255), userid CHAR(255), doc JSON)',
658
+ 'CREATE TABLE IF NOT EXISTS eventids(fkid INT NOT NULL, target CHAR(255), CONSTRAINT fk_eventid FOREIGN KEY (fkid) REFERENCES events (id) ON DELETE CASCADE ON UPDATE RESTRICT)',
659
+ 'CREATE TABLE IF NOT EXISTS serverstats (time TIMESTAMP PRIMARY KEY, expire TIMESTAMP, doc JSON)',
660
+ 'CREATE TABLE IF NOT EXISTS power (id SERIAL PRIMARY KEY, time TIMESTAMP, nodeid CHAR(255), doc JSON)',
661
+ 'CREATE TABLE IF NOT EXISTS smbios (id CHAR(255) PRIMARY KEY, time TIMESTAMP, expire TIMESTAMP, doc JSON)',
662
+ 'CREATE TABLE IF NOT EXISTS plugin (id SERIAL PRIMARY KEY, doc JSON)'
663
+ ], function (results) {
664
+ parent.debug('db', 'Checking indexes...');
665
+ sqlDbExec('CREATE INDEX ndxtypedomainextra ON main (type, domain, extra)', null, function (err, response) { });
666
+ sqlDbExec('CREATE INDEX ndxextra ON main (extra)', null, function (err, response) { });
667
+ sqlDbExec('CREATE INDEX ndxextraex ON main (extraex)', null, function (err, response) { });
668
+ sqlDbExec('CREATE INDEX ndxeventstime ON events(time)', null, function (err, response) { });
669
+ sqlDbExec('CREATE INDEX ndxeventsusername ON events(domain, userid, time)', null, function (err, response) { });
670
+ sqlDbExec('CREATE INDEX ndxeventsdomainnodeidtime ON events(domain, nodeid, time)', null, function (err, response) { });
671
+ sqlDbExec('CREATE INDEX ndxeventids ON eventids(target)', null, function (err, response) { });
672
+ sqlDbExec('CREATE INDEX ndxserverstattime ON serverstats (time)', null, function (err, response) { });
673
+ sqlDbExec('CREATE INDEX ndxserverstatexpire ON serverstats (expire)', null, function (err, response) { });
674
+ sqlDbExec('CREATE INDEX ndxpowernodeidtime ON power (nodeid, time)', null, function (err, response) { });
675
+ sqlDbExec('CREATE INDEX ndxsmbiostime ON smbios (time)', null, function (err, response) { });
676
+ sqlDbExec('CREATE INDEX ndxsmbiosexpire ON smbios (expire)', null, function (err, response) { });
677
+ setupFunctions(func);
678
+ });
679
+ });
680
} else if (parent.args.mongodb) {
681
// Use MongoDB
682
obj.databaseType = 3;
@@ -1011,12 +1048,12 @@ module.exports.CreateDB = function (parent, func) {
1048
.then(function (rows) {
1049
conn.release();
1050
const docs = [];
1014
- for (var i in rows) { if (rows[i].doc) { docs.push(performTypedRecordDecrypt((typeof rows[i].doc == 'object')? rows[i].doc : JSON.parse(rows[i].doc))); } }
1051
+ for (var i in rows) { if (rows[i].doc) { docs.push(performTypedRecordDecrypt((typeof rows[i].doc == 'object') ? rows[i].doc : JSON.parse(rows[i].doc))); } }
1052
if (func) try { func(null, docs); } catch (ex) { console.log('SQLERR1', ex); }
1053
})
1054
.catch(function (err) { conn.release(); if (func) try { func(err); } catch (ex) { console.log('SQLERR2', ex); } });
1055
}).catch(function (err) { if (func) { try { func(err); } catch (ex) { console.log('SQLERR3', ex); } } });
1019
- } else if (obj.databaseType == 5) { // MySQL
1056
+ } else if ((obj.databaseType == 5) || (obj.databaseType == 6)) { // MySQL or Postgres SQL
1057
Datastore.query(query, args, function (error, results, fields) {
1058
if (error != null) {
1059
if (func) try { func(error); } catch (ex) { console.log('SQLERR4', ex); }
@@ -1041,10 +1078,10 @@ module.exports.CreateDB = function (parent, func) {
1078
if (func) try { func(null, rows[0]); } catch (ex) { console.log(ex); }
1079
})
1080
.catch(function (err) { conn.release(); if (func) try { func(err); } catch (ex) { console.log(ex); } });
1044
- }).catch(function (err) { if (func) { try { func(err); } catch (ex) { console.log(ex); } } });
1045
- } else if (obj.databaseType == 5) { // MySQL
1081
+ }).catch(function (err) { if (func) { try { func(err); } catch (ex) { console.log(ex); } } });
1082
+ } else if ((obj.databaseType == 5) || (obj.databaseType == 6)) { // MySQL or Postgres SQL
1083
Datastore.query(query, args, function (error, results, fields) {
1047
- if (func) try { func(error, results?results[0]:null); } catch (ex) { console.log(ex); }
1084
+ if (func) try { func(error, results ? results[0] : null); } catch (ex) { console.log(ex); }
1085
});
1086
}
1087
}
@@ -1061,7 +1098,7 @@ module.exports.CreateDB = function (parent, func) {
1098
.catch(function (err) { conn.release(); if (func) { try { func(err); } catch (ex) { console.log(ex); } } });
1099
})
1100
.catch(function (err) { if (func) { try { func(err); } catch (ex) { console.log(ex); } } });
1064
- } else if (obj.databaseType == 5) { // MySQL
1101
+ } else if ((obj.databaseType == 5) || (obj.databaseType == 6)) { // MySQL or Postgres SQL
1102
var Promises = [];
1103
for (var i in queries) { if (typeof queries[i] == 'string') { Promises.push(Datastore.query(queries[i])); } else { Promises.push(Datastore.query(queries[i][0], queries[i][1])); } }
1104
Promise.all(Promises)
@@ -1071,7 +1108,7 @@ module.exports.CreateDB = function (parent, func) {
1108
}
1109
1110
function setupFunctions(func) {
1074
- if ((obj.databaseType == 4) || (obj.databaseType == 5)) {
1111
+ if ((obj.databaseType == 4) || (obj.databaseType == 5) || (obj.databaseType == 6)) {
1112
// Database actions on the main collection (MariaDB or MySQL)
1113
obj.Set = function (value, func) {
1114
obj.dbCounters.fileSet++;
meshcentral.js
+1
@@ -3341,6 +3341,7 @@ function mainStart() {
3341
if (config.settings.mysql != null) { modules.push('mysql'); } // Add MySQL.
3342
//if (config.settings.mysql != null) { modules.push('@mysql/xdevapi'); } // Add MySQL, official driver (https://dev.mysql.com/doc/dev/connector-nodejs/8.0/)
3343
if (config.settings.mongodb != null) { modules.push('mongodb@4.1.0'); modules.push('saslprep'); } // Add MongoDB, official driver.
3344
+ if (config.settings.postgres != null) { modules.push('pg@8.7.1'); modules.push('pgtools@0.3.2'); } // Add Postgres, Postgres driver.
3345
if (config.settings.mariadb != null) { modules.push('mariadb'); } // Add MariaDB, official driver.
3346
if (config.settings.vault != null) { modules.push('node-vault'); } // Add official HashiCorp's Vault module.
3347
if (config.settings.plugins != null) { modules.push('semver'); } // Required for version compat testing and update checks
package.json
+16
-2
@@ -36,6 +36,9 @@
36
"sample-config-advanced.json"
37
],
38
"dependencies": {
39
+ "@yetzt/nedb": "^1.8.0",
40
+ "archiver": "^4.0.2",
41
+ "archiver-zip-encrypted": "^1.0.10",
42
"body-parser": "^1.19.0",
43
"cbor": "~5.2.0",
44
"compression": "^1.7.4",
@@ -43,13 +46,24 @@
46
"express": "^4.17.0",
47
"express-handlebars": "^3.1.0",
48
"express-ws": "^4.0.0",
49
+ "image-size": "^1.0.0",
50
"ipcheck": "^0.1.0",
51
+ "loadavg-windows": "^1.1.1",
52
"minimist": "^1.2.5",
53
+ "mongodb": "^4.1.0",
54
"multiparty": "^4.2.1",
49
- "@yetzt/nedb": "^1.8.0",
55
"node-forge": "^0.10.0",
56
+ "node-rdpjs-2": "^0.3.5",
57
+ "node-windows": "^0.1.4",
58
+ "otplib": "^10.2.3",
59
+ "pg": "^8.7.1",
60
+ "pgtools": "^0.3.2",
61
+ "saslprep": "^1.0.3",
62
+ "ssh2": "^1.5.0",
63
+ "web-push": "^3.4.5",
64
"ws": "^5.2.3",
52
- "yauzl": "^2.10.0"
65
+ "yauzl": "^2.10.0",
66
+ "yubikeyotp": "^0.2.0"
67
},
68
"repository": {
69
"type": "git",