@constellation-network/node-pilot 0.0.17 → 0.0.18
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 +39 -10
- package/dist/checks/check-dependencies.js +32 -26
- package/dist/checks/check-network.js +2 -2
- package/dist/checks/check-project.js +2 -1
- package/dist/checks/check-wallet.js +1 -1
- package/dist/commands/clean.d.ts +14 -0
- package/dist/commands/clean.js +45 -0
- package/dist/commands/restart.js +8 -3
- package/dist/commands/shutdown.d.ts +3 -0
- package/dist/commands/shutdown.js +19 -4
- package/dist/helpers/project-helper.d.ts +1 -0
- package/dist/helpers/project-helper.js +11 -5
- package/dist/helpers/status-table-helper.js +14 -9
- package/dist/services/cluster-service.js +4 -1
- package/dist/services/docker-service.d.ts +2 -1
- package/dist/services/docker-service.js +10 -3
- package/dist/services/fastforward-service.js +14 -3
- package/install-dependencies.sh +0 -48
- package/oclif.manifest.json +62 -2
- package/package.json +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.0.18 darwin-arm64 node-v24.8.0
|
|
25
25
|
$ cpilot --help [COMMAND]
|
|
26
26
|
USAGE
|
|
27
27
|
$ cpilot COMMAND
|
|
@@ -37,6 +37,7 @@ If no command is entered, node-pilot will automatically perform a series of chec
|
|
|
37
37
|
|
|
38
38
|
# Commands
|
|
39
39
|
<!-- commands -->
|
|
40
|
+
* [`cpilot clean LAYER`](#cpilot-clean-layer)
|
|
40
41
|
* [`cpilot config`](#cpilot-config)
|
|
41
42
|
* [`cpilot config get [NAME]`](#cpilot-config-get-name)
|
|
42
43
|
* [`cpilot config set NAME VALUE`](#cpilot-config-set-name-value)
|
|
@@ -47,6 +48,31 @@ If no command is entered, node-pilot will automatically perform a series of chec
|
|
|
47
48
|
* [`cpilot shutdown`](#cpilot-shutdown)
|
|
48
49
|
* [`cpilot status`](#cpilot-status)
|
|
49
50
|
|
|
51
|
+
## `cpilot clean LAYER`
|
|
52
|
+
|
|
53
|
+
Remove data and/or logs from a validator node
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
USAGE
|
|
57
|
+
$ cpilot clean LAYER [-a] [-d] [-l]
|
|
58
|
+
|
|
59
|
+
ARGUMENTS
|
|
60
|
+
LAYER network layer to clean. e.g. gl0
|
|
61
|
+
|
|
62
|
+
FLAGS
|
|
63
|
+
-a, --all remove all data and logs
|
|
64
|
+
-d, --data remove data
|
|
65
|
+
-l, --logs remove logs
|
|
66
|
+
|
|
67
|
+
DESCRIPTION
|
|
68
|
+
Remove data and/or logs from a validator node
|
|
69
|
+
|
|
70
|
+
EXAMPLES
|
|
71
|
+
$ cpilot clean
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
_See code: [src/commands/clean.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.18/src/commands/clean.ts)_
|
|
75
|
+
|
|
50
76
|
## `cpilot config`
|
|
51
77
|
|
|
52
78
|
Update configuration settings
|
|
@@ -62,7 +88,7 @@ EXAMPLES
|
|
|
62
88
|
$ cpilot config
|
|
63
89
|
```
|
|
64
90
|
|
|
65
|
-
_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.0.18/src/commands/config.ts)_
|
|
66
92
|
|
|
67
93
|
## `cpilot config get [NAME]`
|
|
68
94
|
|
|
@@ -86,7 +112,7 @@ EXAMPLES
|
|
|
86
112
|
$ cpilot config get gl0:CL_PUBLIC_HTTP_PORT
|
|
87
113
|
```
|
|
88
114
|
|
|
89
|
-
_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.0.18/src/commands/config/get.ts)_
|
|
90
116
|
|
|
91
117
|
## `cpilot config set NAME VALUE`
|
|
92
118
|
|
|
@@ -109,7 +135,7 @@ EXAMPLES
|
|
|
109
135
|
$ cpilot config set gl0:CL_PUBLIC_HTTP_PORT 9000
|
|
110
136
|
```
|
|
111
137
|
|
|
112
|
-
_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.0.18/src/commands/config/set.ts)_
|
|
113
139
|
|
|
114
140
|
## `cpilot help [COMMAND]`
|
|
115
141
|
|
|
@@ -146,7 +172,7 @@ EXAMPLES
|
|
|
146
172
|
$ cpilot info
|
|
147
173
|
```
|
|
148
174
|
|
|
149
|
-
_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.0.18/src/commands/info.ts)_
|
|
150
176
|
|
|
151
177
|
## `cpilot logs LAYER`
|
|
152
178
|
|
|
@@ -170,7 +196,7 @@ EXAMPLES
|
|
|
170
196
|
$ cpilot logs
|
|
171
197
|
```
|
|
172
198
|
|
|
173
|
-
_See code: [src/commands/logs.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.
|
|
199
|
+
_See code: [src/commands/logs.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.18/src/commands/logs.ts)_
|
|
174
200
|
|
|
175
201
|
## `cpilot restart [LAYER]`
|
|
176
202
|
|
|
@@ -198,7 +224,7 @@ EXAMPLES
|
|
|
198
224
|
$ cpilot restart
|
|
199
225
|
```
|
|
200
226
|
|
|
201
|
-
_See code: [src/commands/restart.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.
|
|
227
|
+
_See code: [src/commands/restart.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.18/src/commands/restart.ts)_
|
|
202
228
|
|
|
203
229
|
## `cpilot shutdown`
|
|
204
230
|
|
|
@@ -206,7 +232,10 @@ A full shutdown of the validator node
|
|
|
206
232
|
|
|
207
233
|
```
|
|
208
234
|
USAGE
|
|
209
|
-
$ cpilot shutdown
|
|
235
|
+
$ cpilot shutdown [-l <value>]
|
|
236
|
+
|
|
237
|
+
FLAGS
|
|
238
|
+
-l, --layer=<value> specify a layer to shutdown. e.g. gl0
|
|
210
239
|
|
|
211
240
|
DESCRIPTION
|
|
212
241
|
A full shutdown of the validator node
|
|
@@ -215,7 +244,7 @@ EXAMPLES
|
|
|
215
244
|
$ cpilot shutdown
|
|
216
245
|
```
|
|
217
246
|
|
|
218
|
-
_See code: [src/commands/shutdown.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.
|
|
247
|
+
_See code: [src/commands/shutdown.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.18/src/commands/shutdown.ts)_
|
|
219
248
|
|
|
220
249
|
## `cpilot status`
|
|
221
250
|
|
|
@@ -229,5 +258,5 @@ DESCRIPTION
|
|
|
229
258
|
Display node status and configuration settings
|
|
230
259
|
```
|
|
231
260
|
|
|
232
|
-
_See code: [src/commands/status.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.
|
|
261
|
+
_See code: [src/commands/status.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.18/src/commands/status.ts)_
|
|
233
262
|
<!-- commandsstop -->
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
4
5
|
import shell from "shelljs";
|
|
@@ -8,37 +9,42 @@ import { shellService } from "../services/shell-service.js";
|
|
|
8
9
|
export const checkDependencies = async () => {
|
|
9
10
|
const dockerComposeVersion = await shellService.runCommand('docker compose version').catch(() => '');
|
|
10
11
|
clm.debug(`Docker compose version check: ${dockerComposeVersion || 'NOT_INSTALLED'}`);
|
|
11
|
-
if (dockerComposeVersion) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
process.exit(0);
|
|
12
|
+
if (!dockerComposeVersion) {
|
|
13
|
+
const isDockerV1Installed = await shellService.checkCommandAvailable('docker-compose');
|
|
14
|
+
if (isDockerV1Installed) {
|
|
15
|
+
clm.warn('You are using docker-compose v1. It needs to be uninstalled before upgrading to the latest version.');
|
|
16
|
+
// await promptHelper.doYouWishToContinue();
|
|
17
|
+
clm.step('\nRun the following command to uninstall docker-compose v1 and then run cpilot again:');
|
|
18
|
+
clm.preStep('for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done');
|
|
19
|
+
clm.echo('');
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
22
|
}
|
|
23
23
|
const isDockerInstalled = await shellService.checkCommandAvailable('docker');
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
await promptHelper.doYouWishToContinue();
|
|
31
|
-
}
|
|
32
|
-
clm.debug(`Running install-dependencies.sh from ${pilotDir}`);
|
|
33
|
-
// const silent = !process.env.DEBUG;
|
|
34
|
-
const result = shell.exec('bash install-dependencies.sh', { cwd: pilotDir });
|
|
35
|
-
if (result.code > 0) {
|
|
36
|
-
console.log(result.stderr);
|
|
37
|
-
clm.error(`Failed to install dependencies. Please try again after resolving any errors.`);
|
|
38
|
-
}
|
|
24
|
+
const pilotDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), `../..`);
|
|
25
|
+
if (fs.existsSync(path.join(pilotDir, 'install-dependencies.sh'))) {
|
|
26
|
+
if (!isDockerInstalled) {
|
|
27
|
+
clm.step('Docker is required and needs to be installed.');
|
|
28
|
+
await promptHelper.doYouWishToContinue();
|
|
29
|
+
await installDependencies(pilotDir);
|
|
39
30
|
clm.postStep(`\nDocker has been installed. Please logout and login again to ensure the changes take effect. Then run cpilot again.`);
|
|
40
31
|
clm.echo('');
|
|
41
32
|
process.exit(0);
|
|
42
33
|
}
|
|
34
|
+
const isACLInstalled = await shellService.checkCommandAvailable('setfacl');
|
|
35
|
+
if (!isACLInstalled && os.platform() === 'linux') {
|
|
36
|
+
clm.step('ACL is required and needs to be installed.');
|
|
37
|
+
await promptHelper.doYouWishToContinue();
|
|
38
|
+
await installDependencies(pilotDir);
|
|
39
|
+
}
|
|
43
40
|
}
|
|
44
41
|
};
|
|
42
|
+
async function installDependencies(pilotDir) {
|
|
43
|
+
clm.debug(`Running install-dependencies.sh from ${pilotDir}`);
|
|
44
|
+
// const silent = !process.env.DEBUG;
|
|
45
|
+
const result = shell.exec('bash install-dependencies.sh', { cwd: pilotDir });
|
|
46
|
+
if (result.code > 0) {
|
|
47
|
+
console.log(result.stderr);
|
|
48
|
+
clm.error(`Failed to install dependencies. Please try again after resolving any errors.`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -29,7 +29,7 @@ export const checkNetwork = {
|
|
|
29
29
|
clm.error(`Or to change the node ID, configure the Key File: use ${chalk.cyan('cpilot config')}, and select ${chalk.cyan('Key File')}`);
|
|
30
30
|
}
|
|
31
31
|
configStore.setProjectFlag('duplicateNodeIdChecked', true);
|
|
32
|
-
clm.postStep('No duplicate Node found.');
|
|
32
|
+
clm.postStep('✅ No duplicate Node found.');
|
|
33
33
|
},
|
|
34
34
|
async checkSeedList() {
|
|
35
35
|
if (configStore.hasProjectFlag('seedListChecked')) {
|
|
@@ -42,7 +42,7 @@ export const checkNetwork = {
|
|
|
42
42
|
if (fs.existsSync(seedListFile)) {
|
|
43
43
|
const found = fs.readFileSync(seedListFile, 'utf8').includes(nodeId);
|
|
44
44
|
if (found) {
|
|
45
|
-
clm.postStep(
|
|
45
|
+
clm.postStep(`✅ Node ID found in ${type.toUpperCase()} seed list.`);
|
|
46
46
|
configStore.setProjectFlag('seedListChecked', true);
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
@@ -103,7 +103,8 @@ export const checkProject = {
|
|
|
103
103
|
// spinner.color = 'green';
|
|
104
104
|
// }
|
|
105
105
|
// else {
|
|
106
|
-
clm.preStep('
|
|
106
|
+
clm.preStep('Tessellation and dependencies need to be installed. This may take a few minutes...');
|
|
107
|
+
await promptHelper.doYouWishToContinue();
|
|
107
108
|
// }
|
|
108
109
|
// const node = await clusterService.getClusterNodeInfo();
|
|
109
110
|
// const NODE_URL = `http://${node.host}:${node.publicPort}`;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class Clean extends Command {
|
|
3
|
+
static args: {
|
|
4
|
+
layer: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static description: string;
|
|
7
|
+
static examples: string[];
|
|
8
|
+
static flags: {
|
|
9
|
+
all: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
data: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
logs: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
2
|
+
import { clm } from "../clm.js";
|
|
3
|
+
import { configStore } from "../config-store.js";
|
|
4
|
+
import { projectHelper } from "../helpers/project-helper.js";
|
|
5
|
+
import { promptHelper } from "../helpers/prompt-helper.js";
|
|
6
|
+
import { dockerService } from "../services/docker-service.js";
|
|
7
|
+
import { shellService } from "../services/shell-service.js";
|
|
8
|
+
export default class Clean extends Command {
|
|
9
|
+
static args = {
|
|
10
|
+
layer: Args.string({ description: 'network layer to clean. e.g. gl0', required: true }),
|
|
11
|
+
};
|
|
12
|
+
static description = 'Remove data and/or logs from a validator node';
|
|
13
|
+
static examples = [
|
|
14
|
+
'<%= config.bin %> <%= command.id %>',
|
|
15
|
+
];
|
|
16
|
+
static flags = {
|
|
17
|
+
all: Flags.boolean({ char: 'a', description: 'remove all data and logs' }),
|
|
18
|
+
data: Flags.boolean({ char: 'd', description: 'remove data' }),
|
|
19
|
+
logs: Flags.boolean({ char: 'l', description: 'remove logs' })
|
|
20
|
+
};
|
|
21
|
+
async run() {
|
|
22
|
+
const { args, flags } = await this.parse(Clean);
|
|
23
|
+
const { layersToRun } = configStore.getProjectInfo();
|
|
24
|
+
if (!layersToRun.includes(args.layer)) {
|
|
25
|
+
this.error(`Invalid layer: ${args.layer}. Available layers: ${layersToRun.join(',')}`);
|
|
26
|
+
}
|
|
27
|
+
const deleteLogs = flags.logs || flags.all;
|
|
28
|
+
const deleteData = flags.data || flags.all;
|
|
29
|
+
if (!deleteLogs && !deleteData) {
|
|
30
|
+
this.error('At least one of --data or --logs must be specified.');
|
|
31
|
+
}
|
|
32
|
+
if (await dockerService.isRunning()) {
|
|
33
|
+
clm.preStep('The validator node must be stopped first.');
|
|
34
|
+
await promptHelper.doYouWishToContinue();
|
|
35
|
+
await dockerService.dockerDown();
|
|
36
|
+
}
|
|
37
|
+
if (deleteData) {
|
|
38
|
+
await shellService.runProjectCommand(`sudo rm -rf ${args.layer}/data`);
|
|
39
|
+
projectHelper.prepareDataFolder();
|
|
40
|
+
}
|
|
41
|
+
if (deleteLogs) {
|
|
42
|
+
await shellService.runProjectCommand(`sudo rm -rf ${args.layer}/logs`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
package/dist/commands/restart.js
CHANGED
|
@@ -36,6 +36,9 @@ export default class Restart extends BaseCommand {
|
|
|
36
36
|
// eslint-disable-next-line no-await-in-loop
|
|
37
37
|
await this.restart();
|
|
38
38
|
}
|
|
39
|
+
else {
|
|
40
|
+
serviceLog.log(' ' + project + ' version is the same. ');
|
|
41
|
+
}
|
|
39
42
|
}
|
|
40
43
|
configStore.setActiveProject(project);
|
|
41
44
|
return;
|
|
@@ -46,7 +49,7 @@ export default class Restart extends BaseCommand {
|
|
|
46
49
|
const activeProjects = configStore.getRunningProjects();
|
|
47
50
|
// serviceLog.log(` Active projects: ${activeProjects.join(', ')}...`);
|
|
48
51
|
for (const project of activeProjects) {
|
|
49
|
-
serviceLog.log(' ' + project + ' is
|
|
52
|
+
serviceLog.log(' ' + project + ' is being auto started...');
|
|
50
53
|
configStore.setActiveProject(project);
|
|
51
54
|
// eslint-disable-next-line no-await-in-loop
|
|
52
55
|
await this.restart();
|
|
@@ -75,8 +78,10 @@ export default class Restart extends BaseCommand {
|
|
|
75
78
|
// const pAll = layersToRun.map(l => nodeService.getNodeInfo(l));
|
|
76
79
|
// const info = await Promise.all(pAll);
|
|
77
80
|
// const isRunning = info.some(n => n.state !== 'Unavailable');
|
|
78
|
-
if (configStore.isRestarting())
|
|
81
|
+
if (configStore.isRestarting()) {
|
|
82
|
+
serviceLog.log('Restart already ACTIVE');
|
|
79
83
|
return;
|
|
84
|
+
}
|
|
80
85
|
configStore.setIsRestarting(true);
|
|
81
86
|
try {
|
|
82
87
|
if (await dockerService.isRunning()) {
|
|
@@ -89,7 +94,7 @@ export default class Restart extends BaseCommand {
|
|
|
89
94
|
clm.preStep('Checking for a new version...');
|
|
90
95
|
await checkProject.runUpgrade();
|
|
91
96
|
clm.preStep('Starting the node...');
|
|
92
|
-
await dockerService.
|
|
97
|
+
await dockerService.dockerRestartAll();
|
|
93
98
|
}
|
|
94
99
|
finally {
|
|
95
100
|
configStore.setIsRestarting(false);
|
|
@@ -2,5 +2,8 @@ import { Command } from '@oclif/core';
|
|
|
2
2
|
export default class Shutdown extends Command {
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
layer: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
};
|
|
5
8
|
run(): Promise<void>;
|
|
6
9
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Command } from '@oclif/core';
|
|
1
|
+
import { Command, Flags } from '@oclif/core';
|
|
2
2
|
import { configStore } from "../config-store.js";
|
|
3
3
|
import { configHelper } from "../helpers/config-helper.js";
|
|
4
4
|
import { dockerService } from "../services/docker-service.js";
|
|
@@ -8,11 +8,26 @@ export default class Shutdown extends Command {
|
|
|
8
8
|
static examples = [
|
|
9
9
|
'<%= config.bin %> <%= command.id %>',
|
|
10
10
|
];
|
|
11
|
+
static flags = {
|
|
12
|
+
layer: Flags.string({ char: 'l', description: 'specify a layer to shutdown. e.g. gl0' })
|
|
13
|
+
};
|
|
11
14
|
async run() {
|
|
12
15
|
configHelper.assertProject('No project found. ');
|
|
16
|
+
const { flags } = await this.parse(Shutdown);
|
|
13
17
|
const { layersToRun } = configStore.getProjectInfo();
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
const layer = flags.layer;
|
|
19
|
+
if (layer) {
|
|
20
|
+
if (!layersToRun.includes(layer)) {
|
|
21
|
+
this.error(`Invalid layer: ${layer}. Available layers: ${layersToRun.join(',')}`);
|
|
22
|
+
}
|
|
23
|
+
await nodeService.leaveCluster(layer);
|
|
24
|
+
await nodeService.pollForLayersState([], 'Offline');
|
|
25
|
+
await dockerService.dockerDown([layer]);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
await nodeService.leaveClusterAllLayers();
|
|
29
|
+
await nodeService.pollForLayersState(layersToRun, 'Offline');
|
|
30
|
+
await dockerService.dockerDown();
|
|
31
|
+
}
|
|
17
32
|
}
|
|
18
33
|
}
|
|
@@ -65,11 +65,7 @@ export const projectHelper = {
|
|
|
65
65
|
await this.installEmbedded('hypergraph');
|
|
66
66
|
const { projectDir } = configStore.getProjectInfo();
|
|
67
67
|
const { platform } = configStore.getSystemInfo();
|
|
68
|
-
|
|
69
|
-
const gl0DataDir = path.join(projectDir, 'gl0', 'data');
|
|
70
|
-
fs.mkdirSync(path.join(gl0DataDir, 'incremental_snapshot'), { recursive: true });
|
|
71
|
-
fs.mkdirSync(path.join(gl0DataDir, 'snapshot_info'));
|
|
72
|
-
fs.mkdirSync(path.join(gl0DataDir, 'tmp'));
|
|
68
|
+
this.prepareDataFolder();
|
|
73
69
|
if (platform === 'linux') {
|
|
74
70
|
const layerDir = path.join(projectDir, 'gl0');
|
|
75
71
|
// set permission for group "docker" on the layer folder and any subfolders created later
|
|
@@ -91,6 +87,16 @@ export const projectHelper = {
|
|
|
91
87
|
clm.debug(`Installing project from ${projectFolder} to ${projectDir}`);
|
|
92
88
|
fs.cpSync(projectFolder, projectDir, { recursive: true });
|
|
93
89
|
},
|
|
90
|
+
prepareDataFolder() {
|
|
91
|
+
const { projectDir } = configStore.getProjectInfo();
|
|
92
|
+
// Create gl0 folder for the fast-forward feature before Docker does
|
|
93
|
+
const gl0DataDir = path.join(projectDir, 'gl0', 'data');
|
|
94
|
+
if (!fs.existsSync(gl0DataDir)) {
|
|
95
|
+
fs.mkdirSync(path.join(gl0DataDir, 'incremental_snapshot'), { recursive: true });
|
|
96
|
+
fs.mkdirSync(path.join(gl0DataDir, 'snapshot_info'));
|
|
97
|
+
fs.mkdirSync(path.join(gl0DataDir, 'tmp'));
|
|
98
|
+
}
|
|
99
|
+
},
|
|
94
100
|
async selectProject() {
|
|
95
101
|
// prompt user to install hypergraph or metagraph
|
|
96
102
|
const networkType = await select({
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
+
import os from "node:os";
|
|
1
2
|
class CellFormatter {
|
|
2
3
|
formatCpu(value) {
|
|
3
4
|
if (value === '-')
|
|
4
5
|
return value;
|
|
5
|
-
const
|
|
6
|
+
const cores = os.cpus().length;
|
|
7
|
+
const num = Number.parseFloat(value) / cores;
|
|
8
|
+
value = num.toFixed(1) + '%';
|
|
6
9
|
if (num === 0)
|
|
7
10
|
return value;
|
|
8
|
-
if (num <
|
|
9
|
-
return this.style(value
|
|
10
|
-
if (num <
|
|
11
|
-
return this.style(value
|
|
12
|
-
return this.style(value
|
|
11
|
+
if (num < 40)
|
|
12
|
+
return this.style(value, "green");
|
|
13
|
+
if (num < 85)
|
|
14
|
+
return this.style(value, "yellow", "bold");
|
|
15
|
+
return this.style(value, "bgRed", "bold");
|
|
13
16
|
}
|
|
14
17
|
formatDistance(value) {
|
|
15
18
|
if (value === '-')
|
|
@@ -29,12 +32,12 @@ class CellFormatter {
|
|
|
29
32
|
formatMem(value) {
|
|
30
33
|
if (value === '-')
|
|
31
34
|
return value;
|
|
32
|
-
const num = Number.parseInt(value
|
|
35
|
+
const num = Number.parseInt(value, 10);
|
|
33
36
|
if (num === 0)
|
|
34
37
|
return value;
|
|
35
|
-
if (num <
|
|
38
|
+
if (num < 86)
|
|
36
39
|
return this.style(value.toString(), "green");
|
|
37
|
-
if (num <
|
|
40
|
+
if (num < 99)
|
|
38
41
|
return this.style(value.toString(), "yellow", "bold");
|
|
39
42
|
return this.style(value.toString(), "red", "bold");
|
|
40
43
|
}
|
|
@@ -57,6 +60,8 @@ class CellFormatter {
|
|
|
57
60
|
return this.style(value, "white");
|
|
58
61
|
}
|
|
59
62
|
formatUpTIme(startTime) {
|
|
63
|
+
if (!startTime)
|
|
64
|
+
return '-';
|
|
60
65
|
const formattedTime = formatTime(Date.now() - Number(startTime), true);
|
|
61
66
|
return formattedTime ?? '-';
|
|
62
67
|
}
|
|
@@ -68,6 +68,9 @@ export const clusterService = {
|
|
|
68
68
|
const { CL_L0_PEER_HTTP_HOST } = configStore.getEnvNetworkInfo(type);
|
|
69
69
|
clm.debug(`http://${CL_L0_PEER_HTTP_HOST}:${CL_PUBLIC_HTTP_PORT}/${path}`);
|
|
70
70
|
return fetch(`http://${CL_L0_PEER_HTTP_HOST}:${CL_PUBLIC_HTTP_PORT}/${path}`)
|
|
71
|
-
.then(res => res.json())
|
|
71
|
+
.then(res => res.json())
|
|
72
|
+
.catch(() => {
|
|
73
|
+
throw new Error(`Unable to connect to source node at http://${CL_L0_PEER_HTTP_HOST}:${CL_PUBLIC_HTTP_PORT}/${path}`);
|
|
74
|
+
});
|
|
72
75
|
}
|
|
73
76
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { TessellationLayer } from "../types.js";
|
|
2
2
|
export declare const dockerService: {
|
|
3
3
|
dockerBuild(): Promise<void>;
|
|
4
|
-
dockerDown(): Promise<void>;
|
|
4
|
+
dockerDown(layers?: TessellationLayer[]): Promise<void>;
|
|
5
5
|
dockerRestart(layer: TessellationLayer): Promise<void>;
|
|
6
|
+
dockerRestartAll(): Promise<void>;
|
|
6
7
|
dockerStartLayers(layers: TessellationLayer[]): Promise<void>;
|
|
7
8
|
dockerUp(): Promise<void>;
|
|
8
9
|
isRunning(): Promise<boolean>;
|
|
@@ -19,16 +19,23 @@ export const dockerService = {
|
|
|
19
19
|
if (silent) {
|
|
20
20
|
spinner.stop();
|
|
21
21
|
}
|
|
22
|
-
clm.postStep('Node container built.');
|
|
22
|
+
clm.postStep('✅ Node container built.');
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
|
-
async dockerDown() {
|
|
26
|
-
await run('down');
|
|
25
|
+
async dockerDown(layers) {
|
|
26
|
+
await run('down', layers);
|
|
27
27
|
configStore.setProjectStatusToRunning(false);
|
|
28
28
|
},
|
|
29
29
|
async dockerRestart(layer) {
|
|
30
30
|
await run('restart', [layer]);
|
|
31
31
|
},
|
|
32
|
+
async dockerRestartAll() {
|
|
33
|
+
if (await this.isRunning()) {
|
|
34
|
+
await this.dockerDown();
|
|
35
|
+
}
|
|
36
|
+
await run('up -d');
|
|
37
|
+
configStore.setProjectStatusToRunning(true);
|
|
38
|
+
},
|
|
32
39
|
async dockerStartLayers(layers) {
|
|
33
40
|
await run('up -d', layers);
|
|
34
41
|
},
|
|
@@ -6,6 +6,7 @@ import path from "node:path";
|
|
|
6
6
|
import { clm } from "../clm.js";
|
|
7
7
|
import { configStore } from "../config-store.js";
|
|
8
8
|
import { promptHelper } from "../helpers/prompt-helper.js";
|
|
9
|
+
import { shellService } from "./shell-service.js";
|
|
9
10
|
const CHUNK_SIZE = 20_000;
|
|
10
11
|
export class FastforwardService {
|
|
11
12
|
dataDir;
|
|
@@ -51,7 +52,7 @@ export class FastforwardService {
|
|
|
51
52
|
clm.debug('Saving compressedSnapshotIncremental to: ' + this.tmpDir);
|
|
52
53
|
fs.writeFileSync(path.join(this.tmpDir, ordinal.toString() + '.c'), compressedSnapshotIncremental);
|
|
53
54
|
await this.saveSnapshotFiles(ordinal.toString(), hash);
|
|
54
|
-
clm.postStep(
|
|
55
|
+
clm.postStep(`✅ Fastforward to snapshot ${chalk.bold(ordinal)} completed.`);
|
|
55
56
|
}
|
|
56
57
|
async fetchLatestSnapshot() {
|
|
57
58
|
const url = `${this.lbUrl}/global-snapshots/latest/combined`;
|
|
@@ -92,8 +93,18 @@ export class FastforwardService {
|
|
|
92
93
|
const incrementalSnapshotDir = path.join(this.dataDir, 'incremental_snapshot');
|
|
93
94
|
const hashDir = path.join(incrementalSnapshotDir, 'hash', hashSubdir);
|
|
94
95
|
const ordinalDir = path.join(incrementalSnapshotDir, 'ordinal', ordinalRounded.toString());
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
try {
|
|
97
|
+
fs.mkdirSync(hashDir, { recursive: true });
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
await shellService.runCommand(`sudo mkdir -p ${hashDir}`);
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
fs.mkdirSync(ordinalDir, { recursive: true });
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
await shellService.runCommand(`sudo mkdir -p ${ordinalDir}`);
|
|
107
|
+
}
|
|
97
108
|
const destOrdinalFile = path.join(ordinalDir, ordinal);
|
|
98
109
|
if (fs.existsSync(destOrdinalFile)) {
|
|
99
110
|
clm.warn(`Snapshot ${destOrdinalFile} already exists. Skipping...`);
|
package/install-dependencies.sh
CHANGED
|
@@ -29,53 +29,6 @@ check_acl() {
|
|
|
29
29
|
fi
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
# Check and install curl
|
|
33
|
-
check_curl() {
|
|
34
|
-
# echo "Checking for curl..."
|
|
35
|
-
if command -v curl >/dev/null 2>&1; then
|
|
36
|
-
echo "✅ curl is already installed."
|
|
37
|
-
return 0
|
|
38
|
-
fi
|
|
39
|
-
|
|
40
|
-
echo "⚠️ curl not found. Will attempt to install curl."
|
|
41
|
-
|
|
42
|
-
case "$(uname)" in
|
|
43
|
-
Linux)
|
|
44
|
-
if command -v apt >/dev/null 2>&1; then
|
|
45
|
-
echo "Installing curl using apt..."
|
|
46
|
-
sudo apt update
|
|
47
|
-
sudo apt install -y curl
|
|
48
|
-
elif command -v yum >/dev/null 2>&1; then
|
|
49
|
-
echo "Installing curl using yum..."
|
|
50
|
-
sudo yum install -y curl
|
|
51
|
-
else
|
|
52
|
-
echo "⚠️ Unsupported Linux distribution. Please install curl manually."
|
|
53
|
-
return 1
|
|
54
|
-
fi
|
|
55
|
-
;;
|
|
56
|
-
Darwin)
|
|
57
|
-
if command -v brew >/dev/null 2>&1; then
|
|
58
|
-
echo "Installing curl using Homebrew..."
|
|
59
|
-
brew install curl
|
|
60
|
-
else
|
|
61
|
-
echo "⚠️ Homebrew not found. Please install curl manually."
|
|
62
|
-
return 1
|
|
63
|
-
fi
|
|
64
|
-
;;
|
|
65
|
-
MINGW*|MSYS*|CYGWIN*)
|
|
66
|
-
echo "On Windows, please install curl manually."
|
|
67
|
-
return 1
|
|
68
|
-
;;
|
|
69
|
-
*)
|
|
70
|
-
echo "⚠️ Unsupported OS: $(uname). Please install curl manually."
|
|
71
|
-
return 1
|
|
72
|
-
;;
|
|
73
|
-
esac
|
|
74
|
-
|
|
75
|
-
echo "✅ curl installation complete."
|
|
76
|
-
return 0
|
|
77
|
-
}
|
|
78
|
-
|
|
79
32
|
# Check and install Docker Engine
|
|
80
33
|
check_docker() {
|
|
81
34
|
# echo "Checking for Docker..."
|
|
@@ -115,5 +68,4 @@ check_docker() {
|
|
|
115
68
|
# Run all checks
|
|
116
69
|
echo "🔍 Checking and installing required dependencies..."
|
|
117
70
|
check_acl
|
|
118
|
-
check_curl
|
|
119
71
|
check_docker
|
package/oclif.manifest.json
CHANGED
|
@@ -1,5 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"commands": {
|
|
3
|
+
"clean": {
|
|
4
|
+
"aliases": [],
|
|
5
|
+
"args": {
|
|
6
|
+
"layer": {
|
|
7
|
+
"description": "network layer to clean. e.g. gl0",
|
|
8
|
+
"name": "layer",
|
|
9
|
+
"required": true
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"description": "Remove data and/or logs from a validator node",
|
|
13
|
+
"examples": [
|
|
14
|
+
"<%= config.bin %> <%= command.id %>"
|
|
15
|
+
],
|
|
16
|
+
"flags": {
|
|
17
|
+
"all": {
|
|
18
|
+
"char": "a",
|
|
19
|
+
"description": "remove all data and logs",
|
|
20
|
+
"name": "all",
|
|
21
|
+
"allowNo": false,
|
|
22
|
+
"type": "boolean"
|
|
23
|
+
},
|
|
24
|
+
"data": {
|
|
25
|
+
"char": "d",
|
|
26
|
+
"description": "remove data",
|
|
27
|
+
"name": "data",
|
|
28
|
+
"allowNo": false,
|
|
29
|
+
"type": "boolean"
|
|
30
|
+
},
|
|
31
|
+
"logs": {
|
|
32
|
+
"char": "l",
|
|
33
|
+
"description": "remove logs",
|
|
34
|
+
"name": "logs",
|
|
35
|
+
"allowNo": false,
|
|
36
|
+
"type": "boolean"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"hasDynamicHelp": false,
|
|
40
|
+
"hiddenAliases": [],
|
|
41
|
+
"id": "clean",
|
|
42
|
+
"pluginAlias": "@constellation-network/node-pilot",
|
|
43
|
+
"pluginName": "@constellation-network/node-pilot",
|
|
44
|
+
"pluginType": "core",
|
|
45
|
+
"strict": true,
|
|
46
|
+
"enableJsonFlag": false,
|
|
47
|
+
"isESM": true,
|
|
48
|
+
"relativePath": [
|
|
49
|
+
"dist",
|
|
50
|
+
"commands",
|
|
51
|
+
"clean.js"
|
|
52
|
+
]
|
|
53
|
+
},
|
|
3
54
|
"config": {
|
|
4
55
|
"aliases": [],
|
|
5
56
|
"args": {},
|
|
@@ -151,7 +202,16 @@
|
|
|
151
202
|
"examples": [
|
|
152
203
|
"<%= config.bin %> <%= command.id %>"
|
|
153
204
|
],
|
|
154
|
-
"flags": {
|
|
205
|
+
"flags": {
|
|
206
|
+
"layer": {
|
|
207
|
+
"char": "l",
|
|
208
|
+
"description": "specify a layer to shutdown. e.g. gl0",
|
|
209
|
+
"name": "layer",
|
|
210
|
+
"hasDynamicHelp": false,
|
|
211
|
+
"multiple": false,
|
|
212
|
+
"type": "option"
|
|
213
|
+
}
|
|
214
|
+
},
|
|
155
215
|
"hasDynamicHelp": false,
|
|
156
216
|
"hiddenAliases": [],
|
|
157
217
|
"id": "shutdown",
|
|
@@ -276,5 +336,5 @@
|
|
|
276
336
|
]
|
|
277
337
|
}
|
|
278
338
|
},
|
|
279
|
-
"version": "0.0.
|
|
339
|
+
"version": "0.0.18"
|
|
280
340
|
}
|
package/package.json
CHANGED