@hashgraph/solo
Version:
An opinionated CLI tool to deploy and manage private Hedera Networks.
219 lines • 9.85 kB
JavaScript
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); }
};
/**
* SPDX-License-Identifier: Apache-2.0
*/
import { IsEmail, IsNotEmpty, IsObject, IsString, validateSync } from 'class-validator';
import fs from 'fs';
import * as yaml from 'yaml';
import { Flags as flags } from '../../commands/flags.js';
import { MissingArgumentError, SoloError } from '../errors.js';
import { IsClusterRefs, IsDeployments } from '../validator_decorators.js';
import { ErrorMessages } from '../error_messages.js';
import * as helpers from '../helpers.js';
import { inject, injectable } from 'tsyringe-neo';
import { patchInject } from '../dependency_injection/container_helper.js';
import { InjectTokens } from '../dependency_injection/inject_tokens.js';
let LocalConfig = class LocalConfig {
filePath;
logger;
configManager;
userEmailAddress;
soloVersion;
// The string is the name of the deployment, will be used as the namespace,
// so it needs to be available in all targeted clusters
deployments;
clusterRefs = {};
skipPromptTask = false;
constructor(filePath, logger, configManager) {
this.filePath = filePath;
this.logger = logger;
this.configManager = configManager;
this.filePath = patchInject(filePath, InjectTokens.LocalConfigFilePath, this.constructor.name);
this.logger = patchInject(logger, InjectTokens.SoloLogger, this.constructor.name);
this.configManager = patchInject(configManager, InjectTokens.ConfigManager, this.constructor.name);
if (!this.filePath || this.filePath === '')
throw new MissingArgumentError('a valid filePath is required');
const allowedKeys = ['userEmailAddress', 'deployments', 'clusterRefs', 'soloVersion'];
if (this.configFileExists()) {
const fileContent = fs.readFileSync(filePath, 'utf8');
const parsedConfig = yaml.parse(fileContent);
for (const key in parsedConfig) {
if (!allowedKeys.includes(key)) {
throw new SoloError(ErrorMessages.LOCAL_CONFIG_GENERIC);
}
this[key] = parsedConfig[key];
}
this.validate();
this.skipPromptTask = true;
}
}
validate() {
const errors = validateSync(this, {});
if (errors.length) {
// throw the first error:
const prop = Object.keys(errors[0]?.constraints);
if (prop[0]) {
throw new SoloError(errors[0].constraints[prop[0]]);
}
else {
throw new SoloError(ErrorMessages.LOCAL_CONFIG_GENERIC);
}
}
}
setUserEmailAddress(emailAddress) {
this.userEmailAddress = emailAddress;
this.validate();
return this;
}
setDeployments(deployments) {
this.deployments = deployments;
this.validate();
return this;
}
setClusterRefs(clusterRefs) {
this.clusterRefs = clusterRefs;
this.validate();
return this;
}
setSoloVersion(version) {
this.soloVersion = version;
this.validate();
return this;
}
configFileExists() {
return fs.existsSync(this.filePath);
}
async write() {
const yamlContent = yaml.stringify({
userEmailAddress: this.userEmailAddress,
deployments: this.deployments,
clusterRefs: this.clusterRefs,
soloVersion: this.soloVersion,
});
await fs.promises.writeFile(this.filePath, yamlContent);
this.logger.info(`Wrote local config to ${this.filePath}: ${yamlContent}`);
}
promptLocalConfigTask(k8Factory) {
const self = this;
return {
title: 'Prompt local configuration',
skip: this.skipPromptTask,
task: async (_, task) => {
if (self.configFileExists()) {
self.configManager.setFlag(flags.userEmailAddress, self.userEmailAddress);
}
const isQuiet = self.configManager.getFlag(flags.quiet);
const contexts = self.configManager.getFlag(flags.context);
const deploymentName = self.configManager.getFlag(flags.deployment);
const namespace = self.configManager.getFlag(flags.namespace);
let userEmailAddress = self.configManager.getFlag(flags.userEmailAddress);
let deploymentClusters = self.configManager.getFlag(flags.deploymentClusters);
if (!userEmailAddress) {
if (isQuiet)
throw new SoloError(ErrorMessages.LOCAL_CONFIG_INVALID_EMAIL);
userEmailAddress = await flags.userEmailAddress.prompt(task, userEmailAddress);
self.configManager.setFlag(flags.userEmailAddress, userEmailAddress);
}
if (!deploymentName)
throw new SoloError('Deployment name was not specified');
if (!deploymentClusters) {
if (isQuiet) {
deploymentClusters = k8Factory.default().clusters().readCurrent();
}
else {
deploymentClusters = await flags.deploymentClusters.prompt(task, deploymentClusters);
}
self.configManager.setFlag(flags.deploymentClusters, deploymentClusters);
}
const parsedClusterRefs = helpers.splitFlagInput(deploymentClusters);
const deployments = {
[deploymentName]: {
clusters: parsedClusterRefs,
namespace: namespace.name,
},
};
const parsedContexts = helpers.splitFlagInput(contexts);
if (parsedContexts.length < parsedClusterRefs.length) {
if (!isQuiet) {
const promptedContexts = [];
for (const clusterRef of parsedClusterRefs) {
const kubeContexts = k8Factory.default().contexts().list();
const context = await flags.context.prompt(task, kubeContexts, clusterRef);
self.clusterRefs[clusterRef] = context;
promptedContexts.push(context);
self.configManager.setFlag(flags.context, context);
}
self.configManager.setFlag(flags.context, promptedContexts.join(','));
}
else {
const context = k8Factory.default().contexts().readCurrent();
for (const clusterRef of parsedClusterRefs) {
self.clusterRefs[clusterRef] = context;
}
self.configManager.setFlag(flags.context, context);
}
}
else {
for (let i = 0; i < parsedClusterRefs.length; i++) {
const clusterRef = parsedClusterRefs[i];
self.clusterRefs[clusterRef] = parsedContexts[i];
self.configManager.setFlag(flags.context, parsedContexts[i]);
}
}
self.userEmailAddress = userEmailAddress;
self.deployments = deployments;
self.soloVersion = helpers.getSoloVersion();
self.validate();
await self.write();
},
};
}
};
__decorate([
IsEmail({}, {
message: ErrorMessages.LOCAL_CONFIG_INVALID_EMAIL,
}),
__metadata("design:type", String)
], LocalConfig.prototype, "userEmailAddress", void 0);
__decorate([
IsString({ message: ErrorMessages.LOCAL_CONFIG_INVALID_SOLO_VERSION }),
IsNotEmpty({ message: ErrorMessages.LOCAL_CONFIG_INVALID_SOLO_VERSION }),
__metadata("design:type", String)
], LocalConfig.prototype, "soloVersion", void 0);
__decorate([
IsDeployments({
message: ErrorMessages.LOCAL_CONFIG_INVALID_DEPLOYMENTS_FORMAT,
}),
IsNotEmpty(),
IsObject({
message: ErrorMessages.LOCAL_CONFIG_INVALID_DEPLOYMENTS_FORMAT,
}),
__metadata("design:type", Object)
], LocalConfig.prototype, "deployments", void 0);
__decorate([
IsClusterRefs({
message: ErrorMessages.LOCAL_CONFIG_CONTEXT_CLUSTER_MAPPING_FORMAT,
}),
IsNotEmpty(),
__metadata("design:type", Object)
], LocalConfig.prototype, "clusterRefs", void 0);
LocalConfig = __decorate([
injectable(),
__param(0, inject(InjectTokens.LocalConfigFilePath)),
__param(1, inject(InjectTokens.SoloLogger)),
__param(2, inject(InjectTokens.ConfigManager)),
__metadata("design:paramtypes", [String, Function, Function])
], LocalConfig);
export { LocalConfig };
//# sourceMappingURL=local_config.js.map