UNPKG

@hashgraph/solo

Version:

An opinionated CLI tool to deploy and manage private Hedera Networks.

263 lines 11.6 kB
// SPDX-License-Identifier: Apache-2.0 import fs from 'node:fs'; import * as constants from './constants.js'; import { PathEx } from '../business/utils/path-ex.js'; import yaml from 'yaml'; export class HelmValuesHelper { constructor() { } buildPerNodeExtraEnvironmentValuesStructure(consensusNodes, options = {}) { const hedera = { nodes: [] }; for (const [nodeIndex, consensusNode] of consensusNodes.entries()) { const extraEnvironmentVariables = [ ...(options.baseExtraEnvironmentVariables?.[consensusNode.name] ?? []), ]; if (options.useJavaMainClass) { this.setExtraEnvironmentVariable(extraEnvironmentVariables, 'JAVA_MAIN_CLASS', 'com.swirlds.platform.Browser'); } if (options.wrapsEnabled && options.tss) { const wrapPath = `${constants.HEDERA_HAPI_PATH}/${options.tss.wraps.artifactsFolderName}`; this.setExtraEnvironmentVariable(extraEnvironmentVariables, 'TSS_LIB_WRAPS_ARTIFACTS_PATH', wrapPath); } if (options.debugNodeAlias === consensusNode.name) { const debugJavaOptions = `-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:${constants.JVM_DEBUG_PORT}`; const javaOptionsIndex = extraEnvironmentVariables.findIndex((environmentVariable) => environmentVariable.name === 'JAVA_OPTS'); if (javaOptionsIndex === -1) { extraEnvironmentVariables.push({ name: 'JAVA_OPTS', value: debugJavaOptions, }); } else { extraEnvironmentVariables[javaOptionsIndex].value = `${debugJavaOptions} ${extraEnvironmentVariables[javaOptionsIndex].value}`.trim(); } } if (options.additionalEnvironmentVariables && options.additionalEnvironmentVariables[consensusNode.name]) { for (const additionalEnvironmentVariable of options.additionalEnvironmentVariables[consensusNode.name]) { this.setExtraEnvironmentVariable(extraEnvironmentVariables, additionalEnvironmentVariable.name, additionalEnvironmentVariable.value); } } const finalJavaOptionsIndex = extraEnvironmentVariables.findIndex((environmentVariable) => environmentVariable.name === 'JAVA_OPTS'); if (finalJavaOptionsIndex !== -1) { extraEnvironmentVariables[finalJavaOptionsIndex].value = this.sanitizeJavaOptionsForHeapSettings(extraEnvironmentVariables[finalJavaOptionsIndex].value); } while (hedera.nodes.length <= nodeIndex) { hedera.nodes.push({}); } const nodeValues = {}; if (extraEnvironmentVariables.length > 0) { nodeValues.root = { extraEnv: extraEnvironmentVariables }; } const additionalNodeValues = options.additionalNodeValues?.[consensusNode.name]; if (additionalNodeValues?.name) { nodeValues.name = additionalNodeValues.name; } if (typeof additionalNodeValues?.nodeId === 'number') { nodeValues.nodeId = additionalNodeValues.nodeId; } if (additionalNodeValues?.accountId) { nodeValues.accountId = additionalNodeValues.accountId; } if (additionalNodeValues?.blockNodesJson) { nodeValues.blockNodesJson = additionalNodeValues.blockNodesJson; } hedera.nodes[nodeIndex] = nodeValues; } return { hedera }; } generateExtraEnvironmentValuesFile(consensusNodes, options = {}, cacheDirectory) { const perNodeExtraEnvironmentValues = this.buildPerNodeExtraEnvironmentValuesStructure(consensusNodes, options); const filename = `per-node-extra-env-${Date.now()}-${Math.random().toString(36).slice(2)}.yaml`; const filePath = PathEx.join(cacheDirectory, filename); const yamlContent = yaml.stringify(perNodeExtraEnvironmentValues, { indent: 2 }); fs.writeFileSync(filePath, yamlContent); return filePath; } parseValuesFilePaths(valuesArgument) { const filePaths = []; const regex = /--values\s+"([^"]+)"|--values\s+(\S+)/g; let match; while ((match = regex.exec(valuesArgument)) !== null) { filePaths.push(match[1] ?? match[2]); } return filePaths; } parseValuesFile(filePath) { let content; try { content = fs.readFileSync(filePath, 'utf8'); } catch { return undefined; } let parsedValues; try { parsedValues = yaml.parse(content); } catch { return undefined; } if (!parsedValues || typeof parsedValues !== 'object') { return undefined; } return parsedValues; } readHederaNodes(valuesFilePath) { const parsedRecord = this.parseValuesFile(valuesFilePath); if (!parsedRecord) { return undefined; } const hederaSection = parsedRecord.hedera; if (!hederaSection || typeof hederaSection !== 'object') { return undefined; } const nodesArray = hederaSection.nodes; if (!Array.isArray(nodesArray)) { return undefined; } return nodesArray; } extractExtraEnvironmentFromValuesFiles(filePaths, consensusNodes) { const result = {}; for (const filePath of filePaths) { const parsedRecord = this.parseValuesFile(filePath); if (!parsedRecord) { continue; } const defaultsSection = parsedRecord.defaults; if (defaultsSection && typeof defaultsSection === 'object') { const defaultsRootSection = defaultsSection.root; const defaultsEnvironmentVariables = this.extractExtraEnvironmentArray(defaultsRootSection); if (defaultsEnvironmentVariables.length > 0) { for (const consensusNode of consensusNodes) { this.mergeIntoResult(result, consensusNode.name, defaultsEnvironmentVariables); } } } const hederaSection = parsedRecord.hedera; if (!hederaSection || typeof hederaSection !== 'object') { continue; } const nodesArray = hederaSection.nodes; if (!Array.isArray(nodesArray)) { continue; } for (const [helmNodeIndex, consensusNode] of consensusNodes.entries()) { const nodeEntry = nodesArray[helmNodeIndex]; if (!nodeEntry || typeof nodeEntry !== 'object') { continue; } const nodeRootSection = nodeEntry.root; const nodeEnvironmentVariables = this.extractExtraEnvironmentArray(nodeRootSection); if (nodeEnvironmentVariables.length > 0) { this.mergeIntoResult(result, consensusNode.name, nodeEnvironmentVariables); } } } return result; } extractPerNodeBlockNodesJsonFromValuesFile(valuesFilePath, consensusNodes) { const result = {}; const nodesArray = this.readHederaNodes(valuesFilePath); if (!nodesArray) { return result; } for (const [helmNodeIndex, consensusNode] of consensusNodes.entries()) { const nodeEntry = nodesArray[helmNodeIndex]; if (!nodeEntry || typeof nodeEntry !== 'object') { continue; } const blockNodesJson = nodeEntry.blockNodesJson; if (typeof blockNodesJson === 'string') { result[consensusNode.name] = blockNodesJson; } } return result; } extractPerNodeIdentityFromValuesFile(valuesFilePath, consensusNodes) { const result = {}; const nodesArray = this.readHederaNodes(valuesFilePath); if (!nodesArray) { return result; } for (const [helmNodeIndex, consensusNode] of consensusNodes.entries()) { const nodeEntry = nodesArray[helmNodeIndex]; if (!nodeEntry || typeof nodeEntry !== 'object') { continue; } const entry = nodeEntry; const identity = {}; if (typeof entry.name === 'string') { identity.name = entry.name; } if (typeof entry.nodeId === 'number') { identity.nodeId = entry.nodeId; } else if (typeof entry.nodeId === 'string') { const parsed = Number.parseInt(entry.nodeId, 10); if (!Number.isNaN(parsed)) { identity.nodeId = parsed; } } if (typeof entry.accountId === 'string') { identity.accountId = entry.accountId; } result[consensusNode.name] = identity; } return result; } sanitizeJavaOptionsForHeapSettings(javaOptions) { return javaOptions .replaceAll(/(^|\s)-Xms\s*\S+/g, '$1') .replaceAll(/(^|\s)-Xmx\s*\S+/g, '$1') .replaceAll(/\s+/g, ' ') .trim(); } setExtraEnvironmentVariable(extraEnvironmentVariables, name, value) { const environmentVariableIndex = extraEnvironmentVariables.findIndex((environmentVariable) => environmentVariable.name === name); if (environmentVariableIndex === -1) { extraEnvironmentVariables.push({ name, value }); } else { extraEnvironmentVariables[environmentVariableIndex].value = value; } } mergeIntoResult(result, nodeAlias, environmentVariables) { if (!result[nodeAlias]) { result[nodeAlias] = []; } for (const environmentVariable of environmentVariables) { const existingIndex = result[nodeAlias].findIndex((variable) => variable.name === environmentVariable.name); const environmentVariableClone = { ...environmentVariable }; if (existingIndex === -1) { result[nodeAlias].push(environmentVariableClone); } else { result[nodeAlias][existingIndex] = environmentVariableClone; } } } extractExtraEnvironmentArray(rootSection) { if (!rootSection || typeof rootSection !== 'object') { return []; } const extraEnvironmentArray = rootSection.extraEnv; if (!Array.isArray(extraEnvironmentArray)) { return []; } const environmentVariables = []; for (const entry of extraEnvironmentArray) { if (!entry || typeof entry !== 'object') { continue; } const entryRecord = entry; if (typeof entryRecord.name !== 'string' || typeof entryRecord.value !== 'string') { continue; } environmentVariables.push({ name: entryRecord.name, value: entryRecord.value }); } return environmentVariables; } } export const helmValuesHelper = new HelmValuesHelper(); //# sourceMappingURL=helm-values-helper.js.map