dbgate-api 5.2.0 → 5.2.2-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -6
- package/src/controllers/archive.js +4 -1
- package/src/controllers/auth.js +14 -7
- package/src/controllers/config.js +8 -7
- package/src/controllers/connections.js +23 -13
- package/src/controllers/databaseConnections.js +35 -12
- package/src/controllers/runners.js +21 -13
- package/src/controllers/scheduler.js +4 -1
- package/src/controllers/serverConnections.js +41 -10
- package/src/controllers/sessions.js +27 -10
- package/src/controllers/uploads.js +3 -1
- package/src/currentVersion.js +2 -2
- package/src/index.js +96 -2
- package/src/main.js +12 -9
- package/src/proc/databaseConnectionProcess.js +8 -6
- package/src/proc/serverConnectionProcess.js +4 -3
- package/src/proc/sessionProcess.js +26 -1
- package/src/proc/sshForwardProcess.js +5 -2
- package/src/shell/archiveWriter.js +4 -1
- package/src/shell/dumpDatabase.js +5 -2
- package/src/shell/executeQuery.js +5 -2
- package/src/shell/generateModelSql.js +30 -0
- package/src/shell/importDatabase.js +5 -2
- package/src/shell/index.js +4 -0
- package/src/shell/jsonArrayWriter.js +4 -1
- package/src/shell/jsonLinesReader.js +3 -1
- package/src/shell/jsonLinesWriter.js +3 -1
- package/src/shell/loadDatabase.js +21 -0
- package/src/shell/queryReader.js +4 -2
- package/src/shell/requirePlugin.js +3 -1
- package/src/shell/runScript.js +3 -1
- package/src/shell/sqlDataWriter.js +3 -2
- package/src/shell/tableReader.js +6 -5
- package/src/shell/tableWriter.js +4 -3
- package/src/utility/DatastoreProxy.js +29 -9
- package/src/utility/childProcessChecker.js +6 -2
- package/src/utility/cleanDirectory.js +2 -2
- package/src/utility/directories.js +22 -6
- package/src/utility/pipeForkLogs.js +19 -0
- package/src/utility/processArgs.js +2 -0
- package/src/utility/sshTunnel.js +23 -14
- package/src/utility/sshTunnelProxy.js +7 -1
- package/src/utility/useController.js +9 -7
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dbgate-api",
|
|
3
3
|
"main": "src/index.js",
|
|
4
|
-
"version": "5.2.
|
|
4
|
+
"version": "5.2.2-alpha.11",
|
|
5
5
|
"homepage": "https://dbgate.org/",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"cors": "^2.8.5",
|
|
28
28
|
"cross-env": "^6.0.3",
|
|
29
29
|
"dbgate-query-splitter": "^4.9.3",
|
|
30
|
-
"dbgate-sqltree": "^5.2.
|
|
31
|
-
"dbgate-tools": "^5.2.
|
|
30
|
+
"dbgate-sqltree": "^5.2.2-alpha.11",
|
|
31
|
+
"dbgate-tools": "^5.2.2-alpha.11",
|
|
32
32
|
"debug": "^4.3.4",
|
|
33
33
|
"diff": "^5.0.0",
|
|
34
34
|
"diff2html": "^3.4.13",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"ncp": "^2.0.0",
|
|
50
50
|
"node-cron": "^2.0.3",
|
|
51
51
|
"on-finished": "^2.4.1",
|
|
52
|
+
"pinomin": "^1.0.1",
|
|
52
53
|
"portfinder": "^1.0.28",
|
|
53
54
|
"simple-encryptor": "^4.0.0",
|
|
54
55
|
"ssh2": "^1.11.0",
|
|
@@ -69,7 +70,7 @@
|
|
|
69
70
|
"devDependencies": {
|
|
70
71
|
"@types/fs-extra": "^9.0.11",
|
|
71
72
|
"@types/lodash": "^4.14.149",
|
|
72
|
-
"dbgate-types": "^5.2.
|
|
73
|
+
"dbgate-types": "^5.2.2-alpha.11",
|
|
73
74
|
"env-cmd": "^10.1.0",
|
|
74
75
|
"node-loader": "^1.0.2",
|
|
75
76
|
"nodemon": "^2.0.2",
|
|
@@ -79,7 +80,7 @@
|
|
|
79
80
|
},
|
|
80
81
|
"optionalDependencies": {
|
|
81
82
|
"better-sqlite3": "7.6.2",
|
|
82
|
-
"
|
|
83
|
-
"
|
|
83
|
+
"msnodesqlv8": "^2.6.0",
|
|
84
|
+
"oracledb": "^5.5.0"
|
|
84
85
|
}
|
|
85
86
|
}
|
|
@@ -6,6 +6,9 @@ const socket = require('../utility/socket');
|
|
|
6
6
|
const { saveFreeTableData } = require('../utility/freeTableStorage');
|
|
7
7
|
const loadFilesRecursive = require('../utility/loadFilesRecursive');
|
|
8
8
|
const getJslFileName = require('../utility/getJslFileName');
|
|
9
|
+
const { getLogger } = require('dbgate-tools');
|
|
10
|
+
|
|
11
|
+
const logger = getLogger('archive');
|
|
9
12
|
|
|
10
13
|
module.exports = {
|
|
11
14
|
folders_meta: true,
|
|
@@ -68,7 +71,7 @@ module.exports = {
|
|
|
68
71
|
...fileType('.matview.sql', 'matview.sql'),
|
|
69
72
|
];
|
|
70
73
|
} catch (err) {
|
|
71
|
-
|
|
74
|
+
logger.error({ err }, 'Error reading archive files');
|
|
72
75
|
return [];
|
|
73
76
|
}
|
|
74
77
|
},
|
package/src/controllers/auth.js
CHANGED
|
@@ -3,8 +3,11 @@ const jwt = require('jsonwebtoken');
|
|
|
3
3
|
const getExpressPath = require('../utility/getExpressPath');
|
|
4
4
|
const uuidv1 = require('uuid/v1');
|
|
5
5
|
const { getLogins } = require('../utility/hasPermission');
|
|
6
|
+
const { getLogger } = require('dbgate-tools');
|
|
6
7
|
const AD = require('activedirectory2').promiseWrapper;
|
|
7
8
|
|
|
9
|
+
const logger = getLogger('auth');
|
|
10
|
+
|
|
8
11
|
const tokenSecret = uuidv1();
|
|
9
12
|
|
|
10
13
|
function shouldAuthorizeApi() {
|
|
@@ -51,7 +54,7 @@ function authMiddleware(req, res, next) {
|
|
|
51
54
|
return next();
|
|
52
55
|
}
|
|
53
56
|
|
|
54
|
-
|
|
57
|
+
logger.error({ err }, 'Sending invalid token error');
|
|
55
58
|
|
|
56
59
|
return unauthorizedResponse(req, res, 'invalid token');
|
|
57
60
|
}
|
|
@@ -62,20 +65,24 @@ module.exports = {
|
|
|
62
65
|
async oauthToken(params) {
|
|
63
66
|
const { redirectUri, code } = params;
|
|
64
67
|
|
|
68
|
+
const scopeParam = process.env.OAUTH_SCOPE ? `&scope=${process.env.OAUTH_SCOPE}` : '';
|
|
65
69
|
const resp = await axios.default.post(
|
|
66
70
|
`${process.env.OAUTH_TOKEN}`,
|
|
67
71
|
`grant_type=authorization_code&code=${encodeURIComponent(code)}&redirect_uri=${encodeURIComponent(
|
|
68
72
|
redirectUri
|
|
69
|
-
)}&client_id=${process.env.OAUTH_CLIENT_ID}&client_secret=${process.env.OAUTH_CLIENT_SECRET}`
|
|
73
|
+
)}&client_id=${process.env.OAUTH_CLIENT_ID}&client_secret=${process.env.OAUTH_CLIENT_SECRET}${scopeParam}`
|
|
70
74
|
);
|
|
71
75
|
|
|
72
76
|
const { access_token, refresh_token } = resp.data;
|
|
73
77
|
|
|
74
78
|
const payload = jwt.decode(access_token);
|
|
75
79
|
|
|
76
|
-
|
|
80
|
+
logger.info({ payload }, 'User payload returned from OAUTH');
|
|
77
81
|
|
|
78
|
-
const login =
|
|
82
|
+
const login =
|
|
83
|
+
process.env.OAUTH_LOGIN_FIELD && payload && payload[process.env.OAUTH_LOGIN_FIELD]
|
|
84
|
+
? payload[process.env.OAUTH_LOGIN_FIELD]
|
|
85
|
+
: 'oauth';
|
|
79
86
|
|
|
80
87
|
if (
|
|
81
88
|
process.env.OAUTH_ALLOWED_LOGINS &&
|
|
@@ -113,12 +120,12 @@ module.exports = {
|
|
|
113
120
|
!process.env.AD_ALLOWED_LOGINS.split(',').find(x => x.toLowerCase().trim() == login.toLowerCase().trim())
|
|
114
121
|
) {
|
|
115
122
|
return { error: `Username ${login} not allowed to log in` };
|
|
116
|
-
}
|
|
123
|
+
}
|
|
117
124
|
return {
|
|
118
125
|
accessToken: jwt.sign({ login }, tokenSecret, { expiresIn: getTokenLifetime() }),
|
|
119
126
|
};
|
|
120
127
|
} catch (err) {
|
|
121
|
-
|
|
128
|
+
logger.error({ err }, 'Failed active directory authentization');
|
|
122
129
|
return {
|
|
123
130
|
error: err.message,
|
|
124
131
|
};
|
|
@@ -129,7 +136,7 @@ module.exports = {
|
|
|
129
136
|
if (!logins) {
|
|
130
137
|
return { error: 'Logins not configured' };
|
|
131
138
|
}
|
|
132
|
-
const foundLogin = logins.find(x => x.login == login)
|
|
139
|
+
const foundLogin = logins.find(x => x.login == login);
|
|
133
140
|
if (foundLogin && foundLogin.password == password) {
|
|
134
141
|
return {
|
|
135
142
|
accessToken: jwt.sign({ login }, tokenSecret, { expiresIn: getTokenLifetime() }),
|
|
@@ -2,7 +2,7 @@ const fs = require('fs-extra');
|
|
|
2
2
|
const os = require('os');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const axios = require('axios');
|
|
5
|
-
const { datadir } = require('../utility/directories');
|
|
5
|
+
const { datadir, getLogsFilePath } = require('../utility/directories');
|
|
6
6
|
const { hasPermission, getLogins } = require('../utility/hasPermission');
|
|
7
7
|
const socket = require('../utility/socket');
|
|
8
8
|
const _ = require('lodash');
|
|
@@ -28,12 +28,9 @@ module.exports = {
|
|
|
28
28
|
get_meta: true,
|
|
29
29
|
async get(_params, req) {
|
|
30
30
|
const logins = getLogins();
|
|
31
|
-
const
|
|
32
|
-
req && req.user
|
|
33
|
-
|
|
34
|
-
: logins
|
|
35
|
-
? logins.find(x => x.login == (req && req.auth && req.auth.user))
|
|
36
|
-
: null;
|
|
31
|
+
const loginName =
|
|
32
|
+
req && req.user && req.user.login ? req.user.login : req && req.auth && req.auth.user ? req.auth.user : null;
|
|
33
|
+
const login = logins && loginName ? logins.find(x => x.login == loginName) : null;
|
|
37
34
|
const permissions = login ? login.permissions : process.env.PERMISSIONS;
|
|
38
35
|
|
|
39
36
|
return {
|
|
@@ -47,8 +44,12 @@ module.exports = {
|
|
|
47
44
|
permissions,
|
|
48
45
|
login,
|
|
49
46
|
oauth: process.env.OAUTH_AUTH,
|
|
47
|
+
oauthClient: process.env.OAUTH_CLIENT_ID,
|
|
48
|
+
oauthScope: process.env.OAUTH_SCOPE,
|
|
50
49
|
oauthLogout: process.env.OAUTH_LOGOUT,
|
|
51
50
|
isLoginForm: !!process.env.AD_URL || (!!logins && !process.env.BASIC_AUTH),
|
|
51
|
+
logsFilePath: getLogsFilePath(),
|
|
52
|
+
connectionsFilePath: path.join(datadir(), 'connections.jsonl'),
|
|
52
53
|
...currentVersion,
|
|
53
54
|
};
|
|
54
55
|
},
|
|
@@ -12,9 +12,12 @@ const { pickSafeConnectionInfo } = require('../utility/crypting');
|
|
|
12
12
|
const JsonLinesDatabase = require('../utility/JsonLinesDatabase');
|
|
13
13
|
|
|
14
14
|
const processArgs = require('../utility/processArgs');
|
|
15
|
-
const { safeJsonParse } = require('dbgate-tools');
|
|
15
|
+
const { safeJsonParse, getLogger } = require('dbgate-tools');
|
|
16
16
|
const platformInfo = require('../utility/platformInfo');
|
|
17
17
|
const { connectionHasPermission, testConnectionPermission } = require('../utility/hasPermission');
|
|
18
|
+
const pipeForkLogs = require('../utility/pipeForkLogs');
|
|
19
|
+
|
|
20
|
+
const logger = getLogger('connections');
|
|
18
21
|
|
|
19
22
|
let volatileConnections = {};
|
|
20
23
|
|
|
@@ -86,13 +89,13 @@ function getPortalCollections() {
|
|
|
86
89
|
sslKeyFile: process.env[`SSL_KEY_FILE_${id}`],
|
|
87
90
|
sslRejectUnauthorized: process.env[`SSL_REJECT_UNAUTHORIZED_${id}`],
|
|
88
91
|
}));
|
|
89
|
-
|
|
90
|
-
|
|
92
|
+
|
|
93
|
+
logger.info({ connections: connections.map(pickSafeConnectionInfo) }, 'Using connections from ENV variables');
|
|
91
94
|
const noengine = connections.filter(x => !x.engine);
|
|
92
95
|
if (noengine.length > 0) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
logger.warn(
|
|
97
|
+
{ connections: noengine.map(x => x._id) },
|
|
98
|
+
'Invalid CONNECTIONS configutation, missing ENGINE for connection ID'
|
|
96
99
|
);
|
|
97
100
|
}
|
|
98
101
|
return connections;
|
|
@@ -203,13 +206,20 @@ module.exports = {
|
|
|
203
206
|
|
|
204
207
|
test_meta: true,
|
|
205
208
|
test(connection) {
|
|
206
|
-
const subprocess = fork(
|
|
207
|
-
'
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
209
|
+
const subprocess = fork(
|
|
210
|
+
global['API_PACKAGE'] || process.argv[1],
|
|
211
|
+
[
|
|
212
|
+
'--is-forked-api',
|
|
213
|
+
'--start-process',
|
|
214
|
+
'connectProcess',
|
|
215
|
+
...processArgs.getPassArgs(),
|
|
216
|
+
// ...process.argv.slice(3),
|
|
217
|
+
],
|
|
218
|
+
{
|
|
219
|
+
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
pipeForkLogs(subprocess);
|
|
213
223
|
subprocess.send(connection);
|
|
214
224
|
return new Promise(resolve => {
|
|
215
225
|
subprocess.on('message', resp => {
|
|
@@ -12,6 +12,7 @@ const {
|
|
|
12
12
|
matchPairedObjects,
|
|
13
13
|
extendDatabaseInfo,
|
|
14
14
|
modelCompareDbDiffOptions,
|
|
15
|
+
getLogger,
|
|
15
16
|
} = require('dbgate-tools');
|
|
16
17
|
const { html, parse } = require('diff2html');
|
|
17
18
|
const { handleProcessCommunication } = require('../utility/processComm');
|
|
@@ -28,6 +29,9 @@ const diff2htmlPage = require('../utility/diff2htmlPage');
|
|
|
28
29
|
const processArgs = require('../utility/processArgs');
|
|
29
30
|
const { testConnectionPermission } = require('../utility/hasPermission');
|
|
30
31
|
const { MissingCredentialsError } = require('../utility/exceptions');
|
|
32
|
+
const pipeForkLogs = require('../utility/pipeForkLogs');
|
|
33
|
+
|
|
34
|
+
const logger = getLogger('databaseConnections');
|
|
31
35
|
|
|
32
36
|
module.exports = {
|
|
33
37
|
/** @type {import('dbgate-types').OpenedDatabaseConnection[]} */
|
|
@@ -60,7 +64,7 @@ module.exports = {
|
|
|
60
64
|
|
|
61
65
|
handle_error(conid, database, props) {
|
|
62
66
|
const { error } = props;
|
|
63
|
-
|
|
67
|
+
logger.error(`Error in database connection ${conid}, database ${database}: ${error}`);
|
|
64
68
|
},
|
|
65
69
|
handle_response(conid, database, { msgid, ...response }) {
|
|
66
70
|
const [resolve, reject] = this.requests[msgid];
|
|
@@ -85,13 +89,20 @@ module.exports = {
|
|
|
85
89
|
if (connection.passwordMode == 'askPassword' || connection.passwordMode == 'askUser') {
|
|
86
90
|
throw new MissingCredentialsError({ conid, passwordMode: connection.passwordMode });
|
|
87
91
|
}
|
|
88
|
-
const subprocess = fork(
|
|
89
|
-
'
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
const subprocess = fork(
|
|
93
|
+
global['API_PACKAGE'] || process.argv[1],
|
|
94
|
+
[
|
|
95
|
+
'--is-forked-api',
|
|
96
|
+
'--start-process',
|
|
97
|
+
'databaseConnectionProcess',
|
|
98
|
+
...processArgs.getPassArgs(),
|
|
99
|
+
// ...process.argv.slice(3),
|
|
100
|
+
],
|
|
101
|
+
{
|
|
102
|
+
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
pipeForkLogs(subprocess);
|
|
95
106
|
const lastClosed = this.closed[`${conid}/${database}`];
|
|
96
107
|
const newOpened = {
|
|
97
108
|
conid,
|
|
@@ -129,7 +140,12 @@ module.exports = {
|
|
|
129
140
|
const msgid = uuidv1();
|
|
130
141
|
const promise = new Promise((resolve, reject) => {
|
|
131
142
|
this.requests[msgid] = [resolve, reject];
|
|
132
|
-
|
|
143
|
+
try {
|
|
144
|
+
conn.subprocess.send({ msgid, ...message });
|
|
145
|
+
} catch (err) {
|
|
146
|
+
logger.error({ err }, 'Error sending request do process');
|
|
147
|
+
this.close(conn.conid, conn.database);
|
|
148
|
+
}
|
|
133
149
|
});
|
|
134
150
|
return promise;
|
|
135
151
|
},
|
|
@@ -137,7 +153,7 @@ module.exports = {
|
|
|
137
153
|
queryData_meta: true,
|
|
138
154
|
async queryData({ conid, database, sql }, req) {
|
|
139
155
|
testConnectionPermission(conid, req);
|
|
140
|
-
|
|
156
|
+
logger.info({ conid, database, sql }, 'Processing query');
|
|
141
157
|
const opened = await this.ensureOpened(conid, database);
|
|
142
158
|
// if (opened && opened.status && opened.status.name == 'error') {
|
|
143
159
|
// return opened.status;
|
|
@@ -157,7 +173,7 @@ module.exports = {
|
|
|
157
173
|
runScript_meta: true,
|
|
158
174
|
async runScript({ conid, database, sql }, req) {
|
|
159
175
|
testConnectionPermission(conid, req);
|
|
160
|
-
|
|
176
|
+
logger.info({ conid, database, sql }, 'Processing script');
|
|
161
177
|
const opened = await this.ensureOpened(conid, database);
|
|
162
178
|
const res = await this.sendRequest(opened, { msgtype: 'runScript', sql });
|
|
163
179
|
return res;
|
|
@@ -278,6 +294,7 @@ module.exports = {
|
|
|
278
294
|
if (existing) {
|
|
279
295
|
existing.subprocess.send({ msgtype: 'ping' });
|
|
280
296
|
} else {
|
|
297
|
+
// @ts-ignore
|
|
281
298
|
existing = await this.ensureOpened(conid, database);
|
|
282
299
|
}
|
|
283
300
|
|
|
@@ -308,7 +325,13 @@ module.exports = {
|
|
|
308
325
|
const existing = this.opened.find(x => x.conid == conid && x.database == database);
|
|
309
326
|
if (existing) {
|
|
310
327
|
existing.disconnected = true;
|
|
311
|
-
if (kill)
|
|
328
|
+
if (kill) {
|
|
329
|
+
try {
|
|
330
|
+
existing.subprocess.kill();
|
|
331
|
+
} catch (err) {
|
|
332
|
+
logger.error({ err }, 'Error killing subprocess');
|
|
333
|
+
}
|
|
334
|
+
}
|
|
312
335
|
this.opened = this.opened.filter(x => x.conid != conid || x.database != database);
|
|
313
336
|
this.closed[`${conid}/${database}`] = {
|
|
314
337
|
status: {
|
|
@@ -6,10 +6,17 @@ const byline = require('byline');
|
|
|
6
6
|
const socket = require('../utility/socket');
|
|
7
7
|
const { fork } = require('child_process');
|
|
8
8
|
const { rundir, uploadsdir, pluginsdir, getPluginBackendPath, packagedPluginList } = require('../utility/directories');
|
|
9
|
-
const {
|
|
9
|
+
const {
|
|
10
|
+
extractShellApiPlugins,
|
|
11
|
+
extractShellApiFunctionName,
|
|
12
|
+
jsonScriptToJavascript,
|
|
13
|
+
getLogger,
|
|
14
|
+
safeJsonParse,
|
|
15
|
+
} = require('dbgate-tools');
|
|
10
16
|
const { handleProcessCommunication } = require('../utility/processComm');
|
|
11
17
|
const processArgs = require('../utility/processArgs');
|
|
12
18
|
const platformInfo = require('../utility/platformInfo');
|
|
19
|
+
const logger = getLogger('runners');
|
|
13
20
|
|
|
14
21
|
function extractPlugins(script) {
|
|
15
22
|
const requireRegex = /\s*\/\/\s*@require\s+([^\s]+)\s*\n/g;
|
|
@@ -29,13 +36,14 @@ const requirePluginsTemplate = (plugins, isExport) =>
|
|
|
29
36
|
|
|
30
37
|
const scriptTemplate = (script, isExport) => `
|
|
31
38
|
const dbgateApi = require(${isExport ? `'dbgate-api'` : 'process.env.DBGATE_API'});
|
|
39
|
+
const logger = dbgateApi.getLogger('script');
|
|
32
40
|
dbgateApi.initializeApiEnvironment();
|
|
33
41
|
${requirePluginsTemplate(extractPlugins(script), isExport)}
|
|
34
42
|
require=null;
|
|
35
43
|
async function run() {
|
|
36
44
|
${script}
|
|
37
45
|
await dbgateApi.finalizer.run();
|
|
38
|
-
|
|
46
|
+
logger.info('Finished job script');
|
|
39
47
|
}
|
|
40
48
|
dbgateApi.runScript(run);
|
|
41
49
|
`;
|
|
@@ -59,19 +67,17 @@ module.exports = {
|
|
|
59
67
|
requests: {},
|
|
60
68
|
|
|
61
69
|
dispatchMessage(runid, message) {
|
|
62
|
-
if (message)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
if (_.isPlainObject(message)) {
|
|
70
|
+
if (message) {
|
|
71
|
+
const json = safeJsonParse(message.message);
|
|
72
|
+
|
|
73
|
+
if (json) logger.info(json);
|
|
74
|
+
else logger.info(message.message);
|
|
75
|
+
|
|
71
76
|
socket.emit(`runner-info-${runid}`, {
|
|
72
77
|
time: new Date(),
|
|
73
78
|
severity: 'info',
|
|
74
79
|
...message,
|
|
80
|
+
message: json ? json.msg : message.message,
|
|
75
81
|
});
|
|
76
82
|
}
|
|
77
83
|
},
|
|
@@ -98,13 +104,15 @@ module.exports = {
|
|
|
98
104
|
fs.writeFileSync(`${scriptFile}`, scriptText);
|
|
99
105
|
fs.mkdirSync(directory);
|
|
100
106
|
const pluginNames = _.union(fs.readdirSync(pluginsdir()), packagedPluginList);
|
|
101
|
-
|
|
107
|
+
logger.info({ scriptFile }, 'Running script');
|
|
102
108
|
// const subprocess = fork(scriptFile, ['--checkParent', '--max-old-space-size=8192'], {
|
|
103
109
|
const subprocess = fork(
|
|
104
110
|
scriptFile,
|
|
105
111
|
[
|
|
106
112
|
'--checkParent', // ...process.argv.slice(3)
|
|
107
113
|
'--is-forked-api',
|
|
114
|
+
'--process-display-name',
|
|
115
|
+
'script',
|
|
108
116
|
...processArgs.getPassArgs(),
|
|
109
117
|
],
|
|
110
118
|
{
|
|
@@ -124,7 +132,7 @@ module.exports = {
|
|
|
124
132
|
byline(subprocess.stderr).on('data', pipeDispatcher('error'));
|
|
125
133
|
subprocess.on('exit', code => {
|
|
126
134
|
this.rejectRequest(runid, { message: 'No data retured, maybe input data source is too big' });
|
|
127
|
-
|
|
135
|
+
logger.info({ code, pid: subprocess.pid }, 'Exited process');
|
|
128
136
|
socket.emit(`runner-done-${runid}`, code);
|
|
129
137
|
});
|
|
130
138
|
subprocess.on('error', error => {
|
|
@@ -4,6 +4,9 @@ const path = require('path');
|
|
|
4
4
|
const cron = require('node-cron');
|
|
5
5
|
const runners = require('./runners');
|
|
6
6
|
const { hasPermission } = require('../utility/hasPermission');
|
|
7
|
+
const { getLogger } = require('dbgate-tools');
|
|
8
|
+
|
|
9
|
+
const logger = getLogger('scheduler');
|
|
7
10
|
|
|
8
11
|
const scheduleRegex = /\s*\/\/\s*@schedule\s+([^\n]+)\n/;
|
|
9
12
|
|
|
@@ -21,7 +24,7 @@ module.exports = {
|
|
|
21
24
|
if (!match) return;
|
|
22
25
|
const pattern = match[1];
|
|
23
26
|
if (!cron.validate(pattern)) return;
|
|
24
|
-
|
|
27
|
+
logger.info(`Schedule script ${file} with pattern ${pattern}`);
|
|
25
28
|
const task = cron.schedule(pattern, () => runners.start({ script: text }));
|
|
26
29
|
this.tasks.push(task);
|
|
27
30
|
},
|
|
@@ -10,6 +10,10 @@ const config = require('./config');
|
|
|
10
10
|
const processArgs = require('../utility/processArgs');
|
|
11
11
|
const { testConnectionPermission } = require('../utility/hasPermission');
|
|
12
12
|
const { MissingCredentialsError } = require('../utility/exceptions');
|
|
13
|
+
const pipeForkLogs = require('../utility/pipeForkLogs');
|
|
14
|
+
const { getLogger } = require('dbgate-tools');
|
|
15
|
+
|
|
16
|
+
const logger = getLogger('serverConnection');
|
|
13
17
|
|
|
14
18
|
module.exports = {
|
|
15
19
|
opened: [],
|
|
@@ -47,16 +51,26 @@ module.exports = {
|
|
|
47
51
|
const existing = this.opened.find(x => x.conid == conid);
|
|
48
52
|
if (existing) return existing;
|
|
49
53
|
const connection = await connections.getCore({ conid });
|
|
54
|
+
if (!connection) {
|
|
55
|
+
throw new Error(`Connection with conid="${conid}" not fund`);
|
|
56
|
+
}
|
|
50
57
|
if (connection.passwordMode == 'askPassword' || connection.passwordMode == 'askUser') {
|
|
51
58
|
throw new MissingCredentialsError({ conid, passwordMode: connection.passwordMode });
|
|
52
59
|
}
|
|
53
|
-
const subprocess = fork(
|
|
54
|
-
'
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
const subprocess = fork(
|
|
61
|
+
global['API_PACKAGE'] || process.argv[1],
|
|
62
|
+
[
|
|
63
|
+
'--is-forked-api',
|
|
64
|
+
'--start-process',
|
|
65
|
+
'serverConnectionProcess',
|
|
66
|
+
...processArgs.getPassArgs(),
|
|
67
|
+
// ...process.argv.slice(3),
|
|
68
|
+
],
|
|
69
|
+
{
|
|
70
|
+
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
pipeForkLogs(subprocess);
|
|
60
74
|
const newOpened = {
|
|
61
75
|
conid,
|
|
62
76
|
subprocess,
|
|
@@ -91,7 +105,13 @@ module.exports = {
|
|
|
91
105
|
const existing = this.opened.find(x => x.conid == conid);
|
|
92
106
|
if (existing) {
|
|
93
107
|
existing.disconnected = true;
|
|
94
|
-
if (kill)
|
|
108
|
+
if (kill) {
|
|
109
|
+
try {
|
|
110
|
+
existing.subprocess.kill();
|
|
111
|
+
} catch (err) {
|
|
112
|
+
logger.error({ err }, 'Error killing subprocess');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
95
115
|
this.opened = this.opened.filter(x => x.conid != conid);
|
|
96
116
|
this.closed[conid] = {
|
|
97
117
|
...existing.status,
|
|
@@ -110,6 +130,7 @@ module.exports = {
|
|
|
110
130
|
|
|
111
131
|
listDatabases_meta: true,
|
|
112
132
|
async listDatabases({ conid }, req) {
|
|
133
|
+
if (!conid) return [];
|
|
113
134
|
testConnectionPermission(conid, req);
|
|
114
135
|
const opened = await this.ensureOpened(conid);
|
|
115
136
|
return opened.databases;
|
|
@@ -140,7 +161,12 @@ module.exports = {
|
|
|
140
161
|
}
|
|
141
162
|
this.lastPinged[conid] = new Date().getTime();
|
|
142
163
|
const opened = await this.ensureOpened(conid);
|
|
143
|
-
|
|
164
|
+
try {
|
|
165
|
+
opened.subprocess.send({ msgtype: 'ping' });
|
|
166
|
+
} catch (err) {
|
|
167
|
+
logger.error({ err }, 'Error calling ping');
|
|
168
|
+
this.close(conid);
|
|
169
|
+
}
|
|
144
170
|
})
|
|
145
171
|
);
|
|
146
172
|
return { status: 'ok' };
|
|
@@ -177,7 +203,12 @@ module.exports = {
|
|
|
177
203
|
const msgid = uuidv1();
|
|
178
204
|
const promise = new Promise((resolve, reject) => {
|
|
179
205
|
this.requests[msgid] = [resolve, reject];
|
|
180
|
-
|
|
206
|
+
try {
|
|
207
|
+
conn.subprocess.send({ msgid, ...message });
|
|
208
|
+
} catch (err) {
|
|
209
|
+
logger.error({ err }, 'Error sending request');
|
|
210
|
+
this.close(conn.conid);
|
|
211
|
+
}
|
|
181
212
|
});
|
|
182
213
|
return promise;
|
|
183
214
|
},
|
|
@@ -8,6 +8,11 @@ const path = require('path');
|
|
|
8
8
|
const { handleProcessCommunication } = require('../utility/processComm');
|
|
9
9
|
const processArgs = require('../utility/processArgs');
|
|
10
10
|
const { appdir } = require('../utility/directories');
|
|
11
|
+
const { getLogger } = require('dbgate-tools');
|
|
12
|
+
const pipeForkLogs = require('../utility/pipeForkLogs');
|
|
13
|
+
const config = require('./config');
|
|
14
|
+
|
|
15
|
+
const logger = getLogger('sessions');
|
|
11
16
|
|
|
12
17
|
module.exports = {
|
|
13
18
|
/** @type {import('dbgate-types').OpenedSession[]} */
|
|
@@ -82,13 +87,20 @@ module.exports = {
|
|
|
82
87
|
async create({ conid, database }) {
|
|
83
88
|
const sesid = uuidv1();
|
|
84
89
|
const connection = await connections.getCore({ conid });
|
|
85
|
-
const subprocess = fork(
|
|
86
|
-
'
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
const subprocess = fork(
|
|
91
|
+
global['API_PACKAGE'] || process.argv[1],
|
|
92
|
+
[
|
|
93
|
+
'--is-forked-api',
|
|
94
|
+
'--start-process',
|
|
95
|
+
'sessionProcess',
|
|
96
|
+
...processArgs.getPassArgs(),
|
|
97
|
+
// ...process.argv.slice(3),
|
|
98
|
+
],
|
|
99
|
+
{
|
|
100
|
+
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
pipeForkLogs(subprocess);
|
|
92
104
|
const newOpened = {
|
|
93
105
|
conid,
|
|
94
106
|
database,
|
|
@@ -109,7 +121,12 @@ module.exports = {
|
|
|
109
121
|
socket.emit(`session-closed-${sesid}`);
|
|
110
122
|
});
|
|
111
123
|
|
|
112
|
-
subprocess.send({
|
|
124
|
+
subprocess.send({
|
|
125
|
+
msgtype: 'connect',
|
|
126
|
+
...connection,
|
|
127
|
+
database,
|
|
128
|
+
globalSettings: await config.getSettings(),
|
|
129
|
+
});
|
|
113
130
|
return _.pick(newOpened, ['conid', 'database', 'sesid']);
|
|
114
131
|
},
|
|
115
132
|
|
|
@@ -120,7 +137,7 @@ module.exports = {
|
|
|
120
137
|
throw new Error('Invalid session');
|
|
121
138
|
}
|
|
122
139
|
|
|
123
|
-
|
|
140
|
+
logger.info({ sesid, sql }, 'Processing query');
|
|
124
141
|
this.dispatchMessage(sesid, 'Query execution started');
|
|
125
142
|
session.subprocess.send({ msgtype: 'executeQuery', sql });
|
|
126
143
|
|
|
@@ -158,7 +175,7 @@ module.exports = {
|
|
|
158
175
|
throw new Error('Invalid session');
|
|
159
176
|
}
|
|
160
177
|
|
|
161
|
-
|
|
178
|
+
logger.info({ sesid }, 'Starting profiler');
|
|
162
179
|
session.loadingReader_jslid = jslid;
|
|
163
180
|
session.subprocess.send({ msgtype: 'startProfiler', jslid });
|
|
164
181
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
const { uploadsdir } = require('../utility/directories');
|
|
3
3
|
const uuidv1 = require('uuid/v1');
|
|
4
|
+
const { getLogger } = require('dbgate-tools');
|
|
5
|
+
const logger = getLogger('uploads');
|
|
4
6
|
|
|
5
7
|
module.exports = {
|
|
6
8
|
upload_meta: {
|
|
@@ -15,7 +17,7 @@ module.exports = {
|
|
|
15
17
|
}
|
|
16
18
|
const uploadName = uuidv1();
|
|
17
19
|
const filePath = path.join(uploadsdir(), uploadName);
|
|
18
|
-
|
|
20
|
+
logger.info(`Uploading file ${data.name}, size=${data.size}`);
|
|
19
21
|
|
|
20
22
|
data.mv(filePath, () => {
|
|
21
23
|
res.json({
|
package/src/currentVersion.js
CHANGED