@constellation-network/node-pilot 0.0.21 → 0.2.0
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 +13 -11
- package/dist/checks/check-pilot.js +38 -9
- package/dist/checks/check-project.js +1 -1
- package/dist/clm.js +11 -6
- package/dist/commands/clean.js +1 -0
- package/dist/commands/logs.d.ts +1 -0
- package/dist/commands/logs.js +3 -1
- package/dist/commands/restart.d.ts +1 -0
- package/dist/commands/restart.js +22 -25
- package/dist/commands/test.js +3 -3
- package/dist/config-store.d.ts +1 -1
- package/dist/config-store.js +5 -1
- package/dist/helpers/service-log.d.ts +2 -0
- package/dist/helpers/service-log.js +6 -0
- package/dist/helpers/status-table-helper.d.ts +14 -0
- package/dist/helpers/status-table-helper.js +18 -0
- package/dist/helpers/status-table.d.ts +4 -2
- package/dist/helpers/status-table.js +123 -33
- package/oclif.manifest.json +14 -1
- package/package.json +3 -1
- package/projects/hypergraph/Dockerfile +1 -1
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ $ npm install -g @constellation-network/node-pilot
|
|
|
21
21
|
$ cpilot COMMAND
|
|
22
22
|
running command...
|
|
23
23
|
$ cpilot (--version|-v)
|
|
24
|
-
@constellation-network/node-pilot/0.0
|
|
24
|
+
@constellation-network/node-pilot/0.2.0 darwin-arm64 node-v22.15.0
|
|
25
25
|
$ cpilot --help [COMMAND]
|
|
26
26
|
USAGE
|
|
27
27
|
$ cpilot COMMAND
|
|
@@ -71,7 +71,7 @@ EXAMPLES
|
|
|
71
71
|
$ cpilot clean
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
-
_See code: [src/commands/clean.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0
|
|
74
|
+
_See code: [src/commands/clean.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.2.0/src/commands/clean.ts)_
|
|
75
75
|
|
|
76
76
|
## `cpilot config`
|
|
77
77
|
|
|
@@ -88,7 +88,7 @@ EXAMPLES
|
|
|
88
88
|
$ cpilot config
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
_See code: [src/commands/config.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0
|
|
91
|
+
_See code: [src/commands/config.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.2.0/src/commands/config.ts)_
|
|
92
92
|
|
|
93
93
|
## `cpilot config get [NAME]`
|
|
94
94
|
|
|
@@ -112,7 +112,7 @@ EXAMPLES
|
|
|
112
112
|
$ cpilot config get gl0:CL_PUBLIC_HTTP_PORT
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
-
_See code: [src/commands/config/get.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0
|
|
115
|
+
_See code: [src/commands/config/get.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.2.0/src/commands/config/get.ts)_
|
|
116
116
|
|
|
117
117
|
## `cpilot config set NAME VALUE`
|
|
118
118
|
|
|
@@ -135,7 +135,7 @@ EXAMPLES
|
|
|
135
135
|
$ cpilot config set gl0:CL_PUBLIC_HTTP_PORT 9000
|
|
136
136
|
```
|
|
137
137
|
|
|
138
|
-
_See code: [src/commands/config/set.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0
|
|
138
|
+
_See code: [src/commands/config/set.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.2.0/src/commands/config/set.ts)_
|
|
139
139
|
|
|
140
140
|
## `cpilot help [COMMAND]`
|
|
141
141
|
|
|
@@ -172,7 +172,7 @@ EXAMPLES
|
|
|
172
172
|
$ cpilot info
|
|
173
173
|
```
|
|
174
174
|
|
|
175
|
-
_See code: [src/commands/info.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0
|
|
175
|
+
_See code: [src/commands/info.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.2.0/src/commands/info.ts)_
|
|
176
176
|
|
|
177
177
|
## `cpilot logs LAYER`
|
|
178
178
|
|
|
@@ -180,12 +180,14 @@ view validator node runtime logs
|
|
|
180
180
|
|
|
181
181
|
```
|
|
182
182
|
USAGE
|
|
183
|
-
$ cpilot logs LAYER [-f] [-n <value>]
|
|
183
|
+
$ cpilot logs LAYER [-a app|hc] [-f] [-n <value>]
|
|
184
184
|
|
|
185
185
|
ARGUMENTS
|
|
186
186
|
LAYER network layer to view. e.g. gl0
|
|
187
187
|
|
|
188
188
|
FLAGS
|
|
189
|
+
-a, --area=<option> [default: hc] area to view logs for. e.g. "app" or "hc" for health-check
|
|
190
|
+
<options: app|hc>
|
|
189
191
|
-f, --follow continuously wait for additional data to be appended
|
|
190
192
|
-n, --numOfLines=<value> number of lines at the end of the log to display
|
|
191
193
|
|
|
@@ -196,7 +198,7 @@ EXAMPLES
|
|
|
196
198
|
$ cpilot logs
|
|
197
199
|
```
|
|
198
200
|
|
|
199
|
-
_See code: [src/commands/logs.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0
|
|
201
|
+
_See code: [src/commands/logs.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.2.0/src/commands/logs.ts)_
|
|
200
202
|
|
|
201
203
|
## `cpilot restart [LAYER]`
|
|
202
204
|
|
|
@@ -224,7 +226,7 @@ EXAMPLES
|
|
|
224
226
|
$ cpilot restart
|
|
225
227
|
```
|
|
226
228
|
|
|
227
|
-
_See code: [src/commands/restart.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0
|
|
229
|
+
_See code: [src/commands/restart.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.2.0/src/commands/restart.ts)_
|
|
228
230
|
|
|
229
231
|
## `cpilot shutdown`
|
|
230
232
|
|
|
@@ -244,7 +246,7 @@ EXAMPLES
|
|
|
244
246
|
$ cpilot shutdown
|
|
245
247
|
```
|
|
246
248
|
|
|
247
|
-
_See code: [src/commands/shutdown.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0
|
|
249
|
+
_See code: [src/commands/shutdown.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.2.0/src/commands/shutdown.ts)_
|
|
248
250
|
|
|
249
251
|
## `cpilot status`
|
|
250
252
|
|
|
@@ -258,5 +260,5 @@ DESCRIPTION
|
|
|
258
260
|
Display node status and configuration settings
|
|
259
261
|
```
|
|
260
262
|
|
|
261
|
-
_See code: [src/commands/status.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0
|
|
263
|
+
_See code: [src/commands/status.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.2.0/src/commands/status.ts)_
|
|
262
264
|
<!-- commandsstop -->
|
|
@@ -2,11 +2,13 @@ import { JSONStorage } from "node-localstorage";
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
import semver from "semver";
|
|
5
6
|
import packageJson from '../../package.json' with { type: 'json' };
|
|
6
7
|
import { clm } from "../clm.js";
|
|
7
8
|
import { configStore } from "../config-store.js";
|
|
8
9
|
import { projectHelper } from "../helpers/project-helper.js";
|
|
9
10
|
import { promptHelper } from "../helpers/prompt-helper.js";
|
|
11
|
+
import { dockerService } from "../services/docker-service.js";
|
|
10
12
|
import { shellService } from "../services/shell-service.js";
|
|
11
13
|
const REGISTRY_URL = 'https://registry.npmjs.org/';
|
|
12
14
|
export const checkNodePilot = {
|
|
@@ -26,17 +28,44 @@ export const checkNodePilot = {
|
|
|
26
28
|
if (!result) {
|
|
27
29
|
return;
|
|
28
30
|
}
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
const latestVer = semver.parse(result['dist-tags'].latest);
|
|
32
|
+
const currentVer = semver.parse(packageJson.version);
|
|
33
|
+
if (!latestVer || !currentVer || latestVer.compare(currentVer) === 0)
|
|
34
|
+
return;
|
|
35
|
+
clm.echo(`There is a new node-pilot version available. Current version: "${currentVer.version}", Latest version: "${latestVer.version}"`);
|
|
36
|
+
if (os.platform() !== 'linux')
|
|
37
|
+
return;
|
|
38
|
+
const hasMajorMinorChange = latestVer.major !== currentVer.major || latestVer.minor !== currentVer.minor;
|
|
39
|
+
if (hasMajorMinorChange) {
|
|
40
|
+
const dockerIsRunning = await dockerService.isRunning();
|
|
41
|
+
if (dockerIsRunning) {
|
|
42
|
+
clm.warn('This update requires the Node to shutdown before proceeding.');
|
|
43
|
+
}
|
|
44
|
+
if (await promptHelper.confirmPrompt('Do you wish to upgrade now?')) {
|
|
45
|
+
if (dockerIsRunning) {
|
|
46
|
+
await dockerService.dockerDown();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
clm.postStep('Skipping update...');
|
|
51
|
+
return;
|
|
38
52
|
}
|
|
39
53
|
}
|
|
54
|
+
else {
|
|
55
|
+
clm.preStep('This update includes a minor change. There is no need to restart your Node.');
|
|
56
|
+
if (!await promptHelper.confirmPrompt('Do you wish to upgrade now?')) {
|
|
57
|
+
clm.postStep('Skipping update...');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
clm.step('Updating Node Pilot to the latest version...');
|
|
62
|
+
await shellService.runCommand(`sudo npm install -g @constellation-network/node-pilot@${latestVer.version}`);
|
|
63
|
+
if (hasMajorMinorChange) {
|
|
64
|
+
clm.step('Updating scripts and configuration files...');
|
|
65
|
+
await projectHelper.upgradeHypergraph();
|
|
66
|
+
}
|
|
67
|
+
clm.postStep('Update completed. Run cpilot again to use the latest version');
|
|
68
|
+
process.exit(0);
|
|
40
69
|
},
|
|
41
70
|
async promptDiscordRegistration() {
|
|
42
71
|
const hcStorage = getHcStorage();
|
|
@@ -70,7 +70,7 @@ export const checkProject = {
|
|
|
70
70
|
if (nInfo.version !== clusterVersion) {
|
|
71
71
|
const answer = await input({
|
|
72
72
|
default: 'y',
|
|
73
|
-
message: `A new required network version has been detected. Do you want to upgrade now? (y/n): `
|
|
73
|
+
message: `A new required network version has been detected. ${clusterVersion}. Do you want to upgrade now? (y/n): `
|
|
74
74
|
});
|
|
75
75
|
if (answer !== 'y') {
|
|
76
76
|
process.exit(0);
|
package/dist/clm.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
+
import { configStore } from "./config-store.js";
|
|
3
|
+
import { serviceLog } from "./helpers/service-log.js";
|
|
2
4
|
/*
|
|
3
5
|
Command Line Messaging with color styling
|
|
4
6
|
*/
|
|
@@ -9,25 +11,28 @@ export const clm = {
|
|
|
9
11
|
}
|
|
10
12
|
},
|
|
11
13
|
echo(msg) {
|
|
12
|
-
|
|
14
|
+
o().log(msg);
|
|
13
15
|
},
|
|
14
16
|
echoRepeatLine(char) {
|
|
15
17
|
process.stdout.write('\r' + char);
|
|
16
18
|
},
|
|
17
19
|
error(msg, silent = true) {
|
|
18
|
-
|
|
20
|
+
o().error(chalk.red(msg));
|
|
19
21
|
process.exit(silent ? 0 : 1);
|
|
20
22
|
},
|
|
21
23
|
postStep(s) {
|
|
22
|
-
|
|
24
|
+
o().log(chalk.green(s));
|
|
23
25
|
},
|
|
24
26
|
preStep(s) {
|
|
25
|
-
|
|
27
|
+
o().log('\n' + chalk.italic(chalk.green(s)));
|
|
26
28
|
},
|
|
27
29
|
step(msg) {
|
|
28
|
-
|
|
30
|
+
o().warn(chalk.whiteBright(msg));
|
|
29
31
|
},
|
|
30
32
|
warn(msg) {
|
|
31
|
-
|
|
33
|
+
o().warn(chalk.red(msg));
|
|
32
34
|
}
|
|
33
35
|
};
|
|
36
|
+
function o() {
|
|
37
|
+
return configStore.isRestarting() ? serviceLog : console;
|
|
38
|
+
}
|
package/dist/commands/clean.js
CHANGED
|
@@ -37,6 +37,7 @@ export default class Clean extends Command {
|
|
|
37
37
|
if (deleteData) {
|
|
38
38
|
await shellService.runProjectCommand(`sudo rm -rf ${args.layer}/data`);
|
|
39
39
|
projectHelper.prepareDataFolder();
|
|
40
|
+
configStore.setProjectFlag('discordChecked', false);
|
|
40
41
|
}
|
|
41
42
|
if (deleteLogs) {
|
|
42
43
|
await shellService.runProjectCommand(`sudo rm -rf ${args.layer}/logs`);
|
package/dist/commands/logs.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export default class Logs extends Command {
|
|
|
6
6
|
static description: string;
|
|
7
7
|
static examples: string[];
|
|
8
8
|
static flags: {
|
|
9
|
+
area: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
10
|
follow: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
11
|
numOfLines: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
12
|
};
|
package/dist/commands/logs.js
CHANGED
|
@@ -12,6 +12,7 @@ export default class Logs extends Command {
|
|
|
12
12
|
'<%= config.bin %> <%= command.id %>',
|
|
13
13
|
];
|
|
14
14
|
static flags = {
|
|
15
|
+
area: Flags.string({ char: 'a', default: 'hc', description: 'area to view logs for. e.g. "app" or "hc" for health-check', options: ['app', 'hc'] }),
|
|
15
16
|
follow: Flags.boolean({ char: 'f', description: 'continuously wait for additional data to be appended' }),
|
|
16
17
|
numOfLines: Flags.string({ char: 'n', description: 'number of lines at the end of the log to display' }),
|
|
17
18
|
};
|
|
@@ -27,8 +28,9 @@ export default class Logs extends Command {
|
|
|
27
28
|
if (flags.follow) {
|
|
28
29
|
tailFlag = ' -f';
|
|
29
30
|
}
|
|
31
|
+
const file = flags.area === 'app' ? 'app.log' : 'health-check.log';
|
|
30
32
|
const { projectDir } = configStore.getProjectInfo();
|
|
31
|
-
const logPath = path.join(projectDir, args.layer, 'logs',
|
|
33
|
+
const logPath = path.join(projectDir, args.layer, 'logs', file);
|
|
32
34
|
await shellService.runCommand(`tail ${tailFlag} ${logPath}`).catch(() => 1);
|
|
33
35
|
}
|
|
34
36
|
}
|
package/dist/commands/restart.js
CHANGED
|
@@ -25,9 +25,9 @@ export default class Restart extends BaseCommand {
|
|
|
25
25
|
configHelper.assertProject('No project found. ');
|
|
26
26
|
if (flags.update) {
|
|
27
27
|
serviceLog.log('Executing "cpilot restart --update" at ' + new Date().toLocaleString('en-US', { timeZone: 'America/Los_Angeles' }));
|
|
28
|
+
this.setIsRestarting(true);
|
|
28
29
|
const project = configStore.getActiveProject();
|
|
29
30
|
const activeProjects = configStore.getRunningProjects();
|
|
30
|
-
// serviceLog.log(` Active projects: ${activeProjects.join(', ')}...`);
|
|
31
31
|
for (const project of activeProjects) {
|
|
32
32
|
configStore.setActiveProject(project);
|
|
33
33
|
// eslint-disable-next-line no-await-in-loop
|
|
@@ -41,13 +41,14 @@ export default class Restart extends BaseCommand {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
configStore.setActiveProject(project);
|
|
44
|
+
this.setIsRestarting(false);
|
|
44
45
|
return;
|
|
45
46
|
}
|
|
46
47
|
if (flags.autostart) {
|
|
47
48
|
serviceLog.log('Executing "cpilot restart --autostart" at ' + new Date().toLocaleString('en-US', { timeZone: 'America/Los_Angeles' }));
|
|
49
|
+
this.setIsRestarting(true);
|
|
48
50
|
const project = configStore.getActiveProject();
|
|
49
51
|
const activeProjects = configStore.getRunningProjects();
|
|
50
|
-
// serviceLog.log(` Active projects: ${activeProjects.join(', ')}...`);
|
|
51
52
|
for (const project of activeProjects) {
|
|
52
53
|
serviceLog.log(' ' + project + ' is being auto started...');
|
|
53
54
|
configStore.setActiveProject(project);
|
|
@@ -55,6 +56,7 @@ export default class Restart extends BaseCommand {
|
|
|
55
56
|
await this.restart();
|
|
56
57
|
}
|
|
57
58
|
configStore.setActiveProject(project);
|
|
59
|
+
this.setIsRestarting(false);
|
|
58
60
|
return;
|
|
59
61
|
}
|
|
60
62
|
if (!await dockerService.isRunning()) {
|
|
@@ -75,32 +77,27 @@ export default class Restart extends BaseCommand {
|
|
|
75
77
|
await this.restart();
|
|
76
78
|
}
|
|
77
79
|
async restart() {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return;
|
|
80
|
+
if (await dockerService.isRunning()) {
|
|
81
|
+
await nodeService.leaveClusterAllLayers();
|
|
82
|
+
const { layersToRun } = configStore.getProjectInfo();
|
|
83
|
+
await nodeService.pollForLayersState(layersToRun, 'Offline');
|
|
84
|
+
clm.preStep('Stopping the node...');
|
|
85
|
+
await dockerService.dockerDown();
|
|
85
86
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
87
|
+
clm.preStep('Checking for a new version...');
|
|
88
|
+
await checkProject.runUpgrade();
|
|
89
|
+
clm.preStep('Starting the node...');
|
|
90
|
+
await dockerService.dockerRestartAll();
|
|
91
|
+
}
|
|
92
|
+
setIsRestarting(val) {
|
|
93
|
+
if (val) {
|
|
94
|
+
if (configStore.isRestarting()) {
|
|
95
|
+
serviceLog.log('Restart already ACTIVE');
|
|
96
|
+
process.exit(0);
|
|
95
97
|
}
|
|
96
|
-
|
|
97
|
-
serviceLog.log('Checking for a new version...');
|
|
98
|
-
await checkProject.runUpgrade();
|
|
99
|
-
clm.preStep('Starting the node...');
|
|
100
|
-
serviceLog.log('Starting the node...');
|
|
101
|
-
await dockerService.dockerRestartAll();
|
|
98
|
+
configStore.setIsRestarting(Date.now());
|
|
102
99
|
}
|
|
103
|
-
|
|
100
|
+
else {
|
|
104
101
|
configStore.setIsRestarting(0);
|
|
105
102
|
}
|
|
106
103
|
}
|
package/dist/commands/test.js
CHANGED
|
@@ -4,7 +4,7 @@ import fs from "node:fs";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { getRandomNode } from "../services/get-random-node.js";
|
|
7
|
-
import {
|
|
7
|
+
import { StatusTable } from "../helpers/status-table.js";
|
|
8
8
|
export default class Test extends Command {
|
|
9
9
|
static description = 'node pilot test command';
|
|
10
10
|
static hidden = true;
|
|
@@ -18,8 +18,8 @@ export default class Test extends Command {
|
|
|
18
18
|
//
|
|
19
19
|
// await archiverService.syncToLatestSnapshot();
|
|
20
20
|
// await archiverService.checkLogsForMissingSnapshots();
|
|
21
|
-
|
|
22
|
-
await checkNodePilot.checkVersion();
|
|
21
|
+
await StatusTable.run();
|
|
22
|
+
// await checkNodePilot.checkVersion();
|
|
23
23
|
}
|
|
24
24
|
async testRandomNode() {
|
|
25
25
|
const filePath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), `../../projects/hypergraph/networks/mainnet/source-nodes.env`);
|
package/dist/config-store.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ declare class ConfigStore {
|
|
|
18
18
|
getSystemInfo(): SystemInfo;
|
|
19
19
|
hasProjectFlag(name: string): any;
|
|
20
20
|
hasProjects(): boolean;
|
|
21
|
-
isRestarting():
|
|
21
|
+
isRestarting(): boolean;
|
|
22
22
|
setActiveProject(name: string): void;
|
|
23
23
|
setClusterStats(info: Partial<ClusterStats>): void;
|
|
24
24
|
setDockerEnvInfo(info: Partial<{
|
package/dist/config-store.js
CHANGED
|
@@ -106,7 +106,11 @@ class ConfigStore {
|
|
|
106
106
|
}
|
|
107
107
|
isRestarting() {
|
|
108
108
|
const { restarting } = this.pilotStore.getItem('pilot');
|
|
109
|
-
|
|
109
|
+
if (restarting && restarting + 1000 * 60 * 5 < Date.now()) {
|
|
110
|
+
this.setIsRestarting(0);
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
return restarting > 0;
|
|
110
114
|
}
|
|
111
115
|
setActiveProject(name) {
|
|
112
116
|
const { appDir, project, projects } = this.pilotStore.getItem('pilot');
|
|
@@ -2,9 +2,15 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { configStore } from "../config-store.js";
|
|
4
4
|
export const serviceLog = {
|
|
5
|
+
error(s) {
|
|
6
|
+
this.log(s);
|
|
7
|
+
},
|
|
5
8
|
log(s) {
|
|
6
9
|
const appDir = configStore.getAppDir();
|
|
7
10
|
const logFile = path.join(appDir, 'logs', 'service.log');
|
|
8
11
|
fs.appendFileSync(logFile, s + '\n');
|
|
9
12
|
},
|
|
13
|
+
warn(s) {
|
|
14
|
+
this.log(s);
|
|
15
|
+
},
|
|
10
16
|
};
|
|
@@ -19,6 +19,20 @@ export declare const statusTableHeader: ({
|
|
|
19
19
|
value: string;
|
|
20
20
|
width: number;
|
|
21
21
|
})[];
|
|
22
|
+
export declare const glHeader1: {
|
|
23
|
+
color: string;
|
|
24
|
+
formatter: (value: string) => string;
|
|
25
|
+
headerColor: string;
|
|
26
|
+
value: string;
|
|
27
|
+
width: number;
|
|
28
|
+
}[];
|
|
29
|
+
export declare const glHeader2: {
|
|
30
|
+
color: string;
|
|
31
|
+
formatter: (value: string) => string;
|
|
32
|
+
headerColor: string;
|
|
33
|
+
value: string;
|
|
34
|
+
width: number;
|
|
35
|
+
}[];
|
|
22
36
|
export type NodeStatusInfo = {
|
|
23
37
|
clusterOrdinal: number;
|
|
24
38
|
clusterSession: string;
|
|
@@ -57,10 +57,14 @@ class CellFormatter {
|
|
|
57
57
|
return this.style(value, "bgRed", "bold");
|
|
58
58
|
if (value === 'Ready')
|
|
59
59
|
return this.style(value, "green");
|
|
60
|
+
if (value === 'HydratingSnapshots')
|
|
61
|
+
return this.style(value, "cyan");
|
|
60
62
|
if (value === 'ReadyToJoin' || value === 'JoiningCluster')
|
|
61
63
|
return this.style(value, "yellow", "bold");
|
|
62
64
|
if (value === 'Restarting')
|
|
63
65
|
return this.style(value, "yellow", "bold");
|
|
66
|
+
if (value.startsWith('Ready'))
|
|
67
|
+
return this.style(value, "green");
|
|
64
68
|
return this.style(value, "white");
|
|
65
69
|
}
|
|
66
70
|
formatUpTIme(startTime) {
|
|
@@ -108,3 +112,17 @@ export const statusTableHeader = [
|
|
|
108
112
|
{ color: 'white', formatter: formatMem, headerColor: 'whiteBright', value: 'Mem Usage (GB)', width: 16 },
|
|
109
113
|
{ color: 'white', formatter: formatError, headerColor: 'whiteBright', value: 'Error', width: 22 },
|
|
110
114
|
];
|
|
115
|
+
export const glHeader1 = [
|
|
116
|
+
// { color: 'white', headerColor: 'whiteBright', value: 'Network' },
|
|
117
|
+
// { color: 'whiteBright', headerColor: 'whiteBright', value: 'Layer' },
|
|
118
|
+
{ color: 'white', formatter: formatState, headerColor: 'whiteBright', value: 'Node State', width: 22 },
|
|
119
|
+
{ color: 'white', formatter: formatUpTIme, headerColor: 'whiteBright', value: 'Uptime', width: 13 },
|
|
120
|
+
{ color: 'white', formatter: formatOrdinal, headerColor: 'whiteBright', value: 'Ordinal', width: 16 },
|
|
121
|
+
{ color: 'white', formatter: formatDistance, headerColor: 'whiteBright', value: 'Distance', width: 22 },
|
|
122
|
+
];
|
|
123
|
+
export const glHeader2 = [
|
|
124
|
+
{ color: 'white', formatter: formatState, headerColor: 'whiteBright', value: 'Cluster State', width: 22 },
|
|
125
|
+
{ color: 'white', formatter: formatCpu, headerColor: 'whiteBright', value: 'CPU Usage', width: 13 },
|
|
126
|
+
{ color: 'white', formatter: formatMem, headerColor: 'whiteBright', value: 'Mem Usage (GB)', width: 16 },
|
|
127
|
+
{ color: 'white', formatter: formatError, headerColor: 'whiteBright', value: 'Error', width: 22 },
|
|
128
|
+
];
|
|
@@ -5,7 +5,7 @@ import os from "node:os";
|
|
|
5
5
|
import ttyTable from "tty-table";
|
|
6
6
|
import { clm } from "../clm.js";
|
|
7
7
|
import { configStore } from "../config-store.js";
|
|
8
|
-
import { formatTimeAgo, statusTableHeader } from "./status-table-helper.js";
|
|
8
|
+
import { formatTimeAgo, glHeader1, glHeader2, statusTableHeader } from "./status-table-helper.js";
|
|
9
9
|
export class StatusTable {
|
|
10
10
|
alreadyRendered = false;
|
|
11
11
|
previousHeight = 0;
|
|
@@ -18,7 +18,14 @@ export class StatusTable {
|
|
|
18
18
|
process.exit();
|
|
19
19
|
});
|
|
20
20
|
const table = new StatusTable();
|
|
21
|
-
|
|
21
|
+
const cols = process.stdout.columns;
|
|
22
|
+
console.log(String('Colspan: ' + cols));
|
|
23
|
+
if (cols > 120) {
|
|
24
|
+
table.monitorWide();
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
table.monitorNarrow();
|
|
28
|
+
}
|
|
22
29
|
const onKeyPress = createPrompt((_, done) => {
|
|
23
30
|
useKeypress(() => { done(''); });
|
|
24
31
|
return '';
|
|
@@ -45,23 +52,73 @@ export class StatusTable {
|
|
|
45
52
|
configStore.setActiveProject(activeProject);
|
|
46
53
|
return info;
|
|
47
54
|
}
|
|
48
|
-
async
|
|
49
|
-
const
|
|
55
|
+
async monitorNarrow() {
|
|
56
|
+
const projectInfos = this.getProjectInfo();
|
|
57
|
+
const values = {};
|
|
58
|
+
// const err = { date: '', layer: '', msg:'', timeAgo: '' }
|
|
59
|
+
while (true) {
|
|
60
|
+
// const rows = [];
|
|
61
|
+
const tables = [];
|
|
62
|
+
for (const info of projectInfos) {
|
|
63
|
+
if (!values[info.layer])
|
|
64
|
+
values[info.layer] = {};
|
|
65
|
+
const n = fs.existsSync(info.path) ? JSON.parse(fs.readFileSync(info.path, 'utf8')) : {};
|
|
66
|
+
const projectName = info.project === 'hypergraph' ? '' : ':' + info.project;
|
|
67
|
+
const network = info.network === 'integrationnet' ? 'intnet' : info.network;
|
|
68
|
+
const distance = Number.isNaN(n.clusterOrdinal - n.ordinal) ? '-' : String(n.clusterOrdinal - n.ordinal);
|
|
69
|
+
const ordinal = (values[info.layer].ordinal === n.ordinal) ? String(n.ordinal) : n.ordinal + ':true';
|
|
70
|
+
const label = info.layer + ':' + network + projectName;
|
|
71
|
+
const row1 = [
|
|
72
|
+
n.state,
|
|
73
|
+
n.session,
|
|
74
|
+
n.ordinal ? ordinal : '-',
|
|
75
|
+
distance,
|
|
76
|
+
];
|
|
77
|
+
const row2 = [
|
|
78
|
+
n.clusterState || 'Ready',
|
|
79
|
+
n.cpuUsage || '-',
|
|
80
|
+
n.memUsage || '-',
|
|
81
|
+
n.error || '-'
|
|
82
|
+
];
|
|
83
|
+
values[info.layer].ordinal = n.ordinal;
|
|
84
|
+
let errorMsg = '';
|
|
85
|
+
if ((info.layer === 'gl0' || info.layer === 'ml0') && n.lastError) {
|
|
86
|
+
const d = new Date(n.errorDate);
|
|
87
|
+
// if under 8 hours ago
|
|
88
|
+
if ((d.getTime() + (8 * 60 * 60 * 1000) > Date.now())) {
|
|
89
|
+
const date = new Date(n.errorDate).toISOString();
|
|
90
|
+
const timeAgo = formatTimeAgo(Date.now() - n.errorDate) || '';
|
|
91
|
+
errorMsg = chalk.green(` AUTO HEALED (${timeAgo}): `) + chalk.yellowBright(`${n.lastError} - ${date}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
tables.push({ error: errorMsg, label, row1: [row1], row2: [row2] });
|
|
95
|
+
}
|
|
96
|
+
this.renderNarrow(tables);
|
|
97
|
+
process.stdout.write("\n * press any key to cancel");
|
|
98
|
+
// eslint-disable-next-line no-await-in-loop
|
|
99
|
+
await sleep(1);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async monitorWide() {
|
|
103
|
+
const projectInfos = this.getProjectInfo();
|
|
50
104
|
const values = {};
|
|
51
|
-
const err = { date: '', layer: '', msg:
|
|
105
|
+
// const err = { date: '', layer: '', msg:'', timeAgo: '' }
|
|
52
106
|
while (true) {
|
|
53
107
|
const rows = [];
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const
|
|
108
|
+
// const projects: { error: string; label: string, row1: string[][], row2: string[][] }[] = [];
|
|
109
|
+
let errorMsg = '';
|
|
110
|
+
for (const info of projectInfos) {
|
|
111
|
+
if (!values[info.layer])
|
|
112
|
+
values[info.layer] = {};
|
|
113
|
+
const n = fs.existsSync(info.path) ? JSON.parse(fs.readFileSync(info.path, 'utf8')) : {};
|
|
114
|
+
const projectName = info.project === 'hypergraph' ? '' : ':' + info.project;
|
|
115
|
+
const network = info.network === 'integrationnet' ? 'intnet' : info.network;
|
|
60
116
|
const distance = Number.isNaN(n.clusterOrdinal - n.ordinal) ? '-' : String(n.clusterOrdinal - n.ordinal);
|
|
61
|
-
const ordinal = (values[
|
|
117
|
+
const ordinal = (values[info.layer].ordinal === n.ordinal) ? String(n.ordinal) : n.ordinal + ':true';
|
|
118
|
+
// const label = info.layer + ':' + network + projectName;
|
|
62
119
|
rows.push([
|
|
63
120
|
projectName + ':' + network,
|
|
64
|
-
|
|
121
|
+
info.layer,
|
|
65
122
|
n.session, // n.pilotSession,
|
|
66
123
|
n.state,
|
|
67
124
|
n.ordinal ? ordinal : '-',
|
|
@@ -71,30 +128,59 @@ export class StatusTable {
|
|
|
71
128
|
n.memUsage || '-',
|
|
72
129
|
n.error || '-'
|
|
73
130
|
]);
|
|
74
|
-
values[
|
|
75
|
-
if ((
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
131
|
+
values[info.layer].ordinal = n.ordinal;
|
|
132
|
+
if ((info.layer === 'gl0' || info.layer === 'ml0') && n.lastError) {
|
|
133
|
+
const d = new Date(n.errorDate);
|
|
134
|
+
// if under 8 hours ago
|
|
135
|
+
if ((d.getTime() + (8 * 60 * 60 * 1000) > Date.now())) {
|
|
136
|
+
const date = new Date(n.errorDate).toISOString();
|
|
137
|
+
const timeAgo = formatTimeAgo(Date.now() - n.errorDate) || '';
|
|
138
|
+
errorMsg = chalk.green(` AUTO HEALED (${timeAgo}): `) + chalk.yellowBright(`${n.lastError} - ${date}`);
|
|
139
|
+
}
|
|
80
140
|
}
|
|
141
|
+
// projects.push({ error: errorMsg, label, row1, row2 });
|
|
81
142
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const d = new Date(err.date);
|
|
85
|
-
// if under 8 hours ago
|
|
86
|
-
hasError = (d.getTime() + (8 * 60 * 60 * 1000) > Date.now());
|
|
87
|
-
}
|
|
88
|
-
this.render(rows, hasError);
|
|
89
|
-
if (hasError) {
|
|
90
|
-
process.stdout.write(chalk.green(` AUTO HEALED (${err.timeAgo}): `) + chalk.red(`${err.layer}:${err.msg} - ${err.date}\n`));
|
|
91
|
-
}
|
|
92
|
-
process.stdout.write(" * press any key to cancel");
|
|
143
|
+
this.renderWide({ error: errorMsg, label: '', row1: rows, row2: [] });
|
|
144
|
+
process.stdout.write("\n * press any key to cancel");
|
|
93
145
|
// eslint-disable-next-line no-await-in-loop
|
|
94
146
|
await sleep(1);
|
|
95
147
|
}
|
|
96
148
|
}
|
|
97
|
-
|
|
149
|
+
renderNarrow(project) {
|
|
150
|
+
const options = { terminalAdapter: true };
|
|
151
|
+
// hide cursor
|
|
152
|
+
console.log("\u001B[?25l");
|
|
153
|
+
// wipe existing if already rendered
|
|
154
|
+
if (this.alreadyRendered) {
|
|
155
|
+
// move cursor up number to the top of the previous print before deleting
|
|
156
|
+
console.log(`\u001B[${this.previousHeight}A`);
|
|
157
|
+
// delete to end of terminal
|
|
158
|
+
console.log("\u001B[0J");
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
this.alreadyRendered = true;
|
|
162
|
+
}
|
|
163
|
+
this.previousHeight = 0;
|
|
164
|
+
for (const p of project) {
|
|
165
|
+
const t1 = ttyTable(glHeader1, p.row1, options);
|
|
166
|
+
const t2 = ttyTable(glHeader2, p.row2, options);
|
|
167
|
+
process.stdout.write(" " + chalk.cyanBright(chalk.bold(p.label)));
|
|
168
|
+
process.stdout.write(t1.render());
|
|
169
|
+
process.stdout.write(t2.render());
|
|
170
|
+
// reset the previous height to the height of this output
|
|
171
|
+
// for when we next clear the print
|
|
172
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
173
|
+
// @ts-expect-error
|
|
174
|
+
this.previousHeight += t1.height + t2.height + 1;
|
|
175
|
+
if (p.error) {
|
|
176
|
+
process.stdout.write("\n" + p.error + "\n");
|
|
177
|
+
this.previousHeight++;
|
|
178
|
+
this.previousHeight++;
|
|
179
|
+
}
|
|
180
|
+
console.log("");
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
renderWide(table) {
|
|
98
184
|
const header = [...statusTableHeader];
|
|
99
185
|
// const emptyColumns = Array.from({length: rows[0].length}).fill(0) as number[];
|
|
100
186
|
// for (const [, row] of rows.entries()) {
|
|
@@ -112,13 +198,13 @@ export class StatusTable {
|
|
|
112
198
|
// }
|
|
113
199
|
// }
|
|
114
200
|
const options = { terminalAdapter: true };
|
|
115
|
-
const t1 = ttyTable(header,
|
|
201
|
+
const t1 = ttyTable(header, table.row1, options);
|
|
116
202
|
// hide cursor
|
|
117
203
|
console.log("\u001B[?25l");
|
|
118
204
|
// wipe existing if already rendered
|
|
119
205
|
if (this.alreadyRendered) {
|
|
120
206
|
// move cursor up number to the top of the previous print before deleting
|
|
121
|
-
console.log(`\u001B[${this.previousHeight +
|
|
207
|
+
console.log(`\u001B[${this.previousHeight + 4}A`);
|
|
122
208
|
// delete to end of terminal
|
|
123
209
|
console.log("\u001B[0J");
|
|
124
210
|
}
|
|
@@ -131,6 +217,10 @@ export class StatusTable {
|
|
|
131
217
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
132
218
|
// @ts-expect-error
|
|
133
219
|
this.previousHeight = t1.height;
|
|
220
|
+
if (table.error) {
|
|
221
|
+
console.log(table.error);
|
|
222
|
+
this.previousHeight++;
|
|
223
|
+
}
|
|
134
224
|
}
|
|
135
225
|
}
|
|
136
226
|
function sleep(sec) {
|
package/oclif.manifest.json
CHANGED
|
@@ -111,6 +111,19 @@
|
|
|
111
111
|
"<%= config.bin %> <%= command.id %>"
|
|
112
112
|
],
|
|
113
113
|
"flags": {
|
|
114
|
+
"area": {
|
|
115
|
+
"char": "a",
|
|
116
|
+
"description": "area to view logs for. e.g. \"app\" or \"hc\" for health-check",
|
|
117
|
+
"name": "area",
|
|
118
|
+
"default": "hc",
|
|
119
|
+
"hasDynamicHelp": false,
|
|
120
|
+
"multiple": false,
|
|
121
|
+
"options": [
|
|
122
|
+
"app",
|
|
123
|
+
"hc"
|
|
124
|
+
],
|
|
125
|
+
"type": "option"
|
|
126
|
+
},
|
|
114
127
|
"follow": {
|
|
115
128
|
"char": "f",
|
|
116
129
|
"description": "continuously wait for additional data to be appended",
|
|
@@ -336,5 +349,5 @@
|
|
|
336
349
|
]
|
|
337
350
|
}
|
|
338
351
|
},
|
|
339
|
-
"version": "0.0
|
|
352
|
+
"version": "0.2.0"
|
|
340
353
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constellation-network/node-pilot",
|
|
3
3
|
"description": "An easy deployment and monitoring tool for Constellation nodes.",
|
|
4
|
-
"version": "0.0
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"author": "Frank Fox",
|
|
6
6
|
"bin": {
|
|
7
7
|
"cpilot": "bin/run.js"
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"json-bigint-patch": "^0.0.8",
|
|
40
40
|
"node-localstorage": "^3.0.5",
|
|
41
41
|
"ora": "^8.2.0",
|
|
42
|
+
"semver": "^7.7.3",
|
|
42
43
|
"shelljs": "^0.10.0",
|
|
43
44
|
"tty-table": "^4.2.3",
|
|
44
45
|
"yaml": "^2.8.1"
|
|
@@ -51,6 +52,7 @@
|
|
|
51
52
|
"@types/mocha": "^10",
|
|
52
53
|
"@types/node": "^22.17.1",
|
|
53
54
|
"@types/node-localstorage": "^1.3.3",
|
|
55
|
+
"@types/semver": "^7.7.1",
|
|
54
56
|
"@types/shelljs": "^0.8.17",
|
|
55
57
|
"chai": "^4",
|
|
56
58
|
"eslint": "^9",
|
|
@@ -39,7 +39,7 @@ COPY dist/gl0.jar /app/jars/gl0.jar
|
|
|
39
39
|
#COPY ./health-check /health-check
|
|
40
40
|
#RUN chmod +x /health-check/bin/run.sh
|
|
41
41
|
#RUN chmod +x /health-check/bin/hydrate.sh
|
|
42
|
-
RUN npm install -g "@constellation-network/node-pilot-health-check@0.0.
|
|
42
|
+
RUN npm install -g "@constellation-network/node-pilot-health-check@0.0.16"
|
|
43
43
|
|
|
44
44
|
# Add entrypoint
|
|
45
45
|
COPY ./entrypoint.sh /app/entrypoint.sh
|