@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.
- package/README.md +26 -18
- package/bin/dev.js +1 -6
- package/bin/run.js +1 -1
- package/dist/base-command.d.ts +9 -0
- package/dist/base-command.js +20 -0
- package/dist/checks/check-dependencies.d.ts +1 -0
- package/dist/checks/check-dependencies.js +44 -0
- package/dist/checks/check-hardware.js +3 -3
- package/dist/checks/check-initial-setup.js +6 -4
- package/dist/checks/check-layers.js +7 -7
- package/dist/checks/check-network.d.ts +3 -0
- package/dist/checks/check-network.js +92 -9
- package/dist/checks/check-node-ctl.d.ts +5 -0
- package/dist/checks/check-node-ctl.js +88 -0
- package/dist/checks/check-project.js +33 -13
- package/dist/checks/check-wallet.d.ts +3 -0
- package/dist/checks/check-wallet.js +37 -0
- package/dist/clm.d.ts +1 -0
- package/dist/clm.js +4 -1
- package/dist/commands/config/get.d.ts +6 -0
- package/dist/commands/config/get.js +57 -11
- package/dist/commands/config/set.d.ts +0 -1
- package/dist/commands/config/set.js +13 -11
- package/dist/commands/config.js +17 -22
- package/dist/commands/info.js +3 -2
- package/dist/commands/logs.d.ts +2 -1
- package/dist/commands/logs.js +12 -6
- package/dist/commands/restart.d.ts +5 -2
- package/dist/commands/restart.js +25 -5
- package/dist/commands/shutdown.js +3 -3
- package/dist/commands/status.js +8 -0
- package/dist/commands/test.d.ts +1 -0
- package/dist/commands/test.js +35 -5
- package/dist/config-store.d.ts +50 -34
- package/dist/config-store.js +80 -32
- package/dist/helpers/config-helper.js +2 -2
- package/dist/helpers/env-templates.d.ts +4 -3
- package/dist/helpers/env-templates.js +28 -20
- package/dist/helpers/key-file-helper.d.ts +2 -0
- package/dist/helpers/key-file-helper.js +52 -17
- package/dist/helpers/project-helper.d.ts +3 -2
- package/dist/helpers/project-helper.js +86 -35
- package/dist/helpers/prompt-helper.d.ts +0 -2
- package/dist/helpers/prompt-helper.js +15 -66
- package/dist/services/archiver-service.d.ts +17 -0
- package/dist/services/archiver-service.js +104 -0
- package/dist/services/cluster-service.d.ts +10 -5
- package/dist/services/cluster-service.js +46 -36
- package/dist/services/docker-service.d.ts +9 -0
- package/dist/services/docker-service.js +53 -0
- package/dist/services/fastforward-service.js +12 -6
- package/dist/services/get-random-node.d.ts +2 -0
- package/dist/services/get-random-node.js +16 -0
- package/dist/{helpers/github-helper.d.ts → services/github-service.d.ts} +1 -1
- package/dist/{helpers/github-helper.js → services/github-service.js} +1 -1
- package/dist/services/node-service.d.ts +4 -0
- package/dist/services/node-service.js +29 -14
- package/dist/services/shell-service.d.ts +3 -1
- package/dist/services/shell-service.js +32 -6
- package/dist/test.d.ts +1 -0
- package/dist/test.js +50 -0
- package/dist/types.d.ts +42 -3
- package/install-dependencies.sh +98 -0
- package/oclif.manifest.json +31 -4
- package/package.json +12 -8
- package/projects/hypergraph/Dockerfile +27 -18
- package/projects/hypergraph/docker-compose.yml +14 -12
- package/projects/hypergraph/networks/integrationnet/gl0.env +4 -0
- package/projects/hypergraph/networks/integrationnet/gl1.env +4 -0
- package/projects/hypergraph/networks/integrationnet/network.env +8 -0
- package/projects/hypergraph/networks/integrationnet/source-nodes.env +9 -0
- package/projects/hypergraph/networks/mainnet/gl0.env +4 -0
- package/projects/hypergraph/networks/mainnet/gl1.env +4 -0
- package/projects/hypergraph/networks/mainnet/network.env +8 -0
- package/projects/hypergraph/networks/mainnet/source-nodes.env +9 -0
- package/projects/hypergraph/networks/testnet/gl0.env +5 -0
- package/projects/hypergraph/networks/testnet/gl1.env +4 -0
- package/projects/hypergraph/networks/testnet/network.env +8 -0
- package/projects/hypergraph/networks/testnet/source-nodes.env +9 -0
- package/projects/hypergraph/scripts/check-version.sh +31 -0
- package/projects/hypergraph/scripts/docker-build.sh +12 -1
- package/projects/hypergraph/scripts/install-dependencies.sh +3 -3
- package/projects/hypergraph/scripts/install.sh +34 -31
- package/projects/hypergraph/seedlist +268 -0
- package/scripts/autoheal.sh +8 -0
- package/scripts/services/io.constellationnetwork.nodepilot.Updater.plist +16 -0
- package/scripts/services/node-pilot-autoheal.service +14 -0
- package/scripts/services/node-pilot-updater-hypergraph.service +15 -0
- package/scripts/updater.sh +13 -0
- package/dist/helpers/docker-helper.d.ts +0 -7
- package/dist/helpers/docker-helper.js +0 -37
- package/projects/hypergraph/layers/gl1.env +0 -3
- package/projects/hypergraph/networks/integrationnet.env +0 -9
- package/projects/hypergraph/networks/mainnet.env +0 -8
- package/projects/hypergraph/networks/testnet.env +0 -9
- package/projects/scripts/docker-cleanup.sh +0 -64
@@ -0,0 +1,16 @@
|
|
1
|
+
export const getRandomNode = (nodes) => {
|
2
|
+
const randomNodeIndex = Math.floor(Math.random() * nodes.length);
|
3
|
+
const node = nodes[randomNodeIndex];
|
4
|
+
console.log(`Getting random node from ${nodes.length} nodes: ${node.host}:${node.publicPort}`);
|
5
|
+
return fetch(`http://${node.host}:${node.publicPort}/node/info`)
|
6
|
+
.then(async (res) => {
|
7
|
+
if (res.ok)
|
8
|
+
return res.json();
|
9
|
+
throw new Error(`Failed`);
|
10
|
+
})
|
11
|
+
.catch(() => {
|
12
|
+
if (nodes.length === 1)
|
13
|
+
throw new Error(`Failed to get random node. All nodes are offline.`);
|
14
|
+
return getRandomNode(nodes.toSpliced(randomNodeIndex, 1));
|
15
|
+
});
|
16
|
+
};
|
@@ -2,6 +2,10 @@ import { NodeInfo, TessellationLayer } from "../types.js";
|
|
2
2
|
export declare const nodeService: {
|
3
3
|
getNodeInfo(layer: "first" | TessellationLayer): Promise<NodeInfo>;
|
4
4
|
getSnapshotHash(ipAddr: string, ordinal: number): Promise<string>;
|
5
|
+
getStatusInfo(layer: TessellationLayer): Promise<TessellationLayer>;
|
6
|
+
isPortExposed(port: number): Promise<boolean>;
|
7
|
+
isPortInUse(port: number): Promise<boolean>;
|
8
|
+
isPortOpen(port: number): Promise<boolean>;
|
5
9
|
joinCluster(layer: TessellationLayer): Promise<void>;
|
6
10
|
leaveCluster(layer: TessellationLayer): Promise<boolean>;
|
7
11
|
leaveClusterAllLayers(): Promise<boolean>;
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import chalk from "chalk";
|
1
2
|
import { clm } from "../clm.js";
|
2
3
|
import { configStore } from "../config-store.js";
|
3
4
|
import { clusterService } from "./cluster-service.js";
|
@@ -26,6 +27,21 @@ export const nodeService = {
|
|
26
27
|
})
|
27
28
|
.catch(() => (''));
|
28
29
|
},
|
30
|
+
async getStatusInfo(layer) {
|
31
|
+
return layer;
|
32
|
+
},
|
33
|
+
async isPortExposed(port) {
|
34
|
+
const command = configStore.getSystemInfo().platform === 'linux' ? `ss -tuln | grep 0.0.0.0:${port}` : `netstat -an | grep '*.${port}'`;
|
35
|
+
return shellService.runCommandWithOutput(command).then(o => o.length > 0);
|
36
|
+
},
|
37
|
+
async isPortInUse(port) {
|
38
|
+
clm.preStep('Making a sudo call to check if a port is in use...');
|
39
|
+
return shellService.runCommandWithOutput(`sudo lsof -i :${port}`).then(Boolean).catch(() => false);
|
40
|
+
},
|
41
|
+
async isPortOpen(port) {
|
42
|
+
const command = configStore.getSystemInfo().platform === 'linux' ? `ss -tuln | grep :${port}` : `netstat -an | grep '.${port}'`;
|
43
|
+
return shellService.runCommandWithOutput(command).then(o => o.length > 0);
|
44
|
+
},
|
29
45
|
async joinCluster(layer) {
|
30
46
|
const { state } = await this.getNodeInfo(layer);
|
31
47
|
if (state !== "ReadyToJoin") {
|
@@ -33,7 +49,7 @@ export const nodeService = {
|
|
33
49
|
return;
|
34
50
|
}
|
35
51
|
const layerPortInfo = configStore.getLayerPortInfo(layer);
|
36
|
-
const peerInfo = await clusterService.
|
52
|
+
const peerInfo = await clusterService.getClusterNodeInfo(layer);
|
37
53
|
const nodeId = peerInfo.id;
|
38
54
|
const nodeIp = peerInfo.host;
|
39
55
|
const cliPort = layerPortInfo.CLI;
|
@@ -90,25 +106,24 @@ export const nodeService = {
|
|
90
106
|
for (let i = 1; i <= 60; i++) {
|
91
107
|
// eslint-disable-next-line no-await-in-loop
|
92
108
|
const { state } = await this.getNodeInfo(layer);
|
93
|
-
if (state === "Unavailable" || state === "ReadyToJoin")
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
clm.echo(` [${layer}] Attempt ${i}: Current state is "${state}"`);
|
100
|
-
}
|
101
|
-
else {
|
102
|
-
clm.echo(` [${layer}] Attempt ${i}: Current state is "${state}"`);
|
103
|
-
}
|
109
|
+
if (expectedState === 'Offline' && (state === "Unavailable" || state === "ReadyToJoin" || state === "SessionStarted"))
|
110
|
+
return true;
|
111
|
+
clm.echoRepeatLine(`[${layer}] ${chalk.bgGray.cyan('Attempt ' + i)}: Current state is "${state}" `);
|
112
|
+
// eslint-disable-next-line no-await-in-loop
|
113
|
+
await sleep(0.5);
|
114
|
+
clm.echoRepeatLine(`[${layer}] Attempt ${i}: Current state is "${state}" `);
|
104
115
|
if (state === expectedState) {
|
105
|
-
clm.postStep(
|
116
|
+
clm.postStep(`${layer} is ${expectedState}`);
|
106
117
|
return true;
|
107
118
|
}
|
119
|
+
if (state === "Unavailable" && i > 2) {
|
120
|
+
clm.warn(`${layer} is not connectable. Please try again later.`);
|
121
|
+
return false;
|
122
|
+
}
|
108
123
|
// eslint-disable-next-line no-await-in-loop
|
109
124
|
await sleep(5);
|
110
125
|
}
|
111
|
-
clm.warn(
|
126
|
+
clm.warn(`${layer} is not ${expectedState} after 5 minutes`);
|
112
127
|
return false;
|
113
128
|
}
|
114
129
|
};
|
@@ -2,8 +2,10 @@ import shell from "shelljs";
|
|
2
2
|
export declare const shellService: {
|
3
3
|
checkCommandAvailable(cmd: string): Promise<boolean>;
|
4
4
|
execDockerShell(serviceName: string, command: string): Promise<string>;
|
5
|
-
|
5
|
+
existsProjectScript(filePath: string): boolean;
|
6
6
|
resolvePath(keyPath: string): string;
|
7
7
|
runCommand(command: string, env?: object, silent?: boolean): Promise<shell.ShellString>;
|
8
8
|
runCommandWithOutput(command: string, env?: object): Promise<string>;
|
9
|
+
runProjectCommand(command: string, env?: object, silent?: boolean): Promise<string>;
|
10
|
+
runProjectCommandWithOutput(command: string, env?: object): Promise<string>;
|
9
11
|
};
|
@@ -6,9 +6,13 @@ import { clm } from "../clm.js";
|
|
6
6
|
import { configStore } from "../config-store.js";
|
7
7
|
export const shellService = {
|
8
8
|
async checkCommandAvailable(cmd) {
|
9
|
-
|
9
|
+
clm.debug(`Checking if command ${cmd} is available...`);
|
10
|
+
return this.runCommand(`command -v ${cmd}`)
|
10
11
|
.then(() => true)
|
11
|
-
.catch(() =>
|
12
|
+
.catch((error) => {
|
13
|
+
clm.debug(`Run command error: ${error}`);
|
14
|
+
return false;
|
15
|
+
});
|
12
16
|
},
|
13
17
|
async execDockerShell(serviceName, command) {
|
14
18
|
const { projectDir } = configStore.getProjectInfo();
|
@@ -19,7 +23,7 @@ export const shellService = {
|
|
19
23
|
}
|
20
24
|
return result.stdout;
|
21
25
|
},
|
22
|
-
|
26
|
+
existsProjectScript(filePath) {
|
23
27
|
const { projectDir } = configStore.getProjectInfo();
|
24
28
|
return fs.existsSync(path.join(projectDir, filePath));
|
25
29
|
},
|
@@ -33,13 +37,12 @@ export const shellService = {
|
|
33
37
|
return path.resolve(process.cwd(), keyPath);
|
34
38
|
},
|
35
39
|
async runCommand(command, env, silent = false) {
|
36
|
-
|
40
|
+
clm.debug(`START Running command: "${command}"`);
|
37
41
|
let nodeEnv;
|
38
42
|
if (env) {
|
39
43
|
nodeEnv = { ...env, ...process.env };
|
40
44
|
}
|
41
|
-
|
42
|
-
const result = shell.exec(command, { cwd: projectDir, env: nodeEnv, silent });
|
45
|
+
const result = shell.exec(command, { env: nodeEnv, silent });
|
43
46
|
clm.debug(`END ${command}. Exit code: ${result.code}`);
|
44
47
|
if (result.code > 0) {
|
45
48
|
throw new Error(`Failed running command: ${result.stderr}`);
|
@@ -49,5 +52,28 @@ export const shellService = {
|
|
49
52
|
async runCommandWithOutput(command, env) {
|
50
53
|
const result = await this.runCommand(command, env, true);
|
51
54
|
return result.stdout.trim();
|
55
|
+
},
|
56
|
+
async runProjectCommand(command, env, silent = false) {
|
57
|
+
const { projectDir } = configStore.getProjectInfo();
|
58
|
+
let nodeEnv;
|
59
|
+
if (env) {
|
60
|
+
nodeEnv = { ...env, ...process.env };
|
61
|
+
}
|
62
|
+
clm.debug(`START Running command: "${command}" in directory: "${projectDir}"`);
|
63
|
+
return new Promise((resolve, reject) => {
|
64
|
+
shell.exec(command, { async: true, cwd: projectDir, env: nodeEnv, silent }, (code, stdout, stderr) => {
|
65
|
+
if (code === 0) {
|
66
|
+
clm.debug(`END ${command}.`);
|
67
|
+
resolve(stdout);
|
68
|
+
}
|
69
|
+
else {
|
70
|
+
reject(new Error(`Command failed with code ${code}: ${stderr}`));
|
71
|
+
}
|
72
|
+
});
|
73
|
+
});
|
74
|
+
},
|
75
|
+
async runProjectCommandWithOutput(command, env) {
|
76
|
+
const stdout = await this.runProjectCommand(command, env, true);
|
77
|
+
return stdout.trim();
|
52
78
|
}
|
53
79
|
};
|
package/dist/test.d.ts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
package/dist/test.js
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
import * as crypto from "node:crypto";
|
2
|
+
// convert base64 to hex
|
3
|
+
const val = 'MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgeYLAOmnJ6FYQ3Uddr6lq5PEVgoiAdWIJ89x6fx3n8JihRANCAASNoaVq/vT5k5Akdzjv8ifybl9icGnMKRpeyZhOxTMnwxGjxANTuKLfUGWUOEngV6HaWGxgkXTU/VXRma+mu0hD';
|
4
|
+
// const val = 'MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgKy/2tKuoO5V0iXJmTlaWPl9PeDo8TO5ZD+JmD3pOlzihRANCAASffXYMsILTOYSM4pEuBiYO1RR/hfuO+k4WvnNup21HT7CGThWfRjIemS3QDMHncK0Shsy43nb6kD9Fo8DTKpI6';
|
5
|
+
const der = Buffer.from(val, 'base64').toString('hex');
|
6
|
+
console.log(der);
|
7
|
+
// convert DER to PEM
|
8
|
+
const ecKey = crypto.createPrivateKey({
|
9
|
+
encoding: "base64",
|
10
|
+
format: "der",
|
11
|
+
key: val,
|
12
|
+
type: "pkcs8",
|
13
|
+
});
|
14
|
+
console.log(ecKey.export({ 'format': 'jwk' }));
|
15
|
+
// Generate an RSA key pair
|
16
|
+
const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
|
17
|
+
modulusLength: 2048, // Recommended key size
|
18
|
+
privateKeyEncoding: {
|
19
|
+
format: 'der', // DER encoding for binary output
|
20
|
+
type: 'pkcs8' // PKCS#8 format
|
21
|
+
},
|
22
|
+
publicKeyEncoding: {
|
23
|
+
format: 'der',
|
24
|
+
type: 'spki' // SubjectPublicKeyInfo
|
25
|
+
}
|
26
|
+
});
|
27
|
+
// The 'privateKey' variable now holds a Buffer containing the PKCS#8 DER private key.
|
28
|
+
// To get the Base64 encoded string:
|
29
|
+
const privateKeyBase64 = privateKey.toString('base64');
|
30
|
+
console.log('PKCS#8 DER Private Key (Base64):');
|
31
|
+
console.log(privateKeyBase64);
|
32
|
+
// openssl pkcs8 -inform DER -in privatekey.der -outform PEM -out privatekey.pem
|
33
|
+
// openssl pkcs8 -inform DER -in privatekey.der -nocrypt -out privatekey.pem -traditional
|
34
|
+
async function createP256Pkcs8DerBase64PrivateKey() {
|
35
|
+
// Generate an ECDSA key pair with the P-256 named curve
|
36
|
+
const keyPair = await crypto.subtle.generateKey({
|
37
|
+
name: 'ECDSA',
|
38
|
+
namedCurve: 'P-256',
|
39
|
+
}, true, // extractable
|
40
|
+
['sign', 'verify']);
|
41
|
+
// Export the private key in PKCS#8 DER format
|
42
|
+
const privateKeyDerBuffer = await crypto.subtle.exportKey('pkcs8', // format
|
43
|
+
keyPair.privateKey);
|
44
|
+
console.log('PKCS#8 DER Private Key (DER Buffer): ' + Buffer.from(privateKeyDerBuffer).toString('hex'));
|
45
|
+
// Convert the DER buffer to a Base64 encoded string
|
46
|
+
const privateKeyBase64 = Buffer.from(privateKeyDerBuffer).toString('base64');
|
47
|
+
console.log('PKCS#8 DER Private Key (Base64):' + privateKeyBase64);
|
48
|
+
return privateKeyBase64;
|
49
|
+
}
|
50
|
+
await createP256Pkcs8DerBase64PrivateKey();
|
package/dist/types.d.ts
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
export type TessellationLayer = 'cl1' | 'dl1' | 'gl0' | 'gl1' | 'ml0';
|
2
2
|
export type NodeInfo = {
|
3
|
-
clusterSession: number;
|
3
|
+
clusterSession: number | string;
|
4
4
|
host: string;
|
5
5
|
id: string;
|
6
6
|
layer: TessellationLayer;
|
7
7
|
p2pPort: number;
|
8
|
-
publicPort: number;
|
9
|
-
session: number;
|
8
|
+
publicPort: number | string;
|
9
|
+
session: number | string;
|
10
10
|
state: string;
|
11
11
|
version: string;
|
12
12
|
};
|
@@ -20,3 +20,42 @@ export type ClusterInfo = {
|
|
20
20
|
session: string;
|
21
21
|
state: 'DownloadInProgress' | 'GenesisReady' | 'Initial' | 'Leaving' | 'LoadingGenesis' | 'Offline' | 'Ready' | 'ReadyToJoin' | 'SessionStarted' | 'StartingSession' | 'Unavailable' | 'WaitingForDownload';
|
22
22
|
};
|
23
|
+
export type ClusterConsensusInfo = {
|
24
|
+
key: number;
|
25
|
+
peers: {
|
26
|
+
clusterSession: string;
|
27
|
+
id: string;
|
28
|
+
ip: string;
|
29
|
+
p2pPort: number;
|
30
|
+
publicPort: number;
|
31
|
+
session: string;
|
32
|
+
state: 'Ready';
|
33
|
+
}[];
|
34
|
+
};
|
35
|
+
export type ClusterStats = {
|
36
|
+
ordinal: number;
|
37
|
+
ready: number;
|
38
|
+
startTime: string;
|
39
|
+
total: number;
|
40
|
+
};
|
41
|
+
export type NodeStatusInfo = {
|
42
|
+
clusterSession: string;
|
43
|
+
id: string;
|
44
|
+
inConsensus: boolean;
|
45
|
+
inNetwork: boolean;
|
46
|
+
ip: string;
|
47
|
+
session: string;
|
48
|
+
};
|
49
|
+
export type NodeDiagnosticInfo = {
|
50
|
+
collateral: number;
|
51
|
+
hasCollateral: boolean;
|
52
|
+
hasHealthyState: boolean;
|
53
|
+
hasLatestVersion: boolean;
|
54
|
+
hasOpenP2PPort: boolean;
|
55
|
+
hasOpenPublicPort: boolean;
|
56
|
+
inSeedList: boolean;
|
57
|
+
p2pPort: number;
|
58
|
+
publicPort: number;
|
59
|
+
state: string;
|
60
|
+
version: string;
|
61
|
+
};
|
@@ -0,0 +1,98 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
# Break on any error
|
4
|
+
set -e
|
5
|
+
|
6
|
+
# Check and install curl
|
7
|
+
check_curl() {
|
8
|
+
# echo "Checking for curl..."
|
9
|
+
if command -v curl >/dev/null 2>&1; then
|
10
|
+
echo "✅ curl is already installed."
|
11
|
+
return 0
|
12
|
+
fi
|
13
|
+
|
14
|
+
echo "⚠️ curl not found. Will attempt to install curl."
|
15
|
+
|
16
|
+
case "$(uname)" in
|
17
|
+
Linux)
|
18
|
+
if command -v apt >/dev/null 2>&1; then
|
19
|
+
echo "Installing curl using apt..."
|
20
|
+
sudo apt update
|
21
|
+
sudo apt install -y curl
|
22
|
+
elif command -v yum >/dev/null 2>&1; then
|
23
|
+
echo "Installing curl using yum..."
|
24
|
+
sudo yum install -y curl
|
25
|
+
else
|
26
|
+
echo "⚠️ Unsupported Linux distribution. Please install curl manually."
|
27
|
+
return 1
|
28
|
+
fi
|
29
|
+
;;
|
30
|
+
Darwin)
|
31
|
+
if command -v brew >/dev/null 2>&1; then
|
32
|
+
echo "Installing curl using Homebrew..."
|
33
|
+
brew install curl
|
34
|
+
else
|
35
|
+
echo "⚠️ Homebrew not found. Please install curl manually."
|
36
|
+
return 1
|
37
|
+
fi
|
38
|
+
;;
|
39
|
+
MINGW*|MSYS*|CYGWIN*)
|
40
|
+
echo "On Windows, please install curl manually."
|
41
|
+
return 1
|
42
|
+
;;
|
43
|
+
*)
|
44
|
+
echo "⚠️ Unsupported OS: $(uname). Please install curl manually."
|
45
|
+
return 1
|
46
|
+
;;
|
47
|
+
esac
|
48
|
+
|
49
|
+
echo "✅ curl installation complete."
|
50
|
+
return 0
|
51
|
+
}
|
52
|
+
|
53
|
+
# Check and install Docker Engine
|
54
|
+
check_docker() {
|
55
|
+
# echo "Checking for Docker..."
|
56
|
+
if command -v docker >/dev/null 2>&1; then
|
57
|
+
echo "✅ Docker is already installed."
|
58
|
+
return 0
|
59
|
+
fi
|
60
|
+
|
61
|
+
echo "⚠️ Docker not found. Will attempt to install Docker."
|
62
|
+
|
63
|
+
case "$(uname)" in
|
64
|
+
Linux)
|
65
|
+
if command -v apt >/dev/null 2>&1; then
|
66
|
+
echo "Installing Docker using script..."
|
67
|
+
curl -fsSL https://get.docker.com -o get-docker.sh
|
68
|
+
sudo sh ./get-docker.sh
|
69
|
+
sudo usermod -aG docker $USER
|
70
|
+
echo "Docker installed. You may need to log out and back in for group changes to take effect."
|
71
|
+
else
|
72
|
+
echo "⚠️ Unsupported Linux distribution. Please install Docker manually."
|
73
|
+
return 1
|
74
|
+
fi
|
75
|
+
;;
|
76
|
+
Darwin)
|
77
|
+
echo "Please install Docker Desktop manually from https://www.docker.com/products/docker-desktop"
|
78
|
+
return 1
|
79
|
+
;;
|
80
|
+
MINGW*|MSYS*|CYGWIN*)
|
81
|
+
echo "On Windows, please install Docker Desktop manually from https://www.docker.com/products/docker-desktop"
|
82
|
+
return 1
|
83
|
+
;;
|
84
|
+
*)
|
85
|
+
echo "⚠️ Unsupported OS: $(uname). Please install Docker manually."
|
86
|
+
return 1
|
87
|
+
;;
|
88
|
+
esac
|
89
|
+
|
90
|
+
echo "✅ Docker installation complete."
|
91
|
+
return 0
|
92
|
+
}
|
93
|
+
|
94
|
+
|
95
|
+
# Run all checks
|
96
|
+
echo "🔍 Checking and installing required dependencies..."
|
97
|
+
check_curl
|
98
|
+
check_docker
|
package/oclif.manifest.json
CHANGED
@@ -51,7 +51,8 @@
|
|
51
51
|
"args": {
|
52
52
|
"layer": {
|
53
53
|
"description": "network layer to view. e.g. gl0",
|
54
|
-
"name": "layer"
|
54
|
+
"name": "layer",
|
55
|
+
"required": true
|
55
56
|
}
|
56
57
|
},
|
57
58
|
"description": "view validator node runtime logs",
|
@@ -65,6 +66,14 @@
|
|
65
66
|
"name": "follow",
|
66
67
|
"allowNo": false,
|
67
68
|
"type": "boolean"
|
69
|
+
},
|
70
|
+
"numOfLines": {
|
71
|
+
"char": "n",
|
72
|
+
"description": "number of lines at the end of the log to display",
|
73
|
+
"name": "numOfLines",
|
74
|
+
"hasDynamicHelp": false,
|
75
|
+
"multiple": false,
|
76
|
+
"type": "option"
|
68
77
|
}
|
69
78
|
},
|
70
79
|
"hasDynamicHelp": false,
|
@@ -84,12 +93,30 @@
|
|
84
93
|
},
|
85
94
|
"restart": {
|
86
95
|
"aliases": [],
|
87
|
-
"args": {
|
96
|
+
"args": {
|
97
|
+
"layer": {
|
98
|
+
"description": "network layer to view. e.g. gl0",
|
99
|
+
"name": "layer"
|
100
|
+
}
|
101
|
+
},
|
88
102
|
"description": "A full shutdown of the validator node, then restart",
|
89
103
|
"examples": [
|
90
104
|
"<%= config.bin %> <%= command.id %>"
|
91
105
|
],
|
92
|
-
"flags": {
|
106
|
+
"flags": {
|
107
|
+
"project": {
|
108
|
+
"char": "p",
|
109
|
+
"description": "Specify the project name to use",
|
110
|
+
"helpGroup": "GLOBAL",
|
111
|
+
"name": "project",
|
112
|
+
"hasDynamicHelp": false,
|
113
|
+
"multiple": false,
|
114
|
+
"options": [
|
115
|
+
"hypergraph"
|
116
|
+
],
|
117
|
+
"type": "option"
|
118
|
+
}
|
119
|
+
},
|
93
120
|
"hasDynamicHelp": false,
|
94
121
|
"hiddenAliases": [],
|
95
122
|
"id": "restart",
|
@@ -237,5 +264,5 @@
|
|
237
264
|
]
|
238
265
|
}
|
239
266
|
},
|
240
|
-
"version": "0.0.
|
267
|
+
"version": "0.0.9"
|
241
268
|
}
|
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.0.9",
|
5
5
|
"author": "Frank Fox",
|
6
6
|
"bin": {
|
7
7
|
"cpilot": "bin/run.js"
|
@@ -38,8 +38,10 @@
|
|
38
38
|
"js-sha256": "^0.11.1",
|
39
39
|
"json-bigint-patch": "^0.0.8",
|
40
40
|
"node-localstorage": "^3.0.5",
|
41
|
+
"ora": "^8.2.0",
|
41
42
|
"shelljs": "^0.10.0",
|
42
|
-
"tty-table": "^4.2.3"
|
43
|
+
"tty-table": "^4.2.3",
|
44
|
+
"yaml": "^2.8.1"
|
43
45
|
},
|
44
46
|
"devDependencies": {
|
45
47
|
"@eslint/compat": "^1",
|
@@ -61,12 +63,14 @@
|
|
61
63
|
"typescript": "^5"
|
62
64
|
},
|
63
65
|
"files": [
|
64
|
-
"
|
65
|
-
"
|
66
|
-
"
|
67
|
-
"
|
68
|
-
"
|
69
|
-
"
|
66
|
+
"bin",
|
67
|
+
"dist",
|
68
|
+
"oclif.manifest.json",
|
69
|
+
"install-dependencies.sh",
|
70
|
+
"projects",
|
71
|
+
"scripts",
|
72
|
+
"README.md",
|
73
|
+
"LICENSE"
|
70
74
|
],
|
71
75
|
"homepage": "https://github.com/Constellation-Labs/node-pilot",
|
72
76
|
"keywords": [
|
@@ -5,23 +5,28 @@ RUN apt update && apt install -y openjdk-11-jre
|
|
5
5
|
RUN apt install -y curl jq wget
|
6
6
|
|
7
7
|
# Install necessary dependencies for adding NodeSource repository
|
8
|
-
|
9
|
-
#
|
10
|
-
## Import the NodeSource GPG key
|
11
|
-
#RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
12
|
-
#
|
13
|
-
## Add the NodeSource repository for Node.js 22
|
14
|
-
#ENV NODE_MAJOR=22
|
15
|
-
#RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
|
16
|
-
#
|
17
|
-
## Update package lists and install Node.js and npm
|
18
|
-
#RUN apt-get update && apt-get install -y nodejs
|
19
|
-
#
|
20
|
-
## Verify the installation
|
21
|
-
#RUN node -v
|
22
|
-
#RUN npm -v
|
8
|
+
RUN apt-get update && apt-get install -y gnupg ca-certificates
|
23
9
|
|
10
|
+
# Import the NodeSource GPG key
|
11
|
+
RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
24
12
|
|
13
|
+
# Add the NodeSource repository for Node.js 22
|
14
|
+
ENV NODE_MAJOR=22
|
15
|
+
RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
|
16
|
+
|
17
|
+
# Update package lists and install Node.js and npm
|
18
|
+
RUN apt-get update && apt-get install -y nodejs
|
19
|
+
|
20
|
+
# Verify the installation
|
21
|
+
RUN node -v
|
22
|
+
RUN npm -v
|
23
|
+
|
24
|
+
# Create a directory for global npm packages
|
25
|
+
RUN mkdir -p /home/node/.npm-global
|
26
|
+
ENV NPM_CONFIG_PREFIX=/home/node/.npm-global
|
27
|
+
ENV PATH=$PATH:/home/node/.npm-global/bin
|
28
|
+
|
29
|
+
# Add app JARS
|
25
30
|
RUN mkdir -p /app/jars
|
26
31
|
|
27
32
|
COPY dist/keytool.jar /app/jars/keytool.jar
|
@@ -30,10 +35,14 @@ COPY dist/wallet.jar /app/jars/wallet.jar
|
|
30
35
|
COPY dist/gl1.jar /app/jars/gl1.jar
|
31
36
|
COPY dist/gl0.jar /app/jars/gl0.jar
|
32
37
|
|
33
|
-
|
34
|
-
|
35
|
-
#
|
38
|
+
# Add health-check
|
39
|
+
#COPY ./health-check /health-check
|
40
|
+
#RUN chmod +x /health-check/bin/run.sh
|
41
|
+
#RUN chmod +x /health-check/bin/hydrate.sh
|
42
|
+
RUN npm install -g "@constellation-network/node-pilot-health-check"
|
36
43
|
|
44
|
+
# Add entrypoint
|
45
|
+
COPY ./entrypoint.sh /app/entrypoint.sh
|
37
46
|
RUN chmod +x /app/entrypoint.sh
|
38
47
|
|
39
48
|
WORKDIR /app
|
@@ -3,12 +3,16 @@ networks:
|
|
3
3
|
driver: bridge
|
4
4
|
|
5
5
|
services:
|
6
|
+
autoheal:
|
7
|
+
image: willfarrell/autoheal
|
8
|
+
volumes:
|
9
|
+
- /var/run/docker.sock:/var/run/docker.sock
|
6
10
|
gl0:
|
7
11
|
image: constellationnetwork/tessellation${CL_DOCKER_CORE_REPO:-}:${DOCKER_IMAGE_VERSION:-latest}
|
8
12
|
container_name: gl0
|
9
13
|
networks:
|
10
14
|
- tessellation-network
|
11
|
-
|
15
|
+
restart: unless-stopped
|
12
16
|
env_file:
|
13
17
|
- gl0.env
|
14
18
|
ports:
|
@@ -19,18 +23,19 @@ services:
|
|
19
23
|
- ./seedlist:/app/seedlist:ro
|
20
24
|
- ./app-data/gl0-logs:/app/logs
|
21
25
|
- ./app-data/gl0-data:/app/data
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
26
|
+
healthcheck:
|
27
|
+
test: ["CMD", "cpilotHC"]
|
28
|
+
interval: 15s
|
29
|
+
retries: 1
|
30
|
+
timeout: 15s
|
31
|
+
start_period: 30s
|
28
32
|
profiles: ["gl0"]
|
29
|
-
|
33
|
+
labels:
|
34
|
+
autoheal: "true"
|
30
35
|
gl1:
|
31
36
|
image: constellationnetwork/tessellation${CL_DOCKER_CORE_REPO:-}:${DOCKER_IMAGE_VERSION:-latest}
|
32
37
|
container_name: gl1
|
33
|
-
|
38
|
+
restart: unless-stopped
|
34
39
|
networks:
|
35
40
|
- tessellation-network
|
36
41
|
env_file:
|
@@ -40,10 +45,8 @@ services:
|
|
40
45
|
- "9011:9011" # P2P HTTP
|
41
46
|
volumes:
|
42
47
|
- ./key.p12:/app/key.p12:ro
|
43
|
-
- ./seedlist:/app/seedlist:ro
|
44
48
|
- ./app-data/gl1-logs:/app/logs
|
45
49
|
- ./app-data/gl1-data:/app/data
|
46
|
-
- ${CL_DOCKER_PRIORITY_SEEDLIST:-/dev/null}:/app/priority-seedlist:ro
|
47
50
|
# healthcheck:
|
48
51
|
# test: ["CMD", "/app/internal-health-check.sh"]
|
49
52
|
# interval: 3s
|
@@ -51,4 +54,3 @@ services:
|
|
51
54
|
# retries: 5
|
52
55
|
# start_period: 10s
|
53
56
|
profiles: ["gl1"]
|
54
|
-
# user: ${DOCKER_USER_ID:-}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
CL_APP_ENV=integrationnet
|
2
|
+
CL_COLLATERAL=0
|
3
|
+
CL_L0_PEER_HTTP_HOST=13.52.205.240
|
4
|
+
CL_L0_PEER_ID=e2f4496e5872682d7a55aa06e507a58e96b5d48a5286bfdff7ed780fa464d9e789b2760ecd840f4cb3ee6e1c1d81b2ee844c88dbebf149b1084b7313eb680714
|
5
|
+
CL_L0_PEER_HTTP_PORT=9000
|
6
|
+
CL_GLOBAL_L0_PEER_HOST=13.52.205.240
|
7
|
+
CL_GLOBAL_L0_PEER_ID=e2f4496e5872682d7a55aa06e507a58e96b5d48a5286bfdff7ed780fa464d9e789b2760ecd840f4cb3ee6e1c1d81b2ee844c88dbebf149b1084b7313eb680714
|
8
|
+
CL_GLOBAL_L0_PEER_HTTP_PORT=9000
|
@@ -0,0 +1,9 @@
|
|
1
|
+
SOURCE_NODE_1_PORT=9000
|
2
|
+
SOURCE_NODE_1_HOST=13.52.205.240
|
3
|
+
SOURCE_NODE_1_ID=e2f4496e5872682d7a55aa06e507a58e96b5d48a5286bfdff7ed780fa464d9e789b2760ecd840f4cb3ee6e1c1d81b2ee844c88dbebf149b1084b7313eb680714
|
4
|
+
SOURCE_NODE_2_PORT=9000
|
5
|
+
SOURCE_NODE_2_HOST=50.18.155.22
|
6
|
+
SOURCE_NODE_2_ID=3458a688925a4bd89f2ac2c695362e44d2e0c2903bdbb41b341a4d39283b22d8c85b487bd33cc5d36dbe5e31b5b00a10a6eab802718ead4ed7192ade5a5d1941
|
7
|
+
SOURCE_NODE_3_PORT=9000
|
8
|
+
SOURCE_NODE_3_HOST=52.9.216.57
|
9
|
+
SOURCE_NODE_3_ID=46daea11ca239cb8c0c8cdeb27db9dbe9c03744908a8a389a60d14df2ddde409260a93334d74957331eec1af323f458b12b3a6c3b8e05885608aae7e3a77eac7
|