From 6c707c9f7d74025d64d10244c0114c62e35942f4 Mon Sep 17 00:00:00 2001 From: Jeromy Cannon Date: Mon, 23 Dec 2024 13:33:13 +0000 Subject: [PATCH 1/9] Squashed commit of the following: commit 6b8ada1a98b9be16ffd6a5335fe5e667593de4b8 Author: instamenta Date: Fri Dec 20 16:55:18 2024 +0200 fixing the nodeSequence, switched to haproxy fQDN for the service endpoint and new version of the solo-charts Signed-off-by: instamenta commit bcdef8bed52be59aaa09be73e073974fcca69966 Merge: 847cd457 861c579e Author: instamenta Date: Fri Dec 20 12:15:25 2024 +0200 Merge remote-tracking branch 'origin/main' into 00949-production-readiness-dynamically-construct-the-genesis-networkjson-and-add-it-to-the-values-file-to-be-used-during-network-deploy commit 847cd45765beff33a06b27b4cec830e983a76886 Author: instamenta Date: Fri Dec 20 09:33:54 2024 +0200 renamed the GenesisNetowrkNodeDataWrapper filename to follow convention Signed-off-by: instamenta commit 861c579e353be7d452ff52e12c152123f5a84aef Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu Dec 19 11:06:35 2024 -0600 chore(deps-dev): bump globals from 15.13.0 to 15.14.0 (#1007) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit e80bda8e002692f8fa19db17d77f1ee5bae5a164 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu Dec 19 11:06:22 2024 -0600 chore(deps): bump chalk from 5.3.0 to 5.4.0 (#1008) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit f4b49aa49e0e4343a4db108b15965e0919605733 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu Dec 19 10:47:50 2024 -0600 chore(deps): bump @hashgraph/sdk from 2.55.1 to 2.56.0 (#1009) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit c9711c5282a43e85645216949213d4ed264c8dbe Author: Ivo Yankov Date: Thu Dec 19 18:47:03 2024 +0200 feat: update `solo context connect` to connect to single remote cluster (#993) Signed-off-by: Ivo Yankov commit c91b8aba44e022509755dc9f49df30d49d244962 Author: instamenta Date: Thu Dec 19 17:04:11 2024 +0200 add mock to fix failing unit test Signed-off-by: instamenta commit 7c63989de7b01e9de03d61c4f4903134b16d1dfd Author: instamenta Date: Thu Dec 19 16:43:31 2024 +0200 updated package-lock.jsonn Signed-off-by: instamenta commit c06e32af96f10f661fe92691c9c4dc7416a466ab Merge: 7a3ef9d6 043efcfb Author: instamenta Date: Thu Dec 19 16:42:31 2024 +0200 Merge remote-tracking branch 'origin/main' into 00949-production-readiness-dynamically-construct-the-genesis-networkjson-and-add-it-to-the-values-file-to-be-used-during-network-deploy commit 7a3ef9d6a7fe2836f9fc613b0233d40b3ec6fbad Author: instamenta Date: Thu Dec 19 16:35:01 2024 +0200 bump up the solo-charts version Signed-off-by: instamenta commit 043efcfb81929997c6bc82233c1788a34e450d68 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed Dec 18 16:56:19 2024 -0600 chore(deps): bump actions/upload-artifact from 4.4.3 to 4.5.0 (#1002) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 8115945b5ead242415f51f392b830f3d91545c99 Author: Pranali Deshmukh Date: Thu Dec 19 00:55:58 2024 +0200 docs(README): Updated the "Install Solo" section. (#1004) Signed-off-by: Pranali Deshmukh commit 01ed96933a6afa8458745d58fff604467324f8c3 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed Dec 18 11:19:09 2024 -0600 chore(deps): bump actions/setup-java from 4.5.0 to 4.6.0 (#1003) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 23238fc6f8fe1bbcda2188db3f09259c9f84b3c5 Merge: 1e30538a a4ef7006 Author: instamenta Date: Wed Dec 18 09:50:20 2024 +0200 Merge remote-tracking branch 'origin/main' into 00949-production-readiness-dynamically-construct-the-genesis-networkjson-and-add-it-to-the-values-file-to-be-used-during-network-deploy commit 1e30538a964380ac898b00382226e5a2b9e96a0b Author: instamenta Date: Wed Dec 18 09:50:13 2024 +0200 fix type of the grpc cert hash to be digested to base64 and conditional logic to not break tests Signed-off-by: instamenta commit a4ef7006edbe46595b66dd5d0842f705b4178b21 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue Dec 17 07:35:39 2024 -0600 chore(deps-dev): bump typescript-eslint from 8.18.0 to 8.18.1 (#996) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 4dfbf2f07ee3aa19e44db7f53deaea7867fed171 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue Dec 17 07:35:19 2024 -0600 chore(deps-dev): bump @typescript-eslint/utils from 8.18.0 to 8.18.1 (#997) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit b82610a181681cc1bf2fd0785b18c0408751991c Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue Dec 17 07:11:27 2024 -0600 chore(deps): bump jfrog/setup-jfrog-cli from 4.5.1 to 4.5.2 (#995) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 0b2326b33476b7267d733a4ec401aba5a9373647 Author: instamenta Date: Mon Dec 16 19:16:58 2024 +0200 changes to the genesis-network.json constructor that resolve the error's while parsing the json inside the node root containerpull Signed-off-by: instamenta commit 7ec2527fec0aa59a0922da2c39748027dc13d633 Merge: 28875108 a5fab1e2 Author: instamenta Date: Mon Dec 16 19:16:41 2024 +0200 Merge remote-tracking branch 'origin/main' into 00949-production-readiness-dynamically-construct-the-genesis-networkjson-and-add-it-to-the-values-file-to-be-used-during-network-deploy commit a5fab1e2d258f6b731fd69dada094f98ebde38b6 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon Dec 16 07:22:14 2024 -0600 chore(deps): bump helm/kind-action from 1.10.0 to 1.11.0 (#992) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 72a6433830bf80bb3158ae2e48fa642eca480fd1 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon Dec 16 07:14:47 2024 -0600 chore(deps-dev): bump @eslint/js from 9.16.0 to 9.17.0 (#989) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 41d079f7b6aae65ccaf05d9a75ebcdef1e583037 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon Dec 16 07:13:53 2024 -0600 chore(deps-dev): bump eslint from 9.16.0 to 9.17.0 (#990) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit c3a693caf94284caaa6717d6f76d2b207d1a92e7 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon Dec 16 07:13:26 2024 -0600 chore(deps-dev): bump typedoc from 0.27.4 to 0.27.5 (#991) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 2887510803362327521a44c100b8c08841be3af9 Author: instamenta Date: Mon Dec 16 12:49:29 2024 +0200 dont use string but AccountId for the genesis-network.json constructor Signed-off-by: instamenta commit f4c3cc740a8ed45a4052963ba448cfa37ef3edc8 Merge: d1020c49 8e4fe044 Author: instamenta Date: Mon Dec 16 09:20:45 2024 +0200 merge with main Signed-off-by: instamenta commit 8e4fe0441dace480ecb965cd492f1844b55a1736 Author: JeffreyDallas <39912573+JeffreyDallas@users.noreply.github.com> Date: Sat Dec 14 02:48:33 2024 -0600 fix: document typo (#988) Signed-off-by: Jeffrey Tang commit 06e60263a8beb0faddd2d521edd65f385d40feb0 Author: Jeromy Cannon Date: Fri Dec 13 15:25:37 2024 +0000 refactor: added http status code enums/library (#987) Signed-off-by: Jeromy Cannon commit d1020c4960d7485a36d2b898a3d2f610384c0b18 Author: instamenta Date: Fri Dec 13 17:12:53 2024 +0200 fixes Signed-off-by: instamenta commit 79410f0c52119f29980c193ab1b45d671612b0ce Author: JeffreyDallas <39912573+JeffreyDallas@users.noreply.github.com> Date: Fri Dec 13 07:36:52 2024 -0600 feat: add solo smoke test to test flow (#905) Signed-off-by: Jeffrey Tang Signed-off-by: Jeromy Cannon Co-authored-by: Jeromy Cannon commit a13e9dbbaab2e84df75f03beffb0b7aef31a43dd Author: instamenta Date: Fri Dec 13 15:32:31 2024 +0200 bump the charts version Signed-off-by: instamenta commit 4f0b286522de5809bb56cfbda854324ca5c9d917 Author: instamenta Date: Fri Dec 13 14:36:57 2024 +0200 remove unused params Signed-off-by: instamenta commit 336108153754d7b56e7faabf9cf172f974fb62f4 Author: instamenta Date: Fri Dec 13 14:14:53 2024 +0200 renamed models to follow snake_case convention Signed-off-by: instamenta commit d6ae342ecc7f2cf47c04f5ab67c28d2a79889aef Merge: 4bfd9985 b3789370 Author: instamenta Date: Fri Dec 13 12:42:15 2024 +0200 merge with main Signed-off-by: instamenta commit 4bfd9985f3af4afb8541f8e701ee936d7fc5818d Author: instamenta Date: Thu Dec 12 22:44:04 2024 +0200 added logic for setting the value file Signed-off-by: instamenta commit 59b156cba22a51612c25a26d78dbbdfc0a3f8f60 Author: instamenta Date: Thu Dec 12 21:35:49 2024 +0200 polishing and cleaning up the profile_manager, adding comments, aliases and keeping it D.R.Y. Signed-off-by: instamenta commit b3789370d700c86f47c09acefadeeac9e93b2886 Author: JeffreyDallas <39912573+JeffreyDallas@users.noreply.github.com> Date: Thu Dec 12 12:58:46 2024 -0600 feat: Update document (#956) Signed-off-by: Jeffrey Tang commit 58e96e1b796319007ad7f40fa35370f22603fc24 Author: JeffreyDallas <39912573+JeffreyDallas@users.noreply.github.com> Date: Thu Dec 12 12:56:41 2024 -0600 fix: local chart directory not being taken correctly (#983) Signed-off-by: Jeffrey Tang commit 437bbc6d125f1a01d12df2ea6096852ad776905c Author: Jeromy Cannon Date: Thu Dec 12 18:26:55 2024 +0000 fix: performance improvements for node stop (#986) Signed-off-by: Jeromy Cannon commit 83fb584e835d0eaaee64b634f52fc65a1ecf8db2 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu Dec 12 08:53:01 2024 -0600 chore(deps): bump @hashgraph/sdk from 2.55.0 to 2.55.1 (#984) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 9cae0116986e42c7515b2201403f4abbe5dcf923 Author: Jeromy Cannon Date: Thu Dec 12 14:52:36 2024 +0000 fix: bump chart and hedera version, re-enable node add (#985) Signed-off-by: Jeromy Cannon commit 45c69a0dfe5b73a9c2c18c09f53ade57ec9043d3 Author: instamenta Date: Thu Dec 12 16:40:40 2024 +0200 changed version Signed-off-by: instamenta commit 75964fc36d3e67b59721b52bc0d8d468e8d7b4c0 Author: instamenta Date: Thu Dec 12 15:56:46 2024 +0200 finishing up, and fixes Signed-off-by: instamenta commit dac6d6de2c2f6a8e25ab0fc4c555f50ad2534497 Author: instamenta Date: Thu Dec 12 14:05:36 2024 +0200 lint-fix, added .madgerc and configured it to dont count typed imports as circular dependencies Signed-off-by: instamenta commit 1a29c8216ffda8ba0d02c6566f8179ba162a20f8 Author: instamenta Date: Thu Dec 12 11:59:16 2024 +0200 polishing new classes added new interfaces and aliases to make clarify what they do Signed-off-by: instamenta commit 74285bfb4439f2fac542e95e9cda333d0f2e516c Author: Ivo Yankov Date: Thu Dec 12 11:08:39 2024 +0200 fix: node update with single node (#981) Signed-off-by: Ivo Yankov commit d6b823a89c6b439d8d9b607aa890d00630bae6c4 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed Dec 11 12:07:16 2024 -0600 chore(deps-dev): bump @types/node from 22.10.1 to 22.10.2 (#980) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 3e3cdd91904ff33b70c6c623957dfff137d6a2ae Author: instamenta Date: Wed Dec 11 18:50:55 2024 +0200 updating data wrapper properties Signed-off-by: instamenta commit f2760fd515e68c2dee0cd83a5f7318ec4b644771 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed Dec 11 09:04:35 2024 -0600 chore(deps-dev): bump c8 from 10.1.2 to 10.1.3 (#979) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 1948c26f997bcd40ea751d47bc5cf3d10e184a9b Author: instamenta Date: Wed Dec 11 16:27:19 2024 +0200 wiring Signed-off-by: instamenta commit 7b115504edb079fbeb7b9767676caa9398273f69 Author: instamenta Date: Wed Dec 11 16:09:08 2024 +0200 remove obsolete comments Signed-off-by: instamenta commit d965c12176f5b6d5202e54a324e9536b23b3251b Author: instamenta Date: Wed Dec 11 16:04:28 2024 +0200 lemove obsolete comments Signed-off-by: instamenta commit 26f9341336b5433fcff0b9672f21057b22934bc5 Author: instamenta Date: Wed Dec 11 16:01:14 2024 +0200 cleanup Signed-off-by: instamenta commit 5a62289d6e22aad1d1a96462552cee63e6660160 Author: instamenta Date: Wed Dec 11 15:42:13 2024 +0200 changes from other branch Signed-off-by: instamenta Signed-off-by: Jeromy Cannon --- .madgerc | 7 + examples/performance-tuning/README.md | 0 src/commands/flags.ts | 2 + src/commands/network.ts | 55 +++-- src/commands/node/configs.ts | 4 +- src/commands/node/tasks.ts | 3 +- src/core/constants.ts | 1 + .../genesis_network_data_constructor.ts | 86 +++++++ .../genesis_network_node_data_wrapper.ts | 69 ++++++ src/core/helpers.ts | 10 +- src/core/profile_manager.ts | 220 ++++++++++-------- src/core/templates.ts | 6 +- src/types/aliases.ts | 10 + src/types/index.ts | 37 ++- test/data/local-config.yaml | 2 +- test/unit/commands/network.test.ts | 3 + tsconfig.json | 1 + 17 files changed, 389 insertions(+), 127 deletions(-) create mode 100644 .madgerc create mode 100644 examples/performance-tuning/README.md create mode 100644 src/core/genesis_network_models/genesis_network_data_constructor.ts create mode 100644 src/core/genesis_network_models/genesis_network_node_data_wrapper.ts diff --git a/.madgerc b/.madgerc new file mode 100644 index 000000000..b407c6b4b --- /dev/null +++ b/.madgerc @@ -0,0 +1,7 @@ +{ + "detectiveOptions": { + "ts": { + "skipTypeImports": true + } + } +} diff --git a/examples/performance-tuning/README.md b/examples/performance-tuning/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/src/commands/flags.ts b/src/commands/flags.ts index 3608799f0..485278a50 100644 --- a/src/commands/flags.ts +++ b/src/commands/flags.ts @@ -1645,6 +1645,7 @@ export class Flags { Flags.envoyIps, Flags.generateEcdsaKey, Flags.generateGossipKeys, + Flags.generateEcdsaKey, Flags.generateTlsKeys, Flags.gossipEndpoints, Flags.gossipPrivateKey, @@ -1665,6 +1666,7 @@ export class Flags { Flags.namespace, Flags.newAccountNumber, Flags.newAdminKey, + Flags.createAmount, Flags.nodeAlias, Flags.nodeAliasesUnparsed, Flags.operatorId, diff --git a/src/commands/network.ts b/src/commands/network.ts index a85009b12..ea6db9bdc 100644 --- a/src/commands/network.ts +++ b/src/commands/network.ts @@ -38,6 +38,7 @@ import {ConsensusNodeComponent} from '../core/config/remote/components/consensus import {ConsensusNodeStates} from '../core/config/remote/enumerations.js'; import {EnvoyProxyComponent} from '../core/config/remote/components/envoy_proxy_component.js'; import {HaProxyComponent} from '../core/config/remote/components/ha_proxy_component.js'; +import {GenesisNetworkDataConstructor} from '../core/genesis_network_models/genesis_network_data_constructor.js'; export interface NetworkDeployConfigClass { applicationEnv: string; @@ -61,6 +62,7 @@ export interface NetworkDeployConfigClass { grpcWebTlsCertificatePath: string; grpcTlsKeyPath: string; grpcWebTlsKeyPath: string; + genesisNetworkData: GenesisNetworkDataConstructor; getUnusedConfigs: () => string[]; haproxyIps: string; envoyIps: string; @@ -130,20 +132,19 @@ export class NetworkCommand extends BaseCommand { ]; } - async prepareValuesArg( - config: { - chartDirectory?: string; - app?: string; - nodeAliases?: string[]; - debugNodeAlias?: NodeAlias; - enablePrometheusSvcMonitor?: boolean; - releaseTag?: string; - persistentVolumeClaims?: string; - valuesFile?: string; - haproxyIpsParsed?: Record; - envoyIpsParsed?: Record; - } = {}, - ) { + async prepareValuesArg(config: { + chartDirectory?: string; + app?: string; + nodeAliases: string[]; + debugNodeAlias?: NodeAlias; + enablePrometheusSvcMonitor?: boolean; + releaseTag?: string; + persistentVolumeClaims?: string; + valuesFile?: string; + haproxyIpsParsed?: Record; + envoyIpsParsed?: Record; + genesisNetworkData: GenesisNetworkDataConstructor; + }) { let valuesArg = config.chartDirectory ? `-f ${path.join(config.chartDirectory, 'solo-deployment', 'values.yaml')}` : ''; @@ -160,7 +161,10 @@ export class NetworkCommand extends BaseCommand { } const profileName = this.configManager.getFlag(flags.profileName) as string; - this.profileValuesFile = await this.profileManager.prepareValuesForSoloChart(profileName); + this.profileValuesFile = await this.profileManager.prepareValuesForSoloChart( + profileName, + config.genesisNetworkData, + ); if (this.profileValuesFile) { valuesArg += this.prepareValuesFiles(this.profileValuesFile); } @@ -172,7 +176,7 @@ export class NetworkCommand extends BaseCommand { // Iterate over each node and set static IPs for HAProxy if (config.haproxyIpsParsed) { - config.nodeAliases?.forEach((nodeAlias, index) => { + config.nodeAliases.forEach((nodeAlias, index) => { const ip = config.haproxyIpsParsed?.[nodeAlias]; if (ip) valuesArg += ` --set "hedera.nodes[${index}].haproxyStaticIP=${ip}"`; @@ -181,7 +185,7 @@ export class NetworkCommand extends BaseCommand { // Iterate over each node and set static IPs for Envoy Proxy if (config.envoyIpsParsed) { - config.nodeAliases?.forEach((nodeAlias, index) => { + config.nodeAliases.forEach((nodeAlias, index) => { const ip = config.envoyIpsParsed?.[nodeAlias]; if (ip) valuesArg += ` --set "hedera.nodes[${index}].envoyProxyStaticIP=${ip}"`; @@ -253,13 +257,19 @@ export class NetworkCommand extends BaseCommand { constants.SOLO_DEPLOYMENT_CHART, ); - config.valuesArg = await this.prepareValuesArg(config); - // compute other config parameters config.keysDir = path.join(validatePath(config.cacheDir), 'keys'); config.stagingDir = Templates.renderStagingDir(config.cacheDir, config.releaseTag); config.stagingKeysDir = path.join(validatePath(config.stagingDir), 'keys'); + config.genesisNetworkData = await GenesisNetworkDataConstructor.initialize( + config.nodeAliases, + this.keyManager, + config.keysDir, + ); + + config.valuesArg = await this.prepareValuesArg(config); + if (!(await this.k8.hasNamespace(config.namespace))) { await this.k8.createNamespace(config.namespace); } @@ -341,7 +351,7 @@ export class NetworkCommand extends BaseCommand { }, { title: 'Check if cluster setup chart is installed', - task: async (ctx, task) => { + task: async () => { const isChartInstalled = await this.chartManager.isChartInstalled('', constants.SOLO_CLUSTER_SETUP_CHART); if (!isChartInstalled) { throw new SoloError( @@ -386,7 +396,7 @@ export class NetworkCommand extends BaseCommand { task: (ctx, parentTask) => { const config = ctx.config; - // set up the sub-tasks + // set up the subtasks return parentTask.newListr(self.platformInstaller.copyNodeKeys(config.stagingDir, config.nodeAliases), { concurrent: true, rendererOptions: constants.LISTR_DEFAULT_RENDERER_OPTION, @@ -502,7 +512,7 @@ export class NetworkCommand extends BaseCommand { ), }); - // set up the sub-tasks + // set up the subtasks return task.newListr(subTasks, { concurrent: false, // no need to run concurrently since if one node is up, the rest should be up by then rendererOptions: { @@ -754,6 +764,7 @@ export class NetworkCommand extends BaseCommand { }, }; } + /** Adds the consensus node, envoy and haproxy components to remote config. */ public addNodesAndProxies(): ListrTask { return { diff --git a/src/commands/node/configs.ts b/src/commands/node/configs.ts index d3c7b50e3..9c924f113 100644 --- a/src/commands/node/configs.ts +++ b/src/commands/node/configs.ts @@ -24,8 +24,8 @@ import path from 'path'; import fs from 'fs'; import {validatePath} from '../../core/helpers.js'; import {Flags as flags} from '../flags.js'; -import {type NodeAlias, type NodeAliases, type PodName} from '../../types/aliases.js'; -import {type NetworkNodeServices} from '../../core/network_node_services.js'; +import type {NodeAlias, NodeAliases, PodName} from '../../types/aliases.js'; +import type {NetworkNodeServices} from '../../core/network_node_services.js'; export const PREPARE_UPGRADE_CONFIGS_NAME = 'prepareUpgradeConfig'; export const DOWNLOAD_GENERATED_FILES_CONFIGS_NAME = 'downloadGeneratedFilesConfig'; diff --git a/src/commands/node/tasks.ts b/src/commands/node/tasks.ts index 3e143bcc8..e0cbf0f19 100644 --- a/src/commands/node/tasks.ts +++ b/src/commands/node/tasks.ts @@ -455,6 +455,7 @@ export class NodeCommandTasks { */ _generateGossipKeys(generateMultiple: boolean) { const self = this; + return new Task( 'Generate gossip keys', (ctx: any, task: ListrTaskWrapper) => { @@ -701,7 +702,7 @@ export class NodeCommandTasks { config.stagingDir, ); - // if directory data/upgrade/current/data/keys does not exist then use data/upgrade/current + // if directory data/upgrade/current/data/keys does not exist, then use data/upgrade/current let keyDir = `${constants.HEDERA_HAPI_PATH}/data/upgrade/current/data/keys`; if (!(await self.k8.hasDir(nodeFullyQualifiedPodName, constants.ROOT_CONTAINER, keyDir))) { keyDir = `${constants.HEDERA_HAPI_PATH}/data/upgrade/current`; diff --git a/src/core/constants.ts b/src/core/constants.ts index cfc767c1e..abe827b35 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -196,6 +196,7 @@ export const RELAY_PODS_RUNNING_MAX_ATTEMPTS = +process.env.RELAY_PODS_RUNNING_M export const RELAY_PODS_RUNNING_DELAY = +process.env.RELAY_PODS_RUNNING_DELAY || 1_000; export const RELAY_PODS_READY_MAX_ATTEMPTS = +process.env.RELAY_PODS_READY_MAX_ATTEMPTS || 100; export const RELAY_PODS_READY_DELAY = +process.env.RELAY_PODS_READY_DELAY || 1_000; +export const GRPC_PORT = +process.env.GRPC_PORT || 50_211; export const NETWORK_DESTROY_WAIT_TIMEOUT = +process.env.NETWORK_DESTROY_WAIT_TIMEOUT || 120; diff --git a/src/core/genesis_network_models/genesis_network_data_constructor.ts b/src/core/genesis_network_models/genesis_network_data_constructor.ts new file mode 100644 index 000000000..4498c6e3d --- /dev/null +++ b/src/core/genesis_network_models/genesis_network_data_constructor.ts @@ -0,0 +1,86 @@ +/** + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import crypto from 'node:crypto'; +import {PrivateKey} from '@hashgraph/sdk'; +import {Templates} from '../templates.js'; +import {GenesisNetworkNodeDataWrapper} from './genesis_network_node_data_wrapper.js'; +import * as x509 from '@peculiar/x509'; +import * as constants from '../constants.js'; + +import type {KeyManager} from '../key_manager.js'; +import type {ToJSON} from '../../types/index.js'; +import type {JsonString, NodeAlias, NodeAliases} from '../../types/aliases.js'; + +/** + * Used to construct the nodes data and convert them to JSON + */ +export class GenesisNetworkDataConstructor implements ToJSON { + public readonly nodes: Record = {}; + + private constructor( + private readonly nodeAliases: NodeAliases, + private readonly keyManager: KeyManager, + private readonly keysDir: string, + ) { + nodeAliases.forEach((nodeAlias, nodeId) => { + // TODO: get nodeId from label in pod. + const adminPrivateKey = PrivateKey.fromStringED25519(constants.GENESIS_KEY); + const adminPubKey = adminPrivateKey.publicKey; + + this.nodes[nodeAlias] = new GenesisNetworkNodeDataWrapper(nodeId, adminPubKey, nodeAlias); + }); + } + + public static async initialize( + nodeAliases: NodeAliases, + keyManager: KeyManager, + keysDir: string, + ): Promise { + const instance = new GenesisNetworkDataConstructor(nodeAliases, keyManager, keysDir); + + await instance.load(); + + return instance; + } + + /** + * Loads the gossipCaCertificate and grpcCertificateHash + */ + private async load() { + await Promise.all( + this.nodeAliases.map(async nodeAlias => { + const nodeKeys = await this.keyManager.loadSigningKey(nodeAlias, this.keysDir); + + //* Convert the certificate to PEM format + const certPem = nodeKeys.certificate.toString(); + + //* Assign the PEM certificate + this.nodes[nodeAlias].gossipCaCertificate = nodeKeys.certificate.toString('base64'); + + //* Decode the PEM to DER format + const tlsCertDer = new Uint8Array(x509.PemConverter.decode(certPem)[0]); + + //* Generate the SHA-384 hash + this.nodes[nodeAlias].grpcCertificateHash = crypto.createHash('sha384').update(tlsCertDer).digest('base64'); + }), + ); + } + + public toJSON(): JsonString { + return JSON.stringify({nodeMetadata: Object.values(this.nodes).map(node => node.toObject())}); + } +} diff --git a/src/core/genesis_network_models/genesis_network_node_data_wrapper.ts b/src/core/genesis_network_models/genesis_network_node_data_wrapper.ts new file mode 100644 index 000000000..20183c393 --- /dev/null +++ b/src/core/genesis_network_models/genesis_network_node_data_wrapper.ts @@ -0,0 +1,69 @@ +/** + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import type {AccountId, PublicKey} from '@hashgraph/sdk'; +import type {GenesisNetworkNodeStructure, ServiceEndpoint, ToObject} from '../../types/index.js'; + +export class GenesisNetworkNodeDataWrapper + implements GenesisNetworkNodeStructure, ToObject<{node: GenesisNetworkNodeStructure}> +{ + public accountId: AccountId; + public gossipEndpoint: ServiceEndpoint[] = []; + public serviceEndpoint: ServiceEndpoint[] = []; + public gossipCaCertificate: string; + public grpcCertificateHash: string; + public weight: number; + public readonly deleted = false; + + constructor( + public readonly nodeId: number, + public readonly adminKey: PublicKey, + public readonly description: string, + ) {} + + /** + * @param domainName - a fully qualified domain name + * @param port + */ + public addServiceEndpoint(domainName: string, port: number): void { + this.serviceEndpoint.push({domainName, port, ipAddressV4: ''}); + } + + /** + * @param domainName - a fully qualified domain name + * @param port + */ + public addGossipEndpoint(domainName: string, port: number): void { + this.gossipEndpoint.push({domainName, port, ipAddressV4: ''}); + } + + public toObject() { + return { + node: { + nodeId: this.nodeId, + accountId: this.accountId, + description: this.description, + gossipEndpoint: this.gossipEndpoint, + serviceEndpoint: this.serviceEndpoint, + gossipCaCertificate: this.gossipCaCertificate, + grpcCertificateHash: this.grpcCertificateHash, + weight: this.weight, + deleted: this.deleted, + adminKey: this.adminKey, + }, + }; + } +} diff --git a/src/core/helpers.ts b/src/core/helpers.ts index 4d83c2c8a..889fb56ee 100644 --- a/src/core/helpers.ts +++ b/src/core/helpers.ts @@ -27,6 +27,7 @@ import {type NodeAlias, type NodeAliases} from '../types/aliases.js'; import {type CommandFlag} from '../types/flag_types.js'; import {type SoloLogger} from './logging.js'; import {type Duration} from './time/duration.js'; +import {type NodeAddConfigClass} from '../commands/node/configs.js'; export function sleep(duration: Duration) { return new Promise(resolve => { @@ -241,13 +242,14 @@ export function addDebugOptions(valuesArg: string, debugNodeAlias: NodeAlias, in export function addSaveContextParser(ctx: any) { const exportedCtx = {} as Record; - const config = /** @type {NodeAddConfigClass} **/ ctx.config; + const config = ctx.config as NodeAddConfigClass; const exportedFields = ['tlsCertHash', 'upgradeZipHash', 'newNode']; exportedCtx.signingCertDer = ctx.signingCertDer.toString(); exportedCtx.gossipEndpoints = ctx.gossipEndpoints.map((ep: any) => `${ep.getDomainName}:${ep.getPort}`); exportedCtx.grpcServiceEndpoints = ctx.grpcServiceEndpoints.map((ep: any) => `${ep.getDomainName}:${ep.getPort}`); exportedCtx.adminKey = ctx.adminKey.toString(); + // @ts-ignore exportedCtx.existingNodeAliases = config.existingNodeAliases; for (const prop of exportedFields) { @@ -308,16 +310,14 @@ export function prepareEndpoints(endpointType: string, endpoints: string[], defa if (endpointType.toUpperCase() === constants.ENDPOINT_TYPE_IP) { ret.push( new ServiceEndpoint({ - // @ts-ignore - port, + port: +port, ipAddressV4: parseIpAddressToUint8Array(url), }), ); } else { ret.push( new ServiceEndpoint({ - // @ts-ignore - port, + port: +port, domainName: url, }), ); diff --git a/src/core/profile_manager.ts b/src/core/profile_manager.ts index cf0d89923..61a07d790 100644 --- a/src/core/profile_manager.ts +++ b/src/core/profile_manager.ts @@ -20,7 +20,6 @@ import {SoloError, IllegalArgumentError, MissingArgumentError} from './errors.js import * as yaml from 'yaml'; import dot from 'dot-object'; import * as semver from 'semver'; -import type {SemVer} from 'semver'; import {readFile, writeFile} from 'fs/promises'; import {Flags as flags} from '../commands/flags.js'; @@ -29,8 +28,12 @@ import * as constants from './constants.js'; import {type ConfigManager} from './config_manager.js'; import * as helpers from './helpers.js'; import {getNodeAccountMap} from './helpers.js'; +import {AccountId} from '@hashgraph/sdk'; +import type {SemVer} from 'semver'; import type {SoloLogger} from './logging.js'; -import type {NodeAlias, NodeAliases} from '../types/aliases.js'; +import type {AnyObject, DirPath, NodeAlias, NodeAliases, Path} from '../types/aliases.js'; +import type {GenesisNetworkDataConstructor} from './genesis_network_models/genesis_network_data_constructor.js'; +import type {Optional} from '../types/index.js'; const consensusSidecars = [ 'recordStreamUploader', @@ -43,12 +46,12 @@ const consensusSidecars = [ export class ProfileManager { private readonly logger: SoloLogger; private readonly configManager: ConfigManager; - private readonly cacheDir: string; + private readonly cacheDir: DirPath; - private profiles: Map; - private profileFile: string | undefined; + private profiles: Map; + private profileFile: Optional; - constructor(logger: SoloLogger, configManager: ConfigManager, cacheDir: string = constants.SOLO_VALUES_DIR) { + constructor(logger: SoloLogger, configManager: ConfigManager, cacheDir: DirPath = constants.SOLO_VALUES_DIR) { if (!logger) throw new MissingArgumentError('An instance of core/SoloLogger is required'); if (!configManager) throw new MissingArgumentError('An instance of core/ConfigManager is required'); @@ -61,7 +64,15 @@ export class ProfileManager { this.cacheDir = cacheDir; } - loadProfiles(forceReload = false): Map { + /** + * Load profiles from a profile file and populate the profiles map. + * + * @param [forceReload = false] - forces the profiles map to override even if it exists. + * @returns reference to the populated profiles map. + * + * @throws {IllegalArgumentError} if the profile file is not found. + */ + loadProfiles(forceReload = false): Map { const profileFile = this.configManager.getFlag(flags.profileFile); if (!profileFile) throw new MissingArgumentError('profileFile is required'); @@ -75,7 +86,7 @@ export class ProfileManager { // load profile file this.profiles = new Map(); const yamlData = fs.readFileSync(profileFile, 'utf8'); - const profileItems = yaml.parse(yamlData) as Record; + const profileItems = yaml.parse(yamlData) as Record; // add profiles for (const key in profileItems) { @@ -88,26 +99,36 @@ export class ProfileManager { return this.profiles; } - getProfile(profileName: string): object { + /** + * Get profile from the profiles map, loads them on demand if they are not loaded already. + * + * @param profileName - profile name (key in the map). + * @returns the profile. + * + * @throws {IllegalArgumentError} if profiles can't be loaded or the profile name is not found in the map. + */ + getProfile(profileName: string): AnyObject { if (!profileName) throw new MissingArgumentError('profileName is required'); if (!this.profiles || this.profiles.size <= 0) { this.loadProfiles(); } - if (!this.profiles || !this.profiles.has(profileName)) + if (!this.profiles || !this.profiles.has(profileName)) { throw new IllegalArgumentError(`Profile does not exists with name: ${profileName}`); - return this.profiles.get(profileName) as object; + } + + return this.profiles.get(profileName) as AnyObject; } /** - * Set value in the yaml object + * Set value in the YAML object * @param itemPath - item path in the yaml * @param value - value to be set - * @param yamlRoot - root of the yaml object + * @param yamlRoot - root of the YAML object * @returns */ - _setValue(itemPath: string, value: any, yamlRoot: object): object { - // find the location where to set the value in the yaml + _setValue(itemPath: string, value: any, yamlRoot: AnyObject): AnyObject { + // find the location where to set the value in the YAML const itemPathParts: string[] = itemPath.split('.'); let parent = yamlRoot; let current = parent; @@ -115,7 +136,7 @@ export class ProfileManager { for (let itemPathPart of itemPathParts) { if (helpers.isNumeric(itemPathPart)) { // @ts-ignore - itemPathPart = Number.parseInt(itemPathPart); // numeric path part can only be array index i.e. an integer + itemPathPart = Number.parseInt(itemPathPart); // numeric path part can only be array index i.e., an integer if (!Array.isArray(parent[prevItemPath])) { parent[prevItemPath] = []; } @@ -144,12 +165,12 @@ export class ProfileManager { /** * Set items for the chart - * @param itemPath - item path in the yaml, if empty then root of the yaml object will be used + * @param itemPath - item path in the YAML, if empty then root of the YAML object will be used * @param items - the element object - * @param yamlRoot - root of the yaml object to update + * @param yamlRoot - root of the YAML object to update * @private */ - _setChartItems(itemPath: string, items: any, yamlRoot: object) { + _setChartItems(itemPath: string, items: any, yamlRoot: AnyObject) { if (!items) return; const dotItems = dot.dot(items); @@ -157,7 +178,7 @@ export class ProfileManager { for (const key in dotItems) { let itemKey = key; - // if it is an array key like extraEnv[0].JAVA_OPTS, convert it into dot separated key as extraEnv.0.JAVA_OPTS + // if it is an array key like extraEnv[0].JAVA_OPTS, convert it into a dot separated key as extraEnv.0.JAVA_OPTS if (key.indexOf('[') !== -1) { itemKey = key.replace('[', '.').replace(']', ''); } @@ -170,7 +191,12 @@ export class ProfileManager { } } - resourcesForConsensusPod(profile: any, nodeAliases: NodeAliases, yamlRoot: object): object { + resourcesForConsensusPod( + profile: AnyObject, + nodeAliases: NodeAliases, + yamlRoot: AnyObject, + genesisNetworkData?: GenesisNetworkDataConstructor, + ): AnyObject { if (!profile) throw new MissingArgumentError('profile is required'); const accountMap = getNodeAccountMap(nodeAliases); @@ -197,6 +223,7 @@ export class ProfileManager { this.configManager.getFlag(flags.releaseTag), this.configManager.getFlag(flags.app), this.configManager.getFlag(flags.chainId), + genesisNetworkData, ); for (const flag of flags.nodeConfigFileFlags.values()) { @@ -238,6 +265,15 @@ export class ProfileManager { path.join(stagingDir, 'templates', 'bootstrap.properties'), yamlRoot, ); + + if (genesisNetworkData) { + const genesisNetworkJson = path.join(stagingDir, 'genesis-network.json'); + + fs.writeFileSync(genesisNetworkJson, genesisNetworkData.toJSON()); + + this._setFileContentsAsValue('hedera.configMaps.genesisNetworkJson', genesisNetworkJson, yamlRoot); + } + if (this.configManager.getFlag(flags.applicationEnv)) { this._setFileContentsAsValue( 'hedera.configMaps.applicationEnv', @@ -259,26 +295,26 @@ export class ProfileManager { return yamlRoot; } - resourcesForHaProxyPod(profile: any, yamlRoot: object) { + private resourcesForHaProxyPod(profile: AnyObject, yamlRoot: AnyObject) { if (!profile) throw new MissingArgumentError('profile is required'); if (!profile.haproxy) return; // use chart defaults return this._setChartItems('defaults.haproxy', profile.haproxy, yamlRoot); } - resourcesForEnvoyProxyPod(profile: any, yamlRoot: object) { + private resourcesForEnvoyProxyPod(profile: AnyObject, yamlRoot: AnyObject) { if (!profile) throw new MissingArgumentError('profile is required'); if (!profile.envoyProxy) return; // use chart defaults return this._setChartItems('defaults.envoyProxy', profile.envoyProxy, yamlRoot); } - resourcesForHederaExplorerPod(profile: any, yamlRoot: object) { + private resourcesForHederaExplorerPod(profile: AnyObject, yamlRoot: AnyObject) { if (!profile) throw new MissingArgumentError('profile is required'); if (!profile.explorer) return; return this._setChartItems('', profile.explorer, yamlRoot); } - resourcesForMinioTenantPod(profile: any, yamlRoot: object) { + private resourcesForMinioTenantPod(profile: AnyObject, yamlRoot: AnyObject) { if (!profile) throw new MissingArgumentError('profile is required'); // @ts-ignore if (!profile.minio || !profile.minio.tenant) return; // use chart defaults @@ -299,37 +335,29 @@ export class ProfileManager { /** * Prepare a values file for Solo Helm chart - * @param profileName resource profile name + * @param profileName - resource profile name + * @param genesisNetworkData - reference to the constructor * @returns return the full path to the values file */ - prepareValuesForSoloChart(profileName: string) { + public async prepareValuesForSoloChart(profileName: string, genesisNetworkData?: GenesisNetworkDataConstructor) { if (!profileName) throw new MissingArgumentError('profileName is required'); const profile = this.getProfile(profileName); const nodeAliases = helpers.parseNodeAliases(this.configManager.getFlag(flags.nodeAliasesUnparsed)); if (!nodeAliases) throw new SoloError('Node IDs are not set in the config'); - // generate the yaml + // generate the YAML const yamlRoot = {}; - this.resourcesForConsensusPod(profile, nodeAliases, yamlRoot); + this.resourcesForConsensusPod(profile, nodeAliases, yamlRoot, genesisNetworkData); this.resourcesForHaProxyPod(profile, yamlRoot); this.resourcesForEnvoyProxyPod(profile, yamlRoot); this.resourcesForMinioTenantPod(profile, yamlRoot); - // write the yaml const cachedValuesFile = path.join(this.cacheDir, `solo-${profileName}.yaml`); - return new Promise((resolve, reject) => { - fs.writeFile(cachedValuesFile, yaml.stringify(yamlRoot), err => { - if (err) { - reject(err); - } - - resolve(cachedValuesFile); - }); - }); + return this.writeToYaml(cachedValuesFile, yamlRoot); } - async bumpHederaConfigVersion(applicationPropertiesPath: string) { + private async bumpHederaConfigVersion(applicationPropertiesPath: string) { const lines = (await readFile(applicationPropertiesPath, 'utf-8')).split('\n'); for (const line of lines) { @@ -343,23 +371,14 @@ export class ProfileManager { await writeFile(applicationPropertiesPath, lines.join('\n')); } - async prepareValuesForNodeAdd(configTxtPath: string, applicationPropertiesPath: string) { + public async prepareValuesForNodeAdd(configTxtPath: string, applicationPropertiesPath: string) { const yamlRoot = {}; this._setFileContentsAsValue('hedera.configMaps.configTxt', configTxtPath, yamlRoot); await this.bumpHederaConfigVersion(applicationPropertiesPath); this._setFileContentsAsValue('hedera.configMaps.applicationProperties', applicationPropertiesPath, yamlRoot); - // write the yaml const cachedValuesFile = path.join(this.cacheDir, 'solo-node-add.yaml'); - return new Promise((resolve, reject) => { - fs.writeFile(cachedValuesFile, yaml.stringify(yamlRoot), err => { - if (err) { - reject(err); - } - - resolve(cachedValuesFile); - }); - }); + return this.writeToYaml(cachedValuesFile, yamlRoot); } /** @@ -367,38 +386,38 @@ export class ProfileManager { * @param profileName - resource profile name * @returns return the full path to the values file */ - prepareValuesForRpcRelayChart(profileName: string) { + public async prepareValuesForRpcRelayChart(profileName: string) { if (!profileName) throw new MissingArgumentError('profileName is required'); - const profile = this.getProfile(profileName) as any; + const profile = this.getProfile(profileName) as AnyObject; if (!profile.rpcRelay) return Promise.resolve(); // use chart defaults - // generate the yaml + // generate the YAML const yamlRoot = {}; this._setChartItems('', profile.rpcRelay, yamlRoot); - // write the yaml const cachedValuesFile = path.join(this.cacheDir, `rpcRelay-${profileName}.yaml`); - return new Promise((resolve, reject) => { - fs.writeFile(cachedValuesFile, yaml.stringify(yamlRoot), err => { - if (err) { - reject(err); - } - - resolve(cachedValuesFile); - }); - }); + return this.writeToYaml(cachedValuesFile, yamlRoot); } - prepareValuesHederaExplorerChart(profileName: string) { + public async prepareValuesHederaExplorerChart(profileName: string) { if (!profileName) throw new MissingArgumentError('profileName is required'); - const profile = this.getProfile(profileName) as any; - // generate the yaml + const profile = this.getProfile(profileName) as AnyObject; + // generate the YAML const yamlRoot = {}; this.resourcesForHederaExplorerPod(profile, yamlRoot); - // write the yaml const cachedValuesFile = path.join(this.cacheDir, `explorer-${profileName}.yaml`); - return new Promise((resolve, reject) => { + return this.writeToYaml(cachedValuesFile, yamlRoot); + } + + /** + * Writes the YAML to file. + * + * @param cachedValuesFile - the target file to write the YAML root to. + * @param yamlRoot - object to turn into YAML and write to file. + */ + private async writeToYaml(cachedValuesFile: Path, yamlRoot: AnyObject) { + return await new Promise((resolve, reject) => { fs.writeFile(cachedValuesFile, yaml.stringify(yamlRoot), err => { if (err) { reject(err); @@ -412,14 +431,14 @@ export class ProfileManager { /** * Prepare a values file for mirror-node Helm chart * @param profileName - resource profile name - * @returns return the full path to the values file + * @returns the full path to the values file */ - prepareValuesForMirrorNodeChart(profileName: string) { + public async prepareValuesForMirrorNodeChart(profileName: string) { if (!profileName) throw new MissingArgumentError('profileName is required'); - const profile = this.getProfile(profileName) as any; + const profile = this.getProfile(profileName) as AnyObject; if (!profile.mirror) return Promise.resolve(); // use chart defaults - // generate the yaml + // generate the YAML const yamlRoot = {}; if (profile.mirror.postgresql) { if (profile.mirror.postgresql.persistence) { @@ -435,26 +454,17 @@ export class ProfileManager { this._setChartItems('grpc', profile.mirror.grpc, yamlRoot); this._setChartItems('monitor', profile.mirror.monitor, yamlRoot); - // write the yaml const cachedValuesFile = path.join(this.cacheDir, `mirror-${profileName}.yaml`); - return new Promise((resolve, reject) => { - fs.writeFile(cachedValuesFile, yaml.stringify(yamlRoot), err => { - if (err) { - reject(err); - } - - resolve(cachedValuesFile); - }); - }); + return this.writeToYaml(cachedValuesFile, yamlRoot); } /** - * Writes the contents of a file as a value for the given nested item path in the yaml object - * @param itemPath - nested item path in the yaml object to store the file contents - * @param valueFilePath - path to the file whose contents will be stored in the yaml object - * @param yamlRoot - root of the yaml object + * Writes the contents of a file as a value for the given nested item path in the YAML object + * @param itemPath - nested item path in the YAML object to store the file contents + * @param valueFilePath - path to the file whose contents will be stored in the YAML object + * @param yamlRoot - root of the YAML object */ - private _setFileContentsAsValue(itemPath: string, valueFilePath: string, yamlRoot: object) { + private _setFileContentsAsValue(itemPath: string, valueFilePath: string, yamlRoot: AnyObject) { const fileContents = fs.readFileSync(valueFilePath, 'utf8'); this._setValue(itemPath, fileContents, yamlRoot); } @@ -467,6 +477,7 @@ export class ProfileManager { * @param releaseTag - release tag e.g. v0.42.0 * @param [appName] - the app name (default: HederaNode.jar) * @param [chainId] - chain ID (298 for local network) + * @param genesisNetworkData * @returns the config.txt file path */ prepareConfigTxt( @@ -476,17 +487,21 @@ export class ProfileManager { releaseTag: string, appName = constants.HEDERA_APP_NAME, chainId = constants.HEDERA_CHAIN_ID, + genesisNetworkData?: GenesisNetworkDataConstructor, ) { - if (!nodeAccountMap || nodeAccountMap.size === 0) + if (!nodeAccountMap || nodeAccountMap.size === 0) { throw new MissingArgumentError('nodeAccountMap the map of node IDs to account IDs is required'); + } + if (!releaseTag) throw new MissingArgumentError('release tag is required'); - if (!fs.existsSync(destPath)) + if (!fs.existsSync(destPath)) { throw new IllegalArgumentError(`config destPath does not exist: ${destPath}`, destPath); + } // init variables - const internalPort = constants.HEDERA_NODE_INTERNAL_GOSSIP_PORT; - const externalPort = constants.HEDERA_NODE_EXTERNAL_GOSSIP_PORT; + const internalPort = +constants.HEDERA_NODE_INTERNAL_GOSSIP_PORT; + const externalPort = +constants.HEDERA_NODE_EXTERNAL_GOSSIP_PORT; const nodeStakeAmount = constants.HEDERA_NODE_DEFAULT_STAKE_AMOUNT; // @ts-ignore @@ -501,8 +516,25 @@ export class ProfileManager { for (const nodeAlias of nodeAccountMap.keys()) { const internalIP = Templates.renderFullyQualifiedNetworkPodName(namespace, nodeAlias); const externalIP = Templates.renderFullyQualifiedNetworkSvcName(namespace, nodeAlias); - const account = nodeAccountMap.get(nodeAlias); + + if (genesisNetworkData) { + // TODO: Use the "nodeSeq" + + const nodeDataWrapper = genesisNetworkData.nodes[nodeAlias]; + + nodeDataWrapper.weight = nodeStakeAmount; + nodeDataWrapper.accountId = AccountId.fromString(account); + + //? Add gossip endpoints + nodeDataWrapper.addGossipEndpoint(externalIP, externalPort); + + const haProxyFqdn = Templates.renderFullyQualifiedHaProxyName(nodeAlias, namespace); + + //? Add service endpoints + nodeDataWrapper.addServiceEndpoint(haProxyFqdn, constants.GRPC_PORT); + } + configLines.push( `address, ${nodeSeq}, ${nodeSeq}, ${nodeAlias}, ${nodeStakeAmount}, ${internalIP}, ${internalPort}, ${externalIP}, ${externalPort}, ${account}`, ); @@ -519,7 +551,7 @@ export class ProfileManager { fs.writeFileSync(configFilePath, configLines.join('\n')); return configFilePath; - } catch (e: Error | any) { + } catch (e: Error | unknown) { throw new SoloError('failed to generate config.txt', e); } } diff --git a/src/core/templates.ts b/src/core/templates.ts index 17a65eab0..a4274bd59 100644 --- a/src/core/templates.ts +++ b/src/core/templates.ts @@ -23,7 +23,7 @@ import {type AccountId} from '@hashgraph/sdk'; import type {IP, NodeAlias, NodeId, PodName} from '../types/aliases.js'; import {GrpcProxyTlsEnums} from './enumerations.js'; import {type ContextClusterStructure} from '../types/config_types.js'; -import type {Cluster, Context} from './config/remote/types.js'; +import type {Cluster, Context, Namespace} from './config/remote/types.js'; export class Templates { public static renderNetworkPodName(nodeAlias: NodeAlias): PodName { @@ -263,6 +263,10 @@ export class Templates { return `haproxy-${nodeAlias}`; } + public static renderFullyQualifiedHaProxyName(nodeAlias: NodeAlias, namespace: Namespace): string { + return `${Templates.renderHaProxyName(nodeAlias)}-svc.${namespace}.svc.cluster.local`; + } + public static parseNodeAliasToIpMapping(unparsed: string): Record { const mapping: Record = {}; diff --git a/src/types/aliases.ts b/src/types/aliases.ts index 40c6337f0..a4cfffe7d 100644 --- a/src/types/aliases.ts +++ b/src/types/aliases.ts @@ -39,6 +39,16 @@ export type TaskFunction = ( export type ConfigBuilder = (argv, ctx, task, shouldLoadNodeClient?) => Promise; +export type Nullable = T | null; + export type IP = string; +export type JsonString = string; + +export type Path = string; +export type FilePath = string; +export type DirPath = string; + +export type AnyObject = Record; + export type SdkNetworkEndpoint = `${string}:${number}`; diff --git a/src/types/index.ts b/src/types/index.ts index 655a49334..be22a2a13 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -18,7 +18,9 @@ import type * as x509 from '@peculiar/x509'; import type net from 'net'; import type * as WebSocket from 'ws'; import type crypto from 'crypto'; -import type {ListrTask} from 'listr2'; +import type {ListrTask, ListrTaskWrapper} from 'listr2'; +import type {AccountId, PublicKey} from '@hashgraph/sdk'; +import type {JsonString} from './aliases.js'; // NOTE: DO NOT add any Solo imports in this file to avoid circular dependencies @@ -77,6 +79,39 @@ export interface ToObject { toObject(): T; } +/** + * Interface for converting class to JSON string. + */ +export interface ToJSON { + /** + * Converts the class instance to a plain JSON string. + * + * @returns the plain JSON string of the class. + */ + toJSON(): JsonString; +} + export type SoloListrTask = ListrTask; export type EmptyContextConfig = object; + +export type SoloListrTaskWrapper = ListrTaskWrapper; + +export interface ServiceEndpoint { + ipAddressV4?: string; + port: number; + domainName: string; +} + +export interface GenesisNetworkNodeStructure { + nodeId: number; + accountId: AccountId; + description: string; + gossipEndpoint: ServiceEndpoint[]; + serviceEndpoint: ServiceEndpoint[]; + gossipCaCertificate: string; + grpcCertificateHash: string; + weight: number; + deleted: boolean; + adminKey: PublicKey; +} diff --git a/test/data/local-config.yaml b/test/data/local-config.yaml index fdac33ca3..ad1342c1f 100644 --- a/test/data/local-config.yaml +++ b/test/data/local-config.yaml @@ -6,4 +6,4 @@ deployments: currentDeploymentName: deployment-1 clusterContextMapping: cluster-1: context-1 - cluster-2: context-2 \ No newline at end of file + cluster-2: context-2 diff --git a/test/unit/commands/network.test.ts b/test/unit/commands/network.test.ts index 86fea8b34..57a0988c7 100644 --- a/test/unit/commands/network.test.ts +++ b/test/unit/commands/network.test.ts @@ -40,6 +40,7 @@ import {ProfileManager} from '../../../src/core/profile_manager.js'; import {KeyManager} from '../../../src/core/key_manager.js'; import {ROOT_DIR} from '../../../src/core/constants.js'; import {ListrLease} from '../../../src/core/lease/listr_lease.js'; +import {GenesisNetworkDataConstructor} from '../../../src/core/genesis_network_models/genesis_network_data_constructor.js'; const getBaseCommandOpts = () => ({ logger: sinon.stub(), @@ -112,6 +113,8 @@ describe('NetworkCommand unit tests', () => { opts.configManager = new ConfigManager(opts.logger); opts.leaseManager = new LeaseManager(opts.k8, opts.configManager, opts.logger, new IntervalLeaseRenewalService()); opts.leaseManager.currentNamespace = sinon.stub().returns(testName); + + GenesisNetworkDataConstructor.initialize = sinon.stub().returns(null); }); it('Install function is called with expected parameters', async () => { diff --git a/tsconfig.json b/tsconfig.json index ec1fa8b60..5832eae0a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "./tsconfig-google.json", "compilerOptions": { + "isolatedModules": true, "target": "ES2022", "lib": [ "ES2022", From 6efa74bc11eb839173afe0e592b75aca3078ec4b Mon Sep 17 00:00:00 2001 From: Jeromy Cannon Date: Mon, 23 Dec 2024 13:49:38 +0000 Subject: [PATCH 2/9] removed unused imports Signed-off-by: Jeromy Cannon --- src/commands/node/tasks.ts | 1 - version.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/commands/node/tasks.ts b/src/commands/node/tasks.ts index e0cbf0f19..983d36ba9 100644 --- a/src/commands/node/tasks.ts +++ b/src/commands/node/tasks.ts @@ -31,7 +31,6 @@ import { FREEZE_ADMIN_ACCOUNT, HEDERA_NODE_DEFAULT_STAKE_AMOUNT, IGNORED_NODE_ACCOUNT_ID, - LOCAL_HOST, TREASURY_ACCOUNT_ID, } from '../../core/constants.js'; import { diff --git a/version.ts b/version.ts index 2f408860f..fb867b700 100644 --- a/version.ts +++ b/version.ts @@ -19,7 +19,6 @@ * This file should only contain versions for dependencies */ -export const JAVA_VERSION = '21.0.1+12'; export const HELM_VERSION = 'v3.14.2'; export const SOLO_CHART_VERSION = '0.38.2'; export const HEDERA_PLATFORM_VERSION = 'v0.58.0'; From 379eff5de370523c35ecf1e9763456fe8c3c41e9 Mon Sep 17 00:00:00 2001 From: Jeromy Cannon Date: Mon, 23 Dec 2024 14:11:07 +0000 Subject: [PATCH 3/9] upgrade all files to v0.58.0 which is required for genesis-network.json Signed-off-by: Jeromy Cannon --- .github/workflows/zxc-e2e-test.yaml | 2 +- Taskfile.yml | 2 +- examples/custom-network-config/Taskfile.yml | 2 +- examples/performance-tuning/Latitude/Taskfile.yml | 2 +- examples/performance-tuning/solo-perf-test/Taskfile.yml | 2 +- examples/solo-gke-test/Taskfile.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/zxc-e2e-test.yaml b/.github/workflows/zxc-e2e-test.yaml index 3bf1b57f6..eb064a635 100644 --- a/.github/workflows/zxc-e2e-test.yaml +++ b/.github/workflows/zxc-e2e-test.yaml @@ -167,7 +167,7 @@ jobs: if: ${{ runner.os == 'linux' && (inputs.npm-test-script == 'test-e2e-node-local-hedera' || inputs.npm-test-script == 'test-e2e-node-local-ptt' || inputs.npm-test-script == 'test-e2e-node-add-local') && !cancelled() && !failure() }} run: | cd .. - git clone https://github.com/hashgraph/hedera-services.git --depth 1 --branch v0.57.3 + git clone https://github.com/hashgraph/hedera-services.git --depth 1 --branch v0.58.0 cd hedera-services ls -ltr ${{ env.CG_EXEC }} ./gradlew assemble --stacktrace --info diff --git a/Taskfile.yml b/Taskfile.yml index 37a255a69..342ebaca4 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -7,7 +7,7 @@ env: SOLO_NETWORK_SIZE: 2 SOLO_NAMESPACE: solo-e2e SOLO_CHART_VERSION: 0.36.3 - CONSENSUS_NODE_VERSION: v0.57.3 + CONSENSUS_NODE_VERSION: v0.58.0 vars: use_port_forwards: "true" diff --git a/examples/custom-network-config/Taskfile.yml b/examples/custom-network-config/Taskfile.yml index bfe97d02e..51aa756f1 100644 --- a/examples/custom-network-config/Taskfile.yml +++ b/examples/custom-network-config/Taskfile.yml @@ -7,7 +7,7 @@ env: SOLO_NETWORK_SIZE: 10 SOLO_NAMESPACE: solo-alex-kuzmin-n4 SOLO_CHART_VERSION: 0.36.3 - CONSENSUS_NODE_VERSION: v0.57.3 + CONSENSUS_NODE_VERSION: v0.58.0 VALUES_FLAG: "--values-file {{.USER_WORKING_DIR}}/init-containers-values.yaml" SETTINGS_FLAG: "--settings-txt {{.USER_WORKING_DIR}}/settings.txt" SOLO_HOME: "/Users/user/.solo-alex-kuzmin-n4" diff --git a/examples/performance-tuning/Latitude/Taskfile.yml b/examples/performance-tuning/Latitude/Taskfile.yml index a82e80d68..f22c7fca7 100644 --- a/examples/performance-tuning/Latitude/Taskfile.yml +++ b/examples/performance-tuning/Latitude/Taskfile.yml @@ -7,7 +7,7 @@ env: SOLO_NETWORK_SIZE: 10 SOLO_NAMESPACE: solo-perf-lat SOLO_CHART_VERSION: 0.36.3 - CONSENSUS_NODE_VERSION: v0.57.3 + CONSENSUS_NODE_VERSION: v0.58.0 VALUES_FLAG: "--values-file {{.USER_WORKING_DIR}}/init-containers-values.yaml" SETTINGS_FLAG: "--settings-txt {{.USER_WORKING_DIR}}/settings.txt" SOLO_HOME: "/Users/user/.solo-perf-lat" diff --git a/examples/performance-tuning/solo-perf-test/Taskfile.yml b/examples/performance-tuning/solo-perf-test/Taskfile.yml index ff2901e3c..3961c47ff 100644 --- a/examples/performance-tuning/solo-perf-test/Taskfile.yml +++ b/examples/performance-tuning/solo-perf-test/Taskfile.yml @@ -7,7 +7,7 @@ env: SOLO_NETWORK_SIZE: 7 SOLO_NAMESPACE: solo-perf-test SOLO_CHART_VERSION: 0.36.3 - CONSENSUS_NODE_VERSION: v0.57.3 + CONSENSUS_NODE_VERSION: v0.58.0 VALUES_FLAG: "--values-file {{.USER_WORKING_DIR}}/init-containers-values.yaml" SETTINGS_FLAG: "--settings-txt {{.USER_WORKING_DIR}}/settings.txt" SOLO_HOME: "/Users/user/.solo-perf-test" diff --git a/examples/solo-gke-test/Taskfile.yml b/examples/solo-gke-test/Taskfile.yml index be3496025..6be48f5c1 100644 --- a/examples/solo-gke-test/Taskfile.yml +++ b/examples/solo-gke-test/Taskfile.yml @@ -9,7 +9,7 @@ env: SOLO_NETWORK_SIZE: 5 SOLO_NAMESPACE: solo-gke-test SOLO_CHART_VERSION: 0.36.3 - CONSENSUS_NODE_VERSION: v0.57.3 + CONSENSUS_NODE_VERSION: v0.58.0 VALUES_FLAG: "--values-file {{.USER_WORKING_DIR}}/init-containers-values.yaml" SETTINGS_FLAG: "--settings-txt {{.USER_WORKING_DIR}}/settings.txt" SOLO_HOME: "{{.solo_home_override_dir}}" From 97b58e389336ca99ad1f56af6cf912a6b2f4b0c3 Mon Sep 17 00:00:00 2001 From: Jeromy Cannon Date: Mon, 23 Dec 2024 16:53:58 +0000 Subject: [PATCH 4/9] previously deleted, rebase issue Signed-off-by: Jeromy Cannon --- examples/performance-tuning/README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 examples/performance-tuning/README.md diff --git a/examples/performance-tuning/README.md b/examples/performance-tuning/README.md deleted file mode 100644 index e69de29bb..000000000 From e6b1597b6bdd59468b0c75ca8d791deca780b58d Mon Sep 17 00:00:00 2001 From: Jeromy Cannon Date: Mon, 23 Dec 2024 16:54:09 +0000 Subject: [PATCH 5/9] rebase issue Signed-off-by: Jeromy Cannon --- src/commands/flags.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/commands/flags.ts b/src/commands/flags.ts index 485278a50..3608799f0 100644 --- a/src/commands/flags.ts +++ b/src/commands/flags.ts @@ -1645,7 +1645,6 @@ export class Flags { Flags.envoyIps, Flags.generateEcdsaKey, Flags.generateGossipKeys, - Flags.generateEcdsaKey, Flags.generateTlsKeys, Flags.gossipEndpoints, Flags.gossipPrivateKey, @@ -1666,7 +1665,6 @@ export class Flags { Flags.namespace, Flags.newAccountNumber, Flags.newAdminKey, - Flags.createAmount, Flags.nodeAlias, Flags.nodeAliasesUnparsed, Flags.operatorId, From ffc773de38f7a8842b16ca8089f90a3a5160a40f Mon Sep 17 00:00:00 2001 From: Jeromy Cannon Date: Mon, 23 Dec 2024 16:54:25 +0000 Subject: [PATCH 6/9] disable block streams to avoid running out of disk space Signed-off-by: Jeromy Cannon --- resources/templates/application.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/templates/application.properties b/resources/templates/application.properties index ae8714f90..213d33929 100644 --- a/resources/templates/application.properties +++ b/resources/templates/application.properties @@ -14,4 +14,4 @@ hedera.profiles.active=TEST # TODO: this is a workaround until prepareUpgrade freeze will recalculate the weight prior to writing the config.txt staking.periodMins=1 nodes.updateAccountIdAllowed=true - +blockStream.streamMode=RECORDS From f5050fd3f3f65dae23a62a4320a5c59fb1feac22 Mon Sep 17 00:00:00 2001 From: Jeromy Cannon Date: Mon, 23 Dec 2024 17:05:59 +0000 Subject: [PATCH 7/9] added todo for re-enabling block streams Signed-off-by: Jeromy Cannon --- resources/templates/application.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/templates/application.properties b/resources/templates/application.properties index 213d33929..aa70f28fb 100644 --- a/resources/templates/application.properties +++ b/resources/templates/application.properties @@ -14,4 +14,5 @@ hedera.profiles.active=TEST # TODO: this is a workaround until prepareUpgrade freeze will recalculate the weight prior to writing the config.txt staking.periodMins=1 nodes.updateAccountIdAllowed=true +# TODO: remove once we have the uploader enabled, required for current p0 deadline blockStream.streamMode=RECORDS From 70137f49f6ac436f4ef08e0dd1ba2f2fe43aa8e9 Mon Sep 17 00:00:00 2001 From: Jeromy Cannon Date: Mon, 23 Dec 2024 17:22:44 +0000 Subject: [PATCH 8/9] remove testSocketConnection calls Signed-off-by: Jeromy Cannon --- src/core/account_manager.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/core/account_manager.ts b/src/core/account_manager.ts index d760471cc..4af1b9987 100644 --- a/src/core/account_manager.ts +++ b/src/core/account_manager.ts @@ -294,7 +294,6 @@ export class AccountManager { const host = networkNodeService.haProxyLoadBalancerIp as string; const targetPort = port; try { - await this.k8.testSocketConnection(host, targetPort); obj[`${host}:${targetPort}`] = accountId; await this.pingNetworkNode(obj, accountId); this.logger.debug(`using load balancer IP: ${host}:${targetPort}`); @@ -312,8 +311,6 @@ export class AccountManager { this._portForwards.push(await this.k8.portForward(networkNodeService.haProxyPodName, localPort, port)); } - await this.k8.testSocketConnection(host, targetPort); - this.logger.debug(`using local host port forward: ${host}:${targetPort}`); obj[`${host}:${targetPort}`] = accountId; From 4e7ad7e942514099e628252c56561e865c83bcc1 Mon Sep 17 00:00:00 2001 From: Jeromy Cannon Date: Mon, 23 Dec 2024 17:23:06 +0000 Subject: [PATCH 9/9] remove circular dependency Signed-off-by: Jeromy Cannon --- .madgerc | 7 ---- src/commands/node/configs.ts | 41 +------------------ src/commands/node/node_add_config.ts | 59 ++++++++++++++++++++++++++++ src/commands/node/tasks.ts | 8 +--- src/core/helpers.ts | 2 +- 5 files changed, 63 insertions(+), 54 deletions(-) delete mode 100644 .madgerc create mode 100644 src/commands/node/node_add_config.ts diff --git a/.madgerc b/.madgerc deleted file mode 100644 index b407c6b4b..000000000 --- a/.madgerc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "detectiveOptions": { - "ts": { - "skipTypeImports": true - } - } -} diff --git a/src/commands/node/configs.ts b/src/commands/node/configs.ts index 9c924f113..105dacd5d 100644 --- a/src/commands/node/configs.ts +++ b/src/commands/node/configs.ts @@ -26,6 +26,7 @@ import {validatePath} from '../../core/helpers.js'; import {Flags as flags} from '../flags.js'; import type {NodeAlias, NodeAliases, PodName} from '../../types/aliases.js'; import type {NetworkNodeServices} from '../../core/network_node_services.js'; +import {type NodeAddConfigClass} from './node_add_config.js'; export const PREPARE_UPGRADE_CONFIGS_NAME = 'prepareUpgradeConfig'; export const DOWNLOAD_GENERATED_FILES_CONFIGS_NAME = 'downloadGeneratedFilesConfig'; @@ -357,46 +358,6 @@ export interface NodeStartConfigClass { nodeAliasesUnparsed: string; } -export interface NodeAddConfigClass { - app: string; - cacheDir: string; - chainId: string; - chartDirectory: string; - devMode: boolean; - debugNodeAlias: NodeAlias; - endpointType: string; - soloChartVersion: string; - generateGossipKeys: boolean; - generateTlsKeys: boolean; - gossipEndpoints: string; - grpcEndpoints: string; - localBuildPath: string; - namespace: string; - nodeAlias: NodeAlias; - releaseTag: string; - adminKey: PrivateKey; - allNodeAliases: NodeAliases; - chartPath: string; - curDate: Date; - existingNodeAliases: NodeAliases; - freezeAdminPrivateKey: string; - keysDir: string; - lastStateZipPath: string; - nodeClient: any; - podNames: Record; - serviceMap: Map; - treasuryKey: PrivateKey; - stagingDir: string; - stagingKeysDir: string; - grpcTlsCertificatePath: string; - grpcWebTlsCertificatePath: string; - grpcTlsKeyPath: string; - grpcWebTlsKeyPath: string; - haproxyIps: string; - envoyIps: string; - getUnusedConfigs: () => string[]; -} - export interface NodeDeleteConfigClass { app: string; cacheDir: string; diff --git a/src/commands/node/node_add_config.ts b/src/commands/node/node_add_config.ts new file mode 100644 index 000000000..f5129c909 --- /dev/null +++ b/src/commands/node/node_add_config.ts @@ -0,0 +1,59 @@ +/** + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the ""License""); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an ""AS IS"" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import type {NodeAlias, NodeAliases, PodName} from '../../types/aliases.js'; +import type {NetworkNodeServices} from '../../core/network_node_services.js'; +import {type PrivateKey} from '@hashgraph/sdk'; + +export interface NodeAddConfigClass { + app: string; + cacheDir: string; + chainId: string; + chartDirectory: string; + devMode: boolean; + debugNodeAlias: NodeAlias; + endpointType: string; + soloChartVersion: string; + generateGossipKeys: boolean; + generateTlsKeys: boolean; + gossipEndpoints: string; + grpcEndpoints: string; + localBuildPath: string; + namespace: string; + nodeAlias: NodeAlias; + releaseTag: string; + adminKey: PrivateKey; + allNodeAliases: NodeAliases; + chartPath: string; + curDate: Date; + existingNodeAliases: NodeAliases; + freezeAdminPrivateKey: string; + keysDir: string; + lastStateZipPath: string; + nodeClient: any; + podNames: Record; + serviceMap: Map; + treasuryKey: PrivateKey; + stagingDir: string; + stagingKeysDir: string; + grpcTlsCertificatePath: string; + grpcWebTlsCertificatePath: string; + grpcTlsKeyPath: string; + grpcWebTlsKeyPath: string; + haproxyIps: string; + envoyIps: string; + getUnusedConfigs: () => string[]; +} diff --git a/src/commands/node/tasks.ts b/src/commands/node/tasks.ts index 983d36ba9..482dbca28 100644 --- a/src/commands/node/tasks.ts +++ b/src/commands/node/tasks.ts @@ -74,16 +74,12 @@ import { } from '../../types/aliases.js'; import {NodeStatusCodes, NodeStatusEnums, NodeSubcommandType} from '../../core/enumerations.js'; import * as x509 from '@peculiar/x509'; -import type { - NodeAddConfigClass, - NodeDeleteConfigClass, - NodeRefreshConfigClass, - NodeUpdateConfigClass, -} from './configs.js'; +import type {NodeDeleteConfigClass, NodeRefreshConfigClass, NodeUpdateConfigClass} from './configs.js'; import {type Lease} from '../../core/lease/lease.js'; import {ListrLease} from '../../core/lease/listr_lease.js'; import {Duration} from '../../core/time/duration.js'; import {type BaseCommand} from '../base.js'; +import {type NodeAddConfigClass} from './node_add_config.js'; export class NodeCommandTasks { private readonly accountManager: AccountManager; diff --git a/src/core/helpers.ts b/src/core/helpers.ts index 889fb56ee..ca9329195 100644 --- a/src/core/helpers.ts +++ b/src/core/helpers.ts @@ -27,7 +27,7 @@ import {type NodeAlias, type NodeAliases} from '../types/aliases.js'; import {type CommandFlag} from '../types/flag_types.js'; import {type SoloLogger} from './logging.js'; import {type Duration} from './time/duration.js'; -import {type NodeAddConfigClass} from '../commands/node/configs.js'; +import {type NodeAddConfigClass} from '../commands/node/node_add_config.js'; export function sleep(duration: Duration) { return new Promise(resolve => {