Skip to content

Commit

Permalink
moved generate network json to node setup, updated nodeId to do the -…
Browse files Browse the repository at this point in the history
…1 inside the template function, add nodeid into network service map

Signed-off-by: Jeromy Cannon <[email protected]>
  • Loading branch information
jeromy-cannon committed Jan 7, 2025
1 parent 0766b0f commit 214fe28
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 81 deletions.
12 changes: 12 additions & 0 deletions src/commands/flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1619,6 +1619,17 @@ export class Flags {
prompt: undefined,
};

static readonly loadBalancerEnabled: CommandFlag = {
constName: 'loadBalancerEnabled',
name: 'load-balancer',
definition: {
describe: 'Enable load balancer for network node proxies',
defaultValue: false,
type: 'boolean',
},
prompt: undefined,
};

static readonly allFlags: CommandFlag[] = [
Flags.accountId,
Flags.amount,
Expand Down Expand Up @@ -1671,6 +1682,7 @@ export class Flags {
Flags.hederaExplorerTlsLoadBalancerIp,
Flags.hederaExplorerVersion,
Flags.inputDir,
Flags.loadBalancerEnabled,
Flags.localBuildPath,
Flags.log4j2Xml,
Flags.mirrorNodeVersion,
Expand Down
24 changes: 10 additions & 14 deletions src/commands/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ 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;
cacheDir: string;
chartDirectory: string;
enablePrometheusSvcMonitor: boolean;
loadBalancerEnabled: boolean;
soloChartVersion: string;
namespace: string;
nodeAliasesUnparsed: string;
Expand All @@ -62,7 +62,6 @@ export interface NetworkDeployConfigClass {
grpcWebTlsCertificatePath: string;
grpcTlsKeyPath: string;
grpcWebTlsKeyPath: string;
genesisNetworkData: GenesisNetworkDataConstructor;
genesisThrottlesFile: string;
resolvedThrottlesFile: string;
getUnusedConfigs: () => string[];
Expand Down Expand Up @@ -116,6 +115,7 @@ export class NetworkCommand extends BaseCommand {
flags.enablePrometheusSvcMonitor,
flags.soloChartVersion,
flags.debugNodeAlias,
flags.loadBalancerEnabled,
flags.log4j2Xml,
flags.namespace,
flags.nodeAliasesUnparsed,
Expand Down Expand Up @@ -146,8 +146,8 @@ export class NetworkCommand extends BaseCommand {
valuesFile?: string;
haproxyIpsParsed?: Record<NodeAlias, IP>;
envoyIpsParsed?: Record<NodeAlias, IP>;
genesisNetworkData: GenesisNetworkDataConstructor;
resolvedThrottlesFile: string;
loadBalancerEnabled: boolean;
}) {
let valuesArg = config.chartDirectory
? `-f ${path.join(config.chartDirectory, 'solo-deployment', 'values.yaml')}`
Expand All @@ -165,15 +165,11 @@ export class NetworkCommand extends BaseCommand {
}

const profileName = this.configManager.getFlag<string>(flags.profileName) as string;
this.profileValuesFile = await this.profileManager.prepareValuesForSoloChart(
profileName,
config.genesisNetworkData,
);
this.profileValuesFile = await this.profileManager.prepareValuesForSoloChart(profileName);
if (this.profileValuesFile) {
valuesArg += this.prepareValuesFiles(this.profileValuesFile);
}

// do not deploy mirror node until after we have the updated address book
valuesArg += ` --set "telemetry.prometheus.svcMonitor.enabled=${config.enablePrometheusSvcMonitor}"`;

valuesArg += ` --set "defaults.volumeClaims.enabled=${config.persistentVolumeClaims}"`;
Expand All @@ -200,6 +196,11 @@ export class NetworkCommand extends BaseCommand {
valuesArg += ` --set-file "hedera.configMaps.genesisThrottlesJson=${config.resolvedThrottlesFile}"`;
}

if (config.loadBalancerEnabled) {
valuesArg += ' --set "defaults.haproxy.serviceType=LoadBalancer"';
valuesArg += ' --set "defaults.envoyProxy.serviceType=LoadBalancer"';
}

if (config.valuesFile) {
valuesArg += this.prepareValuesFiles(config.valuesFile);
}
Expand All @@ -224,6 +225,7 @@ export class NetworkCommand extends BaseCommand {
flags.chainId,
flags.chartDirectory,
flags.debugNodeAlias,
flags.loadBalancerEnabled,
flags.log4j2Xml,
flags.persistentVolumeClaims,
flags.profileName,
Expand Down Expand Up @@ -272,12 +274,6 @@ export class NetworkCommand extends BaseCommand {
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.resolvedThrottlesFile = resolveValidJsonFilePath(
config.genesisThrottlesFile,
flags.genesisThrottlesFile.definition.defaultValue as string,
Expand Down
45 changes: 31 additions & 14 deletions src/commands/node/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ import {type ChartManager} from '../../core/chart_manager.js';
import {type CertificateManager} from '../../core/certificate_manager.js';
import {Zippy} from '../../core/zippy.js';
import * as constants from '../../core/constants.js';
import {Templates} from '../../core/templates.js';
import {Task} from '../../core/task.js';
import {
DEFAULT_NETWORK_NODE_NAME,
FREEZE_ADMIN_ACCOUNT,
HEDERA_NODE_DEFAULT_STAKE_AMOUNT,
IGNORED_NODE_ACCOUNT_ID,
TREASURY_ACCOUNT_ID,
} from '../../core/constants.js';
import {Templates} from '../../core/templates.js';
import {Task} from '../../core/task.js';
import {
AccountBalanceQuery,
AccountId,
Expand All @@ -42,10 +42,10 @@ import {
FreezeTransaction,
FreezeType,
Long,
PrivateKey,
NodeCreateTransaction,
NodeDeleteTransaction,
NodeUpdateTransaction,
PrivateKey,
Timestamp,
} from '@hashgraph/sdk';
import {IllegalArgumentError, MissingArgumentError, SoloError} from '../../core/errors.js';
Expand All @@ -68,7 +68,6 @@ import {
type ConfigBuilder,
type NodeAlias,
type NodeAliases,
type NodeId,
type PodName,
type SkipCheck,
} from '../../types/aliases.js';
Expand All @@ -79,6 +78,7 @@ 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';
import {GenesisNetworkDataConstructor} from '../../core/genesis_network_models/genesis_network_data_constructor.js';

export class NodeCommandTasks {
private readonly accountManager: AccountManager;
Expand Down Expand Up @@ -542,7 +542,7 @@ export class NodeCommandTasks {
// Create the transaction
const transaction = new AccountUpdateTransaction()
.setAccountId(accountId)
.setStakedNodeId(Templates.nodeIdFromNodeAlias(nodeAlias) - 1)
.setStakedNodeId(Templates.nodeIdFromNodeAlias(nodeAlias))
.freezeWith(client);

// Sign the transaction with the account's private key
Expand Down Expand Up @@ -871,13 +871,26 @@ export class NodeCommandTasks {
}

setupNetworkNodes(nodeAliasesProperty: string) {
return new Task('Setup network nodes', (ctx: any, task: ListrTaskWrapper<any, any, any>) => {
return new Task('Setup network nodes', async (ctx: any, task: ListrTaskWrapper<any, any, any>) => {
// TODO extract method
const networkNodeServiceMap = await this.accountManager.getNodeServiceMap(ctx.config.namespace);

const genesisNetworkData = await GenesisNetworkDataConstructor.initialize(
ctx.config.nodeAliases,
this.keyManager,
ctx.config.keysDir,
networkNodeServiceMap,
);

const genesisNetworkJson = path.join(ctx.config.stagingDir, 'genesis-network.json');

Check warning on line 885 in src/commands/node/tasks.ts

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/commands/node/tasks.ts#L885

Detected possible user input going into a `path.join` or `path.resolve` function.
fs.writeFileSync(genesisNetworkJson, genesisNetworkData.toJSON());

Check warning on line 886 in src/commands/node/tasks.ts

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/commands/node/tasks.ts#L886

The application dynamically constructs file or path information.

const subTasks = [];
for (const nodeAlias of ctx.config[nodeAliasesProperty]) {
const podName = ctx.config.podNames[nodeAlias];
subTasks.push({
title: `Node: ${chalk.yellow(nodeAlias)}`,
task: () => this.platformInstaller.taskSetup(podName),
task: () => this.platformInstaller.taskSetup(podName, ctx.config.stagingDir),
});
}

Expand Down Expand Up @@ -1287,7 +1300,7 @@ export class NodeCommandTasks {
return new Task('Send node update transaction', async (ctx: any, task: ListrTaskWrapper<any, any, any>) => {
const config: NodeUpdateConfigClass = ctx.config;

const nodeId = Templates.nodeIdFromNodeAlias(config.nodeAlias) - 1;
const nodeId = Templates.nodeIdFromNodeAlias(config.nodeAlias);
self.logger.info(`nodeId: ${nodeId}, config.newAccountNumber: ${config.newAccountNumber}`);

if (config.existingNodeAliases.length > 1) {
Expand Down Expand Up @@ -1373,14 +1386,19 @@ export class NodeCommandTasks {
}

const index = config.existingNodeAliases.length;
const nodeId = Templates.nodeIdFromNodeAlias(config.nodeAlias) - 1;
let maxNodeId = 0;
for (const nodeAlias of config.existingNodeAliases) {
const nodeId = config.serviceMap.get(nodeAlias).nodeId;
maxNodeId = Math.max(nodeId, maxNodeId);
}
const nodeId = maxNodeId + 1;

let valuesArg = '';
for (let i = 0; i < index; i++) {
if (transactionType === NodeSubcommandType.UPDATE && config.newAccountNumber && i === nodeId) {
// for the case of updating node
// use new account number for this node id
valuesArg += ` --set "hedera.nodes[${i}].accountId=${config.newAccountNumber}" --set "hedera.nodes[${i}].name=${config.existingNodeAliases[i]}"`;
valuesArg += ` --set "hedera.nodes[${i}].accountId=${config.newAccountNumber}" --set "hedera.nodes[${i}].name=${config.existingNodeAliases[i]}"--set "hedera.nodes[${i}].node-id=${nodeId}" `;
} else if (transactionType !== NodeSubcommandType.DELETE || i !== nodeId) {
// for the case of deleting node
valuesArg += ` --set "hedera.nodes[${i}].accountId=${config.serviceMap.get(config.existingNodeAliases[i]).accountId}" --set "hedera.nodes[${i}].name=${config.existingNodeAliases[i]}"`;
Expand All @@ -1402,8 +1420,7 @@ export class NodeCommandTasks {
}

const nodeAlias: NodeAlias = config.nodeAlias;
const nodeId: NodeId = Templates.nodeIdFromNodeAlias(nodeAlias);
const nodeIndexInValues = nodeId - 1;
const nodeIndexInValues = Templates.nodeIdFromNodeAlias(nodeAlias);

// Set static IPs for HAProxy
if (config.haproxyIpsParsed) {
Expand Down Expand Up @@ -1564,7 +1581,7 @@ export class NodeCommandTasks {
async (ctx: any, task: ListrTaskWrapper<any, any, any>) => {
const config = ctx.config;
const newNodeFullyQualifiedPodName = Templates.renderNetworkPodName(config.nodeAlias);
const nodeId = Templates.nodeIdFromNodeAlias(config.nodeAlias) - 1;
const nodeId = Templates.nodeIdFromNodeAlias(config.nodeAlias);
const savedStateDir = config.lastStateZipPath.match(/\/(\d+)\.zip$/)[1];
const savedStatePath = `${constants.HEDERA_HAPI_PATH}/data/saved/com.hedera.services.ServicesMain/${nodeId}/123/${savedStateDir}`;
await this.k8.execContainer(newNodeFullyQualifiedPodName, constants.ROOT_CONTAINER, [
Expand Down Expand Up @@ -1596,7 +1613,7 @@ export class NodeCommandTasks {
const accountMap = getNodeAccountMap(config.existingNodeAliases);
const deleteAccountId = accountMap.get(config.nodeAlias);
this.logger.debug(`Deleting node: ${config.nodeAlias} with account: ${deleteAccountId}`);
const nodeId = Templates.nodeIdFromNodeAlias(config.nodeAlias) - 1;
const nodeId = Templates.nodeIdFromNodeAlias(config.nodeAlias);
const nodeDeleteTx = new NodeDeleteTransaction().setNodeId(nodeId).freezeWith(config.nodeClient);

const signedTx = await nodeDeleteTx.sign(config.adminKey);
Expand Down
14 changes: 9 additions & 5 deletions src/core/account_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,15 +390,18 @@ export class AccountManager {

// retrieve the list of services and build custom objects for the attributes we need
for (const service of serviceList.body.items) {
const serviceType = service.metadata.labels['solo.hedera.com/type'];
let serviceBuilder = new NetworkNodeServicesBuilder(
service.metadata.labels['solo.hedera.com/node-name'] as NodeAlias,
);
let serviceBuilder: NetworkNodeServicesBuilder;

if (serviceBuilderMap.has(serviceBuilder.key())) {
serviceBuilder = serviceBuilderMap.get(serviceBuilder.key()) as NetworkNodeServicesBuilder;
} else {
serviceBuilder = new NetworkNodeServicesBuilder(
service.metadata.labels['solo.hedera.com/node-name'] as NodeAlias,
);
serviceBuilder.withNamespace(namespace);
}

const serviceType = service.metadata.labels['solo.hedera.com/type'];
switch (serviceType) {
// solo.hedera.com/type: envoy-proxy-svc
case 'envoy-proxy-svc':
Expand All @@ -413,7 +416,6 @@ export class AccountManager {
// solo.hedera.com/type: haproxy-svc
case 'haproxy-svc':
serviceBuilder
.withAccountId(service.metadata!.labels!['solo.hedera.com/account-id'])
.withHaProxyAppSelector(service.spec!.selector!.app)
.withHaProxyName(service.metadata!.name as string)
.withHaProxyClusterIp(service.spec!.clusterIP as string)
Expand All @@ -427,6 +429,8 @@ export class AccountManager {
// solo.hedera.com/type: network-node-svc
case 'network-node-svc':
serviceBuilder
.withNodeId(service.metadata!.labels!['solo.hedera.com/node-id'])
.withAccountId(service.metadata!.labels!['solo.hedera.com/account-id'])
.withNodeServiceName(service.metadata!.name as string)
.withNodeServiceClusterIp(service.spec!.clusterIP as string)
.withNodeServiceLoadBalancerIp(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*
*/
import {PrivateKey} from '@hashgraph/sdk';
import {AccountId, PrivateKey} from '@hashgraph/sdk';
import {GenesisNetworkNodeDataWrapper} from './genesis_network_node_data_wrapper.js';
import * as constants from '../constants.js';

Expand All @@ -24,6 +24,7 @@ import type {JsonString, NodeAlias, NodeAliases} from '../../types/aliases.js';
import {GenesisNetworkRosterEntryDataWrapper} from './genesis_network_roster_entry_data_wrapper.js';
import {Templates} from '../templates.js';
import path from 'path';
import type {NetworkNodeServices} from '../network_node_services.js';

/**
* Used to construct the nodes data and convert them to JSON
Expand All @@ -36,23 +37,45 @@ export class GenesisNetworkDataConstructor implements ToJSON {
private readonly nodeAliases: NodeAliases,
private readonly keyManager: KeyManager,
private readonly keysDir: string,
private readonly networkNodeServiceMap: Map<string, NetworkNodeServices>,
) {
nodeAliases.forEach((nodeAlias, nodeId) => {
// TODO: get nodeId from label in pod.
nodeAliases.forEach(nodeAlias => {
const adminPrivateKey = PrivateKey.fromStringED25519(constants.GENESIS_KEY);
const adminPubKey = adminPrivateKey.publicKey;

this.nodes[nodeAlias] = new GenesisNetworkNodeDataWrapper(nodeId, adminPubKey, nodeAlias);
this.rosters[nodeAlias] = new GenesisNetworkRosterEntryDataWrapper(nodeId);
const nodeDataWrapper = new GenesisNetworkNodeDataWrapper(
+networkNodeServiceMap.get(nodeAlias).nodeId,
adminPubKey,
nodeAlias,
);
this.nodes[nodeAlias] = nodeDataWrapper;
nodeDataWrapper.accountId = AccountId.fromString(networkNodeServiceMap.get(nodeAlias).accountId);

const rosterDataWrapper = new GenesisNetworkRosterEntryDataWrapper(+networkNodeServiceMap.get(nodeAlias).nodeId);
this.rosters[nodeAlias] = rosterDataWrapper;
rosterDataWrapper.weight = this.nodes[nodeAlias].weight = constants.HEDERA_NODE_DEFAULT_STAKE_AMOUNT;

const externalPort = +constants.HEDERA_NODE_EXTERNAL_GOSSIP_PORT;
const namespace = networkNodeServiceMap.get(nodeAlias).namespace;
const externalIP = Templates.renderFullyQualifiedNetworkSvcName(namespace, nodeAlias);
// Add gossip endpoints
nodeDataWrapper.addGossipEndpoint(externalIP, externalPort);
rosterDataWrapper.addGossipEndpoint(externalIP, externalPort);

const haProxyFqdn = Templates.renderFullyQualifiedHaProxyName(nodeAlias, namespace);

// Add service endpoints
nodeDataWrapper.addServiceEndpoint(haProxyFqdn, constants.GRPC_PORT);
});
}

public static async initialize(
nodeAliases: NodeAliases,
keyManager: KeyManager,
keysDir: string,
networkNodeServiceMap: Map<string, NetworkNodeServices>,
): Promise<GenesisNetworkDataConstructor> {
const instance = new GenesisNetworkDataConstructor(nodeAliases, keyManager, keysDir);
const instance = new GenesisNetworkDataConstructor(nodeAliases, keyManager, keysDir, networkNodeServiceMap);

await instance.load();

Expand Down
2 changes: 1 addition & 1 deletion src/core/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ export function renameAndCopyFile(srcFilePath: string, expectedBaseName: string,
*/
export function addDebugOptions(valuesArg: string, debugNodeAlias: NodeAlias, index = 0) {
if (debugNodeAlias) {
const nodeId = Templates.nodeIdFromNodeAlias(debugNodeAlias) - 1;
const nodeId = Templates.nodeIdFromNodeAlias(debugNodeAlias);
valuesArg += ` --set "hedera.nodes[${nodeId}].root.extraEnv[${index}].name=JAVA_OPTS"`;
valuesArg += ` --set "hedera.nodes[${nodeId}].root.extraEnv[${index}].value=-agentlib:jdwp=transport=dt_socket\\,server=y\\,suspend=y\\,address=*:${constants.JVM_DEBUG_PORT}"`;
}
Expand Down
Loading

0 comments on commit 214fe28

Please sign in to comment.