@constellation-network/node-pilot 0.0.7 → 0.0.9

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.
Files changed (96) hide show
  1. package/README.md +26 -18
  2. package/bin/dev.js +1 -6
  3. package/bin/run.js +1 -1
  4. package/dist/base-command.d.ts +9 -0
  5. package/dist/base-command.js +20 -0
  6. package/dist/checks/check-dependencies.d.ts +1 -0
  7. package/dist/checks/check-dependencies.js +44 -0
  8. package/dist/checks/check-hardware.js +3 -3
  9. package/dist/checks/check-initial-setup.js +6 -4
  10. package/dist/checks/check-layers.js +7 -7
  11. package/dist/checks/check-network.d.ts +3 -0
  12. package/dist/checks/check-network.js +92 -9
  13. package/dist/checks/check-node-ctl.d.ts +5 -0
  14. package/dist/checks/check-node-ctl.js +88 -0
  15. package/dist/checks/check-project.js +33 -13
  16. package/dist/checks/check-wallet.d.ts +3 -0
  17. package/dist/checks/check-wallet.js +37 -0
  18. package/dist/clm.d.ts +1 -0
  19. package/dist/clm.js +4 -1
  20. package/dist/commands/config/get.d.ts +6 -0
  21. package/dist/commands/config/get.js +57 -11
  22. package/dist/commands/config/set.d.ts +0 -1
  23. package/dist/commands/config/set.js +13 -11
  24. package/dist/commands/config.js +17 -22
  25. package/dist/commands/info.js +3 -2
  26. package/dist/commands/logs.d.ts +2 -1
  27. package/dist/commands/logs.js +12 -6
  28. package/dist/commands/restart.d.ts +5 -2
  29. package/dist/commands/restart.js +25 -5
  30. package/dist/commands/shutdown.js +3 -3
  31. package/dist/commands/status.js +8 -0
  32. package/dist/commands/test.d.ts +1 -0
  33. package/dist/commands/test.js +35 -5
  34. package/dist/config-store.d.ts +50 -34
  35. package/dist/config-store.js +80 -32
  36. package/dist/helpers/config-helper.js +2 -2
  37. package/dist/helpers/env-templates.d.ts +4 -3
  38. package/dist/helpers/env-templates.js +28 -20
  39. package/dist/helpers/key-file-helper.d.ts +2 -0
  40. package/dist/helpers/key-file-helper.js +52 -17
  41. package/dist/helpers/project-helper.d.ts +3 -2
  42. package/dist/helpers/project-helper.js +86 -35
  43. package/dist/helpers/prompt-helper.d.ts +0 -2
  44. package/dist/helpers/prompt-helper.js +15 -66
  45. package/dist/services/archiver-service.d.ts +17 -0
  46. package/dist/services/archiver-service.js +104 -0
  47. package/dist/services/cluster-service.d.ts +10 -5
  48. package/dist/services/cluster-service.js +46 -36
  49. package/dist/services/docker-service.d.ts +9 -0
  50. package/dist/services/docker-service.js +53 -0
  51. package/dist/services/fastforward-service.js +12 -6
  52. package/dist/services/get-random-node.d.ts +2 -0
  53. package/dist/services/get-random-node.js +16 -0
  54. package/dist/{helpers/github-helper.d.ts → services/github-service.d.ts} +1 -1
  55. package/dist/{helpers/github-helper.js → services/github-service.js} +1 -1
  56. package/dist/services/node-service.d.ts +4 -0
  57. package/dist/services/node-service.js +29 -14
  58. package/dist/services/shell-service.d.ts +3 -1
  59. package/dist/services/shell-service.js +32 -6
  60. package/dist/test.d.ts +1 -0
  61. package/dist/test.js +50 -0
  62. package/dist/types.d.ts +42 -3
  63. package/install-dependencies.sh +98 -0
  64. package/oclif.manifest.json +31 -4
  65. package/package.json +12 -8
  66. package/projects/hypergraph/Dockerfile +27 -18
  67. package/projects/hypergraph/docker-compose.yml +14 -12
  68. package/projects/hypergraph/networks/integrationnet/gl0.env +4 -0
  69. package/projects/hypergraph/networks/integrationnet/gl1.env +4 -0
  70. package/projects/hypergraph/networks/integrationnet/network.env +8 -0
  71. package/projects/hypergraph/networks/integrationnet/source-nodes.env +9 -0
  72. package/projects/hypergraph/networks/mainnet/gl0.env +4 -0
  73. package/projects/hypergraph/networks/mainnet/gl1.env +4 -0
  74. package/projects/hypergraph/networks/mainnet/network.env +8 -0
  75. package/projects/hypergraph/networks/mainnet/source-nodes.env +9 -0
  76. package/projects/hypergraph/networks/testnet/gl0.env +5 -0
  77. package/projects/hypergraph/networks/testnet/gl1.env +4 -0
  78. package/projects/hypergraph/networks/testnet/network.env +8 -0
  79. package/projects/hypergraph/networks/testnet/source-nodes.env +9 -0
  80. package/projects/hypergraph/scripts/check-version.sh +31 -0
  81. package/projects/hypergraph/scripts/docker-build.sh +12 -1
  82. package/projects/hypergraph/scripts/install-dependencies.sh +3 -3
  83. package/projects/hypergraph/scripts/install.sh +34 -31
  84. package/projects/hypergraph/seedlist +268 -0
  85. package/scripts/autoheal.sh +8 -0
  86. package/scripts/services/io.constellationnetwork.nodepilot.Updater.plist +16 -0
  87. package/scripts/services/node-pilot-autoheal.service +14 -0
  88. package/scripts/services/node-pilot-updater-hypergraph.service +15 -0
  89. package/scripts/updater.sh +13 -0
  90. package/dist/helpers/docker-helper.d.ts +0 -7
  91. package/dist/helpers/docker-helper.js +0 -37
  92. package/projects/hypergraph/layers/gl1.env +0 -3
  93. package/projects/hypergraph/networks/integrationnet.env +0 -9
  94. package/projects/hypergraph/networks/mainnet.env +0 -8
  95. package/projects/hypergraph/networks/testnet.env +0 -9
  96. package/projects/scripts/docker-cleanup.sh +0 -64
