hola-server 1.0.11 → 2.0.1
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/README.md +196 -1
- package/core/array.js +79 -142
- package/core/bash.js +208 -259
- package/core/chart.js +26 -16
- package/core/cron.js +14 -3
- package/core/date.js +15 -44
- package/core/encrypt.js +19 -9
- package/core/file.js +42 -29
- package/core/lhs.js +32 -6
- package/core/meta.js +213 -289
- package/core/msg.js +20 -7
- package/core/number.js +105 -103
- package/core/obj.js +15 -12
- package/core/random.js +9 -6
- package/core/role.js +69 -77
- package/core/thread.js +12 -2
- package/core/type.js +300 -261
- package/core/url.js +20 -12
- package/core/validate.js +29 -26
- package/db/db.js +297 -227
- package/db/entity.js +631 -963
- package/db/gridfs.js +120 -166
- package/design/add_default_field_attr.md +56 -0
- package/http/context.js +22 -8
- package/http/cors.js +25 -8
- package/http/error.js +27 -9
- package/http/express.js +70 -41
- package/http/params.js +70 -42
- package/http/router.js +51 -40
- package/http/session.js +59 -36
- package/index.js +85 -9
- package/package.json +2 -2
- package/router/clone.js +28 -36
- package/router/create.js +21 -26
- package/router/delete.js +24 -28
- package/router/read.js +137 -123
- package/router/update.js +38 -56
- package/setting.js +22 -6
- package/skills/array.md +155 -0
- package/skills/bash.md +91 -0
- package/skills/chart.md +54 -0
- package/skills/code.md +422 -0
- package/skills/context.md +177 -0
- package/skills/date.md +58 -0
- package/skills/express.md +255 -0
- package/skills/file.md +60 -0
- package/skills/lhs.md +54 -0
- package/skills/meta.md +1023 -0
- package/skills/msg.md +30 -0
- package/skills/number.md +88 -0
- package/skills/obj.md +36 -0
- package/skills/params.md +206 -0
- package/skills/random.md +22 -0
- package/skills/role.md +59 -0
- package/skills/session.md +281 -0
- package/skills/storage.md +743 -0
- package/skills/thread.md +22 -0
- package/skills/type.md +547 -0
- package/skills/url.md +34 -0
- package/skills/validate.md +48 -0
- package/test/cleanup/close-db.js +5 -0
- package/test/core/array.js +226 -0
- package/test/core/chart.js +51 -0
- package/test/core/file.js +59 -0
- package/test/core/lhs.js +44 -0
- package/test/core/number.js +167 -12
- package/test/core/obj.js +47 -0
- package/test/core/random.js +24 -0
- package/test/core/thread.js +20 -0
- package/test/core/type.js +216 -0
- package/test/core/validate.js +67 -0
- package/test/db/db-ops.js +99 -0
- package/test/db/pipe_test.txt +0 -0
- package/test/db/test_case_design.md +528 -0
- package/test/db/test_db_class.js +613 -0
- package/test/db/test_entity_class.js +414 -0
- package/test/db/test_gridfs_class.js +234 -0
- package/test/entity/create.js +1 -1
- package/test/entity/delete-mixed.js +156 -0
- package/test/entity/ref-filter.js +63 -0
- package/tool/gen_i18n.js +55 -21
- package/test/crud/router.js +0 -99
- package/test/router/user.js +0 -17
package/core/bash.js
CHANGED
|
@@ -1,345 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Bash command execution and SSH utility functions.
|
|
3
|
+
* @module core/bash
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
const fs = require('fs');
|
|
2
7
|
const { exec } = require("child_process");
|
|
3
8
|
const { random_code } = require('./random');
|
|
4
9
|
const { is_log_debug, is_log_error, log_debug, log_error } = require('../db/db');
|
|
5
10
|
|
|
6
11
|
const LOG_BASH = "bash";
|
|
7
|
-
|
|
8
|
-
const get_log_file = async () => {
|
|
9
|
-
const home = await run_simple_local_cmd("echo ~");
|
|
10
|
-
const log_dir = `${home}/.hola/ssh`;
|
|
11
|
-
await run_local_cmd(`mkdir -p ${log_dir}`);
|
|
12
|
-
return `${log_dir}/l_${random_code()}.log`;
|
|
13
|
-
}
|
|
12
|
+
const SSH_OPTIONS = "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no";
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
|
-
*
|
|
17
|
-
* @param {
|
|
18
|
-
* @param {
|
|
19
|
-
* @
|
|
15
|
+
* Execute command with unified logging and error handling.
|
|
16
|
+
* @param {string} cmd - Command to execute.
|
|
17
|
+
* @param {Object} options - Exec options.
|
|
18
|
+
* @param {string} error_msg - Error message prefix.
|
|
19
|
+
* @param {string} success_msg - Success message prefix.
|
|
20
|
+
* @param {Object} [log_extra] - Additional logging context.
|
|
21
|
+
* @returns {Promise<{stdout: string, err?: string}>} Command result.
|
|
20
22
|
*/
|
|
21
|
-
const
|
|
23
|
+
const exec_with_logging = (cmd, options, error_msg, success_msg, log_extra) => {
|
|
22
24
|
return new Promise((resolve) => {
|
|
23
|
-
exec(
|
|
25
|
+
exec(cmd, options, (error, stdout) => {
|
|
24
26
|
if (error) {
|
|
25
|
-
if (is_log_error()) {
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
resolve({ stdout: stdout, err: "error running the script:" + script + ",error:" + error });
|
|
27
|
+
if (is_log_error()) log_error(LOG_BASH, `${error_msg}, error:${error}`, log_extra);
|
|
28
|
+
resolve({ stdout, err: `${error_msg}, error:${error}` });
|
|
29
29
|
} else {
|
|
30
|
-
if (is_log_debug()) {
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
resolve({ stdout: stdout });
|
|
30
|
+
if (is_log_debug()) log_debug(LOG_BASH, `${success_msg}, stdout:${stdout}`, log_extra);
|
|
31
|
+
resolve({ stdout });
|
|
34
32
|
}
|
|
35
33
|
});
|
|
36
34
|
});
|
|
37
35
|
};
|
|
38
36
|
|
|
39
37
|
/**
|
|
40
|
-
*
|
|
41
|
-
* @
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
* Get temporary log file path.
|
|
39
|
+
* @returns {Promise<string>} Path to temporary log file.
|
|
40
|
+
*/
|
|
41
|
+
const get_log_file = async () => {
|
|
42
|
+
const home = await run_simple_local_cmd("echo ~");
|
|
43
|
+
const log_dir = `${home}/.hola/ssh`;
|
|
44
|
+
await run_local_cmd(`mkdir -p ${log_dir}`);
|
|
45
|
+
return `${log_dir}/l_${random_code()}.log`;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Build SSH command prefix.
|
|
50
|
+
* @param {Object} host - Host configuration.
|
|
51
|
+
* @returns {string} SSH command prefix.
|
|
52
|
+
*/
|
|
53
|
+
const build_ssh_prefix = (host) => `ssh ${host.auth} ${SSH_OPTIONS} -p ${host.port} ${host.user}@${host.ip}`;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Build SCP command.
|
|
57
|
+
* @param {Object} host - Host configuration.
|
|
58
|
+
* @param {string} src - Source path.
|
|
59
|
+
* @param {string} dest - Destination path.
|
|
60
|
+
* @param {boolean} to_remote - True if copying to remote.
|
|
61
|
+
* @returns {string} SCP command.
|
|
62
|
+
*/
|
|
63
|
+
const build_scp_cmd = (host, src, dest, to_remote) => {
|
|
64
|
+
const remote_path = `${host.user}@${host.ip}:${to_remote ? dest : src}`;
|
|
65
|
+
const local_path = to_remote ? src : dest;
|
|
66
|
+
const [first, second] = to_remote ? [local_path, remote_path] : [remote_path, local_path];
|
|
67
|
+
return `scp ${host.auth} ${SSH_OPTIONS} -P ${host.port} -q ${first} ${second}`;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Run script on remote host via SSH.
|
|
72
|
+
* @param {Object} host - Host info with user, ip, port, auth, name.
|
|
73
|
+
* @param {string} script - Commands to run.
|
|
74
|
+
* @param {Object} [log_extra] - Additional logging context.
|
|
75
|
+
* @returns {Promise<{stdout: string, err?: string}>} Command result.
|
|
76
|
+
*/
|
|
77
|
+
const run_script = (host, script, log_extra) => {
|
|
78
|
+
const cmd = `${build_ssh_prefix(host)} /bin/bash <<'EOT'\n ${script} \nEOT\n`;
|
|
79
|
+
return exec_with_logging(cmd, { maxBuffer: 1024 * 150000 },
|
|
80
|
+
`error running on host:${host.name} script:${script}`,
|
|
81
|
+
`executing on host:${host.name}, script:${script}`, log_extra);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Run script on remote host with file redirect to avoid progress bar issues.
|
|
86
|
+
* @param {Object} host - Host info with user, ip, port, auth, name.
|
|
87
|
+
* @param {string} script - Commands to run.
|
|
88
|
+
* @param {Object} [log_extra] - Additional logging context.
|
|
89
|
+
* @returns {Promise<{stdout: string, err?: string}>} Command result.
|
|
44
90
|
*/
|
|
45
91
|
const run_script_extra = async (host, script, log_extra) => {
|
|
46
92
|
const log_file = await get_log_file();
|
|
93
|
+
const cmd = `${build_ssh_prefix(host)} /bin/bash <<'EOT' > ${log_file} \n ${script} \nEOT\n`;
|
|
47
94
|
|
|
48
95
|
return new Promise((resolve) => {
|
|
49
|
-
exec(
|
|
96
|
+
exec(cmd, { maxBuffer: 1024 * 150000 }, (error, stdout) => {
|
|
50
97
|
if (error) {
|
|
51
|
-
if (is_log_error()) {
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
resolve({ stdout: stdout, err: "error running the script:" + script + ",error:" + error });
|
|
98
|
+
if (is_log_error()) log_error(LOG_BASH, `error running on host:${host.name} script:${script}, error:${error}`, log_extra);
|
|
99
|
+
resolve({ stdout, err: `error running script:${script}, error:${error}` });
|
|
55
100
|
} else {
|
|
56
101
|
const output = fs.readFileSync(log_file, { encoding: 'utf8', flag: 'r' });
|
|
57
|
-
if (is_log_debug()) {
|
|
58
|
-
log_debug(LOG_BASH, "executing on host:" + host.name + ", script:" + script + ",stdout:" + output, log_extra);
|
|
59
|
-
}
|
|
60
|
-
resolve({ stdout: output });
|
|
102
|
+
if (is_log_debug()) log_debug(LOG_BASH, `executing on host:${host.name}, script:${script}, stdout:${output}`, log_extra);
|
|
61
103
|
fs.unlinkSync(log_file);
|
|
104
|
+
resolve({ stdout: output });
|
|
62
105
|
}
|
|
63
106
|
});
|
|
64
107
|
});
|
|
65
108
|
};
|
|
66
109
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
resolve({ stdout: stdout });
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
});
|
|
110
|
+
/**
|
|
111
|
+
* Run script file on remote host.
|
|
112
|
+
* @param {Object} host - Host info.
|
|
113
|
+
* @param {string} script_file - Path to local script file.
|
|
114
|
+
* @param {Object} [log_extra] - Additional logging context.
|
|
115
|
+
* @returns {Promise<{stdout: string, err?: string}>} Command result.
|
|
116
|
+
*/
|
|
117
|
+
const run_script_file = (host, script_file, log_extra) => {
|
|
118
|
+
const cmd = `${build_ssh_prefix(host)} /bin/bash < ${script_file}`;
|
|
119
|
+
return exec_with_logging(cmd, {},
|
|
120
|
+
`error running on host:${host.name} script_file:${script_file}`,
|
|
121
|
+
`executing on host:${host.name}, script_file:${script_file}`, log_extra);
|
|
83
122
|
};
|
|
84
123
|
|
|
85
124
|
/**
|
|
86
|
-
* Run command
|
|
87
|
-
* @param {
|
|
88
|
-
* @
|
|
125
|
+
* Run command on local host.
|
|
126
|
+
* @param {string} cmd - Command to execute.
|
|
127
|
+
* @param {Object} [log_extra] - Additional logging context.
|
|
128
|
+
* @returns {Promise<{stdout: string, err?: string}>} Command result.
|
|
89
129
|
*/
|
|
90
|
-
const run_local_cmd =
|
|
91
|
-
return
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (is_log_error()) {
|
|
95
|
-
log_error(LOG_BASH, "error running on local host with cmd:" + cmd + ",error:" + error, log_extra);
|
|
96
|
-
}
|
|
97
|
-
resolve({ stdout: stdout, err: "error running the cmd:" + cmd + ",error:" + error }, log_extra);
|
|
98
|
-
} else {
|
|
99
|
-
if (is_log_debug()) {
|
|
100
|
-
log_debug(LOG_BASH, "executing on local host with cmd:" + cmd + ",stdout:" + stdout, log_extra);
|
|
101
|
-
}
|
|
102
|
-
resolve({ stdout: stdout });
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
});
|
|
130
|
+
const run_local_cmd = (cmd, log_extra) => {
|
|
131
|
+
return exec_with_logging(cmd, { maxBuffer: 1024 * 15000000 },
|
|
132
|
+
`error running on local host cmd:${cmd}`,
|
|
133
|
+
`executing on local host cmd:${cmd}`, log_extra);
|
|
106
134
|
};
|
|
107
135
|
|
|
108
136
|
/**
|
|
109
|
-
*
|
|
110
|
-
* @param {
|
|
111
|
-
* @param {
|
|
112
|
-
* @param {
|
|
113
|
-
* @
|
|
137
|
+
* SCP remote file to local.
|
|
138
|
+
* @param {Object} host - Remote host info.
|
|
139
|
+
* @param {string} remote_file - Remote file path.
|
|
140
|
+
* @param {string} local_file - Local file path.
|
|
141
|
+
* @param {Object} [log_extra] - Additional logging context.
|
|
142
|
+
* @returns {Promise<{stdout: string, err?: string}>} Command result.
|
|
114
143
|
*/
|
|
115
|
-
const scp =
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
log_error(LOG_BASH, "error scp on host:" + host.name + " remote:" + remote_file + ",local:" + local_file + ",error:" + error, log_extra);
|
|
121
|
-
}
|
|
122
|
-
resolve({ stdout: stdout, err: "error scp:" + remote_file + " to locale:" + local_file + ",err:" + error });
|
|
123
|
-
} else {
|
|
124
|
-
if (is_log_debug()) {
|
|
125
|
-
log_debug(LOG_BASH, "executing scp on host:" + host.name + ", remote:" + remote_file + ",local:" + local_file + ",stdout:" + stdout, log_extra);
|
|
126
|
-
}
|
|
127
|
-
resolve({ stdout: stdout });
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
});
|
|
144
|
+
const scp = (host, remote_file, local_file, log_extra) => {
|
|
145
|
+
const cmd = build_scp_cmd(host, remote_file, local_file, false);
|
|
146
|
+
return exec_with_logging(cmd, {},
|
|
147
|
+
`error scp on host:${host.name} remote:${remote_file}, local:${local_file}`,
|
|
148
|
+
`executing scp on host:${host.name}, remote:${remote_file}, local:${local_file}`, log_extra);
|
|
131
149
|
};
|
|
132
150
|
|
|
133
151
|
/**
|
|
134
|
-
*
|
|
135
|
-
* @param {
|
|
136
|
-
* @param {
|
|
137
|
-
* @param {
|
|
138
|
-
* @
|
|
152
|
+
* SCP local file to remote.
|
|
153
|
+
* @param {Object} host - Remote host info.
|
|
154
|
+
* @param {string} local_file - Local file path.
|
|
155
|
+
* @param {string} remote_file - Remote file path.
|
|
156
|
+
* @param {Object} [log_extra] - Additional logging context.
|
|
157
|
+
* @returns {Promise<{stdout: string, err?: string}>} Command result.
|
|
139
158
|
*/
|
|
140
|
-
const scpr =
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
log_error(LOG_BASH, "error scpr on host:" + host.name + " remote:" + remote_file + ",local:" + local_file + ",error:" + error, log_extra);
|
|
146
|
-
}
|
|
147
|
-
resolve({ stdout: stdout, err: "error scp:" + remote_file + " to locale:" + local_file + ",err:" + error });
|
|
148
|
-
} else {
|
|
149
|
-
if (is_log_debug()) {
|
|
150
|
-
log_debug(LOG_BASH, "executing scpr on host:" + host.name + ", remote:" + remote_file + ",local:" + local_file + ",stdout:" + stdout, log_extra);
|
|
151
|
-
}
|
|
152
|
-
resolve({ stdout: stdout });
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
});
|
|
159
|
+
const scpr = (host, local_file, remote_file, log_extra) => {
|
|
160
|
+
const cmd = build_scp_cmd(host, local_file, remote_file, true);
|
|
161
|
+
return exec_with_logging(cmd, {},
|
|
162
|
+
`error scpr on host:${host.name} remote:${remote_file}, local:${local_file}`,
|
|
163
|
+
`executing scpr on host:${host.name}, remote:${remote_file}, local:${local_file}`, log_extra);
|
|
156
164
|
};
|
|
157
165
|
|
|
158
166
|
/**
|
|
159
|
-
*
|
|
160
|
-
* @param {host
|
|
161
|
-
* @param {
|
|
162
|
-
* @
|
|
167
|
+
* Run simple command on remote host and get trimmed result.
|
|
168
|
+
* @param {Object} host - Host info.
|
|
169
|
+
* @param {string} cmd - Command to run.
|
|
170
|
+
* @param {Object} [log_extra] - Additional logging context.
|
|
171
|
+
* @returns {Promise<string|null>} Trimmed output or null on error.
|
|
163
172
|
*/
|
|
164
173
|
const run_simple_cmd = async (host, cmd, log_extra) => {
|
|
165
174
|
const { err, stdout } = await run_script(host, cmd, log_extra);
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
} else {
|
|
169
|
-
return stdout.trim();
|
|
170
|
-
}
|
|
171
|
-
}
|
|
175
|
+
return err ? null : stdout.trim();
|
|
176
|
+
};
|
|
172
177
|
|
|
173
178
|
/**
|
|
174
|
-
*
|
|
175
|
-
* @param {
|
|
176
|
-
* @
|
|
179
|
+
* Run simple command locally and get trimmed result.
|
|
180
|
+
* @param {string} cmd - Command to run.
|
|
181
|
+
* @param {Object} [log_extra] - Additional logging context.
|
|
182
|
+
* @returns {Promise<string|null>} Trimmed output or null on error.
|
|
177
183
|
*/
|
|
178
184
|
const run_simple_local_cmd = async (cmd, log_extra) => {
|
|
179
185
|
const { err, stdout } = await run_local_cmd(cmd, log_extra);
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
} else {
|
|
183
|
-
return stdout.trim();
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
+
return err ? null : stdout.trim();
|
|
187
|
+
};
|
|
186
188
|
|
|
187
189
|
/**
|
|
188
|
-
*
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
Part Number: NO DIMM
|
|
194
|
-
Rank: Unknown
|
|
195
|
-
Configured Memory Speed: Unknown
|
|
196
|
-
Minimum Voltage: 1.2 V
|
|
197
|
-
Maximum Voltage: 1.2 V
|
|
198
|
-
Configured Voltage: 1.2 V
|
|
199
|
-
|
|
200
|
-
* @param {stdout of the run_cmd} stdout
|
|
201
|
-
* @param {key to retrieve info} key
|
|
202
|
-
* @returns
|
|
190
|
+
* Extract info from stdout using regex pattern matching.
|
|
191
|
+
* @param {string} stdout - Command output.
|
|
192
|
+
* @param {string} key - Key to search for.
|
|
193
|
+
* @param {Object} [log_extra] - Additional logging context.
|
|
194
|
+
* @returns {string[]} Array of matched values.
|
|
203
195
|
*/
|
|
204
196
|
const get_info = (stdout, key, log_extra) => {
|
|
205
197
|
const word_key = key.split(" ").join("\\s+");
|
|
206
198
|
const regex = new RegExp(`\n\\s?${word_key}\\s?:(.*)\\s`, 'g');
|
|
207
|
-
if (is_log_debug()) {
|
|
208
|
-
log_debug(LOG_BASH, "get_info and regex:" + JSON.stringify(regex), log_extra);
|
|
209
|
-
}
|
|
199
|
+
if (is_log_debug()) log_debug(LOG_BASH, `get_info regex:${JSON.stringify(regex)}`, log_extra);
|
|
210
200
|
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
const matched = [];
|
|
214
|
-
for (let result of results) {
|
|
215
|
-
matched.push(result[1].trim());
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if (is_log_debug()) {
|
|
219
|
-
log_debug(LOG_BASH, "get_info and matched:" + JSON.stringify(matched), log_extra);
|
|
220
|
-
}
|
|
201
|
+
const matched = [...stdout.matchAll(regex)].map(result => result[1].trim());
|
|
202
|
+
if (is_log_debug()) log_debug(LOG_BASH, `get_info matched:${JSON.stringify(matched)}`, log_extra);
|
|
221
203
|
return matched;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Get the lines of array
|
|
226
|
-
* @param {array of lines} array
|
|
227
|
-
* @param {array of line number to get,use range to define the lines} lines
|
|
228
|
-
* @returns
|
|
229
|
-
*/
|
|
230
|
-
const get_lines = (array, lines) => {
|
|
231
|
-
const result = [];
|
|
232
|
-
lines.forEach(line => {
|
|
233
|
-
result.push(array[line]);
|
|
234
|
-
});
|
|
235
|
-
return result;
|
|
236
|
-
}
|
|
204
|
+
};
|
|
237
205
|
|
|
238
206
|
/**
|
|
239
|
-
* Read
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
Model name: Intel(R) Xeon(R) Gold 6258R CPU @ 2.70GHz
|
|
247
|
-
Stepping: 7
|
|
248
|
-
CPU MHz: 2965.749
|
|
249
|
-
CPU max MHz: 4000.0000
|
|
250
|
-
CPU min MHz: 1000.0000
|
|
251
|
-
BogoMIPS: 5400.00
|
|
252
|
-
Virtualization: VT-x
|
|
253
|
-
L1d cache: 32K
|
|
254
|
-
L1i cache: 32K
|
|
255
|
-
|
|
256
|
-
* @param {stdout of the run_cmd} stdout
|
|
257
|
-
* @param {delimiter to split} delimiter
|
|
258
|
-
* @param {lines to retrieve} lines
|
|
259
|
-
* @param {only retrieve the value that has the same property in config} config
|
|
260
|
-
* @returns
|
|
207
|
+
* Read key-value pairs from stdout.
|
|
208
|
+
* @param {string} stdout - Command output.
|
|
209
|
+
* @param {string} [delimiter=":"] - Key-value delimiter.
|
|
210
|
+
* @param {number[]} [lines] - Specific lines to read.
|
|
211
|
+
* @param {Object} [config] - Filter config for keys.
|
|
212
|
+
* @param {boolean} [exclude_mode] - If true, exclude keys in config.
|
|
213
|
+
* @returns {Object} Parsed key-value object.
|
|
261
214
|
*/
|
|
262
215
|
const read_key_value_line = (stdout, delimiter = ":", lines, config, exclude_mode) => {
|
|
263
|
-
|
|
264
|
-
if (!stdout) {
|
|
265
|
-
return obj;
|
|
266
|
-
}
|
|
216
|
+
if (!stdout) return {};
|
|
267
217
|
|
|
268
218
|
const contents = stdout.toString().split(/(?:\r\n|\r|\n)/g);
|
|
269
|
-
const line_texts = lines ?
|
|
270
|
-
|
|
219
|
+
const line_texts = lines ? lines.map(i => contents[i]) : contents;
|
|
220
|
+
|
|
221
|
+
return line_texts.reduce((obj, content) => {
|
|
271
222
|
const key_value = content.split(delimiter);
|
|
272
|
-
if (key_value.length
|
|
273
|
-
const key = key_value[0].trim();
|
|
274
|
-
if (key && !config || (exclude_mode != true && config && config[key]) || exclude_mode == true && config && !config[`!${key}`]) {
|
|
275
|
-
obj[key] = key_value[1].trim();
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
return obj;
|
|
280
|
-
}
|
|
223
|
+
if (key_value.length !== 2) return obj;
|
|
281
224
|
|
|
225
|
+
const key = key_value[0].trim();
|
|
226
|
+
const should_include = !config ||
|
|
227
|
+
(exclude_mode !== true && config[key]) ||
|
|
228
|
+
(exclude_mode === true && !config[`!${key}`]);
|
|
282
229
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
INTEL SSDSC2KB03 3.5T
|
|
288
|
-
INTEL SSDPE2KE032T7 2.9T
|
|
230
|
+
if (key && should_include) obj[key] = key_value[1].trim();
|
|
231
|
+
return obj;
|
|
232
|
+
}, {});
|
|
233
|
+
};
|
|
289
234
|
|
|
290
|
-
|
|
291
|
-
*
|
|
292
|
-
* @param {
|
|
293
|
-
* @param {
|
|
294
|
-
* @
|
|
235
|
+
/**
|
|
236
|
+
* Read structured lines into array of objects.
|
|
237
|
+
* @param {string} stdout - Command output.
|
|
238
|
+
* @param {string[]} keys - Attribute keys for columns.
|
|
239
|
+
* @param {number} [ignore=1] - Lines to skip at start.
|
|
240
|
+
* @param {string} [delimiter=" "] - Column delimiter.
|
|
241
|
+
* @returns {Object[]} Array of parsed objects.
|
|
295
242
|
*/
|
|
296
243
|
const read_obj_line = (stdout, keys, ignore = 1, delimiter = " ") => {
|
|
297
|
-
|
|
298
|
-
if (!stdout) {
|
|
299
|
-
return results;
|
|
300
|
-
}
|
|
244
|
+
if (!stdout) return [];
|
|
301
245
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}
|
|
314
|
-
results.push(obj);
|
|
315
|
-
}
|
|
316
|
-
});
|
|
317
|
-
return results;
|
|
318
|
-
}
|
|
246
|
+
return stdout.toString().split(/(?:\r\n|\r|\n)/g)
|
|
247
|
+
.slice(ignore)
|
|
248
|
+
.filter(content => content.trim().length > 0)
|
|
249
|
+
.map(content => {
|
|
250
|
+
const attrs = content.split(delimiter).filter(f => f.trim().length > 0);
|
|
251
|
+
return keys.reduce((obj, key, i) => {
|
|
252
|
+
if (attrs[i]) obj[key] = attrs[i].trim();
|
|
253
|
+
return obj;
|
|
254
|
+
}, {});
|
|
255
|
+
});
|
|
256
|
+
};
|
|
319
257
|
|
|
320
258
|
/**
|
|
321
|
-
*
|
|
322
|
-
* @param {host
|
|
323
|
-
* @param {
|
|
259
|
+
* Get multiple system attributes from remote host.
|
|
260
|
+
* @param {Object} host - Host info.
|
|
261
|
+
* @param {Array<{name: string, cmd: string}>} attrs - Attributes to fetch.
|
|
262
|
+
* @param {Object} [log_extra] - Additional logging context.
|
|
263
|
+
* @returns {Promise<Object>} Object with attribute values.
|
|
324
264
|
*/
|
|
325
265
|
const get_system_attributes = async (host, attrs, log_extra) => {
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
return obj;
|
|
333
|
-
}
|
|
266
|
+
const results = await Promise.all(attrs.map(attr => run_simple_cmd(host, attr.cmd, log_extra)));
|
|
267
|
+
return attrs.reduce((obj, attr, i) => {
|
|
268
|
+
if (results[i]) obj[attr.name] = results[i];
|
|
269
|
+
return obj;
|
|
270
|
+
}, {});
|
|
271
|
+
};
|
|
334
272
|
|
|
273
|
+
/**
|
|
274
|
+
* Stop process on remote host if running.
|
|
275
|
+
* @param {Object} host - Host info.
|
|
276
|
+
* @param {string} process_name - Process name to stop.
|
|
277
|
+
* @param {string} stop_cmd - Command to stop the process.
|
|
278
|
+
* @param {boolean} [using_full] - Use pgrep -f for full command match.
|
|
279
|
+
* @param {Object} [log_extra] - Additional logging context.
|
|
280
|
+
* @returns {Promise<boolean>} True if process was running and stopped.
|
|
281
|
+
*/
|
|
335
282
|
const stop_process = async (host, process_name, stop_cmd, using_full, log_extra) => {
|
|
336
|
-
const grep_cmd = using_full
|
|
283
|
+
const grep_cmd = using_full ? `pgrep -f "${process_name}" | wc -l` : `pgrep ${process_name} | wc -l`;
|
|
337
284
|
const { stdout } = await run_script(host, grep_cmd, log_extra);
|
|
338
285
|
const has_process = stdout && parseInt(stdout) > 0;
|
|
339
|
-
if (has_process)
|
|
340
|
-
await run_script(host, stop_cmd, log_extra);
|
|
341
|
-
}
|
|
286
|
+
if (has_process) await run_script(host, stop_cmd, log_extra);
|
|
342
287
|
return has_process;
|
|
343
|
-
}
|
|
288
|
+
};
|
|
344
289
|
|
|
345
|
-
module.exports = {
|
|
290
|
+
module.exports = {
|
|
291
|
+
stop_process, scp, scpr, run_script, run_script_extra, run_script_file,
|
|
292
|
+
run_simple_cmd, run_local_cmd, run_simple_local_cmd, get_info,
|
|
293
|
+
get_system_attributes, read_key_value_line, read_obj_line
|
|
294
|
+
};
|
package/core/chart.js
CHANGED
|
@@ -1,36 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Chart data processing utility functions.
|
|
3
|
+
* @module core/chart
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
const { has_value } = require("./validate");
|
|
2
7
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Set chart header prefix for all columns except the first.
|
|
10
|
+
* @param {Array[]} arr - 2D array with headers in first row.
|
|
11
|
+
* @param {string} prefix - Prefix to add to header names.
|
|
12
|
+
*/
|
|
13
|
+
const set_chart_header = (arr, prefix) => {
|
|
14
|
+
if (!arr || arr.length < 1) return;
|
|
15
|
+
const headers = arr[0];
|
|
16
|
+
if (!headers || headers.length < 1) return;
|
|
11
17
|
for (let i = 1; i < headers.length; i++) {
|
|
12
18
|
headers[i] = `${prefix}${headers[i]}`;
|
|
13
19
|
}
|
|
14
|
-
}
|
|
20
|
+
};
|
|
15
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Merge two chart data arrays by combining columns.
|
|
24
|
+
* @param {Array[]} arr1 - First 2D data array (will be modified).
|
|
25
|
+
* @param {Array[]} arr2 - Second 2D data array to merge.
|
|
26
|
+
*/
|
|
16
27
|
const merge_chart_data = (arr1, arr2) => {
|
|
17
|
-
if (!arr1 || arr1.length < 2 || !arr2 || arr2.length < 2)
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
28
|
+
if (!arr1 || arr1.length < 2 || !arr2 || arr2.length < 2) return;
|
|
20
29
|
|
|
21
30
|
const max = Math.max(arr1.length, arr2.length);
|
|
22
31
|
const arr1_cols = arr1[0].length;
|
|
23
32
|
const arr2_cols = arr2[0].length;
|
|
33
|
+
|
|
24
34
|
for (let i = 0; i < max; i++) {
|
|
25
35
|
if (!has_value(arr1[i])) {
|
|
26
|
-
arr1[i] = [...new Array(arr1_cols)].map(
|
|
36
|
+
arr1[i] = [...new Array(arr1_cols)].map(() => "");
|
|
27
37
|
arr1[i][0] = arr2[i][0];
|
|
28
38
|
}
|
|
29
39
|
if (!has_value(arr2[i])) {
|
|
30
|
-
arr2[i] = [...new Array(arr2_cols)].map(
|
|
40
|
+
arr2[i] = [...new Array(arr2_cols)].map(() => "");
|
|
31
41
|
}
|
|
32
42
|
arr1[i] = [...arr1[i], ...arr2[i].splice(1)];
|
|
33
43
|
}
|
|
34
|
-
}
|
|
44
|
+
};
|
|
35
45
|
|
|
36
|
-
module.exports = { set_chart_header, merge_chart_data }
|
|
46
|
+
module.exports = { set_chart_header, merge_chart_data };
|
package/core/cron.js
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Cron job scheduling utility functions.
|
|
3
|
+
* @module core/cron
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
const node_cron = require('node-cron');
|
|
2
7
|
|
|
3
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Initialize and start cron jobs.
|
|
10
|
+
* @param {string[]} crons - Array of cron expressions.
|
|
11
|
+
* @param {Function[]} tasks - Array of task functions to execute.
|
|
12
|
+
* @param {string} [timezone="Asia/Shanghai"] - Timezone for scheduling.
|
|
13
|
+
*/
|
|
14
|
+
const init_cron = async (crons, tasks, timezone = "Asia/Shanghai") => {
|
|
4
15
|
crons.forEach((cron, index) => {
|
|
5
|
-
const schedule = node_cron.schedule(cron, () =>
|
|
16
|
+
const schedule = node_cron.schedule(cron, () => tasks[index](), { scheduled: true, timezone });
|
|
6
17
|
schedule.start();
|
|
7
18
|
});
|
|
8
|
-
}
|
|
19
|
+
};
|
|
9
20
|
|
|
10
21
|
module.exports = { init_cron };
|