UNPKG

@hashgraph/solo

Version:

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

154 lines 8.05 kB
// SPDX-License-Identifier: Apache-2.0 var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var RemoteConfigValidator_1; import { inject, injectable } from 'tsyringe-neo'; import { patchInject } from '../../dependency-injection/container-helper.js'; import { InjectTokens } from '../../dependency-injection/inject-tokens.js'; import { SoloError } from '../../errors/solo-error.js'; import { Templates } from '../../templates.js'; import { DeploymentPhase } from '../../../data/schema/model/remote/deployment-phase.js'; import * as constants from '../../constants.js'; /** * Static class is used to validate that components in the remote config * are present in the kubernetes cluster, and throw errors if there is mismatch. */ let RemoteConfigValidator = class RemoteConfigValidator { static { RemoteConfigValidator_1 = this; } k8Factory; localConfig; chartManager; constructor(k8Factory, localConfig, chartManager) { this.k8Factory = k8Factory; this.localConfig = localConfig; this.chartManager = chartManager; this.k8Factory = patchInject(k8Factory, InjectTokens.K8Factory, this.constructor.name); this.localConfig = patchInject(localConfig, InjectTokens.LocalConfigRuntimeState, this.constructor.name); this.chartManager = patchInject(chartManager, InjectTokens.ChartManager, this.constructor.name); } static consensusNodeSkipConditionCallback(nodeComponent) { return (nodeComponent.metadata.phase === DeploymentPhase.REQUESTED || nodeComponent.metadata.phase === DeploymentPhase.STOPPED); } // This skips components that are requested, because they are not yet deployed. // This is needed to avoid errors during the deployment of the requested components. // Especially during one-shot deployments. static componentSkipConditionCallback(component) { return component.metadata.phase === DeploymentPhase.REQUESTED; } static componentValidationsMapping = { relayNodes: { displayName: 'Relay Nodes', getLabelsCallback: Templates.renderRelayLabels, legacyReleaseName: constants.JSON_RPC_RELAY_RELEASE_NAME, skipCondition: RemoteConfigValidator_1.componentSkipConditionCallback, }, haProxies: { displayName: 'HaProxy', getLabelsCallback: Templates.renderHaProxyLabels, }, mirrorNodes: { displayName: 'Mirror Node', getLabelsCallback: Templates.renderMirrorNodeLabels, legacyReleaseName: constants.MIRROR_NODE_RELEASE_NAME, skipCondition: RemoteConfigValidator_1.componentSkipConditionCallback, }, envoyProxies: { displayName: 'Envoy Proxy', getLabelsCallback: Templates.renderEnvoyProxyLabels, }, explorers: { displayName: 'Explorer', getLabelsCallback: Templates.renderExplorerLabels, legacyReleaseName: 'hiero-explorer', skipCondition: RemoteConfigValidator_1.componentSkipConditionCallback, }, consensusNodes: { displayName: 'Consensus Node', getLabelsCallback: Templates.renderConsensusNodeLabels, skipCondition: RemoteConfigValidator_1.consensusNodeSkipConditionCallback, }, blockNodes: { displayName: 'Block Node', getLabelsCallback: Templates.renderBlockNodeLabels, legacyReleaseName: `${constants.BLOCK_NODE_RELEASE_NAME}-0`, skipCondition: RemoteConfigValidator_1.componentSkipConditionCallback, }, }; async validateComponents(namespace, skipConsensusNodes, state) { const validationPromises = Object.entries(RemoteConfigValidator_1.componentValidationsMapping) .filter(([key]) => key !== 'consensusNodes' || !skipConsensusNodes) .flatMap(([key, { getLabelsCallback, displayName, skipCondition, legacyReleaseName }]) => this.validateComponentGroup(key, namespace, state[key], getLabelsCallback, displayName, skipCondition, legacyReleaseName)); await Promise.all(validationPromises); } validateComponentGroup(key, namespace, components, getLabelsCallback, displayName, skipCondition, legacyReleaseName) { return components.map(async (component) => { if (skipCondition?.(component)) { return; } const context = this.localConfig.configuration.clusterRefs.get(component.metadata.cluster)?.toString(); let useLegacyReleaseName = false; if (legacyReleaseName && component.metadata.id <= 1) { if (key === 'relayNodes') { const nodeAliases = component?.consensusNodeIds.map((nodeId) => Templates.renderNodeAliasFromNumber(nodeId + 1)); legacyReleaseName = `${legacyReleaseName}-${nodeAliases.join('-')}`; } const isLegacyChartInstalled = await this.chartManager.isChartInstalled(namespace, legacyReleaseName, context); if (isLegacyChartInstalled) { useLegacyReleaseName = true; } } const labels = useLegacyReleaseName ? getLabelsCallback(component.metadata.id, legacyReleaseName) : getLabelsCallback(component.metadata.id); try { const pods = await this.k8Factory.getK8(context).pods().list(namespace, labels); if (pods.length === 0) { throw new Error('Pod not found'); // to return the generic error message } } catch (error) { throw RemoteConfigValidator_1.buildValidationError(displayName, component, error, labels); } }); } /** * Generic handler that throws errors. * * @param displayName - name to display in error message * @param component - component which is not found in the cluster * @param error - original error for the kube client * @param labels - labels used to find the component */ static buildValidationError(displayName, component, error, labels) { return new SoloError(RemoteConfigValidator_1.buildValidationErrorMessage(displayName, component, labels), error, component); } static buildValidationErrorMessage(displayName, component, labels = []) { let message = `${displayName} in remote config with id ${component.metadata.id} was not found in ` + `namespace: ${component.metadata.namespace}, ` + `cluster: ${component.metadata.cluster}`; if (labels?.length !== 0) { message += `, labels: ${labels}`; } return message; } }; RemoteConfigValidator = RemoteConfigValidator_1 = __decorate([ injectable(), __param(0, inject(InjectTokens.K8Factory)), __param(1, inject(InjectTokens.LocalConfigRuntimeState)), __param(2, inject(InjectTokens.ChartManager)), __metadata("design:paramtypes", [Object, Function, Function]) ], RemoteConfigValidator); export { RemoteConfigValidator }; //# sourceMappingURL=remote-config-validator.js.map