package/README.md CHANGED
@@ -11,7 +11,7 @@ A new CLI generated with oclif
11
11
 
12
12
  <!-- toc -->
13
13
  * [Usage](#usage)
14
- * [The TLDR Version](#the-tldr-version)
14
+ * [The TL;DR Version](#the-tldr-version)
15
15
  * [Commands](#commands)
16
16
  <!-- tocstop -->
17
17
  # Usage
@@ -21,14 +21,14 @@ $ 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.7 darwin-arm64 node-v22.15.0
24
+ @constellation-network/node-pilot/0.0.9 darwin-arm64 node-v22.15.0
25
25
  $ cpilot --help [COMMAND]
26
26
  USAGE
27
27
  $ cpilot COMMAND
28
28
  ...
29
29
  ```
30
30
  <!-- usagestop -->
31
- # The TLDR Version
31
+ # The TL;DR Version
32
32
  #### Simply run cpilot with no commands.
33
33
  ```sh-session
34
34
  $ cpilot
@@ -42,8 +42,8 @@ If no command is entered, node-pilot will automatically perform a series of chec
42
42
  * [`cpilot config set NAME VALUE`](#cpilot-config-set-name-value)
43
43
  * [`cpilot help [COMMAND]`](#cpilot-help-command)
44
44
  * [`cpilot info`](#cpilot-info)
45
- * [`cpilot logs [LAYER]`](#cpilot-logs-layer)
46
- * [`cpilot restart`](#cpilot-restart)
45
+ * [`cpilot logs LAYER`](#cpilot-logs-layer)
46
+ * [`cpilot restart [LAYER]`](#cpilot-restart-layer)
47
47
  * [`cpilot shutdown`](#cpilot-shutdown)
48
48
  * [`cpilot status`](#cpilot-status)
49
49
 
@@ -62,7 +62,7 @@ EXAMPLES
62
62
  $ cpilot config
63
63
  ```
64
64
 
65
- _See code: [src/commands/config.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.7/src/commands/config.ts)_
65
+ _See code: [src/commands/config.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.9/src/commands/config.ts)_
66
66
 
67
67
  ## `cpilot config get [NAME]`
68
68
 
@@ -86,7 +86,7 @@ EXAMPLES
86
86
  $ cpilot config get gl0:CL_PUBLIC_HTTP_PORT
87
87
  ```
88
88
 
89
- _See code: [src/commands/config/get.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.7/src/commands/config/get.ts)_
89
+ _See code: [src/commands/config/get.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.9/src/commands/config/get.ts)_
90
90
 
91
91
  ## `cpilot config set NAME VALUE`
92
92
 
@@ -109,7 +109,7 @@ EXAMPLES
109
109
  $ cpilot config set gl0:CL_PUBLIC_HTTP_PORT 9000
110
110
  ```
111
111
 
112
- _See code: [src/commands/config/set.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.7/src/commands/config/set.ts)_
112
+ _See code: [src/commands/config/set.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.9/src/commands/config/set.ts)_
113
113
 
114
114
  ## `cpilot help [COMMAND]`
115
115
 
@@ -146,21 +146,22 @@ EXAMPLES
146
146
  $ cpilot info
147
147
  ```
148
148
 
149
- _See code: [src/commands/info.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.7/src/commands/info.ts)_
149
+ _See code: [src/commands/info.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.9/src/commands/info.ts)_
150
150
 
151
- ## `cpilot logs [LAYER]`
151
+ ## `cpilot logs LAYER`
152
152
 
153
153
  view validator node runtime logs
154
154
 
155
155
  ```
156
156
  USAGE
157
- $ cpilot logs [LAYER] [-f]
157
+ $ cpilot logs LAYER [-f] [-n <value>]
158
158
 
159
159
  ARGUMENTS
160
160
  LAYER network layer to view. e.g. gl0
161
161
 
162
162
  FLAGS
163
- -f, --follow continuously wait for additional data to be appended
163
+ -f, --follow continuously wait for additional data to be appended
164
+ -n, --numOfLines=<value> number of lines at the end of the log to display
164
165
 
165
166
  DESCRIPTION
166
167
  view validator node runtime logs
@@ -169,15 +170,22 @@ EXAMPLES
169
170
  $ cpilot logs
170
171
  ```
171
172
 
172
- _See code: [src/commands/logs.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.7/src/commands/logs.ts)_
173
+ _See code: [src/commands/logs.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.9/src/commands/logs.ts)_
173
174
 
174
- ## `cpilot restart`
175
+ ## `cpilot restart [LAYER]`
175
176
 
176
177
  A full shutdown of the validator node, then restart
177
178
 
178
179
  ```
179
180
  USAGE
180
- $ cpilot restart
181
+ $ cpilot restart [LAYER] [-p hypergraph]
182
+
183
+ ARGUMENTS
184
+ LAYER network layer to view. e.g. gl0
185
+
186
+ GLOBAL FLAGS
187
+ -p, --project=<option> Specify the project name to use
188
+ <options: hypergraph>
181
189
 
182
190
  DESCRIPTION
183
191
  A full shutdown of the validator node, then restart
@@ -186,7 +194,7 @@ EXAMPLES
186
194
  $ cpilot restart
187
195
  ```
188
196
 
189
- _See code: [src/commands/restart.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.7/src/commands/restart.ts)_
197
+ _See code: [src/commands/restart.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.9/src/commands/restart.ts)_
190
198
 
191
199
  ## `cpilot shutdown`
192
200
 
@@ -203,7 +211,7 @@ EXAMPLES
203
211
  $ cpilot shutdown
204
212
  ```
205
213
 
206
- _See code: [src/commands/shutdown.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.7/src/commands/shutdown.ts)_
214
+ _See code: [src/commands/shutdown.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.9/src/commands/shutdown.ts)_
207
215
 
208
216
  ## `cpilot status`
209
217
 
@@ -217,5 +225,5 @@ DESCRIPTION
217
225
  Display node status and configuration settings
218
226
  ```
219
227
 
220
- _See code: [src/commands/status.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.7/src/commands/status.ts)_
228
+ _See code: [src/commands/status.ts](https://github.com/Constellation-Labs/node-pilot/blob/v0.0.9/src/commands/status.ts)_
221
229
  <!-- commandsstop -->
package/bin/dev.js CHANGED
@@ -5,15 +5,10 @@ const skipDefaultCommand = {
5
5
  if (process.argv.length === 2) {
6
6
  process.argv[2] = 'status';
7
7
  }
8
- else if (process.argv.length > 2 && process.argv[2].startsWith('-') && !skipDefaultCommand[process.argv[2]]) {
8
+ else if (process.argv.length > 2 && process.argv.every(a => a.startsWith('-')) && !skipDefaultCommand[process.argv[2]]) {
9
9
  process.argv.splice(2, 0 , 'status');
10
10
  }
11
11
 
12
12
  import {execute} from '@oclif/core'
13
13
 
14
14
  await execute({development: true, dir: import.meta.url})
15
-
16
- // eslint-disable-next-line no-warning-comments
17
- // TODO
18
- // cpilot config set project pacaswap-metagraph
19
- // cpilot config --project pacaswap-metagraph
package/bin/run.js CHANGED
@@ -6,7 +6,7 @@ const skipDefaultCommand = {
6
6
  if (process.argv.length === 2) {
7
7
  process.argv[2] = 'status';
8
8
  }
9
- else if (process.argv.length > 2 && process.argv[2].startsWith('-') && !skipDefaultCommand[process.argv[2]]) {
9
+ else if (process.argv.length > 2 && process.argv.every(a => a.startsWith('-')) && !skipDefaultCommand[process.argv[2]]) {
10
10
  process.argv.splice(2, 0 , 'status');
11
11
  }
12
12
 
@@ -0,0 +1,9 @@
1
+ import { Command } from '@oclif/core';
2
+ export declare abstract class BaseCommand extends Command {
3
+ static baseFlags: {
4
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
5
+ };
6
+ checkProject(flags: {
7
+ project?: string;
8
+ }): void;
9
+ }
@@ -0,0 +1,20 @@
1
+ // src/base.ts
2
+ import { Command, Flags } from '@oclif/core';
3
+ import { configStore } from "./config-store.js";
4
+ import { configHelper } from "./helpers/config-helper.js";
5
+ export class BaseCommand extends Command {
6
+ static baseFlags = {
7
+ project: Flags.string({
8
+ char: 'p',
9
+ description: 'Specify the project name to use',
10
+ helpGroup: 'GLOBAL', // Optional: Group this flag in the help output
11
+ options: configStore.getProjects()
12
+ })
13
+ };
14
+ checkProject(flags) {
15
+ configHelper.assertProject('No project found. ');
16
+ if (flags.project) {
17
+ configStore.changeProjectStore(flags.project);
18
+ }
19
+ }
20
+ }
@@ -0,0 +1 @@
1
+ export declare const checkDependencies: () => Promise<void>;
@@ -0,0 +1,44 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import shell from "shelljs";
5
+ import { clm } from "../clm.js";
6
+ import { promptHelper } from "../helpers/prompt-helper.js";
7
+ import { shellService } from "../services/shell-service.js";
8
+ export const checkDependencies = async () => {
9
+ const dockerComposeVersion = await shellService.runCommand('docker compose version').catch(() => '');
10
+ clm.debug(`Docker compose version check: ${dockerComposeVersion || 'NOT_INSTALLED'}`);
11
+ if (dockerComposeVersion) {
12
+ return;
13
+ }
14
+ const isDockerV1Installed = await shellService.checkCommandAvailable('docker-compose');
15
+ if (isDockerV1Installed) {
16
+ clm.warn('You are using docker-compose v1. It needs to be uninstalled before upgrading to the latest version.');
17
+ // await promptHelper.doYouWishToContinue();
18
+ clm.step('\nRun the following command to uninstall docker-compose v1 and then run cpilot again:');
19
+ 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');
20
+ clm.echo('');
21
+ process.exit(0);
22
+ }
23
+ const isDockerInstalled = await shellService.checkCommandAvailable('docker');
24
+ if (!isDockerInstalled) {
25
+ const pilotDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), `../..`);
26
+ if (fs.existsSync(path.join(pilotDir, 'install-dependencies.sh'))) {
27
+ // Skip prompt if already informed user of the upgrade
28
+ if (!isDockerV1Installed) {
29
+ clm.step('Docker is required and needs to be installed.');
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, silent });
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
+ }
39
+ clm.postStep(`\nDocker has been installed. Please logout and login again to ensure the changes take effect. Then run cpilot again.`);
40
+ clm.echo('');
41
+ process.exit(0);
42
+ }
43
+ }
44
+ };
@@ -20,7 +20,7 @@ export const checkHardware = {
20
20
  const numOfCores = os.availableParallelism();
21
21
  let allPassed = true;
22
22
  const formatActual = (value, recommended, units = '') => {
23
- const passed = Number(value) >= recommended;
23
+ const passed = Math.ceil(Number(value)) >= recommended;
24
24
  allPassed = allPassed && passed;
25
25
  return passed ? chalk.greenBright(value + units) : chalk.redBright(value + units);
26
26
  };
@@ -32,8 +32,8 @@ export const checkHardware = {
32
32
  { headerColor: 'white', value: 'ACTUAL' },
33
33
  ];
34
34
  const rows = [
35
- [fc("Disk size"), fc("320 GB"), formatActual(totalSpaceGB, 320, " GB")],
36
- [fc("System memory"), fc("8 GB"), formatActual(totalMemoryGB, 8, " GB")],
35
+ [fc("Disk size"), fc("240 GB"), formatActual(totalSpaceGB, 240, " GB")],
36
+ [fc("System memory"), fc("16 GB"), formatActual(totalMemoryGB, 16, " GB")],
37
37
  [fc("CPU cores"), fc("8 cores"), formatActual(numOfCores, 8, " cores")],
38
38
  ];
39
39
  clm.echo(ttyTable(header, rows).render() + "\n");
@@ -1,15 +1,17 @@
1
1
  import chalk from "chalk";
2
2
  import { configStore } from "../config-store.js";
3
+ import { checkDependencies } from "./check-dependencies.js";
3
4
  import { checkHardware } from "./check-hardware.js";
4
5
  export const checkInitialSetup = {
5
6
  async firstTimeRun() {
6
7
  if (configStore.getSystemInfo() !== null) {
7
8
  return;
8
9
  }
9
- console.log(chalk.white("\n ****************************************"));
10
- console.log(" " + chalk.white("CONSTELLATION NETWORK") + " ");
11
- console.log(" " + chalk.white("NODE PILOT") + " ");
12
- console.log(chalk.white(" ****************************************"));
10
+ await checkDependencies();
11
+ console.log(chalk.whiteBright("\n ****************************************"));
12
+ console.log(" " + chalk.whiteBright("CONSTELLATION NETWORK") + " ");
13
+ console.log(" " + chalk.whiteBright("NODE PILOT") + " ");
14
+ console.log(chalk.whiteBright(" ****************************************"));
13
15
  await checkHardware.systemRequirements();
14
16
  },
15
17
  };
@@ -2,7 +2,7 @@ import { input } from "@inquirer/prompts";
2
2
  import chalk from "chalk";
3
3
  import { clm } from "../clm.js";
4
4
  import { configStore } from "../config-store.js";
5
- import { dockerHelper } from "../helpers/docker-helper.js";
5
+ import { dockerService } from "../services/docker-service.js";
6
6
  import { nodeService } from "../services/node-service.js";
7
7
  export const checkLayers = {
8
8
  async layersReadyToJoin() {
@@ -27,9 +27,9 @@ export const checkLayers = {
27
27
  }
28
28
  await input({ default: 'y', message: 'Would you like to start the validator(s)? (y/n): ' }).then(async (answer) => {
29
29
  if (answer.toLowerCase() === 'y') {
30
- await dockerHelper.dockerBuild();
30
+ await dockerService.dockerBuild();
31
31
  clm.preStep('Starting the node...');
32
- await dockerHelper.dockerUp();
32
+ await dockerService.dockerUp();
33
33
  await nodeService.pollForLayersState(layersToRun);
34
34
  }
35
35
  else {
@@ -40,11 +40,11 @@ export const checkLayers = {
40
40
  else if (notRunningLayers.length > 0) {
41
41
  const layersNotRunning = notRunningLayers.map(r => r.layer);
42
42
  clm.preStep('The following Validator Node layers are not running: ' + chalk.cyan(layersNotRunning.join(', ')));
43
- await input({ default: 'y', message: 'Would you like to restart the docker containers? (y/n): ' }).then(async (answer) => {
43
+ await input({ default: 'y', message: 'Would you like to start the validator(s)? (y/n): ' }).then(async (answer) => {
44
44
  if (answer.toLowerCase() === 'y') {
45
- clm.preStep('Restarting docker containers...');
46
- await dockerHelper.dockerUp();
47
- await nodeService.pollForLayersState(layersToRun);
45
+ clm.preStep('Starting docker containers...');
46
+ await dockerService.dockerStartLayers(layersNotRunning);
47
+ await nodeService.pollForLayersState(layersNotRunning);
48
48
  }
49
49
  else {
50
50
  clm.echo('Node not started.');
@@ -1,6 +1,9 @@
1
1
  export declare const checkNetwork: {
2
+ checkForExistingNodeIdInCluster(): Promise<void>;
3
+ checkSeedList(): Promise<void>;
2
4
  configureIpAddress(): Promise<void>;
3
5
  detectExternalIpAddress(): Promise<void>;
4
6
  enterIpAddressManually(): Promise<string>;
5
7
  fetchIPAddress(): Promise<string>;
8
+ isNetworkConnectable(): Promise<boolean>;
6
9
  };
@@ -1,14 +1,83 @@
1
1
  import { input, select } from "@inquirer/prompts";
2
2
  import chalk from "chalk";
3
+ import fs from "node:fs";
4
+ import path from "node:path";
3
5
  import { clm } from "../clm.js";
4
6
  import { configStore } from "../config-store.js";
7
+ import { clusterService } from "../services/cluster-service.js";
8
+ import { dockerService } from "../services/docker-service.js";
9
+ import { shellService } from "../services/shell-service.js";
5
10
  export const checkNetwork = {
11
+ async checkForExistingNodeIdInCluster() {
12
+ if (configStore.hasProjectFlag('duplicateNodeIdChecked')) {
13
+ return;
14
+ }
15
+ clm.preStep('Checking for existing Node ID in cluster...');
16
+ const { nodeId } = configStore.getProjectInfo();
17
+ const clusterInfo = await clusterService.getClusterInfo();
18
+ const found = clusterInfo.some(node => node.id === nodeId);
19
+ const isDockerRunning = await dockerService.isRunning();
20
+ if (!isDockerRunning && found) {
21
+ clm.warn('Node ID already exists in the cluster.');
22
+ clm.warn('You need to shutdown your node from a previous installation before continuing.');
23
+ clm.error(`Or to change the node ID, configure the Key File: use ${chalk.cyan('cpilot config')}, and select ${chalk.cyan('Key File')}`);
24
+ }
25
+ configStore.setProjectFlag('duplicateNodeIdChecked', true);
26
+ clm.postStep('No duplicate Node found.');
27
+ },
28
+ async checkSeedList() {
29
+ if (configStore.hasProjectFlag('seedListChecked')) {
30
+ return;
31
+ }
32
+ const { type } = configStore.getNetworkInfo();
33
+ clm.preStep(`Checking inclusion into seed list for ${type.toUpperCase()} network...`);
34
+ const { nodeId, projectDir } = configStore.getProjectInfo();
35
+ const seedListFile = path.resolve(projectDir, 'seedlist');
36
+ if (fs.existsSync(seedListFile)) {
37
+ const found = fs.readFileSync(seedListFile, 'utf8').includes(nodeId);
38
+ if (found) {
39
+ clm.postStep(`Node ID found in ${type.toUpperCase()} seed list.`);
40
+ configStore.setProjectFlag('seedListChecked', true);
41
+ return;
42
+ }
43
+ }
44
+ const printNotFoundError = () => {
45
+ clm.warn(`Node ID not found in ${type.toUpperCase()} seed list. You may try again later.`);
46
+ clm.warn(`To change the Key File: use ${chalk.cyan('cpilot config')}, and select ${chalk.cyan('Key File')}`);
47
+ clm.error(`To change the Network: use ${chalk.cyan('cpilot config')}, and select ${chalk.cyan('Network')}`);
48
+ };
49
+ if (type === 'mainnet') {
50
+ // the mainnet seed list comed from a network release
51
+ printNotFoundError();
52
+ }
53
+ else {
54
+ const url = `https://constellationlabs-dag.s3.us-west-1.amazonaws.com/${type}-seedlist`;
55
+ const seedList = await fetch(url)
56
+ .then(res => {
57
+ if (res.ok)
58
+ return res.text();
59
+ throw new Error(`Failed`);
60
+ })
61
+ .catch(() => {
62
+ clm.error(`Failed to fetch seed list from ${url}. Try again later.`);
63
+ return '';
64
+ });
65
+ if (seedList.includes(nodeId)) {
66
+ clm.postStep(`Node ID found in ${type.toUpperCase()} seed list.`);
67
+ fs.writeFileSync(seedListFile, seedList);
68
+ configStore.setProjectFlag('seedListChecked', true);
69
+ }
70
+ else {
71
+ printNotFoundError();
72
+ }
73
+ }
74
+ },
6
75
  async configureIpAddress() {
7
- const { CL_EXTERNAL_IP: currentIpAddress } = configStore.getEnvCommonInfo();
76
+ const { CL_EXTERNAL_IP: currentIpAddress } = configStore.getEnvInfo();
8
77
  const detectedIpAddress = await checkNetwork.fetchIPAddress().catch(() => '');
9
78
  if (!currentIpAddress && !detectedIpAddress) {
10
79
  const newIpAddress = await checkNetwork.enterIpAddressManually();
11
- configStore.setEnvCommonInfo({ CL_EXTERNAL_IP: newIpAddress });
80
+ configStore.setEnvInfo({ CL_EXTERNAL_IP: newIpAddress });
12
81
  return;
13
82
  }
14
83
  if (currentIpAddress) {
@@ -37,7 +106,7 @@ export const checkNetwork = {
37
106
  else if (answer === 'manual') {
38
107
  selectedIpAddress = await checkNetwork.enterIpAddressManually();
39
108
  }
40
- configStore.setEnvCommonInfo({ CL_EXTERNAL_IP: selectedIpAddress });
109
+ configStore.setEnvInfo({ CL_EXTERNAL_IP: selectedIpAddress });
41
110
  },
42
111
  async detectExternalIpAddress() {
43
112
  const externalIp = await this.fetchIPAddress()
@@ -46,7 +115,7 @@ export const checkNetwork = {
46
115
  return this.enterIpAddressManually();
47
116
  });
48
117
  clm.postStep("\nExternal IP address: " + chalk.cyan(externalIp) + "\n");
49
- configStore.setEnvCommonInfo({ CL_EXTERNAL_IP: externalIp });
118
+ configStore.setEnvInfo({ CL_EXTERNAL_IP: externalIp });
50
119
  },
51
120
  async enterIpAddressManually() {
52
121
  return input({
@@ -62,11 +131,25 @@ export const checkNetwork = {
62
131
  });
63
132
  },
64
133
  async fetchIPAddress() {
65
- return fetch('https://ifconfig.me/ip')
66
- .then(res => {
67
- if (res.ok)
68
- return res.text();
69
- throw new Error('Failed to fetch IP address');
134
+ return shellService.runCommandWithOutput('curl -4 https://ifconfig.me/ip');
135
+ },
136
+ async isNetworkConnectable() {
137
+ return clusterService.getClusterInfo()
138
+ .then(async (nodes) => {
139
+ const someAreReady = nodes.some(node => node.state === 'Ready');
140
+ if (!someAreReady) {
141
+ if (nodes.length > 0) {
142
+ clm.warn(`Found ${nodes.length} nodes in the cluster, but none are READY.`);
143
+ }
144
+ throw new Error(`Network is not connectable.`);
145
+ }
146
+ clm.debug(`Network is live. Found ${nodes.length} nodes in the cluster.`);
147
+ configStore.setClusterStats({ total: nodes.length });
148
+ return true;
149
+ })
150
+ .catch(() => {
151
+ clm.error(`Network is not in service. Please try again later.`);
152
+ return false;
70
153
  });
71
154
  }
72
155
  };
@@ -0,0 +1,5 @@
1
+ export declare const checkNodeCtl: {
2
+ check4Migration(): Promise<void>;
3
+ importKeyInfo(cnPath: string): Promise<void>;
4
+ promptForKeyFile(pilotKeyPath: string): Promise<void>;
5
+ };
@@ -0,0 +1,88 @@
1
+ import { input, password } from "@inquirer/prompts";
2
+ import chalk from "chalk";
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import yaml from "yaml";
6
+ import { clm } from "../clm.js";
7
+ import { configStore } from "../config-store.js";
8
+ import { keyFileHelper } from "../helpers/key-file-helper.js";
9
+ import { promptHelper } from "../helpers/prompt-helper.js";
10
+ import { dockerService } from "../services/docker-service.js";
11
+ import { nodeService } from "../services/node-service.js";
12
+ import { shellService } from "../services/shell-service.js";
13
+ export const checkNodeCtl = {
14
+ async check4Migration() {
15
+ if (configStore.hasProjectFlag('nodeCtlChecked')) {
16
+ return;
17
+ }
18
+ const { name } = configStore.getProjectInfo();
19
+ if (name.toLowerCase() !== 'hypergraph') {
20
+ configStore.setProjectFlag('nodeCtlChecked', true);
21
+ return;
22
+ }
23
+ const hasNodeAdminUser = fs.existsSync('/home/nodeadmin');
24
+ if (hasNodeAdminUser) {
25
+ const isDockerRunning = await dockerService.isRunning();
26
+ const isPortOpen = await nodeService.isPortInUse(9000);
27
+ clm.step(chalk.bold('NODECTL has been detected.'));
28
+ if (!isDockerRunning && isPortOpen) {
29
+ clm.error('Please shutdown any Nodes being managed by NODECTL before proceeding.');
30
+ }
31
+ const cnPath = path.resolve('/var/tessellation/nodectl/cn-config.yaml');
32
+ if (fs.existsSync(cnPath)) {
33
+ const answer = await input({
34
+ default: 'y',
35
+ message: 'Would you like to import key file from nodectl? (y/n): '
36
+ });
37
+ if (answer.toLowerCase() === 'y') {
38
+ await this.importKeyInfo(cnPath);
39
+ }
40
+ }
41
+ }
42
+ configStore.setProjectFlag('nodeCtlChecked', true);
43
+ },
44
+ async importKeyInfo(cnPath) {
45
+ clm.step('Importing key file from nodectl...');
46
+ try {
47
+ clm.preStep('Making a sudo call to read the nodectl config file...');
48
+ await shellService.runCommand(`sudo chmod +r ${cnPath}`);
49
+ const doc = yaml.parse(fs.readFileSync(cnPath, 'utf8'));
50
+ // console.log(JSON.stringify(doc,null,2));
51
+ // eslint-disable-next-line camelcase
52
+ const { key_location, key_name } = doc.nodectl.global_p12;
53
+ const nodeCtlKeyPath = path.resolve(key_location, key_name);
54
+ clm.debug(`Found key file path in nodectl config file: ${nodeCtlKeyPath}`);
55
+ clm.step('Key file found at ' + chalk.cyan(nodeCtlKeyPath));
56
+ clm.preStep('Importing key file...');
57
+ const { projectDir } = configStore.getProjectInfo();
58
+ const pilotKeyPath = path.join(projectDir, 'key.p12');
59
+ // copy file to home directory, change owner to current user, and make it readable by all
60
+ clm.preStep('Making a sudo call to copy the key file...');
61
+ await shellService.runCommand(`sudo cp ${nodeCtlKeyPath} ${pilotKeyPath}; sudo chown $(whoami) ${pilotKeyPath}; chmod +r ${pilotKeyPath}`);
62
+ await this.promptForKeyFile(pilotKeyPath);
63
+ }
64
+ catch (error) {
65
+ console.error(error);
66
+ clm.warn('Failed to import key information from nodectl. You will need to import it manually.');
67
+ await promptHelper.doYouWishToContinue();
68
+ }
69
+ },
70
+ async promptForKeyFile(pilotKeyPath) {
71
+ // prompt for password
72
+ const keyPassword = await password({ message: 'Enter the key file password:' });
73
+ const keyAlias = await input({ message: 'Enter the key file alias:' });
74
+ configStore.setEnvInfo({ CL_KEYALIAS: keyAlias, CL_KEYSTORE: pilotKeyPath, CL_PASSWORD: keyPassword });
75
+ try {
76
+ const dagAddress = await keyFileHelper.getAddress();
77
+ const nodeId = await keyFileHelper.getId();
78
+ configStore.setProjectInfo({ dagAddress, nodeId });
79
+ }
80
+ catch {
81
+ clm.warn('Failed to unlock the key file. Please check your key file information and try again.');
82
+ fs.rmSync(pilotKeyPath);
83
+ await this.promptForKeyFile(pilotKeyPath);
84
+ return;
85
+ }
86
+ clm.postStep('Key file imported successfully.\n');
87
+ }
88
+ };
@@ -1,11 +1,13 @@
1
1
  import { input, select } from "@inquirer/prompts";
2
+ import chalk from "chalk";
3
+ import ora from 'ora';
2
4
  import { clm } from "../clm.js";
3
5
  import { configStore } from "../config-store.js";
4
6
  import { configHelper } from "../helpers/config-helper.js";
5
- import { dockerHelper } from "../helpers/docker-helper.js";
7
+ import { projectHelper } from "../helpers/project-helper.js";
6
8
  import { promptHelper } from "../helpers/prompt-helper.js";
7
9
  import { clusterService } from "../services/cluster-service.js";
8
- import { nodeService } from "../services/node-service.js";
10
+ import { dockerService } from "../services/docker-service.js";
9
11
  import { shellService } from "../services/shell-service.js";
10
12
  import { checkNetwork } from "./check-network.js";
11
13
  export const checkProject = {
@@ -13,7 +15,7 @@ export const checkProject = {
13
15
  let updateNetworkType = false;
14
16
  let updateLayers = false;
15
17
  if (!configStore.hasProjects() || process.env.PILOT_ENV === 'test') {
16
- await promptHelper.selectProject();
18
+ await projectHelper.selectProject();
17
19
  await checkNetwork.configureIpAddress();
18
20
  updateNetworkType = true;
19
21
  updateLayers = true;
@@ -79,20 +81,38 @@ export const checkProject = {
79
81
  },
80
82
  async runInstall() {
81
83
  const nInfo = configStore.getNetworkInfo();
82
- const clusterVersion = await clusterService.getReleaseVersion();
84
+ const node = await clusterService.getClusterNodeInfo();
85
+ const NODE_URL = `http://${node.host}:${node.publicPort}`;
83
86
  let rInfo = await configHelper.getReleaseInfo();
84
- if (rInfo && rInfo.network === nInfo.type && rInfo.version === clusterVersion) {
85
- clm.postStep(`Network files are already installed for ${nInfo.type} version ${clusterVersion}`);
87
+ if (rInfo && rInfo.network === nInfo.type && rInfo.version === node.version) {
88
+ clm.postStep(`Network files are already installed for ${nInfo.type} version ${node.version}`);
86
89
  return false;
87
90
  }
88
- const nodeInfo = await nodeService.getNodeInfo('first');
89
- const isRunning = nodeInfo.state !== 'Unavailable';
91
+ const isRunning = await dockerService.isRunning();
90
92
  if (isRunning) {
91
- await dockerHelper.dockerDown();
93
+ await dockerService.dockerDown();
94
+ }
95
+ const silent = !process.env.DEBUG;
96
+ const spinner = ora('Running install script...');
97
+ if (silent) {
98
+ spinner.start();
99
+ spinner.color = 'green';
100
+ }
101
+ else {
102
+ clm.preStep('Running install script...');
103
+ }
104
+ // NOTE: may be different for metagraphs
105
+ await shellService.runProjectCommand(`scripts/install.sh ${nInfo.type}`, { NODE_URL }, silent)
106
+ .catch(() => {
107
+ spinner.stop();
108
+ if (silent) {
109
+ clm.error(`Install script failed. run: ${chalk.cyan("DEBUG=true cpilot")} for more details`);
110
+ }
111
+ clm.error('Install script failed. Please run cpilot again after correcting the error');
112
+ });
113
+ if (silent) {
114
+ spinner.stop();
92
115
  }
93
- clm.preStep('Running install script...');
94
- const silent = false; // !process.env.DEBUG;
95
- await shellService.runCommand(`scripts/install.sh ${nInfo.type}`, undefined, silent); // different for metagraphs
96
116
  rInfo = await configHelper.getReleaseInfo();
97
117
  configStore.setNetworkInfo({
98
118
  type: rInfo.network,
@@ -103,7 +123,7 @@ export const checkProject = {
103
123
  async runUpgrade() {
104
124
  const changed = await this.runInstall();
105
125
  if (changed) {
106
- await dockerHelper.dockerBuild();
126
+ await dockerService.dockerBuild();
107
127
  }
108
128
  }
109
129
  };
@@ -0,0 +1,3 @@
1
+ export declare const checkWallet: {
2
+ checkCollateral(): Promise<void>;
3
+ };