From a6ee2da5d61f891583a4c6c565ebc20148fa611d Mon Sep 17 00:00:00 2001 From: Ivo Yankov Date: Thu, 23 Jan 2025 12:48:50 +0200 Subject: [PATCH 01/14] wip: refactor classes Signed-off-by: Ivo Yankov --- src/commands/base.ts | 10 +- src/commands/cluster/handlers.ts | 51 +++++----- src/commands/cluster/index.ts | 3 - src/commands/cluster/tasks.ts | 149 ++++++++++++++++------------- src/commands/deployment.ts | 3 +- src/commands/node/handlers.ts | 4 +- src/core/command_handler.ts | 74 ++++++++++++++ src/core/container_init.ts | 10 ++ src/core/helpers.ts | 17 +++- test/unit/commands/cluster.test.ts | 6 +- 10 files changed, 223 insertions(+), 104 deletions(-) create mode 100644 src/core/command_handler.ts diff --git a/src/commands/base.ts b/src/commands/base.ts index 8b2a7860f..27107abad 100644 --- a/src/commands/base.ts +++ b/src/commands/base.ts @@ -35,10 +35,6 @@ import * as constants from '../core/constants.js'; import fs from 'fs'; import {Task} from '../core/task.js'; -export interface CommandHandlers { - parent: BaseCommand; -} - export abstract class BaseCommand extends ShellRunner { protected readonly helm: Helm; protected readonly k8: K8; @@ -71,6 +67,7 @@ export abstract class BaseCommand extends ShellRunner { this.remoteConfigManager = opts.remoteConfigManager; } + // TODO remove async prepareChartPath(chartDir: string, chartRepo: string, chartReleaseName: string) { if (!chartRepo) throw new MissingArgumentError('chart repo name is required'); if (!chartReleaseName) throw new MissingArgumentError('chart release name is required'); @@ -204,8 +201,9 @@ export abstract class BaseCommand extends ShellRunner { abstract close(): Promise; + // TODO remove this commandActionBuilder(actionTasks: any, options: any, errorString: string, lease: Lease | null) { - return async function (argv: any, commandDef: CommandHandlers) { + return async function (argv: any, commandDef) { const tasks = new Listr([...actionTasks], options); try { @@ -246,7 +244,7 @@ export abstract class BaseCommand extends ShellRunner { self.logger.debug(`OK: setup directory: ${dirPath}`); }); } catch (e: Error | any) { - this.logger.error(e); + self.logger.error(e); throw new SoloError(`failed to create directory: ${e.message}`, e); } diff --git a/src/commands/cluster/handlers.ts b/src/commands/cluster/handlers.ts index f361288f8..224fb01bb 100644 --- a/src/commands/cluster/handlers.ts +++ b/src/commands/cluster/handlers.ts @@ -14,37 +14,44 @@ * limitations under the License. * */ -import {type BaseCommand, type CommandHandlers} from '../base.js'; -import {type ClusterCommandTasks} from './tasks.js'; +import {ClusterCommandTasks} from './tasks.js'; import * as helpers from '../../core/helpers.js'; import * as constants from '../../core/constants.js'; import * as ContextFlags from './flags.js'; import {RemoteConfigTasks} from '../../core/config/remote/remote_config_tasks.js'; -import type {RemoteConfigManager} from '../../core/config/remote/remote_config_manager.js'; +import {RemoteConfigManager} from '../../core/config/remote/remote_config_manager.js'; import {connectConfigBuilder, resetConfigBuilder, setupConfigBuilder} from './configs.js'; import {SoloError} from '../../core/errors.js'; - -export class ClusterCommandHandlers implements CommandHandlers { - readonly parent: BaseCommand; - readonly tasks: ClusterCommandTasks; - public readonly remoteConfigManager: RemoteConfigManager; - private getConfig: any; - - constructor(parent: BaseCommand, tasks: ClusterCommandTasks, remoteConfigManager: RemoteConfigManager) { - this.parent = parent; - this.tasks = tasks; - this.remoteConfigManager = remoteConfigManager; - this.getConfig = parent.getConfig.bind(parent); +import {inject, injectable} from "tsyringe-neo"; +import {patchInject} from "../../core/container_helper.js"; +import {K8} from "../../core/k8.js"; +import {CommandHandler} from "../../core/command_handler.js"; +import {LocalConfig} from "../../core/config/local_config.js"; + +@injectable() +export class ClusterCommandHandlers extends CommandHandler { + constructor( + @inject(ClusterCommandTasks) private readonly tasks: ClusterCommandTasks, + @inject(RemoteConfigManager) private readonly remoteConfigManager: RemoteConfigManager, + @inject(LocalConfig) private readonly localConfig: LocalConfig, + @inject(K8) private readonly k8: K8, + ) { + super(); + + this.tasks = patchInject(tasks, ClusterCommandTasks, this.constructor.name); + this.remoteConfigManager = patchInject(remoteConfigManager, RemoteConfigManager, this.constructor.name); + this.k8 = patchInject(k8, K8, this.constructor.name); + this.localConfig = patchInject(localConfig, LocalConfig, this.constructor.name); } async connect(argv: any) { argv = helpers.addFlagsToArgv(argv, ContextFlags.USE_FLAGS); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, connectConfigBuilder.bind(this)), - this.parent.setupHomeDirectoryTask(), - this.parent.getLocalConfig().promptLocalConfigTask(this.parent.getK8()), + this.setupHomeDirectoryTask(), + this.localConfig.promptLocalConfigTask(this.k8), this.tasks.selectContext(), RemoteConfigTasks.loadRemoteConfig.bind(this)(argv), this.tasks.readClustersFromRemoteConfig(argv), @@ -65,7 +72,7 @@ export class ClusterCommandHandlers implements CommandHandlers { async list(argv: any) { argv = helpers.addFlagsToArgv(argv, ContextFlags.USE_FLAGS); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [this.tasks.showClusterList()], { concurrent: false, @@ -82,7 +89,7 @@ export class ClusterCommandHandlers implements CommandHandlers { async info(argv: any) { argv = helpers.addFlagsToArgv(argv, ContextFlags.USE_FLAGS); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [this.tasks.getClusterInfo()], { concurrent: false, @@ -99,7 +106,7 @@ export class ClusterCommandHandlers implements CommandHandlers { async setup(argv: any) { argv = helpers.addFlagsToArgv(argv, ContextFlags.USE_FLAGS); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, setupConfigBuilder.bind(this)), this.tasks.prepareChartValues(argv), @@ -125,7 +132,7 @@ export class ClusterCommandHandlers implements CommandHandlers { async reset(argv: any) { argv = helpers.addFlagsToArgv(argv, ContextFlags.USE_FLAGS); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, resetConfigBuilder.bind(this)), this.tasks.acquireNewLease(argv), diff --git a/src/commands/cluster/index.ts b/src/commands/cluster/index.ts index 1c1fd474d..502f4d141 100644 --- a/src/commands/cluster/index.ts +++ b/src/commands/cluster/index.ts @@ -19,7 +19,6 @@ import * as ContextFlags from './flags.js'; import {YargsCommand} from '../../core/yargs_command.js'; import {BaseCommand} from './../base.js'; import {type Opts} from '../../types/command_types.js'; -import {ClusterCommandTasks} from './tasks.js'; import {ClusterCommandHandlers} from './handlers.js'; import {DEFAULT_FLAGS, RESET_FLAGS, SETUP_FLAGS} from './flags.js'; @@ -31,8 +30,6 @@ export class ClusterCommand extends BaseCommand { constructor(opts: Opts) { super(opts); - - this.handlers = new ClusterCommandHandlers(this, new ClusterCommandTasks(this, this.k8), this.remoteConfigManager); } getCommandDefinition() { diff --git a/src/commands/cluster/tasks.ts b/src/commands/cluster/tasks.ts index d5346388a..5ba37a19a 100644 --- a/src/commands/cluster/tasks.ts +++ b/src/commands/cluster/tasks.ts @@ -18,8 +18,7 @@ import {Task} from '../../core/task.js'; import {Flags as flags} from '../flags.js'; import type {ListrTaskWrapper} from 'listr2'; import type {ConfigBuilder} from '../../types/aliases.js'; -import {type BaseCommand} from '../base.js'; -import {splitFlagInput} from '../../core/helpers.js'; +import {prepareChartPath, splitFlagInput} from '../../core/helpers.js'; import * as constants from '../../core/constants.js'; import path from 'path'; import chalk from 'chalk'; @@ -28,41 +27,61 @@ import {ErrorMessages} from '../../core/error_messages.js'; import {SoloError} from '../../core/errors.js'; import {RemoteConfigManager} from '../../core/config/remote/remote_config_manager.js'; import type {RemoteConfigDataWrapper} from '../../core/config/remote/remote_config_data_wrapper.js'; -import type {K8} from '../../core/k8.js'; +import {K8} from '../../core/k8.js'; import type {Cluster} from '@kubernetes/client-node/dist/config_types.js'; import type {SoloListrTask, SoloListrTaskWrapper} from '../../types/index.js'; import type {SelectClusterContextContext} from './configs.js'; import type {Namespace} from '../../core/config/remote/types.js'; -import type {LocalConfig} from '../../core/config/local_config.js'; +import {LocalConfig} from '../../core/config/local_config.js'; import {ListrEnquirerPromptAdapter} from '@listr2/prompt-adapter-enquirer'; - +import {inject, injectable} from "tsyringe-neo"; +import {patchInject} from "../../core/container_helper.js"; +import {ConfigManager} from "../../core/config_manager.js"; +import {SoloLogger} from "../../core/logging.js"; +import {ChartManager} from "../../core/chart_manager.js"; +import {LeaseManager} from "../../core/lease/lease_manager.js"; +import {Helm} from "../../core/helm.js"; + +@injectable() export class ClusterCommandTasks { - private readonly parent: BaseCommand; + constructor( + @inject(K8) private readonly k8: K8, + @inject(ConfigManager) private readonly configManager: ConfigManager, + @inject(RemoteConfigManager) private readonly remoteConfigManager: RemoteConfigManager, + @inject(LocalConfig) private readonly localConfig: LocalConfig, + @inject(SoloLogger) private readonly logger: SoloLogger, + @inject(ChartManager) private readonly chartManager: ChartManager, + @inject(LeaseManager) private readonly leaseManager: LeaseManager, + @inject(Helm) private readonly helm: Helm, - constructor( - parent, - private readonly k8: K8, ) { - this.parent = parent; + this.k8 = patchInject(k8, K8, this.constructor.name); + this.configManager = patchInject(configManager, ConfigManager, this.constructor.name); + this.remoteConfigManager = patchInject(remoteConfigManager, RemoteConfigManager, this.constructor.name); + this.localConfig = patchInject(localConfig, LocalConfig, this.constructor.name); + this.logger = patchInject(logger, SoloLogger, this.constructor.name); + this.chartManager = patchInject(chartManager, ChartManager, this.constructor.name); + this.leaseManager = patchInject(leaseManager, LeaseManager, this.constructor.name); + this.helm = patchInject(helm, Helm, this.constructor.name); } - testConnectionToCluster(cluster: string, localConfig: LocalConfig, parentTask: ListrTaskWrapper) { + public testConnectionToCluster(cluster: string, localConfig: LocalConfig, parentTask: ListrTaskWrapper) { const self = this; return { title: `Test connection to cluster: ${chalk.cyan(cluster)}`, task: async (_, subTask: ListrTaskWrapper) => { let context = localConfig.clusterContextMapping[cluster]; if (!context) { - const isQuiet = self.parent.getConfigManager().getFlag(flags.quiet); + const isQuiet = self.configManager.getFlag(flags.quiet); if (isQuiet) { - context = self.parent.getK8().getCurrentContext(); + context = self.k8.getCurrentContext(); } else { context = await self.promptForContext(parentTask, cluster); } localConfig.clusterContextMapping[cluster] = context; } - if (!(await self.parent.getK8().testClusterConnection(context, cluster))) { + if (!(await self.k8.testClusterConnection(context, cluster))) { subTask.title = `${subTask.title} - ${chalk.red('Cluster connection failed')}`; throw new SoloError(`${ErrorMessages.INVALID_CONTEXT_FOR_CLUSTER_DETAILED(context, cluster)}`); } @@ -70,7 +89,7 @@ export class ClusterCommandTasks { }; } - validateRemoteConfigForCluster( + public validateRemoteConfigForCluster( cluster: string, currentCluster: Cluster, localConfig: LocalConfig, @@ -81,8 +100,8 @@ export class ClusterCommandTasks { title: `Pull and validate remote configuration for cluster: ${chalk.cyan(cluster)}`, task: async (_, subTask: ListrTaskWrapper) => { const context = localConfig.clusterContextMapping[cluster]; - self.parent.getK8().setCurrentContext(context); - const remoteConfigFromOtherCluster = await self.parent.getRemoteConfigManager().get(); + self.k8.setCurrentContext(context); + const remoteConfigFromOtherCluster = await self.remoteConfigManager.get(); if (!RemoteConfigManager.compare(currentRemoteConfig, remoteConfigFromOtherCluster)) { throw new SoloError(ErrorMessages.REMOTE_CONFIGS_DO_NOT_MATCH(currentCluster.name, cluster)); } @@ -90,15 +109,15 @@ export class ClusterCommandTasks { }; } - readClustersFromRemoteConfig(argv) { + public readClustersFromRemoteConfig(argv) { const self = this; return { title: 'Read clusters from remote config', task: async (ctx, task) => { - const localConfig = this.parent.getLocalConfig(); - const currentCluster = this.parent.getK8().getCurrentCluster(); - const currentClusterName = this.parent.getK8().getCurrentClusterName(); - const currentRemoteConfig: RemoteConfigDataWrapper = await this.parent.getRemoteConfigManager().get(); + const localConfig = this.localConfig; + const currentCluster = this.k8.getCurrentCluster(); + const currentClusterName = this.k8.getCurrentClusterName(); + const currentRemoteConfig: RemoteConfigDataWrapper = await this.remoteConfigManager.get(); const subTasks = []; const remoteConfigClusters = Object.keys(currentRemoteConfig.clusters); const otherRemoteConfigClusters: string[] = remoteConfigClusters.filter(c => c !== currentClusterName); @@ -121,15 +140,15 @@ export class ClusterCommandTasks { }; } - updateLocalConfig(): SoloListrTask { + public updateLocalConfig(): SoloListrTask { return new Task('Update local configuration', async (ctx: any, task: ListrTaskWrapper) => { - this.parent.logger.info('Compare local and remote configuration...'); - const configManager = this.parent.getConfigManager(); + this.logger.info('Compare local and remote configuration...'); + const configManager = this.configManager; const isQuiet = configManager.getFlag(flags.quiet); - await this.parent.getRemoteConfigManager().modify(async remoteConfig => { + await this.remoteConfigManager.modify(async remoteConfig => { // Update current deployment with cluster list from remoteConfig - const localConfig = this.parent.getLocalConfig(); + const localConfig = this.localConfig; const localDeployments = localConfig.deployments; const remoteClusterList: string[] = []; @@ -164,7 +183,7 @@ export class ClusterCommandTasks { } else if (!localConfig.clusterContextMapping[cluster]) { // In quiet mode, use the currently selected context to update the mapping if (isQuiet) { - localConfig.clusterContextMapping[cluster] = this.parent.getK8().getCurrentContext(); + localConfig.clusterContextMapping[cluster] = this.k8.getCurrentContext(); } // Prompt the user to select a context if mapping value is missing @@ -173,7 +192,7 @@ export class ClusterCommandTasks { } } } - this.parent.logger.info('Update local configuration...'); + this.logger.info('Update local configuration...'); await localConfig.write(); }); }); @@ -187,7 +206,7 @@ export class ClusterCommandTasks { ) { let selectedContext; if (isQuiet) { - selectedContext = this.parent.getK8().getCurrentContext(); + selectedContext = this.k8.getCurrentContext(); } else { selectedContext = await this.promptForContext(task, selectedCluster); localConfig.clusterContextMapping[selectedCluster] = selectedContext; @@ -196,7 +215,7 @@ export class ClusterCommandTasks { } private async promptForContext(task: SoloListrTaskWrapper, cluster: string) { - const kubeContexts = this.parent.getK8().getContexts(); + const kubeContexts = this.k8.getContexts(); return flags.context.prompt( task, kubeContexts.map(c => c.name), @@ -246,7 +265,7 @@ export class ClusterCommandTasks { valuesArg += ` --set cloud.minio.enabled=${minioEnabled}`; if (certManagerEnabled && !certManagerCrdsEnabled) { - this.parent.logger.showUser( + this.logger.showUser( chalk.yellowBright('> WARNING:'), chalk.yellow( 'cert-manager CRDs are required for cert-manager, please enable it if you have not installed it independently.', @@ -259,23 +278,23 @@ export class ClusterCommandTasks { /** Show list of installed chart */ private async showInstalledChartList(clusterSetupNamespace: string) { - this.parent.logger.showList( + this.logger.showList( 'Installed Charts', - await this.parent.getChartManager().getInstalledCharts(clusterSetupNamespace), + await this.chartManager.getInstalledCharts(clusterSetupNamespace), ); } - selectContext(): SoloListrTask { + public selectContext(): SoloListrTask { return { title: 'Read local configuration settings', task: async (_, task) => { - this.parent.logger.info('Read local configuration settings...'); - const configManager = this.parent.getConfigManager(); + this.logger.info('Read local configuration settings...'); + const configManager = this.configManager; const isQuiet = configManager.getFlag(flags.quiet); const deploymentName: string = configManager.getFlag(flags.namespace); let clusters = splitFlagInput(configManager.getFlag(flags.clusterName)); const contexts = splitFlagInput(configManager.getFlag(flags.context)); - const localConfig = this.parent.getLocalConfig(); + const localConfig = this.localConfig; let selectedContext: string; let selectedCluster: string; @@ -305,8 +324,8 @@ export class ClusterCommandTasks { else { // Add the deployment to the LocalConfig with the currently selected cluster and context in KubeConfig if (isQuiet) { - selectedContext = this.parent.getK8().getCurrentContext(); - selectedCluster = this.parent.getK8().getCurrentClusterName(); + selectedContext = this.k8.getCurrentContext(); + selectedCluster = this.k8.getCurrentClusterName(); localConfig.deployments[deploymentName] = { clusters: [selectedCluster], }; @@ -333,54 +352,55 @@ export class ClusterCommandTasks { } } - const connectionValid = await this.parent.getK8().testClusterConnection(selectedContext, selectedCluster); + const connectionValid = await this.k8.testClusterConnection(selectedContext, selectedCluster); if (!connectionValid) { throw new SoloError(ErrorMessages.INVALID_CONTEXT_FOR_CLUSTER(selectedContext)); } - this.parent.getK8().setCurrentContext(selectedContext); + this.k8.setCurrentContext(selectedContext); }, }; } - initialize(argv: any, configInit: ConfigBuilder) { + public initialize(argv: any, configInit: ConfigBuilder) { const {requiredFlags, optionalFlags} = argv; argv.flags = [...requiredFlags, ...optionalFlags]; return new Task('Initialize', async (ctx: any, task: ListrTaskWrapper) => { if (argv[flags.devMode.name]) { - this.parent.logger.setDevMode(true); + this.logger.setDevMode(true); } ctx.config = await configInit(argv, ctx, task); }); } - showClusterList() { + public showClusterList() { return new Task('List all available clusters', async (ctx: any, task: ListrTaskWrapper) => { - this.parent.logger.showList('Clusters', this.parent.getK8().getClusters()); + this.logger.showList('Clusters', this.k8.getClusters()); }); } - getClusterInfo() { + public getClusterInfo() { return new Task('Get cluster info', async (ctx: any, task: ListrTaskWrapper) => { try { - const cluster = this.parent.getK8().getCurrentCluster(); - this.parent.logger.showJSON(`Cluster Information (${cluster.name})`, cluster); - this.parent.logger.showUser('\n'); + const cluster = this.k8.getCurrentCluster(); + this.logger.showJSON(`Cluster Information (${cluster.name})`, cluster); + this.logger.showUser('\n'); } catch (e: Error | unknown) { - this.parent.logger.showUserError(e); + this.logger.showUserError(e); } }); } - prepareChartValues(argv) { + public prepareChartValues(argv) { const self = this; return new Task( 'Prepare chart values', async (ctx: any, task: ListrTaskWrapper) => { - ctx.chartPath = await this.parent.prepareChartPath( + ctx.chartPath = await prepareChartPath( + this.helm, ctx.config.chartDir, constants.SOLO_TESTING_CHART_URL, constants.SOLO_CLUSTER_SETUP_CHART, @@ -431,8 +451,8 @@ export class ClusterCommandTasks { ); } - installClusterChart(argv) { - const parent = this.parent; + public installClusterChart(argv) { + const self = this; return new Task( `Install '${constants.SOLO_CLUSTER_SETUP_CHART}' chart`, async (ctx: any, task: ListrTaskWrapper) => { @@ -441,18 +461,16 @@ export class ClusterCommandTasks { const valuesArg = ctx.valuesArg; try { - parent.logger.debug(`Installing chart chartPath = ${ctx.chartPath}, version = ${version}`); - await parent - .getChartManager() - .install(clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART, ctx.chartPath, version, valuesArg); + self.logger.debug(`Installing chart chartPath = ${ctx.chartPath}, version = ${version}`); + await self.chartManager.install(clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART, ctx.chartPath, version, valuesArg); } catch (e: Error | unknown) { // if error, uninstall the chart and rethrow the error - parent.logger.debug( + self.logger.debug( `Error on installing ${constants.SOLO_CLUSTER_SETUP_CHART}. attempting to rollback by uninstalling the chart`, e, ); try { - await parent.getChartManager().uninstall(clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART); + await self.chartManager.uninstall(clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART); } catch { // ignore error during uninstall since we are doing the best-effort uninstall here } @@ -468,15 +486,14 @@ export class ClusterCommandTasks { ); } - acquireNewLease(argv) { + public acquireNewLease(argv) { return new Task('Acquire new lease', async (ctx: any, task: ListrTaskWrapper) => { - const lease = await this.parent.getLeaseManager().create(); + const lease = await this.leaseManager.create(); return ListrLease.newAcquireLeaseTask(lease, task); }); } - uninstallClusterChart(argv) { - const parent = this.parent; + public uninstallClusterChart(argv) { const self = this; return new Task( @@ -499,7 +516,7 @@ export class ClusterCommandTasks { } } - await parent.getChartManager().uninstall(clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART); + await self.chartManager.uninstall(clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART); if (argv.dev) { await this.showInstalledChartList(clusterSetupNamespace); } diff --git a/src/commands/deployment.ts b/src/commands/deployment.ts index 8ace56ebc..756ce6e1b 100644 --- a/src/commands/deployment.ts +++ b/src/commands/deployment.ts @@ -29,6 +29,7 @@ import type {CommandFlag} from '../types/flag_types.js'; import type {CommandBuilder} from '../types/aliases.js'; import type {Opts} from '../types/command_types.js'; import type {SoloListrTask} from '../types/index.js'; +import {container} from "tsyringe-neo"; export class DeploymentCommand extends BaseCommand { readonly tasks: ClusterCommandTasks; @@ -36,7 +37,7 @@ export class DeploymentCommand extends BaseCommand { constructor(opts: Opts) { super(opts); - this.tasks = new ClusterCommandTasks(this, this.k8); + this.tasks = container.resolve(ClusterCommandTasks); } private static get DEPLOY_FLAGS_LIST(): CommandFlag[] { diff --git a/src/commands/node/handlers.ts b/src/commands/node/handlers.ts index e26a72f05..20ec0a9a4 100644 --- a/src/commands/node/handlers.ts +++ b/src/commands/node/handlers.ts @@ -46,7 +46,7 @@ import type {SoloLogger} from '../../core/logging.js'; import type {NodeCommandTasks} from './tasks.js'; import {type Lease} from '../../core/lease/lease.js'; import {NodeSubcommandType} from '../../core/enumerations.js'; -import {type BaseCommand, type CommandHandlers} from '../base.js'; +import {type BaseCommand} from '../base.js'; import {NodeHelper} from './helper.js'; import type {NodeAlias, NodeAliases} from '../../types/aliases.js'; import {ConsensusNodeComponent} from '../../core/config/remote/components/consensus_node_component.js'; @@ -55,7 +55,7 @@ import chalk from 'chalk'; import type {ComponentsDataWrapper} from '../../core/config/remote/components_data_wrapper.js'; import type {Optional} from '../../types/index.js'; -export class NodeCommandHandlers implements CommandHandlers { +export class NodeCommandHandlers { private readonly accountManager: AccountManager; private readonly configManager: ConfigManager; private readonly platformInstaller: PlatformInstaller; diff --git a/src/core/command_handler.ts b/src/core/command_handler.ts new file mode 100644 index 000000000..9a47c1524 --- /dev/null +++ b/src/core/command_handler.ts @@ -0,0 +1,74 @@ +import {inject, injectable} from "tsyringe-neo"; +import {SoloLogger} from "./logging.js"; +import {patchInject} from "./container_helper.js"; +import {Listr} from "listr2"; +import {SoloError} from "./errors.js"; +import {Lease} from "./lease/lease.js"; +import * as constants from "./constants.js"; +import fs from "fs"; +import {Task} from "./task.js"; + +@injectable() +export class CommandHandler { + constructor( + @inject(SoloLogger) public readonly logger?: SoloLogger, + ) { + this.logger = patchInject(logger, SoloLogger, this.constructor.name); + } + + commandActionBuilder(actionTasks: any, options: any, errorString: string, lease: Lease | null) { + return async function (argv: any, commandDef) { + const tasks = new Listr([...actionTasks], options); + + try { + await tasks.run(); + } catch (e: Error | any) { + commandDef.parent.logger.error(`${errorString}: ${e.message}`, e); + throw new SoloError(`${errorString}: ${e.message}`, e); + } finally { + const promises = []; + + promises.push(commandDef.parent.close()); + + if (lease) promises.push(lease.release()); + await Promise.all(promises); + } + }; + } + + + /** + * Setup home directories + * @param dirs a list of directories that need to be created in sequence + */ + setupHomeDirectory( + dirs: string[] = [ + constants.SOLO_HOME_DIR, + constants.SOLO_LOGS_DIR, + constants.SOLO_CACHE_DIR, + constants.SOLO_VALUES_DIR, + ], + ) { + const self = this; + + try { + dirs.forEach(dirPath => { + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath, {recursive: true}); + } + self.logger.debug(`OK: setup directory: ${dirPath}`); + }); + } catch (e: Error | any) { + self.logger.error(e); + throw new SoloError(`failed to create directory: ${e.message}`, e); + } + + return dirs; + } + + setupHomeDirectoryTask() { + return new Task('Setup home directory', async () => { + this.setupHomeDirectory(); + }); + } +} diff --git a/src/core/container_init.ts b/src/core/container_init.ts index 5b16b806a..36faa9439 100644 --- a/src/core/container_init.ts +++ b/src/core/container_init.ts @@ -36,6 +36,10 @@ import {LocalConfig} from './config/local_config.js'; import {RemoteConfigManager} from './config/remote/remote_config_manager.js'; import os from 'os'; import * as version from '../../version.js'; +import {ClusterCommandHandlers} from "../commands/cluster/handlers.js"; +import {ClusterCommandTasks} from "../commands/cluster/tasks.js"; +import {NodeCommandTasks} from "../commands/node/tasks.js"; +import {NodeCommandHandlers} from "../commands/node/handlers.js"; /** * Container class to manage the dependency injection container @@ -111,6 +115,12 @@ export class Container { container.register(RemoteConfigManager, {useClass: RemoteConfigManager}, {lifecycle: Lifecycle.Singleton}); + // Commands + container.register(ClusterCommandHandlers, {useClass: ClusterCommandHandlers}, {lifecycle: Lifecycle.Singleton}); + container.register(ClusterCommandTasks, {useClass: ClusterCommandTasks}, {lifecycle: Lifecycle.Singleton}); + container.register(NodeCommandHandlers, {useClass: NodeCommandHandlers}, {lifecycle: Lifecycle.Singleton}); + container.register(NodeCommandTasks, {useClass: NodeCommandTasks}, {lifecycle: Lifecycle.Singleton}); + Container.isInitialized = true; } diff --git a/src/core/helpers.ts b/src/core/helpers.ts index c4effc803..d05b7bca8 100644 --- a/src/core/helpers.ts +++ b/src/core/helpers.ts @@ -18,7 +18,7 @@ import fs from 'fs'; import os from 'os'; import path from 'path'; import util from 'util'; -import {SoloError} from './errors.js'; +import {MissingArgumentError, SoloError} from './errors.js'; import {Templates} from './templates.js'; import {ROOT_DIR} from './constants.js'; import * as constants from './constants.js'; @@ -28,6 +28,7 @@ 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/node_add_config.js'; +import {Helm} from "./helm.js"; export function sleep(duration: Duration) { return new Promise(resolve => { @@ -384,3 +385,17 @@ export function resolveValidJsonFilePath(filePath: string, defaultPath?: string) throw new SoloError(`Invalid JSON data in file: ${filePath}`); } } + + +export async function prepareChartPath(helm: Helm, chartDir: string, chartRepo: string, chartReleaseName: string) { + if (!chartRepo) throw new MissingArgumentError('chart repo name is required'); + if (!chartReleaseName) throw new MissingArgumentError('chart release name is required'); + + if (chartDir) { + const chartPath = path.join(chartDir, chartReleaseName); + await helm.dependency('update', chartPath); + return chartPath; + } + + return `${chartRepo}/${chartReleaseName}`; +} diff --git a/test/unit/commands/cluster.test.ts b/test/unit/commands/cluster.test.ts index 48b18770a..eb71de2dc 100644 --- a/test/unit/commands/cluster.test.ts +++ b/test/unit/commands/cluster.test.ts @@ -234,7 +234,7 @@ describe('ClusterCommand unit tests', () => { async function runUpdateLocalConfigTask(opts) { command = new ClusterCommand(opts); - tasks = new ClusterCommandTasks(command, opts.k8); + tasks = container.resolve(ClusterCommandTasks); // @ts-expect-error - TS2554: Expected 0 arguments, but got 1. const taskObj = tasks.updateLocalConfig({}); @@ -376,7 +376,7 @@ describe('ClusterCommand unit tests', () => { async function runSelectContextTask(opts) { command = new ClusterCommand(opts); - tasks = new ClusterCommandTasks(command, opts.k8); + tasks = container.resolve(ClusterCommandTasks); // @ts-expect-error - TS2554: Expected 0 arguments, but got 1 const taskObj = tasks.selectContext({}); @@ -503,7 +503,7 @@ describe('ClusterCommand unit tests', () => { async function runReadClustersFromRemoteConfigTask(opts) { command = new ClusterCommand(opts); - tasks = new ClusterCommandTasks(command, k8Stub); + tasks = container.resolve(ClusterCommandTasks); const taskObj = tasks.readClustersFromRemoteConfig({}); taskStub = sandbox.stub() as unknown as ListrTaskWrapper; taskStub.newListr = sandbox.stub(); From 63b214c3b31face699e9cba34daa7b40680c0239 Mon Sep 17 00:00:00 2001 From: Ivo Yankov Date: Thu, 23 Jan 2025 15:38:05 +0200 Subject: [PATCH 02/14] fix: refactor cluster classes Signed-off-by: Ivo Yankov --- src/commands/base.ts | 67 +----------------- src/commands/cluster/configs.ts | 19 ++---- src/commands/cluster/handlers.ts | 25 ++++++- src/commands/cluster/index.ts | 4 ++ src/commands/explorer.ts | 4 +- src/core/command_handler.ts | 4 +- src/core/config/remote/listr_config_tasks.ts | 7 +- src/core/helpers.ts | 72 ++++++++++++++++++++ 8 files changed, 117 insertions(+), 85 deletions(-) diff --git a/src/commands/base.ts b/src/commands/base.ts index 27107abad..6a11455e6 100644 --- a/src/commands/base.ts +++ b/src/commands/base.ts @@ -34,6 +34,7 @@ import path from 'path'; import * as constants from '../core/constants.js'; import fs from 'fs'; import {Task} from '../core/task.js'; +import {getConfig} from "../core/helpers.js"; export abstract class BaseCommand extends ShellRunner { protected readonly helm: Helm; @@ -108,71 +109,7 @@ export abstract class BaseCommand extends ShellRunner { * getUnusedConfigs() to get an array of unused properties. */ getConfig(configName: string, flags: CommandFlag[], extraProperties: string[] = []): object { - const configManager = this.configManager; - - // build the dynamic class that will keep track of which properties are used - const NewConfigClass = class { - private usedConfigs: Map; - constructor() { - // the map to keep track of which properties are used - this.usedConfigs = new Map(); - - // add the flags as properties to this class - flags?.forEach(flag => { - // @ts-ignore - this[`_${flag.constName}`] = configManager.getFlag(flag); - Object.defineProperty(this, flag.constName, { - get() { - this.usedConfigs.set(flag.constName, this.usedConfigs.get(flag.constName) + 1 || 1); - return this[`_${flag.constName}`]; - }, - }); - }); - - // add the extra properties as properties to this class - extraProperties?.forEach(name => { - // @ts-ignore - this[`_${name}`] = ''; - Object.defineProperty(this, name, { - get() { - this.usedConfigs.set(name, this.usedConfigs.get(name) + 1 || 1); - return this[`_${name}`]; - }, - set(value) { - this[`_${name}`] = value; - }, - }); - }); - } - - /** Get the list of unused configurations that were not accessed */ - getUnusedConfigs() { - const unusedConfigs: string[] = []; - - // add the flag constName to the unusedConfigs array if it was not accessed - flags?.forEach(flag => { - if (!this.usedConfigs.has(flag.constName)) { - unusedConfigs.push(flag.constName); - } - }); - - // add the extra properties to the unusedConfigs array if it was not accessed - extraProperties?.forEach(item => { - if (!this.usedConfigs.has(item)) { - unusedConfigs.push(item); - } - }); - return unusedConfigs; - } - }; - - const newConfigInstance = new NewConfigClass(); - - // add the new instance to the configMaps so that it can be used to get the - // unused configurations using the configName from the BaseCommand - this._configMaps.set(configName, newConfigInstance); - - return newConfigInstance; + return getConfig(this.configManager, this._configMaps, configName, flags, extraProperties); } getLeaseManager(): LeaseManager { diff --git a/src/commands/cluster/configs.ts b/src/commands/cluster/configs.ts index d1f9ece95..3971d84a7 100644 --- a/src/commands/cluster/configs.ts +++ b/src/commands/cluster/configs.ts @@ -36,8 +36,7 @@ export const connectConfigBuilder = async function (argv, ctx, task) { }; export const setupConfigBuilder = async function (argv, ctx, task) { - const parent = this.parent; - const configManager = parent.getConfigManager(); + const configManager = this.configManager; configManager.update(argv); flags.disablePrompts([flags.chartDirectory]); @@ -60,11 +59,9 @@ export const setupConfigBuilder = async function (argv, ctx, task) { soloChartVersion: configManager.getFlag(flags.soloChartVersion) as string, } as ClusterSetupConfigClass; - parent.logger.debug('Prepare ctx.config', {config: ctx.config, argv}); + this.logger.debug('Prepare ctx.config', {config: ctx.config, argv}); - ctx.isChartInstalled = await parent - .getChartManager() - .isChartInstalled(ctx.config.clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART); + ctx.isChartInstalled = await this.chartManager.isChartInstalled(ctx.config.clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART); return ctx.config; }; @@ -83,16 +80,14 @@ export const resetConfigBuilder = async function (argv, ctx, task) { } } - this.parent.getConfigManager().update(argv); + this.configManager.update(argv); ctx.config = { - clusterName: this.parent.getConfigManager().getFlag(flags.clusterName) as string, - clusterSetupNamespace: this.parent.getConfigManager().getFlag(flags.clusterSetupNamespace) as string, + clusterName: this.configManager.getFlag(flags.clusterName) as string, + clusterSetupNamespace: this.configManager.getFlag(flags.clusterSetupNamespace) as string, } as ClusterResetConfigClass; - ctx.isChartInstalled = await this.parent - .getChartManager() - .isChartInstalled(ctx.config.clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART); + ctx.isChartInstalled = await this.chartManager.isChartInstalled(ctx.config.clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART); if (!ctx.isChartInstalled) { throw new SoloError('No chart found for the cluster'); } diff --git a/src/commands/cluster/handlers.ts b/src/commands/cluster/handlers.ts index 1b54ddffc..d40eea89e 100644 --- a/src/commands/cluster/handlers.ts +++ b/src/commands/cluster/handlers.ts @@ -27,14 +27,21 @@ import {patchInject} from "../../core/container_helper.js"; import {K8} from "../../core/k8.js"; import {CommandHandler} from "../../core/command_handler.js"; import {LocalConfig} from "../../core/config/local_config.js"; +import type {CommandFlag} from "../../types/flag_types.js"; +import {ConfigManager} from "../../core/config_manager.js"; +import {ChartManager} from "../../core/chart_manager.js"; @injectable() export class ClusterCommandHandlers extends CommandHandler { + protected readonly _configMaps = new Map(); + constructor( @inject(ClusterCommandTasks) private readonly tasks: ClusterCommandTasks, @inject(RemoteConfigManager) private readonly remoteConfigManager: RemoteConfigManager, @inject(LocalConfig) private readonly localConfig: LocalConfig, @inject(K8) private readonly k8: K8, + @inject(ConfigManager) private readonly configManager: ConfigManager, + @inject(ChartManager) private readonly chartManager: ChartManager, ) { super(); @@ -42,6 +49,8 @@ export class ClusterCommandHandlers extends CommandHandler { this.remoteConfigManager = patchInject(remoteConfigManager, RemoteConfigManager, this.constructor.name); this.k8 = patchInject(k8, K8, this.constructor.name); this.localConfig = patchInject(localConfig, LocalConfig, this.constructor.name); + this.configManager = patchInject(configManager, ConfigManager, this.constructor.name); + this.chartManager = patchInject(chartManager, ChartManager, this.constructor.name); } async connect(argv: any) { @@ -53,7 +62,7 @@ export class ClusterCommandHandlers extends CommandHandler { this.setupHomeDirectoryTask(), this.localConfig.promptLocalConfigTask(this.k8), this.tasks.selectContext(), - ListrRemoteConfig.loadRemoteConfig(this.parent, argv), + ListrRemoteConfig.loadRemoteConfig(this.remoteConfigManager, argv), this.tasks.readClustersFromRemoteConfig(argv), this.tasks.updateLocalConfig(), ], @@ -153,4 +162,18 @@ export class ClusterCommandHandlers extends CommandHandler { } return true; } + + close(): Promise { + // no-op + return Promise.resolve(); + } + + // Config related methods: + getConfig(configName: string, flags: CommandFlag[], extraProperties: string[] = []): object { + return helpers.getConfig(this.configManager, this._configMaps, configName, flags, extraProperties); + } + + getUnusedConfigs(configName: string): string[] { + return this._configMaps.get(configName).getUnusedConfigs(); + } } diff --git a/src/commands/cluster/index.ts b/src/commands/cluster/index.ts index 502f4d141..5cf61e407 100644 --- a/src/commands/cluster/index.ts +++ b/src/commands/cluster/index.ts @@ -21,6 +21,7 @@ import {BaseCommand} from './../base.js'; import {type Opts} from '../../types/command_types.js'; import {ClusterCommandHandlers} from './handlers.js'; import {DEFAULT_FLAGS, RESET_FLAGS, SETUP_FLAGS} from './flags.js'; +import {patchInject} from "../../core/container_helper.js"; /** * Defines the core functionalities of 'node' command @@ -30,6 +31,9 @@ export class ClusterCommand extends BaseCommand { constructor(opts: Opts) { super(opts); + + // TODO properly inject + this.handlers = patchInject(null, ClusterCommandHandlers, this.constructor.name); } getCommandDefinition() { diff --git a/src/commands/explorer.ts b/src/commands/explorer.ts index 5b17a8ce9..16c96fc77 100644 --- a/src/commands/explorer.ts +++ b/src/commands/explorer.ts @@ -191,7 +191,7 @@ export class ExplorerCommand extends BaseCommand { return ListrLease.newAcquireLeaseTask(lease, task); }, }, - ListrRemoteConfig.loadRemoteConfig(this, argv), + ListrRemoteConfig.loadRemoteConfig(this.remoteConfigManager, argv), { title: 'Upgrade solo-setup chart', task: async ctx => { @@ -355,7 +355,7 @@ export class ExplorerCommand extends BaseCommand { return ListrLease.newAcquireLeaseTask(lease, task); }, }, - ListrRemoteConfig.loadRemoteConfig(this, argv), + ListrRemoteConfig.loadRemoteConfig(this.remoteConfigManager, argv), { title: 'Destroy explorer', task: async ctx => { diff --git a/src/core/command_handler.ts b/src/core/command_handler.ts index 9a47c1524..d227e17a3 100644 --- a/src/core/command_handler.ts +++ b/src/core/command_handler.ts @@ -23,12 +23,12 @@ export class CommandHandler { try { await tasks.run(); } catch (e: Error | any) { - commandDef.parent.logger.error(`${errorString}: ${e.message}`, e); + commandDef.logger.error(`${errorString}: ${e.message}`, e); throw new SoloError(`${errorString}: ${e.message}`, e); } finally { const promises = []; - promises.push(commandDef.parent.close()); + promises.push(commandDef.close()); if (lease) promises.push(lease.release()); await Promise.all(promises); diff --git a/src/core/config/remote/listr_config_tasks.ts b/src/core/config/remote/listr_config_tasks.ts index 91d967301..f1dc33164 100644 --- a/src/core/config/remote/listr_config_tasks.ts +++ b/src/core/config/remote/listr_config_tasks.ts @@ -18,6 +18,7 @@ import type {ListrTask} from 'listr2'; import type {BaseCommand} from '../../../commands/base.js'; import {type Cluster, type Context, type Namespace} from './types.js'; import type {SoloListrTask} from '../../../types/index.js'; +import {RemoteConfigManager} from "./remote_config_manager.js"; /** * Static class that handles all tasks related to remote config used by other commands. @@ -35,14 +36,14 @@ export class ListrRemoteConfig { /** * Loads the remote config from the config class and performs component validation. * - * @param command - the BaseCommand object on which an action will be performed + * @param remoteConfigManager * @param argv - used to update the last executed command and command history */ - public static loadRemoteConfig(command: BaseCommand, argv: any): ListrTask { + public static loadRemoteConfig(remoteConfigManager: RemoteConfigManager, argv: any): ListrTask { return { title: 'Load remote config', task: async (_, task): Promise => { - await command.getRemoteConfigManager().loadAndValidate(argv); + await remoteConfigManager.loadAndValidate(argv); }, }; } diff --git a/src/core/helpers.ts b/src/core/helpers.ts index d05b7bca8..9ef2ab044 100644 --- a/src/core/helpers.ts +++ b/src/core/helpers.ts @@ -29,6 +29,7 @@ import {type SoloLogger} from './logging.js'; import {type Duration} from './time/duration.js'; import {type NodeAddConfigClass} from '../commands/node/node_add_config.js'; import {Helm} from "./helm.js"; +import {ConfigManager} from "./config_manager.js"; export function sleep(duration: Duration) { return new Promise(resolve => { @@ -399,3 +400,74 @@ export async function prepareChartPath(helm: Helm, chartDir: string, chartRepo: return `${chartRepo}/${chartReleaseName}`; } + +/** + * Dynamically builds a class with properties from the provided list of flags + * and extra properties, will keep track of which properties are used. Call + * getUnusedConfigs() to get an array of unused properties. + */ +export function getConfig(configManager: ConfigManager, configMaps: Map, configName: string, flags: CommandFlag[], extraProperties: string[] = []): object { + // build the dynamic class that will keep track of which properties are used + const NewConfigClass = class { + private usedConfigs: Map; + constructor() { + // the map to keep track of which properties are used + this.usedConfigs = new Map(); + + // add the flags as properties to this class + flags?.forEach(flag => { + // @ts-ignore + this[`_${flag.constName}`] = configManager.getFlag(flag); + Object.defineProperty(this, flag.constName, { + get() { + this.usedConfigs.set(flag.constName, this.usedConfigs.get(flag.constName) + 1 || 1); + return this[`_${flag.constName}`]; + }, + }); + }); + + // add the extra properties as properties to this class + extraProperties?.forEach(name => { + // @ts-ignore + this[`_${name}`] = ''; + Object.defineProperty(this, name, { + get() { + this.usedConfigs.set(name, this.usedConfigs.get(name) + 1 || 1); + return this[`_${name}`]; + }, + set(value) { + this[`_${name}`] = value; + }, + }); + }); + } + + /** Get the list of unused configurations that were not accessed */ + getUnusedConfigs() { + const unusedConfigs: string[] = []; + + // add the flag constName to the unusedConfigs array if it was not accessed + flags?.forEach(flag => { + if (!this.usedConfigs.has(flag.constName)) { + unusedConfigs.push(flag.constName); + } + }); + + // add the extra properties to the unusedConfigs array if it was not accessed + extraProperties?.forEach(item => { + if (!this.usedConfigs.has(item)) { + unusedConfigs.push(item); + } + }); + return unusedConfigs; + } + }; + + const newConfigInstance = new NewConfigClass(); + + // add the new instance to the configMaps so that it can be used to get the + // unused configurations using the configName from the BaseCommand + configMaps.set(configName, newConfigInstance); + + return newConfigInstance; +} From d06dd40105419cb3d04d71a0ed03e91f1a8427f9 Mon Sep 17 00:00:00 2001 From: Ivo Yankov Date: Fri, 24 Jan 2025 12:56:53 +0200 Subject: [PATCH 03/14] fix: refactor node classes Signed-off-by: Ivo Yankov --- src/commands/base.ts | 13 --- src/commands/cluster/handlers.ts | 20 ----- src/commands/explorer.ts | 9 ++- src/commands/mirror_node.ts | 8 +- src/commands/network.ts | 9 +-- src/commands/node/configs.ts | 9 ++- src/commands/node/handlers.ts | 133 ++++++++++++++----------------- src/commands/node/index.ts | 53 +++--------- src/commands/node/tasks.ts | 95 ++++++++-------------- src/commands/relay.ts | 4 +- src/core/command_handler.ts | 20 ++++- src/core/helpers.ts | 14 ++++ test/e2e/e2e_node_util.ts | 4 +- 13 files changed, 158 insertions(+), 233 deletions(-) diff --git a/src/commands/base.ts b/src/commands/base.ts index 6a11455e6..7c6f658d5 100644 --- a/src/commands/base.ts +++ b/src/commands/base.ts @@ -82,19 +82,6 @@ export abstract class BaseCommand extends ShellRunner { return `${chartRepo}/${chartReleaseName}`; } - prepareValuesFiles(valuesFile: string) { - let valuesArg = ''; - if (valuesFile) { - const valuesFiles = valuesFile.split(','); - valuesFiles.forEach(vf => { - const vfp = paths.resolve(vf); - valuesArg += ` --values ${vfp}`; - }); - } - - return valuesArg; - } - getConfigManager(): ConfigManager { return this.configManager; } diff --git a/src/commands/cluster/handlers.ts b/src/commands/cluster/handlers.ts index d40eea89e..b88f53969 100644 --- a/src/commands/cluster/handlers.ts +++ b/src/commands/cluster/handlers.ts @@ -27,20 +27,15 @@ import {patchInject} from "../../core/container_helper.js"; import {K8} from "../../core/k8.js"; import {CommandHandler} from "../../core/command_handler.js"; import {LocalConfig} from "../../core/config/local_config.js"; -import type {CommandFlag} from "../../types/flag_types.js"; -import {ConfigManager} from "../../core/config_manager.js"; import {ChartManager} from "../../core/chart_manager.js"; @injectable() export class ClusterCommandHandlers extends CommandHandler { - protected readonly _configMaps = new Map(); - constructor( @inject(ClusterCommandTasks) private readonly tasks: ClusterCommandTasks, @inject(RemoteConfigManager) private readonly remoteConfigManager: RemoteConfigManager, @inject(LocalConfig) private readonly localConfig: LocalConfig, @inject(K8) private readonly k8: K8, - @inject(ConfigManager) private readonly configManager: ConfigManager, @inject(ChartManager) private readonly chartManager: ChartManager, ) { super(); @@ -49,7 +44,6 @@ export class ClusterCommandHandlers extends CommandHandler { this.remoteConfigManager = patchInject(remoteConfigManager, RemoteConfigManager, this.constructor.name); this.k8 = patchInject(k8, K8, this.constructor.name); this.localConfig = patchInject(localConfig, LocalConfig, this.constructor.name); - this.configManager = patchInject(configManager, ConfigManager, this.constructor.name); this.chartManager = patchInject(chartManager, ChartManager, this.constructor.name); } @@ -162,18 +156,4 @@ export class ClusterCommandHandlers extends CommandHandler { } return true; } - - close(): Promise { - // no-op - return Promise.resolve(); - } - - // Config related methods: - getConfig(configName: string, flags: CommandFlag[], extraProperties: string[] = []): object { - return helpers.getConfig(this.configManager, this._configMaps, configName, flags, extraProperties); - } - - getUnusedConfigs(configName: string): string[] { - return this._configMaps.get(configName).getUnusedConfigs(); - } } diff --git a/src/commands/explorer.ts b/src/commands/explorer.ts index 16c96fc77..efe43a6a2 100644 --- a/src/commands/explorer.ts +++ b/src/commands/explorer.ts @@ -29,6 +29,7 @@ import {ComponentType} from '../core/config/remote/enumerations.js'; import type {Namespace} from '../core/config/remote/types.js'; import {MirrorNodeExplorerComponent} from '../core/config/remote/components/mirror_node_explorer_component.js'; import {type SoloListrTask} from '../types/index.js'; +import {prepareValuesFiles} from "../core/helpers.js"; interface ExplorerDeployConfigClass { chartDirectory: string; @@ -91,11 +92,11 @@ export class ExplorerCommand extends BaseCommand { const profileName = this.configManager.getFlag(flags.profileName) as string; const profileValuesFile = await this.profileManager.prepareValuesHederaExplorerChart(profileName); if (profileValuesFile) { - valuesArg += this.prepareValuesFiles(profileValuesFile); + valuesArg += prepareValuesFiles(profileValuesFile); } if (config.valuesFile) { - valuesArg += this.prepareValuesFiles(config.valuesFile); + valuesArg += prepareValuesFiles(config.valuesFile); } valuesArg += ` --set proxyPass./api="http://${constants.MIRROR_NODE_RELEASE_NAME}-rest" `; @@ -150,7 +151,7 @@ export class ExplorerCommand extends BaseCommand { async prepareValuesArg(config: ExplorerDeployConfigClass) { let valuesArg = ''; if (config.valuesFile) { - valuesArg += this.prepareValuesFiles(config.valuesFile); + valuesArg += prepareValuesFiles(config.valuesFile); } return valuesArg; } @@ -247,7 +248,7 @@ export class ExplorerCommand extends BaseCommand { task: async ctx => { const config = ctx.config; - let exploreValuesArg = self.prepareValuesFiles(constants.EXPLORER_VALUES_FILE); + let exploreValuesArg = prepareValuesFiles(constants.EXPLORER_VALUES_FILE); exploreValuesArg += await self.prepareHederaExplorerValuesArg(config); await self.chartManager.install( diff --git a/src/commands/mirror_node.ts b/src/commands/mirror_node.ts index d7a60335a..9220bd352 100644 --- a/src/commands/mirror_node.ts +++ b/src/commands/mirror_node.ts @@ -22,7 +22,7 @@ import {type AccountManager} from '../core/account_manager.js'; import {type ProfileManager} from '../core/profile_manager.js'; import {BaseCommand} from './base.js'; import {Flags as flags} from './flags.js'; -import {getEnvValue} from '../core/helpers.js'; +import {getEnvValue, prepareValuesFiles} from '../core/helpers.js'; import {type CommandBuilder, type PodName} from '../types/aliases.js'; import {type Opts} from '../types/command_types.js'; import {ListrLease} from '../core/lease/listr_lease.js'; @@ -106,11 +106,11 @@ export class MirrorNodeCommand extends BaseCommand { const profileName = this.configManager.getFlag(flags.profileName) as string; const profileValuesFile = await this.profileManager.prepareValuesForMirrorNodeChart(profileName); if (profileValuesFile) { - valuesArg += this.prepareValuesFiles(profileValuesFile); + valuesArg += prepareValuesFiles(profileValuesFile); } if (config.valuesFile) { - valuesArg += this.prepareValuesFiles(config.valuesFile); + valuesArg += prepareValuesFiles(config.valuesFile); } if (config.storageBucket) { @@ -172,7 +172,7 @@ export class MirrorNodeCommand extends BaseCommand { ); // predefined values first - ctx.config.valuesArg += this.prepareValuesFiles(constants.MIRROR_NODE_VALUES_FILE); + ctx.config.valuesArg += prepareValuesFiles(constants.MIRROR_NODE_VALUES_FILE); // user defined values later to override predefined values ctx.config.valuesArg += await self.prepareValuesArg(ctx.config); diff --git a/src/commands/network.ts b/src/commands/network.ts index 2aead3e95..b001b4d4e 100644 --- a/src/commands/network.ts +++ b/src/commands/network.ts @@ -22,8 +22,7 @@ import {BaseCommand} from './base.js'; import {Flags as flags} from './flags.js'; import * as constants from '../core/constants.js'; import {Templates} from '../core/templates.js'; -import * as helpers from '../core/helpers.js'; -import {addDebugOptions, resolveValidJsonFilePath, validatePath} from '../core/helpers.js'; +import {addDebugOptions, prepareValuesFiles, resolveValidJsonFilePath, validatePath, parseNodeAliases} from '../core/helpers.js'; import path from 'path'; import fs from 'fs'; import {type KeyManager} from '../core/key_manager.js'; @@ -312,7 +311,7 @@ export class NetworkCommand extends BaseCommand { const profileName = this.configManager.getFlag(flags.profileName) as string; this.profileValuesFile = await this.profileManager.prepareValuesForSoloChart(profileName); if (this.profileValuesFile) { - valuesArg += this.prepareValuesFiles(this.profileValuesFile); + valuesArg += prepareValuesFiles(this.profileValuesFile); } valuesArg += ` --set "telemetry.prometheus.svcMonitor.enabled=${config.enablePrometheusSvcMonitor}"`; @@ -347,7 +346,7 @@ export class NetworkCommand extends BaseCommand { } if (config.valuesFile) { - valuesArg += this.prepareValuesFiles(config.valuesFile); + valuesArg += prepareValuesFiles(config.valuesFile); } this.logger.debug('Prepared helm chart values', {valuesArg}); @@ -402,7 +401,7 @@ export class NetworkCommand extends BaseCommand { 'resolvedThrottlesFile', ]) as NetworkDeployConfigClass; - config.nodeAliases = helpers.parseNodeAliases(config.nodeAliasesUnparsed); + config.nodeAliases = parseNodeAliases(config.nodeAliasesUnparsed); if (config.haproxyIps) { config.haproxyIpsParsed = Templates.parseNodeAliasToIpMapping(config.haproxyIps); diff --git a/src/commands/node/configs.ts b/src/commands/node/configs.ts index 553df29ea..4b4e4f316 100644 --- a/src/commands/node/configs.ts +++ b/src/commands/node/configs.ts @@ -108,7 +108,7 @@ export const upgradeConfigBuilder = async function (argv, ctx, task, shouldLoadN // set config in the context for later tasks to use ctx.config = config; - ctx.config.chartPath = await this.prepareChartPath( + ctx.config.chartPath = await helpers.prepareChartPath(this.helm, ctx.config.chartDirectory, constants.SOLO_TESTING_CHART_URL, constants.SOLO_DEPLOYMENT_CHART, @@ -144,7 +144,7 @@ export const updateConfigBuilder = async function (argv, ctx, task, shouldLoadNo // set config in the context for later tasks to use ctx.config = config; - ctx.config.chartPath = await this.prepareChartPath( + ctx.config.chartPath = await helpers.prepareChartPath(this.helm, ctx.config.chartDirectory, constants.SOLO_TESTING_CHART_URL, constants.SOLO_DEPLOYMENT_CHART, @@ -187,7 +187,7 @@ export const deleteConfigBuilder = async function (argv, ctx, task, shouldLoadNo // set config in the context for later tasks to use ctx.config = config; - ctx.config.chartPath = await this.prepareChartPath( + ctx.config.chartPath = await helpers.prepareChartPath(this.helm, ctx.config.chartDirectory, constants.SOLO_TESTING_CHART_URL, constants.SOLO_DEPLOYMENT_CHART, @@ -235,7 +235,8 @@ export const addConfigBuilder = async function (argv, ctx, task, shouldLoadNodeC // set config in the context for later tasks to use ctx.config = config; - ctx.config.chartPath = await this.prepareChartPath( + ctx.config.chartPath = await helpers.prepareChartPath( + this.helm, ctx.config.chartDirectory, constants.SOLO_TESTING_CHART_URL, constants.SOLO_DEPLOYMENT_CHART, diff --git a/src/commands/node/handlers.ts b/src/commands/node/handlers.ts index 2f645cdbc..be7f886fa 100644 --- a/src/commands/node/handlers.ts +++ b/src/commands/node/handlers.ts @@ -33,19 +33,16 @@ import { upgradeConfigBuilder, } from './configs.js'; import * as constants from '../../core/constants.js'; -import {type AccountManager} from '../../core/account_manager.js'; -import {type ConfigManager} from '../../core/config_manager.js'; -import {type PlatformInstaller} from '../../core/platform_installer.js'; -import {type K8} from '../../core/k8.js'; -import {type LeaseManager} from '../../core/lease/lease_manager.js'; -import {type RemoteConfigManager} from '../../core/config/remote/remote_config_manager.js'; -import {IllegalArgumentError, SoloError} from '../../core/errors.js'; +import {AccountManager} from '../../core/account_manager.js'; +import {PlatformInstaller} from '../../core/platform_installer.js'; +import {K8} from '../../core/k8.js'; +import {LeaseManager} from '../../core/lease/lease_manager.js'; +import {RemoteConfigManager} from '../../core/config/remote/remote_config_manager.js'; +import {SoloError} from '../../core/errors.js'; import {ComponentType, ConsensusNodeStates} from '../../core/config/remote/enumerations.js'; -import type {SoloLogger} from '../../core/logging.js'; -import type {NodeCommandTasks} from './tasks.js'; +import {NodeCommandTasks} from './tasks.js'; import {type Lease} from '../../core/lease/lease.js'; import {NodeSubcommandType} from '../../core/enumerations.js'; -import {type BaseCommand} from '../base.js'; import {NodeHelper} from './helper.js'; import type {NodeAlias, NodeAliases} from '../../types/aliases.js'; import {ConsensusNodeComponent} from '../../core/config/remote/components/consensus_node_component.js'; @@ -53,44 +50,32 @@ import {type Listr, type ListrTask} from 'listr2'; import chalk from 'chalk'; import type {ComponentsDataWrapper} from '../../core/config/remote/components_data_wrapper.js'; import type {Optional} from '../../types/index.js'; - -export class NodeCommandHandlers { - private readonly accountManager: AccountManager; - private readonly configManager: ConfigManager; - private readonly platformInstaller: PlatformInstaller; - private readonly logger: SoloLogger; - private readonly k8: K8; - private readonly tasks: NodeCommandTasks; - private readonly leaseManager: LeaseManager; - public readonly remoteConfigManager: RemoteConfigManager; - - private getConfig: any; - private prepareChartPath: any; - - public readonly parent: BaseCommand; - - constructor(opts: any) { - if (!opts || !opts.accountManager) - throw new IllegalArgumentError('An instance of core/AccountManager is required', opts.accountManager); - if (!opts || !opts.configManager) throw new Error('An instance of core/ConfigManager is required'); - if (!opts || !opts.logger) throw new Error('An instance of core/Logger is required'); - if (!opts || !opts.tasks) throw new Error('An instance of NodeCommandTasks is required'); - if (!opts || !opts.k8) throw new Error('An instance of core/K8 is required'); - if (!opts || !opts.platformInstaller) - throw new IllegalArgumentError('An instance of core/PlatformInstaller is required', opts.platformInstaller); - - this.logger = opts.logger; - this.tasks = opts.tasks; - this.accountManager = opts.accountManager; - this.configManager = opts.configManager; - this.k8 = opts.k8; - this.platformInstaller = opts.platformInstaller; - this.leaseManager = opts.leaseManager; - this.remoteConfigManager = opts.remoteConfigManager; - - this.getConfig = opts.parent.getConfig.bind(opts.parent); - this.prepareChartPath = opts.parent.prepareChartPath.bind(opts.parent); - this.parent = opts.parent; +import {inject, injectable} from "tsyringe-neo"; +import {patchInject} from "../../core/container_helper.js"; +import {CommandHandler} from "../../core/command_handler.js"; + +@injectable() +export class NodeCommandHandlers extends CommandHandler { + private _portForwards: any; + + constructor( + @inject(AccountManager) private readonly accountManager: AccountManager, + @inject(K8) private readonly k8: K8, + @inject(PlatformInstaller) private readonly platformInstaller: PlatformInstaller, + @inject(LeaseManager) private readonly leaseManager: LeaseManager, + @inject(RemoteConfigManager) private readonly remoteConfigManager: RemoteConfigManager, + @inject(NodeCommandTasks) private readonly tasks: NodeCommandTasks, + ) { + super(); + + this.accountManager = patchInject(accountManager, AccountManager, this.constructor.name); + this.k8 = patchInject(k8, K8, this.constructor.name); + this.platformInstaller = patchInject(platformInstaller, PlatformInstaller, this.constructor.name); + this.leaseManager = patchInject(leaseManager, LeaseManager, this.constructor.name); + this.remoteConfigManager = patchInject(remoteConfigManager, RemoteConfigManager, this.constructor.name); + this.tasks = patchInject(tasks, NodeCommandTasks, this.constructor.name); + + this._portForwards = []; } static readonly ADD_CONTEXT_FILE = 'node-add.json'; @@ -274,7 +259,7 @@ export class NodeCommandHandlers { const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, prepareUpgradeConfigBuilder.bind(this), lease), this.tasks.prepareUpgradeZip(), @@ -295,7 +280,7 @@ export class NodeCommandHandlers { async freezeUpgrade(argv: any) { argv = helpers.addFlagsToArgv(argv, NodeFlags.DEFAULT_FLAGS); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, prepareUpgradeConfigBuilder.bind(this), null), this.tasks.prepareUpgradeZip(), @@ -318,7 +303,7 @@ export class NodeCommandHandlers { const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, downloadGeneratedFilesConfigBuilder.bind(this), lease), this.tasks.identifyExistingNodes(), @@ -341,7 +326,7 @@ export class NodeCommandHandlers { const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ ...this.updatePrepareTasks(argv, lease), ...this.updateSubmitTransactionsTasks(argv), @@ -363,7 +348,7 @@ export class NodeCommandHandlers { argv = helpers.addFlagsToArgv(argv, NodeFlags.UPDATE_PREPARE_FLAGS); const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ ...this.updatePrepareTasks(argv, lease), this.tasks.saveContextData(argv, NodeCommandHandlers.UPDATE_CONTEXT_FILE, NodeHelper.updateSaveContextParser), @@ -383,7 +368,7 @@ export class NodeCommandHandlers { async updateSubmitTransactions(argv) { const lease = await this.leaseManager.create(); argv = helpers.addFlagsToArgv(argv, NodeFlags.UPDATE_SUBMIT_TRANSACTIONS_FLAGS); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, updateConfigBuilder.bind(this), lease), this.tasks.loadContextData(argv, NodeCommandHandlers.UPDATE_CONTEXT_FILE, NodeHelper.updateLoadContextParser), @@ -404,7 +389,7 @@ export class NodeCommandHandlers { async updateExecute(argv) { const lease = await this.leaseManager.create(); argv = helpers.addFlagsToArgv(argv, NodeFlags.UPDATE_EXECUTE_FLAGS); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, updateConfigBuilder.bind(this), lease, false), this.tasks.loadContextData(argv, NodeCommandHandlers.UPDATE_CONTEXT_FILE, NodeHelper.updateLoadContextParser), @@ -425,7 +410,7 @@ export class NodeCommandHandlers { async upgradePrepare(argv) { argv = helpers.addFlagsToArgv(argv, NodeFlags.UPGRADE_PREPARE_FLAGS); const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ ...this.upgradePrepareTasks(argv, lease), this.tasks.saveContextData(argv, NodeCommandHandlers.UPGRADE_CONTEXT_FILE, NodeHelper.upgradeSaveContextParser), @@ -444,7 +429,7 @@ export class NodeCommandHandlers { async upgradeSubmitTransactions(argv) { const lease = await this.leaseManager.create(); argv = helpers.addFlagsToArgv(argv, NodeFlags.UPGRADE_SUBMIT_TRANSACTIONS_FLAGS); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, upgradeConfigBuilder.bind(this), lease), this.tasks.loadContextData(argv, NodeCommandHandlers.UPGRADE_CONTEXT_FILE, NodeHelper.upgradeLoadContextParser), @@ -465,7 +450,7 @@ export class NodeCommandHandlers { async upgradeExecute(argv) { const lease = await this.leaseManager.create(); argv = helpers.addFlagsToArgv(argv, NodeFlags.UPGRADE_FLAGS); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, upgradeConfigBuilder.bind(this), lease, false), this.tasks.loadContextData(argv, NodeCommandHandlers.UPGRADE_CONTEXT_FILE, NodeHelper.upgradeLoadContextParser), @@ -486,7 +471,7 @@ export class NodeCommandHandlers { async upgrade(argv: any) { argv = helpers.addFlagsToArgv(argv, NodeFlags.UPGRADE_FLAGS); const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ ...this.upgradePrepareTasks(argv, lease), ...this.upgradeSubmitTransactionsTasks(argv), @@ -507,7 +492,7 @@ export class NodeCommandHandlers { async delete(argv: any) { argv = helpers.addFlagsToArgv(argv, NodeFlags.DELETE_FLAGS); const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ ...this.deletePrepareTaskList(argv, lease), ...this.deleteSubmitTransactionsTaskList(argv), @@ -530,7 +515,7 @@ export class NodeCommandHandlers { const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ ...this.deletePrepareTaskList(argv, lease), this.tasks.saveContextData(argv, NodeCommandHandlers.DELETE_CONTEXT_FILE, NodeHelper.deleteSaveContextParser), @@ -552,7 +537,7 @@ export class NodeCommandHandlers { const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, deleteConfigBuilder.bind(this), lease), this.tasks.loadContextData(argv, NodeCommandHandlers.DELETE_CONTEXT_FILE, NodeHelper.deleteLoadContextParser), @@ -575,7 +560,7 @@ export class NodeCommandHandlers { const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, deleteConfigBuilder.bind(this), lease, false), this.tasks.loadContextData(argv, NodeCommandHandlers.DELETE_CONTEXT_FILE, NodeHelper.deleteLoadContextParser), @@ -598,7 +583,7 @@ export class NodeCommandHandlers { const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [...this.addPrepareTasks(argv, lease), ...this.addSubmitTransactionsTasks(argv), ...this.addExecuteTasks(argv)], { concurrent: false, @@ -617,7 +602,7 @@ export class NodeCommandHandlers { const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ ...this.addPrepareTasks(argv, lease), this.tasks.saveContextData(argv, NodeCommandHandlers.ADD_CONTEXT_FILE, helpers.addSaveContextParser), @@ -639,7 +624,7 @@ export class NodeCommandHandlers { const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, addConfigBuilder.bind(this), lease), this.tasks.loadContextData(argv, NodeCommandHandlers.ADD_CONTEXT_FILE, helpers.addLoadContextParser), @@ -662,7 +647,7 @@ export class NodeCommandHandlers { const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, addConfigBuilder.bind(this), lease, false), this.tasks.identifyExistingNodes(), @@ -683,7 +668,7 @@ export class NodeCommandHandlers { async logs(argv: any) { argv = helpers.addFlagsToArgv(argv, NodeFlags.LOGS_FLAGS); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [this.tasks.initialize(argv, logsConfigBuilder.bind(this), null), this.tasks.getNodeLogsAndConfigs()], { concurrent: false, @@ -700,7 +685,7 @@ export class NodeCommandHandlers { async states(argv: any) { argv = helpers.addFlagsToArgv(argv, NodeFlags.STATES_FLAGS); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [this.tasks.initialize(argv, statesConfigBuilder.bind(this), null), this.tasks.getNodeStateFiles()], { concurrent: false, @@ -719,7 +704,7 @@ export class NodeCommandHandlers { const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, refreshConfigBuilder.bind(this), lease), this.validateAllNodeStates({ @@ -748,7 +733,7 @@ export class NodeCommandHandlers { async keys(argv: any) { argv = helpers.addFlagsToArgv(argv, NodeFlags.KEYS_FLAGS); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, keysConfigBuilder.bind(this), null), this.tasks.generateGossipKeys(), @@ -772,7 +757,7 @@ export class NodeCommandHandlers { const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, stopConfigBuilder.bind(this), lease), this.validateAllNodeStates({ @@ -799,7 +784,7 @@ export class NodeCommandHandlers { const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, startConfigBuilder.bind(this), lease), this.validateAllNodeStates({acceptedStates: [ConsensusNodeStates.SETUP]}), @@ -829,7 +814,7 @@ export class NodeCommandHandlers { const lease = await this.leaseManager.create(); - const action = this.parent.commandActionBuilder( + const action = this.commandActionBuilder( [ this.tasks.initialize(argv, setupConfigBuilder.bind(this), lease), this.validateAllNodeStates({ diff --git a/src/commands/node/index.ts b/src/commands/node/index.ts index dceba53b7..669274b5f 100644 --- a/src/commands/node/index.ts +++ b/src/commands/node/index.ts @@ -19,10 +19,10 @@ import {IllegalArgumentError} from '../../core/errors.js'; import {type AccountManager} from '../../core/account_manager.js'; import {YargsCommand} from '../../core/yargs_command.js'; import {BaseCommand} from './../base.js'; -import {NodeCommandTasks} from './tasks.js'; import * as NodeFlags from './flags.js'; import {NodeCommandHandlers} from './handlers.js'; import {type Opts} from '../../types/command_types.js'; +import {patchInject} from "../../core/container_helper.js"; /** * Defines the core functionalities of 'node' command @@ -30,9 +30,7 @@ import {type Opts} from '../../types/command_types.js'; export class NodeCommand extends BaseCommand { private readonly accountManager: AccountManager; - public readonly tasks: NodeCommandTasks; public readonly handlers: NodeCommandHandlers; - public _portForwards: any; constructor(opts: Opts) { super(opts); @@ -51,50 +49,17 @@ export class NodeCommand extends BaseCommand { throw new IllegalArgumentError('An instance of CertificateManager is required', opts.certificateManager); this.accountManager = opts.accountManager; - this._portForwards = []; - - this.tasks = new NodeCommandTasks({ - accountManager: opts.accountManager, - configManager: opts.configManager, - logger: opts.logger, - platformInstaller: opts.platformInstaller, - profileManager: opts.profileManager, - k8: opts.k8, - keyManager: opts.keyManager, - chartManager: opts.chartManager, - certificateManager: opts.certificateManager, - parent: this, - }); - - this.handlers = new NodeCommandHandlers({ - accountManager: opts.accountManager, - configManager: opts.configManager, - platformInstaller: opts.platformInstaller, - logger: opts.logger, - k8: opts.k8, - tasks: this.tasks, - parent: this, - leaseManager: opts.leaseManager, - remoteConfigManager: opts.remoteConfigManager, - }); - } - /** - * stops and closes the port forwards - * - calls the accountManager.close() - * - for all portForwards, calls k8.stopPortForward(srv) - */ - async close() { - await this.accountManager.close(); - if (this._portForwards) { - for (const srv of this._portForwards) { - await this.k8.stopPortForward(srv); - } - } - - this._portForwards = []; + // TODO properly inject + this.handlers = patchInject(null, NodeCommandHandlers, this.constructor.name); } + +close(): Promise { + // no-op + return Promise.resolve(); +} + getCommandDefinition() { const self = this; return { diff --git a/src/commands/node/tasks.ts b/src/commands/node/tasks.ts index a5bf0d111..18f21ed78 100644 --- a/src/commands/node/tasks.ts +++ b/src/commands/node/tasks.ts @@ -14,14 +14,14 @@ * limitations under the License. * */ -import {type AccountManager} from '../../core/account_manager.js'; -import {type ConfigManager} from '../../core/config_manager.js'; -import {type KeyManager} from '../../core/key_manager.js'; -import {type ProfileManager} from '../../core/profile_manager.js'; -import {type PlatformInstaller} from '../../core/platform_installer.js'; -import {type K8} from '../../core/k8.js'; -import {type ChartManager} from '../../core/chart_manager.js'; -import {type CertificateManager} from '../../core/certificate_manager.js'; +import {AccountManager} from '../../core/account_manager.js'; +import {ConfigManager} from '../../core/config_manager.js'; +import {KeyManager} from '../../core/key_manager.js'; +import {ProfileManager} from '../../core/profile_manager.js'; +import {PlatformInstaller} from '../../core/platform_installer.js'; +import {K8} from '../../core/k8.js'; +import {ChartManager} from '../../core/chart_manager.js'; +import {CertificateManager} from '../../core/certificate_manager.js'; import {Zippy} from '../../core/zippy.js'; import * as constants from '../../core/constants.js'; import { @@ -59,10 +59,11 @@ import { renameAndCopyFile, sleep, splitFlagInput, + prepareValuesFiles } from '../../core/helpers.js'; import chalk from 'chalk'; import {Flags as flags} from '../flags.js'; -import {type SoloLogger} from '../../core/logging.js'; +import {SoloLogger} from '../../core/logging.js'; import type {Listr, ListrTaskWrapper} from 'listr2'; import { type ConfigBuilder, @@ -76,61 +77,33 @@ import type {NodeDeleteConfigClass, NodeRefreshConfigClass, NodeUpdateConfigClas 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'; import {GenesisNetworkDataConstructor} from '../../core/genesis_network_models/genesis_network_data_constructor.js'; +import {inject, injectable} from "tsyringe-neo"; +import {patchInject} from "../../core/container_helper.js"; +@injectable() export class NodeCommandTasks { - private readonly accountManager: AccountManager; - private readonly configManager: ConfigManager; - private readonly keyManager: KeyManager; - private readonly profileManager: ProfileManager; - private readonly platformInstaller: PlatformInstaller; - private readonly logger: SoloLogger; - private readonly k8: K8; - private readonly parent: BaseCommand; - private readonly chartManager: ChartManager; - private readonly certificateManager: CertificateManager; - - private readonly prepareValuesFiles: any; - - constructor(opts: { - logger: SoloLogger; - accountManager: AccountManager; - configManager: ConfigManager; - k8: K8; - platformInstaller: PlatformInstaller; - keyManager: KeyManager; - profileManager: ProfileManager; - chartManager: ChartManager; - certificateManager: CertificateManager; - parent: BaseCommand; - }) { - if (!opts || !opts.accountManager) - throw new IllegalArgumentError('An instance of core/AccountManager is required', opts.accountManager as any); - if (!opts || !opts.configManager) throw new Error('An instance of core/ConfigManager is required'); - if (!opts || !opts.logger) throw new Error('An instance of core/Logger is required'); - if (!opts || !opts.k8) throw new Error('An instance of core/K8 is required'); - if (!opts || !opts.platformInstaller) - throw new IllegalArgumentError('An instance of core/PlatformInstaller is required', opts.platformInstaller); - if (!opts || !opts.keyManager) - throw new IllegalArgumentError('An instance of core/KeyManager is required', opts.keyManager); - if (!opts || !opts.profileManager) - throw new IllegalArgumentError('An instance of ProfileManager is required', opts.profileManager); - if (!opts || !opts.certificateManager) - throw new IllegalArgumentError('An instance of CertificateManager is required', opts.certificateManager); - - this.accountManager = opts.accountManager; - this.configManager = opts.configManager; - this.logger = opts.logger; - this.k8 = opts.k8; - - this.platformInstaller = opts.platformInstaller; - this.profileManager = opts.profileManager; - this.keyManager = opts.keyManager; - this.chartManager = opts.chartManager; - this.certificateManager = opts.certificateManager; - this.prepareValuesFiles = opts.parent.prepareValuesFiles.bind(opts.parent); + constructor( + @inject(SoloLogger) private readonly logger: SoloLogger, + @inject(AccountManager) private readonly accountManager: AccountManager, + @inject(ConfigManager) private readonly configManager: ConfigManager, + @inject(K8) private readonly k8: K8, + @inject(PlatformInstaller) private readonly platformInstaller: PlatformInstaller, + @inject(KeyManager) private readonly keyManager: KeyManager, + @inject(ProfileManager) private readonly profileManager: ProfileManager, + @inject(ChartManager) private readonly chartManager: ChartManager, + @inject(CertificateManager) private readonly certificateManager: CertificateManager, + ) { + this.logger = patchInject(logger, SoloLogger, this.constructor.name); + this.accountManager = patchInject(accountManager, AccountManager, this.constructor.name); + this.configManager = patchInject(configManager, ConfigManager, this.constructor.name); + this.k8 = patchInject(k8, K8, this.constructor.name); + this.platformInstaller = patchInject(platformInstaller, PlatformInstaller, this.constructor.name); + this.keyManager = patchInject(keyManager, KeyManager, this.constructor.name); + this.profileManager = patchInject(profileManager, ProfileManager, this.constructor.name); + this.chartManager = patchInject(chartManager, ChartManager, this.constructor.name); + this.certificateManager = patchInject(certificateManager, CertificateManager, this.constructor.name); } private async _prepareUpgradeZip(stagingDir: string) { @@ -1516,7 +1489,7 @@ export class NodeCommandTasks { path.join(config.stagingDir, 'templates', 'application.properties'), ); if (profileValuesFile) { - valuesArg += self.prepareValuesFiles(profileValuesFile); + valuesArg += prepareValuesFiles(profileValuesFile); } valuesArg = addDebugOptions(valuesArg, config.debugNodeAlias); diff --git a/src/commands/relay.ts b/src/commands/relay.ts index e3897e431..a71ca441f 100644 --- a/src/commands/relay.ts +++ b/src/commands/relay.ts @@ -84,7 +84,7 @@ export class RelayCommand extends BaseCommand { const profileName = this.configManager.getFlag(flags.profileName) as string; const profileValuesFile = await this.profileManager.prepareValuesForRpcRelayChart(profileName); if (profileValuesFile) { - valuesArg += this.prepareValuesFiles(profileValuesFile); + valuesArg += helpers.prepareValuesFiles(profileValuesFile); } valuesArg += ` --set config.MIRROR_NODE_URL=http://${constants.MIRROR_NODE_RELEASE_NAME}-rest`; @@ -135,7 +135,7 @@ export class RelayCommand extends BaseCommand { valuesArg += ` --set config.HEDERA_NETWORK='${networkJsonString}'`; if (valuesFile) { - valuesArg += this.prepareValuesFiles(valuesFile); + valuesArg += helpers.prepareValuesFiles(valuesFile); } return valuesArg; diff --git a/src/core/command_handler.ts b/src/core/command_handler.ts index d227e17a3..a79e56e29 100644 --- a/src/core/command_handler.ts +++ b/src/core/command_handler.ts @@ -7,13 +7,20 @@ import {Lease} from "./lease/lease.js"; import * as constants from "./constants.js"; import fs from "fs"; import {Task} from "./task.js"; +import type {CommandFlag} from "../types/flag_types.js"; +import * as helpers from "./helpers.js"; +import {ConfigManager} from "./config_manager.js"; @injectable() export class CommandHandler { + protected readonly _configMaps = new Map(); + constructor( @inject(SoloLogger) public readonly logger?: SoloLogger, + @inject(ConfigManager) private readonly configManager?: ConfigManager, ) { this.logger = patchInject(logger, SoloLogger, this.constructor.name); + this.configManager = patchInject(configManager, ConfigManager, this.constructor.name); } commandActionBuilder(actionTasks: any, options: any, errorString: string, lease: Lease | null) { @@ -28,7 +35,9 @@ export class CommandHandler { } finally { const promises = []; - promises.push(commandDef.close()); + if(commandDef.accountManager) { + promises.push(commandDef.accountManager.close()); + } if (lease) promises.push(lease.release()); await Promise.all(promises); @@ -71,4 +80,13 @@ export class CommandHandler { this.setupHomeDirectory(); }); } + + // Config related methods: + getConfig(configName: string, flags: CommandFlag[], extraProperties: string[] = []): object { + return helpers.getConfig(this.configManager, this._configMaps, configName, flags, extraProperties); + } + + getUnusedConfigs(configName: string): string[] { + return this._configMaps.get(configName).getUnusedConfigs(); + } } diff --git a/src/core/helpers.ts b/src/core/helpers.ts index 9ef2ab044..77ec76d52 100644 --- a/src/core/helpers.ts +++ b/src/core/helpers.ts @@ -30,6 +30,7 @@ import {type Duration} from './time/duration.js'; import {type NodeAddConfigClass} from '../commands/node/node_add_config.js'; import {Helm} from "./helm.js"; import {ConfigManager} from "./config_manager.js"; +import paths from "path"; export function sleep(duration: Duration) { return new Promise(resolve => { @@ -471,3 +472,16 @@ export function getConfig(configManager: ConfigManager, configMaps: Map { + const vfp = paths.resolve(vf); + valuesArg += ` --values ${vfp}`; + }); + } + + return valuesArg; +} \ No newline at end of file diff --git a/test/e2e/e2e_node_util.ts b/test/e2e/e2e_node_util.ts index fd6585eae..dc4502125 100644 --- a/test/e2e/e2e_node_util.ts +++ b/test/e2e/e2e_node_util.ts @@ -34,6 +34,7 @@ import type {ListrTaskWrapper} from 'listr2'; import {ConfigManager} from '../../src/core/config_manager.js'; import {type K8} from '../../src/core/k8.js'; import {type NodeCommand} from '../../src/commands/node/index.js'; +import {NodeCommandTasks} from '../../src/commands/node/tasks.js'; import {Duration} from '../../src/core/time/duration.js'; import {StatusCodes} from 'http-status-codes'; import {container} from 'tsyringe-neo'; @@ -168,11 +169,12 @@ export function e2eNodeKeyRefreshTest(testName: string, mode: string, releaseTag } function nodeShouldNotBeActive(nodeCmd: NodeCommand, nodeAlias: NodeAlias) { + const nodeTasks = container.resolve(NodeCommandTasks); it(`${nodeAlias} should not be ACTIVE`, async () => { expect(2); try { await expect( - nodeCmd.tasks._checkNetworkNodeActiveness( + nodeTasks._checkNetworkNodeActiveness( namespace, nodeAlias, {title: ''} as ListrTaskWrapper, From 9dfe512c2af6b493ffcb0d71265c98ee1a180031 Mon Sep 17 00:00:00 2001 From: Ivo Yankov Date: Fri, 24 Jan 2025 14:17:33 +0200 Subject: [PATCH 04/14] chore: format Signed-off-by: Ivo Yankov --- src/commands/base.ts | 2 +- src/commands/cluster/configs.ts | 10 +- src/commands/cluster/handlers.ts | 34 ++-- src/commands/cluster/index.ts | 2 +- src/commands/cluster/tasks.ts | 78 +++++---- src/commands/deployment.ts | 2 +- src/commands/explorer.ts | 2 +- src/commands/network.ts | 8 +- src/commands/node/configs.ts | 9 +- src/commands/node/handlers.ts | 34 ++-- src/commands/node/index.ts | 11 +- src/commands/node/tasks.ts | 36 ++-- src/core/command_handler.ts | 167 ++++++++++--------- src/core/config/remote/listr_config_tasks.ts | 2 +- src/core/container_init.ts | 8 +- src/core/helpers.ts | 165 +++++++++--------- test/e2e/e2e_node_util.ts | 2 +- 17 files changed, 308 insertions(+), 264 deletions(-) diff --git a/src/commands/base.ts b/src/commands/base.ts index 7c6f658d5..8f498b665 100644 --- a/src/commands/base.ts +++ b/src/commands/base.ts @@ -34,7 +34,7 @@ import path from 'path'; import * as constants from '../core/constants.js'; import fs from 'fs'; import {Task} from '../core/task.js'; -import {getConfig} from "../core/helpers.js"; +import {getConfig} from '../core/helpers.js'; export abstract class BaseCommand extends ShellRunner { protected readonly helm: Helm; diff --git a/src/commands/cluster/configs.ts b/src/commands/cluster/configs.ts index 3971d84a7..e07f0df20 100644 --- a/src/commands/cluster/configs.ts +++ b/src/commands/cluster/configs.ts @@ -61,7 +61,10 @@ export const setupConfigBuilder = async function (argv, ctx, task) { this.logger.debug('Prepare ctx.config', {config: ctx.config, argv}); - ctx.isChartInstalled = await this.chartManager.isChartInstalled(ctx.config.clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART); + ctx.isChartInstalled = await this.chartManager.isChartInstalled( + ctx.config.clusterSetupNamespace, + constants.SOLO_CLUSTER_SETUP_CHART, + ); return ctx.config; }; @@ -87,7 +90,10 @@ export const resetConfigBuilder = async function (argv, ctx, task) { clusterSetupNamespace: this.configManager.getFlag(flags.clusterSetupNamespace) as string, } as ClusterResetConfigClass; - ctx.isChartInstalled = await this.chartManager.isChartInstalled(ctx.config.clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART); + ctx.isChartInstalled = await this.chartManager.isChartInstalled( + ctx.config.clusterSetupNamespace, + constants.SOLO_CLUSTER_SETUP_CHART, + ); if (!ctx.isChartInstalled) { throw new SoloError('No chart found for the cluster'); } diff --git a/src/commands/cluster/handlers.ts b/src/commands/cluster/handlers.ts index b88f53969..c1bf0b41d 100644 --- a/src/commands/cluster/handlers.ts +++ b/src/commands/cluster/handlers.ts @@ -22,29 +22,29 @@ import {ListrRemoteConfig} from '../../core/config/remote/listr_config_tasks.js' import {RemoteConfigManager} from '../../core/config/remote/remote_config_manager.js'; import {connectConfigBuilder, resetConfigBuilder, setupConfigBuilder} from './configs.js'; import {SoloError} from '../../core/errors.js'; -import {inject, injectable} from "tsyringe-neo"; -import {patchInject} from "../../core/container_helper.js"; -import {K8} from "../../core/k8.js"; -import {CommandHandler} from "../../core/command_handler.js"; -import {LocalConfig} from "../../core/config/local_config.js"; -import {ChartManager} from "../../core/chart_manager.js"; +import {inject, injectable} from 'tsyringe-neo'; +import {patchInject} from '../../core/container_helper.js'; +import {K8} from '../../core/k8.js'; +import {CommandHandler} from '../../core/command_handler.js'; +import {LocalConfig} from '../../core/config/local_config.js'; +import {ChartManager} from '../../core/chart_manager.js'; @injectable() export class ClusterCommandHandlers extends CommandHandler { constructor( - @inject(ClusterCommandTasks) private readonly tasks: ClusterCommandTasks, - @inject(RemoteConfigManager) private readonly remoteConfigManager: RemoteConfigManager, - @inject(LocalConfig) private readonly localConfig: LocalConfig, - @inject(K8) private readonly k8: K8, - @inject(ChartManager) private readonly chartManager: ChartManager, + @inject(ClusterCommandTasks) private readonly tasks: ClusterCommandTasks, + @inject(RemoteConfigManager) private readonly remoteConfigManager: RemoteConfigManager, + @inject(LocalConfig) private readonly localConfig: LocalConfig, + @inject(K8) private readonly k8: K8, + @inject(ChartManager) private readonly chartManager: ChartManager, ) { - super(); + super(); - this.tasks = patchInject(tasks, ClusterCommandTasks, this.constructor.name); - this.remoteConfigManager = patchInject(remoteConfigManager, RemoteConfigManager, this.constructor.name); - this.k8 = patchInject(k8, K8, this.constructor.name); - this.localConfig = patchInject(localConfig, LocalConfig, this.constructor.name); - this.chartManager = patchInject(chartManager, ChartManager, this.constructor.name); + this.tasks = patchInject(tasks, ClusterCommandTasks, this.constructor.name); + this.remoteConfigManager = patchInject(remoteConfigManager, RemoteConfigManager, this.constructor.name); + this.k8 = patchInject(k8, K8, this.constructor.name); + this.localConfig = patchInject(localConfig, LocalConfig, this.constructor.name); + this.chartManager = patchInject(chartManager, ChartManager, this.constructor.name); } async connect(argv: any) { diff --git a/src/commands/cluster/index.ts b/src/commands/cluster/index.ts index 5cf61e407..4aea9a6a7 100644 --- a/src/commands/cluster/index.ts +++ b/src/commands/cluster/index.ts @@ -21,7 +21,7 @@ import {BaseCommand} from './../base.js'; import {type Opts} from '../../types/command_types.js'; import {ClusterCommandHandlers} from './handlers.js'; import {DEFAULT_FLAGS, RESET_FLAGS, SETUP_FLAGS} from './flags.js'; -import {patchInject} from "../../core/container_helper.js"; +import {patchInject} from '../../core/container_helper.js'; /** * Defines the core functionalities of 'node' command diff --git a/src/commands/cluster/tasks.ts b/src/commands/cluster/tasks.ts index bcfb9f003..cff1027bd 100644 --- a/src/commands/cluster/tasks.ts +++ b/src/commands/cluster/tasks.ts @@ -34,38 +34,41 @@ import type {SelectClusterContextContext} from './configs.js'; import type {Namespace} from '../../core/config/remote/types.js'; import {LocalConfig} from '../../core/config/local_config.js'; import {ListrEnquirerPromptAdapter} from '@listr2/prompt-adapter-enquirer'; -import {inject, injectable} from "tsyringe-neo"; -import {patchInject} from "../../core/container_helper.js"; -import {ConfigManager} from "../../core/config_manager.js"; -import {SoloLogger} from "../../core/logging.js"; -import {ChartManager} from "../../core/chart_manager.js"; -import {LeaseManager} from "../../core/lease/lease_manager.js"; -import {Helm} from "../../core/helm.js"; +import {inject, injectable} from 'tsyringe-neo'; +import {patchInject} from '../../core/container_helper.js'; +import {ConfigManager} from '../../core/config_manager.js'; +import {SoloLogger} from '../../core/logging.js'; +import {ChartManager} from '../../core/chart_manager.js'; +import {LeaseManager} from '../../core/lease/lease_manager.js'; +import {Helm} from '../../core/helm.js'; @injectable() export class ClusterCommandTasks { - constructor( - @inject(K8) private readonly k8: K8, - @inject(ConfigManager) private readonly configManager: ConfigManager, - @inject(RemoteConfigManager) private readonly remoteConfigManager: RemoteConfigManager, - @inject(LocalConfig) private readonly localConfig: LocalConfig, - @inject(SoloLogger) private readonly logger: SoloLogger, - @inject(ChartManager) private readonly chartManager: ChartManager, - @inject(LeaseManager) private readonly leaseManager: LeaseManager, - @inject(Helm) private readonly helm: Helm, - + constructor( + @inject(K8) private readonly k8: K8, + @inject(ConfigManager) private readonly configManager: ConfigManager, + @inject(RemoteConfigManager) private readonly remoteConfigManager: RemoteConfigManager, + @inject(LocalConfig) private readonly localConfig: LocalConfig, + @inject(SoloLogger) private readonly logger: SoloLogger, + @inject(ChartManager) private readonly chartManager: ChartManager, + @inject(LeaseManager) private readonly leaseManager: LeaseManager, + @inject(Helm) private readonly helm: Helm, ) { - this.k8 = patchInject(k8, K8, this.constructor.name); - this.configManager = patchInject(configManager, ConfigManager, this.constructor.name); - this.remoteConfigManager = patchInject(remoteConfigManager, RemoteConfigManager, this.constructor.name); - this.localConfig = patchInject(localConfig, LocalConfig, this.constructor.name); - this.logger = patchInject(logger, SoloLogger, this.constructor.name); - this.chartManager = patchInject(chartManager, ChartManager, this.constructor.name); - this.leaseManager = patchInject(leaseManager, LeaseManager, this.constructor.name); - this.helm = patchInject(helm, Helm, this.constructor.name); + this.k8 = patchInject(k8, K8, this.constructor.name); + this.configManager = patchInject(configManager, ConfigManager, this.constructor.name); + this.remoteConfigManager = patchInject(remoteConfigManager, RemoteConfigManager, this.constructor.name); + this.localConfig = patchInject(localConfig, LocalConfig, this.constructor.name); + this.logger = patchInject(logger, SoloLogger, this.constructor.name); + this.chartManager = patchInject(chartManager, ChartManager, this.constructor.name); + this.leaseManager = patchInject(leaseManager, LeaseManager, this.constructor.name); + this.helm = patchInject(helm, Helm, this.constructor.name); } - public testConnectionToCluster(cluster: string, localConfig: LocalConfig, parentTask: ListrTaskWrapper) { + public testConnectionToCluster( + cluster: string, + localConfig: LocalConfig, + parentTask: ListrTaskWrapper, + ) { const self = this; return { title: `Test connection to cluster: ${chalk.cyan(cluster)}`, @@ -278,10 +281,7 @@ export class ClusterCommandTasks { /** Show list of installed chart */ private async showInstalledChartList(clusterSetupNamespace: string) { - this.logger.showList( - 'Installed Charts', - await this.chartManager.getInstalledCharts(clusterSetupNamespace), - ); + this.logger.showList('Installed Charts', await this.chartManager.getInstalledCharts(clusterSetupNamespace)); } public selectContext(): SoloListrTask { @@ -382,7 +382,7 @@ export class ClusterCommandTasks { }); } - public getClusterInfo() { + public getClusterInfo() { return new Task('Get cluster info', async (ctx: any, task: ListrTaskWrapper) => { try { const cluster = this.k8.getCurrentCluster(); @@ -394,7 +394,7 @@ export class ClusterCommandTasks { }); } - public prepareChartValues(argv) { + public prepareChartValues(argv) { const self = this; return new Task( @@ -452,7 +452,7 @@ export class ClusterCommandTasks { ); } - public installClusterChart(argv) { + public installClusterChart(argv) { const self = this; return new Task( `Install '${constants.SOLO_CLUSTER_SETUP_CHART}' chart`, @@ -463,7 +463,13 @@ export class ClusterCommandTasks { try { self.logger.debug(`Installing chart chartPath = ${ctx.chartPath}, version = ${version}`); - await self.chartManager.install(clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART, ctx.chartPath, version, valuesArg); + await self.chartManager.install( + clusterSetupNamespace, + constants.SOLO_CLUSTER_SETUP_CHART, + ctx.chartPath, + version, + valuesArg, + ); } catch (e: Error | unknown) { // if error, uninstall the chart and rethrow the error self.logger.debug( @@ -487,14 +493,14 @@ export class ClusterCommandTasks { ); } - public acquireNewLease(argv) { + public acquireNewLease(argv) { return new Task('Acquire new lease', async (ctx: any, task: ListrTaskWrapper) => { const lease = await this.leaseManager.create(); return ListrLease.newAcquireLeaseTask(lease, task); }); } - public uninstallClusterChart(argv) { + public uninstallClusterChart(argv) { const self = this; return new Task( diff --git a/src/commands/deployment.ts b/src/commands/deployment.ts index e3760a912..43a2e4fde 100644 --- a/src/commands/deployment.ts +++ b/src/commands/deployment.ts @@ -29,7 +29,7 @@ import type {CommandFlag} from '../types/flag_types.js'; import type {CommandBuilder} from '../types/aliases.js'; import type {Opts} from '../types/command_types.js'; import type {SoloListrTask} from '../types/index.js'; -import {container} from "tsyringe-neo"; +import {container} from 'tsyringe-neo'; export class DeploymentCommand extends BaseCommand { readonly tasks: ClusterCommandTasks; diff --git a/src/commands/explorer.ts b/src/commands/explorer.ts index efe43a6a2..3174aefb5 100644 --- a/src/commands/explorer.ts +++ b/src/commands/explorer.ts @@ -29,7 +29,7 @@ import {ComponentType} from '../core/config/remote/enumerations.js'; import type {Namespace} from '../core/config/remote/types.js'; import {MirrorNodeExplorerComponent} from '../core/config/remote/components/mirror_node_explorer_component.js'; import {type SoloListrTask} from '../types/index.js'; -import {prepareValuesFiles} from "../core/helpers.js"; +import {prepareValuesFiles} from '../core/helpers.js'; interface ExplorerDeployConfigClass { chartDirectory: string; diff --git a/src/commands/network.ts b/src/commands/network.ts index b001b4d4e..bdb90c299 100644 --- a/src/commands/network.ts +++ b/src/commands/network.ts @@ -22,7 +22,13 @@ import {BaseCommand} from './base.js'; import {Flags as flags} from './flags.js'; import * as constants from '../core/constants.js'; import {Templates} from '../core/templates.js'; -import {addDebugOptions, prepareValuesFiles, resolveValidJsonFilePath, validatePath, parseNodeAliases} from '../core/helpers.js'; +import { + addDebugOptions, + prepareValuesFiles, + resolveValidJsonFilePath, + validatePath, + parseNodeAliases, +} from '../core/helpers.js'; import path from 'path'; import fs from 'fs'; import {type KeyManager} from '../core/key_manager.js'; diff --git a/src/commands/node/configs.ts b/src/commands/node/configs.ts index 4b4e4f316..f46532432 100644 --- a/src/commands/node/configs.ts +++ b/src/commands/node/configs.ts @@ -108,7 +108,8 @@ export const upgradeConfigBuilder = async function (argv, ctx, task, shouldLoadN // set config in the context for later tasks to use ctx.config = config; - ctx.config.chartPath = await helpers.prepareChartPath(this.helm, + ctx.config.chartPath = await helpers.prepareChartPath( + this.helm, ctx.config.chartDirectory, constants.SOLO_TESTING_CHART_URL, constants.SOLO_DEPLOYMENT_CHART, @@ -144,7 +145,8 @@ export const updateConfigBuilder = async function (argv, ctx, task, shouldLoadNo // set config in the context for later tasks to use ctx.config = config; - ctx.config.chartPath = await helpers.prepareChartPath(this.helm, + ctx.config.chartPath = await helpers.prepareChartPath( + this.helm, ctx.config.chartDirectory, constants.SOLO_TESTING_CHART_URL, constants.SOLO_DEPLOYMENT_CHART, @@ -187,7 +189,8 @@ export const deleteConfigBuilder = async function (argv, ctx, task, shouldLoadNo // set config in the context for later tasks to use ctx.config = config; - ctx.config.chartPath = await helpers.prepareChartPath(this.helm, + ctx.config.chartPath = await helpers.prepareChartPath( + this.helm, ctx.config.chartDirectory, constants.SOLO_TESTING_CHART_URL, constants.SOLO_DEPLOYMENT_CHART, diff --git a/src/commands/node/handlers.ts b/src/commands/node/handlers.ts index be7f886fa..468cb30e9 100644 --- a/src/commands/node/handlers.ts +++ b/src/commands/node/handlers.ts @@ -50,32 +50,32 @@ import {type Listr, type ListrTask} from 'listr2'; import chalk from 'chalk'; import type {ComponentsDataWrapper} from '../../core/config/remote/components_data_wrapper.js'; import type {Optional} from '../../types/index.js'; -import {inject, injectable} from "tsyringe-neo"; -import {patchInject} from "../../core/container_helper.js"; -import {CommandHandler} from "../../core/command_handler.js"; +import {inject, injectable} from 'tsyringe-neo'; +import {patchInject} from '../../core/container_helper.js'; +import {CommandHandler} from '../../core/command_handler.js'; @injectable() export class NodeCommandHandlers extends CommandHandler { private _portForwards: any; constructor( - @inject(AccountManager) private readonly accountManager: AccountManager, - @inject(K8) private readonly k8: K8, - @inject(PlatformInstaller) private readonly platformInstaller: PlatformInstaller, - @inject(LeaseManager) private readonly leaseManager: LeaseManager, - @inject(RemoteConfigManager) private readonly remoteConfigManager: RemoteConfigManager, - @inject(NodeCommandTasks) private readonly tasks: NodeCommandTasks, + @inject(AccountManager) private readonly accountManager: AccountManager, + @inject(K8) private readonly k8: K8, + @inject(PlatformInstaller) private readonly platformInstaller: PlatformInstaller, + @inject(LeaseManager) private readonly leaseManager: LeaseManager, + @inject(RemoteConfigManager) private readonly remoteConfigManager: RemoteConfigManager, + @inject(NodeCommandTasks) private readonly tasks: NodeCommandTasks, ) { - super(); + super(); - this.accountManager = patchInject(accountManager, AccountManager, this.constructor.name); - this.k8 = patchInject(k8, K8, this.constructor.name); - this.platformInstaller = patchInject(platformInstaller, PlatformInstaller, this.constructor.name); - this.leaseManager = patchInject(leaseManager, LeaseManager, this.constructor.name); - this.remoteConfigManager = patchInject(remoteConfigManager, RemoteConfigManager, this.constructor.name); - this.tasks = patchInject(tasks, NodeCommandTasks, this.constructor.name); + this.accountManager = patchInject(accountManager, AccountManager, this.constructor.name); + this.k8 = patchInject(k8, K8, this.constructor.name); + this.platformInstaller = patchInject(platformInstaller, PlatformInstaller, this.constructor.name); + this.leaseManager = patchInject(leaseManager, LeaseManager, this.constructor.name); + this.remoteConfigManager = patchInject(remoteConfigManager, RemoteConfigManager, this.constructor.name); + this.tasks = patchInject(tasks, NodeCommandTasks, this.constructor.name); - this._portForwards = []; + this._portForwards = []; } static readonly ADD_CONTEXT_FILE = 'node-add.json'; diff --git a/src/commands/node/index.ts b/src/commands/node/index.ts index 669274b5f..d02ac9727 100644 --- a/src/commands/node/index.ts +++ b/src/commands/node/index.ts @@ -22,7 +22,7 @@ import {BaseCommand} from './../base.js'; import * as NodeFlags from './flags.js'; import {NodeCommandHandlers} from './handlers.js'; import {type Opts} from '../../types/command_types.js'; -import {patchInject} from "../../core/container_helper.js"; +import {patchInject} from '../../core/container_helper.js'; /** * Defines the core functionalities of 'node' command @@ -54,11 +54,14 @@ export class NodeCommand extends BaseCommand { this.handlers = patchInject(null, NodeCommandHandlers, this.constructor.name); } - -close(): Promise { + close(): Promise { // no-op return Promise.resolve(); -} + } + + getUnusedConfigs(configName: string): string[] { + return this.handlers.getUnusedConfigs(configName); + } getCommandDefinition() { const self = this; diff --git a/src/commands/node/tasks.ts b/src/commands/node/tasks.ts index 18f21ed78..3255e9714 100644 --- a/src/commands/node/tasks.ts +++ b/src/commands/node/tasks.ts @@ -59,7 +59,7 @@ import { renameAndCopyFile, sleep, splitFlagInput, - prepareValuesFiles + prepareValuesFiles, } from '../../core/helpers.js'; import chalk from 'chalk'; import {Flags as flags} from '../flags.js'; @@ -79,31 +79,31 @@ import {ListrLease} from '../../core/lease/listr_lease.js'; import {Duration} from '../../core/time/duration.js'; import {type NodeAddConfigClass} from './node_add_config.js'; import {GenesisNetworkDataConstructor} from '../../core/genesis_network_models/genesis_network_data_constructor.js'; -import {inject, injectable} from "tsyringe-neo"; -import {patchInject} from "../../core/container_helper.js"; +import {inject, injectable} from 'tsyringe-neo'; +import {patchInject} from '../../core/container_helper.js'; @injectable() export class NodeCommandTasks { constructor( - @inject(SoloLogger) private readonly logger: SoloLogger, - @inject(AccountManager) private readonly accountManager: AccountManager, - @inject(ConfigManager) private readonly configManager: ConfigManager, - @inject(K8) private readonly k8: K8, - @inject(PlatformInstaller) private readonly platformInstaller: PlatformInstaller, - @inject(KeyManager) private readonly keyManager: KeyManager, - @inject(ProfileManager) private readonly profileManager: ProfileManager, - @inject(ChartManager) private readonly chartManager: ChartManager, - @inject(CertificateManager) private readonly certificateManager: CertificateManager, + @inject(SoloLogger) private readonly logger: SoloLogger, + @inject(AccountManager) private readonly accountManager: AccountManager, + @inject(ConfigManager) private readonly configManager: ConfigManager, + @inject(K8) private readonly k8: K8, + @inject(PlatformInstaller) private readonly platformInstaller: PlatformInstaller, + @inject(KeyManager) private readonly keyManager: KeyManager, + @inject(ProfileManager) private readonly profileManager: ProfileManager, + @inject(ChartManager) private readonly chartManager: ChartManager, + @inject(CertificateManager) private readonly certificateManager: CertificateManager, ) { this.logger = patchInject(logger, SoloLogger, this.constructor.name); this.accountManager = patchInject(accountManager, AccountManager, this.constructor.name); this.configManager = patchInject(configManager, ConfigManager, this.constructor.name); - this.k8 = patchInject(k8, K8, this.constructor.name); - this.platformInstaller = patchInject(platformInstaller, PlatformInstaller, this.constructor.name); - this.keyManager = patchInject(keyManager, KeyManager, this.constructor.name); - this.profileManager = patchInject(profileManager, ProfileManager, this.constructor.name); - this.chartManager = patchInject(chartManager, ChartManager, this.constructor.name); - this.certificateManager = patchInject(certificateManager, CertificateManager, this.constructor.name); + this.k8 = patchInject(k8, K8, this.constructor.name); + this.platformInstaller = patchInject(platformInstaller, PlatformInstaller, this.constructor.name); + this.keyManager = patchInject(keyManager, KeyManager, this.constructor.name); + this.profileManager = patchInject(profileManager, ProfileManager, this.constructor.name); + this.chartManager = patchInject(chartManager, ChartManager, this.constructor.name); + this.certificateManager = patchInject(certificateManager, CertificateManager, this.constructor.name); } private async _prepareUpgradeZip(stagingDir: string) { diff --git a/src/core/command_handler.ts b/src/core/command_handler.ts index a79e56e29..d8028f720 100644 --- a/src/core/command_handler.ts +++ b/src/core/command_handler.ts @@ -1,92 +1,107 @@ -import {inject, injectable} from "tsyringe-neo"; -import {SoloLogger} from "./logging.js"; -import {patchInject} from "./container_helper.js"; -import {Listr} from "listr2"; -import {SoloError} from "./errors.js"; -import {Lease} from "./lease/lease.js"; -import * as constants from "./constants.js"; -import fs from "fs"; -import {Task} from "./task.js"; -import type {CommandFlag} from "../types/flag_types.js"; -import * as helpers from "./helpers.js"; -import {ConfigManager} from "./config_manager.js"; +/** + * 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 {inject, injectable} from 'tsyringe-neo'; +import {SoloLogger} from './logging.js'; +import {patchInject} from './container_helper.js'; +import {Listr} from 'listr2'; +import {SoloError} from './errors.js'; +import {type Lease} from './lease/lease.js'; +import * as constants from './constants.js'; +import fs from 'fs'; +import {Task} from './task.js'; +import type {CommandFlag} from '../types/flag_types.js'; +import * as helpers from './helpers.js'; +import {ConfigManager} from './config_manager.js'; @injectable() export class CommandHandler { - protected readonly _configMaps = new Map(); + protected readonly _configMaps = new Map(); - constructor( - @inject(SoloLogger) public readonly logger?: SoloLogger, - @inject(ConfigManager) private readonly configManager?: ConfigManager, - ) { - this.logger = patchInject(logger, SoloLogger, this.constructor.name); - this.configManager = patchInject(configManager, ConfigManager, this.constructor.name); - } - - commandActionBuilder(actionTasks: any, options: any, errorString: string, lease: Lease | null) { - return async function (argv: any, commandDef) { - const tasks = new Listr([...actionTasks], options); + constructor( + @inject(SoloLogger) public readonly logger?: SoloLogger, + @inject(ConfigManager) private readonly configManager?: ConfigManager, + ) { + this.logger = patchInject(logger, SoloLogger, this.constructor.name); + this.configManager = patchInject(configManager, ConfigManager, this.constructor.name); + } - try { - await tasks.run(); - } catch (e: Error | any) { - commandDef.logger.error(`${errorString}: ${e.message}`, e); - throw new SoloError(`${errorString}: ${e.message}`, e); - } finally { - const promises = []; + commandActionBuilder(actionTasks: any, options: any, errorString: string, lease: Lease | null) { + return async function (argv: any, commandDef) { + const tasks = new Listr([...actionTasks], options); - if(commandDef.accountManager) { - promises.push(commandDef.accountManager.close()); - } + try { + await tasks.run(); + } catch (e: Error | any) { + commandDef.logger.error(`${errorString}: ${e.message}`, e); + throw new SoloError(`${errorString}: ${e.message}`, e); + } finally { + const promises = []; - if (lease) promises.push(lease.release()); - await Promise.all(promises); - } - }; - } + if (commandDef.accountManager) { + promises.push(commandDef.accountManager.close()); + } + if (lease) promises.push(lease.release()); + await Promise.all(promises); + } + }; + } - /** - * Setup home directories - * @param dirs a list of directories that need to be created in sequence - */ - setupHomeDirectory( - dirs: string[] = [ - constants.SOLO_HOME_DIR, - constants.SOLO_LOGS_DIR, - constants.SOLO_CACHE_DIR, - constants.SOLO_VALUES_DIR, - ], - ) { - const self = this; + /** + * Setup home directories + * @param dirs a list of directories that need to be created in sequence + */ + setupHomeDirectory( + dirs: string[] = [ + constants.SOLO_HOME_DIR, + constants.SOLO_LOGS_DIR, + constants.SOLO_CACHE_DIR, + constants.SOLO_VALUES_DIR, + ], + ) { + const self = this; - try { - dirs.forEach(dirPath => { - if (!fs.existsSync(dirPath)) { - fs.mkdirSync(dirPath, {recursive: true}); - } - self.logger.debug(`OK: setup directory: ${dirPath}`); - }); - } catch (e: Error | any) { - self.logger.error(e); - throw new SoloError(`failed to create directory: ${e.message}`, e); + try { + dirs.forEach(dirPath => { + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath, {recursive: true}); } - - return dirs; + self.logger.debug(`OK: setup directory: ${dirPath}`); + }); + } catch (e: Error | any) { + self.logger.error(e); + throw new SoloError(`failed to create directory: ${e.message}`, e); } - setupHomeDirectoryTask() { - return new Task('Setup home directory', async () => { - this.setupHomeDirectory(); - }); - } + return dirs; + } - // Config related methods: - getConfig(configName: string, flags: CommandFlag[], extraProperties: string[] = []): object { - return helpers.getConfig(this.configManager, this._configMaps, configName, flags, extraProperties); - } + setupHomeDirectoryTask() { + return new Task('Setup home directory', async () => { + this.setupHomeDirectory(); + }); + } - getUnusedConfigs(configName: string): string[] { - return this._configMaps.get(configName).getUnusedConfigs(); - } + // Config related methods: + getConfig(configName: string, flags: CommandFlag[], extraProperties: string[] = []): object { + return helpers.getConfig(this.configManager, this._configMaps, configName, flags, extraProperties); + } + + getUnusedConfigs(configName: string): string[] { + return this._configMaps.get(configName).getUnusedConfigs(); + } } diff --git a/src/core/config/remote/listr_config_tasks.ts b/src/core/config/remote/listr_config_tasks.ts index f1dc33164..a227f8d25 100644 --- a/src/core/config/remote/listr_config_tasks.ts +++ b/src/core/config/remote/listr_config_tasks.ts @@ -18,7 +18,7 @@ import type {ListrTask} from 'listr2'; import type {BaseCommand} from '../../../commands/base.js'; import {type Cluster, type Context, type Namespace} from './types.js'; import type {SoloListrTask} from '../../../types/index.js'; -import {RemoteConfigManager} from "./remote_config_manager.js"; +import {type RemoteConfigManager} from './remote_config_manager.js'; /** * Static class that handles all tasks related to remote config used by other commands. diff --git a/src/core/container_init.ts b/src/core/container_init.ts index 36faa9439..b734e0491 100644 --- a/src/core/container_init.ts +++ b/src/core/container_init.ts @@ -36,10 +36,10 @@ import {LocalConfig} from './config/local_config.js'; import {RemoteConfigManager} from './config/remote/remote_config_manager.js'; import os from 'os'; import * as version from '../../version.js'; -import {ClusterCommandHandlers} from "../commands/cluster/handlers.js"; -import {ClusterCommandTasks} from "../commands/cluster/tasks.js"; -import {NodeCommandTasks} from "../commands/node/tasks.js"; -import {NodeCommandHandlers} from "../commands/node/handlers.js"; +import {ClusterCommandHandlers} from '../commands/cluster/handlers.js'; +import {ClusterCommandTasks} from '../commands/cluster/tasks.js'; +import {NodeCommandTasks} from '../commands/node/tasks.js'; +import {NodeCommandHandlers} from '../commands/node/handlers.js'; /** * Container class to manage the dependency injection container diff --git a/src/core/helpers.ts b/src/core/helpers.ts index 77ec76d52..9f0292bb2 100644 --- a/src/core/helpers.ts +++ b/src/core/helpers.ts @@ -28,9 +28,9 @@ 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/node_add_config.js'; -import {Helm} from "./helm.js"; -import {ConfigManager} from "./config_manager.js"; -import paths from "path"; +import {type Helm} from './helm.js'; +import {type ConfigManager} from './config_manager.js'; +import paths from 'path'; export function sleep(duration: Duration) { return new Promise(resolve => { @@ -388,18 +388,17 @@ export function resolveValidJsonFilePath(filePath: string, defaultPath?: string) } } - export async function prepareChartPath(helm: Helm, chartDir: string, chartRepo: string, chartReleaseName: string) { - if (!chartRepo) throw new MissingArgumentError('chart repo name is required'); - if (!chartReleaseName) throw new MissingArgumentError('chart release name is required'); + if (!chartRepo) throw new MissingArgumentError('chart repo name is required'); + if (!chartReleaseName) throw new MissingArgumentError('chart release name is required'); - if (chartDir) { - const chartPath = path.join(chartDir, chartReleaseName); - await helm.dependency('update', chartPath); - return chartPath; - } + if (chartDir) { + const chartPath = path.join(chartDir, chartReleaseName); + await helm.dependency('update', chartPath); + return chartPath; + } - return `${chartRepo}/${chartReleaseName}`; + return `${chartRepo}/${chartReleaseName}`; } /** @@ -407,81 +406,87 @@ export async function prepareChartPath(helm: Helm, chartDir: string, chartRepo: * and extra properties, will keep track of which properties are used. Call * getUnusedConfigs() to get an array of unused properties. */ -export function getConfig(configManager: ConfigManager, configMaps: Map, configName: string, flags: CommandFlag[], extraProperties: string[] = []): object { - // build the dynamic class that will keep track of which properties are used - const NewConfigClass = class { - private usedConfigs: Map; - constructor() { - // the map to keep track of which properties are used - this.usedConfigs = new Map(); - - // add the flags as properties to this class - flags?.forEach(flag => { - // @ts-ignore - this[`_${flag.constName}`] = configManager.getFlag(flag); - Object.defineProperty(this, flag.constName, { - get() { - this.usedConfigs.set(flag.constName, this.usedConfigs.get(flag.constName) + 1 || 1); - return this[`_${flag.constName}`]; - }, - }); - }); - - // add the extra properties as properties to this class - extraProperties?.forEach(name => { - // @ts-ignore - this[`_${name}`] = ''; - Object.defineProperty(this, name, { - get() { - this.usedConfigs.set(name, this.usedConfigs.get(name) + 1 || 1); - return this[`_${name}`]; - }, - set(value) { - this[`_${name}`] = value; - }, - }); - }); +export function getConfig( + configManager: ConfigManager, + configMaps: Map, + configName: string, + flags: CommandFlag[], + extraProperties: string[] = [], +): object { + // build the dynamic class that will keep track of which properties are used + const NewConfigClass = class { + private usedConfigs: Map; + constructor() { + // the map to keep track of which properties are used + this.usedConfigs = new Map(); + + // add the flags as properties to this class + flags?.forEach(flag => { + // @ts-ignore + this[`_${flag.constName}`] = configManager.getFlag(flag); + Object.defineProperty(this, flag.constName, { + get() { + this.usedConfigs.set(flag.constName, this.usedConfigs.get(flag.constName) + 1 || 1); + return this[`_${flag.constName}`]; + }, + }); + }); + + // add the extra properties as properties to this class + extraProperties?.forEach(name => { + // @ts-ignore + this[`_${name}`] = ''; + Object.defineProperty(this, name, { + get() { + this.usedConfigs.set(name, this.usedConfigs.get(name) + 1 || 1); + return this[`_${name}`]; + }, + set(value) { + this[`_${name}`] = value; + }, + }); + }); + } + + /** Get the list of unused configurations that were not accessed */ + getUnusedConfigs() { + const unusedConfigs: string[] = []; + + // add the flag constName to the unusedConfigs array if it was not accessed + flags?.forEach(flag => { + if (!this.usedConfigs.has(flag.constName)) { + unusedConfigs.push(flag.constName); } + }); - /** Get the list of unused configurations that were not accessed */ - getUnusedConfigs() { - const unusedConfigs: string[] = []; - - // add the flag constName to the unusedConfigs array if it was not accessed - flags?.forEach(flag => { - if (!this.usedConfigs.has(flag.constName)) { - unusedConfigs.push(flag.constName); - } - }); - - // add the extra properties to the unusedConfigs array if it was not accessed - extraProperties?.forEach(item => { - if (!this.usedConfigs.has(item)) { - unusedConfigs.push(item); - } - }); - return unusedConfigs; + // add the extra properties to the unusedConfigs array if it was not accessed + extraProperties?.forEach(item => { + if (!this.usedConfigs.has(item)) { + unusedConfigs.push(item); } - }; + }); + return unusedConfigs; + } + }; - const newConfigInstance = new NewConfigClass(); + const newConfigInstance = new NewConfigClass(); - // add the new instance to the configMaps so that it can be used to get the - // unused configurations using the configName from the BaseCommand - configMaps.set(configName, newConfigInstance); + // add the new instance to the configMaps so that it can be used to get the + // unused configurations using the configName from the BaseCommand + configMaps.set(configName, newConfigInstance); - return newConfigInstance; + return newConfigInstance; } export function prepareValuesFiles(valuesFile: string) { - let valuesArg = ''; - if (valuesFile) { - const valuesFiles = valuesFile.split(','); - valuesFiles.forEach(vf => { - const vfp = paths.resolve(vf); - valuesArg += ` --values ${vfp}`; - }); - } + let valuesArg = ''; + if (valuesFile) { + const valuesFiles = valuesFile.split(','); + valuesFiles.forEach(vf => { + const vfp = paths.resolve(vf); + valuesArg += ` --values ${vfp}`; + }); + } - return valuesArg; -} \ No newline at end of file + return valuesArg; +} diff --git a/test/e2e/e2e_node_util.ts b/test/e2e/e2e_node_util.ts index dc4502125..00110ffe9 100644 --- a/test/e2e/e2e_node_util.ts +++ b/test/e2e/e2e_node_util.ts @@ -174,7 +174,7 @@ export function e2eNodeKeyRefreshTest(testName: string, mode: string, releaseTag expect(2); try { await expect( - nodeTasks._checkNetworkNodeActiveness( + nodeTasks._checkNetworkNodeActiveness( namespace, nodeAlias, {title: ''} as ListrTaskWrapper, From 9d0d72dba6cb6e520d7932a39f16e8756174cb07 Mon Sep 17 00:00:00 2001 From: Ivo Yankov Date: Fri, 24 Jan 2025 14:35:15 +0200 Subject: [PATCH 05/14] fix: circular dependencies Signed-off-by: Ivo Yankov --- src/commands/base.ts | 3 +- src/core/command_handler.ts | 4 +- src/core/config_builder.ts | 95 +++++++++++++++++++++++++++++++++++++ src/core/helpers.ts | 78 ------------------------------ 4 files changed, 98 insertions(+), 82 deletions(-) create mode 100644 src/core/config_builder.ts diff --git a/src/commands/base.ts b/src/commands/base.ts index 8f498b665..52b2ac4a2 100644 --- a/src/commands/base.ts +++ b/src/commands/base.ts @@ -15,7 +15,6 @@ * */ -import paths from 'path'; import {MissingArgumentError, SoloError} from '../core/errors.js'; import {ShellRunner} from '../core/shell_runner.js'; import {type LeaseManager} from '../core/lease/lease_manager.js'; @@ -34,7 +33,7 @@ import path from 'path'; import * as constants from '../core/constants.js'; import fs from 'fs'; import {Task} from '../core/task.js'; -import {getConfig} from '../core/helpers.js'; +import {getConfig} from '../core/config_builder.js'; export abstract class BaseCommand extends ShellRunner { protected readonly helm: Helm; diff --git a/src/core/command_handler.ts b/src/core/command_handler.ts index d8028f720..720eae9fc 100644 --- a/src/core/command_handler.ts +++ b/src/core/command_handler.ts @@ -24,8 +24,8 @@ import * as constants from './constants.js'; import fs from 'fs'; import {Task} from './task.js'; import type {CommandFlag} from '../types/flag_types.js'; -import * as helpers from './helpers.js'; import {ConfigManager} from './config_manager.js'; +import {getConfig} from './config_builder.js'; @injectable() export class CommandHandler { @@ -98,7 +98,7 @@ export class CommandHandler { // Config related methods: getConfig(configName: string, flags: CommandFlag[], extraProperties: string[] = []): object { - return helpers.getConfig(this.configManager, this._configMaps, configName, flags, extraProperties); + return getConfig(this.configManager, this._configMaps, configName, flags, extraProperties); } getUnusedConfigs(configName: string): string[] { diff --git a/src/core/config_builder.ts b/src/core/config_builder.ts new file mode 100644 index 000000000..1ecfc6dda --- /dev/null +++ b/src/core/config_builder.ts @@ -0,0 +1,95 @@ +/** + * 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 ConfigManager} from './config_manager.js'; +import {type CommandFlag} from '../types/flag_types.js'; + +/** + * Dynamically builds a class with properties from the provided list of flags + * and extra properties, will keep track of which properties are used. Call + * getUnusedConfigs() to get an array of unused properties. + */ +export function getConfig( + configManager: ConfigManager, + configMaps: Map, + configName: string, + flags: CommandFlag[], + extraProperties: string[] = [], +): object { + // build the dynamic class that will keep track of which properties are used + const NewConfigClass = class { + private usedConfigs: Map; + constructor() { + // the map to keep track of which properties are used + this.usedConfigs = new Map(); + + // add the flags as properties to this class + flags?.forEach(flag => { + // @ts-ignore + this[`_${flag.constName}`] = configManager.getFlag(flag); + Object.defineProperty(this, flag.constName, { + get() { + this.usedConfigs.set(flag.constName, this.usedConfigs.get(flag.constName) + 1 || 1); + return this[`_${flag.constName}`]; + }, + }); + }); + + // add the extra properties as properties to this class + extraProperties?.forEach(name => { + // @ts-ignore + this[`_${name}`] = ''; + Object.defineProperty(this, name, { + get() { + this.usedConfigs.set(name, this.usedConfigs.get(name) + 1 || 1); + return this[`_${name}`]; + }, + set(value) { + this[`_${name}`] = value; + }, + }); + }); + } + + /** Get the list of unused configurations that were not accessed */ + getUnusedConfigs() { + const unusedConfigs: string[] = []; + + // add the flag constName to the unusedConfigs array if it was not accessed + flags?.forEach(flag => { + if (!this.usedConfigs.has(flag.constName)) { + unusedConfigs.push(flag.constName); + } + }); + + // add the extra properties to the unusedConfigs array if it was not accessed + extraProperties?.forEach(item => { + if (!this.usedConfigs.has(item)) { + unusedConfigs.push(item); + } + }); + return unusedConfigs; + } + }; + + const newConfigInstance = new NewConfigClass(); + + // add the new instance to the configMaps so that it can be used to get the + // unused configurations using the configName from the BaseCommand + configMaps.set(configName, newConfigInstance); + + return newConfigInstance; +} diff --git a/src/core/helpers.ts b/src/core/helpers.ts index 9f0292bb2..2c3737c95 100644 --- a/src/core/helpers.ts +++ b/src/core/helpers.ts @@ -29,7 +29,6 @@ import {type SoloLogger} from './logging.js'; import {type Duration} from './time/duration.js'; import {type NodeAddConfigClass} from '../commands/node/node_add_config.js'; import {type Helm} from './helm.js'; -import {type ConfigManager} from './config_manager.js'; import paths from 'path'; export function sleep(duration: Duration) { @@ -401,83 +400,6 @@ export async function prepareChartPath(helm: Helm, chartDir: string, chartRepo: return `${chartRepo}/${chartReleaseName}`; } -/** - * Dynamically builds a class with properties from the provided list of flags - * and extra properties, will keep track of which properties are used. Call - * getUnusedConfigs() to get an array of unused properties. - */ -export function getConfig( - configManager: ConfigManager, - configMaps: Map, - configName: string, - flags: CommandFlag[], - extraProperties: string[] = [], -): object { - // build the dynamic class that will keep track of which properties are used - const NewConfigClass = class { - private usedConfigs: Map; - constructor() { - // the map to keep track of which properties are used - this.usedConfigs = new Map(); - - // add the flags as properties to this class - flags?.forEach(flag => { - // @ts-ignore - this[`_${flag.constName}`] = configManager.getFlag(flag); - Object.defineProperty(this, flag.constName, { - get() { - this.usedConfigs.set(flag.constName, this.usedConfigs.get(flag.constName) + 1 || 1); - return this[`_${flag.constName}`]; - }, - }); - }); - - // add the extra properties as properties to this class - extraProperties?.forEach(name => { - // @ts-ignore - this[`_${name}`] = ''; - Object.defineProperty(this, name, { - get() { - this.usedConfigs.set(name, this.usedConfigs.get(name) + 1 || 1); - return this[`_${name}`]; - }, - set(value) { - this[`_${name}`] = value; - }, - }); - }); - } - - /** Get the list of unused configurations that were not accessed */ - getUnusedConfigs() { - const unusedConfigs: string[] = []; - - // add the flag constName to the unusedConfigs array if it was not accessed - flags?.forEach(flag => { - if (!this.usedConfigs.has(flag.constName)) { - unusedConfigs.push(flag.constName); - } - }); - - // add the extra properties to the unusedConfigs array if it was not accessed - extraProperties?.forEach(item => { - if (!this.usedConfigs.has(item)) { - unusedConfigs.push(item); - } - }); - return unusedConfigs; - } - }; - - const newConfigInstance = new NewConfigClass(); - - // add the new instance to the configMaps so that it can be used to get the - // unused configurations using the configName from the BaseCommand - configMaps.set(configName, newConfigInstance); - - return newConfigInstance; -} - export function prepareValuesFiles(valuesFile: string) { let valuesArg = ''; if (valuesFile) { From 7924da14e88fc50de76b21109e84aa8a06cbe496 Mon Sep 17 00:00:00 2001 From: Ivo Yankov Date: Mon, 27 Jan 2025 11:51:03 +0200 Subject: [PATCH 06/14] fix: unit tests Signed-off-by: Ivo Yankov --- test/unit/commands/cluster.test.ts | 37 ++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/test/unit/commands/cluster.test.ts b/test/unit/commands/cluster.test.ts index eb71de2dc..11e837f1f 100644 --- a/test/unit/commands/cluster.test.ts +++ b/test/unit/commands/cluster.test.ts @@ -37,7 +37,6 @@ import {ROOT_DIR} from '../../../src/core/constants.js'; import path from 'path'; import {container} from 'tsyringe-neo'; import {resetTestContainer} from '../../test_container.js'; -import * as test from 'node:test'; import {ClusterCommandTasks} from '../../../src/commands/cluster/tasks.js'; import type {BaseCommand} from '../../../src/commands/base.js'; import {LocalConfig} from '../../../src/core/config/local_config.js'; @@ -58,8 +57,6 @@ import type {ListrTaskWrapper} from 'listr2'; import fs from 'fs'; import {stringify} from 'yaml'; import {ErrorMessages} from '../../../src/core/error_messages.js'; -import {SoloError} from '../../../src/core/errors.js'; -import {RemoteConfigDataWrapper} from '../../../src/core/config/remote/remote_config_data_wrapper.js'; const getBaseCommandOpts = () => ({ logger: sinon.stub(), @@ -90,7 +87,7 @@ argv[flags.force.name] = true; argv[flags.clusterSetupNamespace.name] = constants.SOLO_SETUP_NAMESPACE; describe('ClusterCommand unit tests', () => { - before(() => { + beforeEach(() => { resetTestContainer(); }); @@ -211,7 +208,23 @@ describe('ClusterCommand unit tests', () => { configManager.getFlag.withArgs(stubbedFlags[i][0]).returns(stubbedFlags[i][1]); } - return { + container.unregister(RemoteConfigManager); + container.registerInstance(RemoteConfigManager, remoteConfigManagerStub); + + container.unregister(K8); + container.registerInstance(K8, k8Stub); + + const localConfig = new LocalConfig(filePath); + container.unregister(LocalConfig); + container.registerInstance(LocalConfig, localConfig); + + container.unregister(ConfigManager); + container.registerInstance(ConfigManager, configManager); + + container.unregister(SoloLogger); + container.registerInstance(SoloLogger, loggerStub); + + const options = { logger: loggerStub, helm: sandbox.createStubInstance(Helm), k8: k8Stub, @@ -228,16 +241,26 @@ describe('ClusterCommand unit tests', () => { certificateManager: sandbox.createStubInstance(CertificateManager), remoteConfigManager: remoteConfigManagerStub, } as Opts; + + // stubDependencies([Object.values(options)]); + + return options; }; + function stubDependencies(deps: any[]) { + for (const dep of deps) { + container.unregister(dep.constructor); + container.registerInstance(dep.constructor, dep); + } + } + describe('updateLocalConfig', () => { async function runUpdateLocalConfigTask(opts) { command = new ClusterCommand(opts); tasks = container.resolve(ClusterCommandTasks); - // @ts-expect-error - TS2554: Expected 0 arguments, but got 1. - const taskObj = tasks.updateLocalConfig({}); + const taskObj = tasks.updateLocalConfig(); await taskObj.task({config: {}} as any, sandbox.stub() as unknown as ListrTaskWrapper); return command; From 60fd0b4fbc99f9ecd79bb1957d1a605a72ba8840 Mon Sep 17 00:00:00 2001 From: Ivo Yankov Date: Mon, 27 Jan 2025 12:24:22 +0200 Subject: [PATCH 07/14] fix: formatting Signed-off-by: Ivo Yankov --- src/core/config/remote/listr_config_tasks.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/config/remote/listr_config_tasks.ts b/src/core/config/remote/listr_config_tasks.ts index 90bea8c13..3acc28d66 100644 --- a/src/core/config/remote/listr_config_tasks.ts +++ b/src/core/config/remote/listr_config_tasks.ts @@ -40,7 +40,10 @@ export class ListrRemoteConfig { * @param remoteConfigManager * @param argv - used to update the last executed command and command history */ - public static loadRemoteConfig(remoteConfigManager: RemoteConfigManager, argv: {_: string[]} & AnyObject): SoloListrTask { + public static loadRemoteConfig( + remoteConfigManager: RemoteConfigManager, + argv: {_: string[]} & AnyObject, + ): SoloListrTask { return { title: 'Load remote config', task: async (): Promise => { From 39a3a900cfa7e49a270baa92c8df9d9d3194a1d1 Mon Sep 17 00:00:00 2001 From: Ivo Yankov Date: Mon, 27 Jan 2025 14:16:33 +0200 Subject: [PATCH 08/14] fix: failing e2e test Signed-off-by: Ivo Yankov --- test/e2e/e2e_node_util.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/e2e_node_util.ts b/test/e2e/e2e_node_util.ts index 00110ffe9..a453a5c42 100644 --- a/test/e2e/e2e_node_util.ts +++ b/test/e2e/e2e_node_util.ts @@ -139,8 +139,8 @@ export function e2eNodeKeyRefreshTest(testName: string, mode: string, releaseTag function nodePodShouldBeRunning(nodeCmd: NodeCommand, namespace: string, nodeAlias: NodeAlias) { it(`${nodeAlias} should be running`, async () => { try { - // @ts-ignore to access tasks which is a private property - expect(await nodeCmd.tasks.checkNetworkNodePod(namespace, nodeAlias)).to.equal(`network-${nodeAlias}-0`); + const nodeTasks = container.resolve(NodeCommandTasks); + expect(await nodeTasks.checkNetworkNodePod(namespace, nodeAlias)).to.equal(`network-${nodeAlias}-0`); } catch (e) { nodeCmd.logger.showUserError(e); expect.fail(); From abcc89af1ee5786b05c523013fb3e7adc2c2a6cd Mon Sep 17 00:00:00 2001 From: Ivo Yankov Date: Tue, 28 Jan 2025 11:53:21 +0200 Subject: [PATCH 09/14] chore: resolve todos Signed-off-by: Ivo Yankov --- src/commands/base.ts | 35 ----------------------------------- src/commands/cluster/index.ts | 1 - src/commands/explorer.ts | 5 +++-- src/commands/mirror_node.ts | 5 +++-- src/commands/network.ts | 4 +++- src/commands/node/index.ts | 1 - src/commands/relay.ts | 5 +++-- src/core/command_handler.ts | 16 +++++++++------- 8 files changed, 21 insertions(+), 51 deletions(-) diff --git a/src/commands/base.ts b/src/commands/base.ts index e5f7d3604..7399c220a 100644 --- a/src/commands/base.ts +++ b/src/commands/base.ts @@ -67,20 +67,6 @@ export abstract class BaseCommand extends ShellRunner { this.remoteConfigManager = opts.remoteConfigManager; } - // TODO remove - async prepareChartPath(chartDir: string, chartRepo: string, chartReleaseName: string) { - if (!chartRepo) throw new MissingArgumentError('chart repo name is required'); - if (!chartReleaseName) throw new MissingArgumentError('chart release name is required'); - - if (chartDir) { - const chartPath = path.join(chartDir, chartReleaseName); - await this.helm.dependency('update', chartPath); - return chartPath; - } - - return `${chartRepo}/${chartReleaseName}`; - } - getConfigManager(): ConfigManager { return this.configManager; } @@ -124,27 +110,6 @@ export abstract class BaseCommand extends ShellRunner { abstract close(): Promise; - // TODO remove this - commandActionBuilder(actionTasks: any, options: any, errorString: string, lease: Lease | null) { - return async function (argv: any, commandDef) { - const tasks = new Listr([...actionTasks], options); - - try { - await tasks.run(); - } catch (e: Error | any) { - commandDef.parent.logger.error(`${errorString}: ${e.message}`, e); - throw new SoloError(`${errorString}: ${e.message}`, e); - } finally { - const promises = []; - - promises.push(commandDef.parent.close()); - - if (lease) promises.push(lease.release()); - await Promise.all(promises); - } - }; - } - /** * Setup home directories * @param dirs a list of directories that need to be created in sequence diff --git a/src/commands/cluster/index.ts b/src/commands/cluster/index.ts index 4aea9a6a7..12c476cbe 100644 --- a/src/commands/cluster/index.ts +++ b/src/commands/cluster/index.ts @@ -32,7 +32,6 @@ export class ClusterCommand extends BaseCommand { constructor(opts: Opts) { super(opts); - // TODO properly inject this.handlers = patchInject(null, ClusterCommandHandlers, this.constructor.name); } diff --git a/src/commands/explorer.ts b/src/commands/explorer.ts index 3174aefb5..8ec293373 100644 --- a/src/commands/explorer.ts +++ b/src/commands/explorer.ts @@ -29,7 +29,7 @@ import {ComponentType} from '../core/config/remote/enumerations.js'; import type {Namespace} from '../core/config/remote/types.js'; import {MirrorNodeExplorerComponent} from '../core/config/remote/components/mirror_node_explorer_component.js'; import {type SoloListrTask} from '../types/index.js'; -import {prepareValuesFiles} from '../core/helpers.js'; +import {prepareChartPath, prepareValuesFiles} from '../core/helpers.js'; interface ExplorerDeployConfigClass { chartDirectory: string; @@ -199,7 +199,8 @@ export class ExplorerCommand extends BaseCommand { const config = ctx.config; const {chartDirectory, clusterSetupNamespace, soloChartVersion} = config; - const chartPath = await this.prepareChartPath( + const chartPath = await prepareChartPath( + self.helm, chartDirectory, constants.SOLO_TESTING_CHART_URL, constants.SOLO_CLUSTER_SETUP_CHART, diff --git a/src/commands/mirror_node.ts b/src/commands/mirror_node.ts index 12c1635f9..41e5c4ad1 100644 --- a/src/commands/mirror_node.ts +++ b/src/commands/mirror_node.ts @@ -22,7 +22,7 @@ import {type AccountManager} from '../core/account_manager.js'; import {type ProfileManager} from '../core/profile_manager.js'; import {BaseCommand} from './base.js'; import {Flags as flags} from './flags.js'; -import {getEnvValue, prepareValuesFiles} from '../core/helpers.js'; +import {getEnvValue, prepareChartPath, prepareValuesFiles} from '../core/helpers.js'; import {type CommandBuilder, type PodName} from '../types/aliases.js'; import {type Opts} from '../types/command_types.js'; import {ListrLease} from '../core/lease/listr_lease.js'; @@ -165,7 +165,8 @@ export class MirrorNodeCommand extends BaseCommand { 'valuesArg', ]) as MirrorNodeDeployConfigClass; - ctx.config.chartPath = await self.prepareChartPath( + ctx.config.chartPath = await prepareChartPath( + self.helm, '', // don't use chartPath which is for local solo-charts only constants.MIRROR_NODE_RELEASE_NAME, constants.MIRROR_NODE_CHART, diff --git a/src/commands/network.ts b/src/commands/network.ts index 4cfc71930..f0375a7bb 100644 --- a/src/commands/network.ts +++ b/src/commands/network.ts @@ -28,6 +28,7 @@ import { resolveValidJsonFilePath, validatePath, parseNodeAliases, + prepareChartPath, } from '../core/helpers.js'; import path from 'path'; import fs from 'fs'; @@ -418,7 +419,8 @@ export class NetworkCommand extends BaseCommand { } // compute values - config.chartPath = await this.prepareChartPath( + config.chartPath = await prepareChartPath( + this.helm, config.chartDirectory, constants.SOLO_TESTING_CHART_URL, constants.SOLO_DEPLOYMENT_CHART, diff --git a/src/commands/node/index.ts b/src/commands/node/index.ts index d02ac9727..849f14467 100644 --- a/src/commands/node/index.ts +++ b/src/commands/node/index.ts @@ -50,7 +50,6 @@ export class NodeCommand extends BaseCommand { this.accountManager = opts.accountManager; - // TODO properly inject this.handlers = patchInject(null, NodeCommandHandlers, this.constructor.name); } diff --git a/src/commands/relay.ts b/src/commands/relay.ts index a71ca441f..2b62a0be3 100644 --- a/src/commands/relay.ts +++ b/src/commands/relay.ts @@ -22,7 +22,7 @@ import {type ProfileManager} from '../core/profile_manager.js'; import {type AccountManager} from '../core/account_manager.js'; import {BaseCommand} from './base.js'; import {Flags as flags} from './flags.js'; -import {getNodeAccountMap} from '../core/helpers.js'; +import {getNodeAccountMap, prepareChartPath} from '../core/helpers.js'; import {type CommandBuilder, type NodeAliases} from '../types/aliases.js'; import {type Opts} from '../types/command_types.js'; import {ListrLease} from '../core/lease/listr_lease.js'; @@ -241,7 +241,8 @@ export class RelayCommand extends BaseCommand { title: 'Prepare chart values', task: async ctx => { const config = ctx.config; - config.chartPath = await self.prepareChartPath( + config.chartPath = await prepareChartPath( + self.helm, config.chartDirectory, constants.JSON_RPC_RELAY_CHART, constants.JSON_RPC_RELAY_CHART, diff --git a/src/core/command_handler.ts b/src/core/command_handler.ts index 720eae9fc..32ea0fa83 100644 --- a/src/core/command_handler.ts +++ b/src/core/command_handler.ts @@ -26,6 +26,7 @@ import {Task} from './task.js'; import type {CommandFlag} from '../types/flag_types.js'; import {ConfigManager} from './config_manager.js'; import {getConfig} from './config_builder.js'; +import {type BaseCommand} from '../commands/base.js'; @injectable() export class CommandHandler { @@ -39,22 +40,23 @@ export class CommandHandler { this.configManager = patchInject(configManager, ConfigManager, this.constructor.name); } - commandActionBuilder(actionTasks: any, options: any, errorString: string, lease: Lease | null) { - return async function (argv: any, commandDef) { + public commandActionBuilder( + actionTasks: any, + options: any, + errorString: string, + lease: Lease | null, + ): (argv: any, handlerObj: CommandHandler) => Promise { + return async function (argv: any, handlerObj: CommandHandler): Promise { const tasks = new Listr([...actionTasks], options); try { await tasks.run(); } catch (e: Error | any) { - commandDef.logger.error(`${errorString}: ${e.message}`, e); + handlerObj.logger.error(`${errorString}: ${e.message}`, e); throw new SoloError(`${errorString}: ${e.message}`, e); } finally { const promises = []; - if (commandDef.accountManager) { - promises.push(commandDef.accountManager.close()); - } - if (lease) promises.push(lease.release()); await Promise.all(promises); } From 6902a5ca3a3e50192cf778a940927905895bea5c Mon Sep 17 00:00:00 2001 From: Ivo Yankov Date: Tue, 28 Jan 2025 12:15:54 +0200 Subject: [PATCH 10/14] chore: add method scopes and return types Signed-off-by: Ivo Yankov --- src/core/command_handler.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/command_handler.ts b/src/core/command_handler.ts index 32ea0fa83..550d5cb40 100644 --- a/src/core/command_handler.ts +++ b/src/core/command_handler.ts @@ -67,14 +67,14 @@ export class CommandHandler { * Setup home directories * @param dirs a list of directories that need to be created in sequence */ - setupHomeDirectory( + public setupHomeDirectory( dirs: string[] = [ constants.SOLO_HOME_DIR, constants.SOLO_LOGS_DIR, constants.SOLO_CACHE_DIR, constants.SOLO_VALUES_DIR, ], - ) { + ): string[] { const self = this; try { @@ -92,18 +92,18 @@ export class CommandHandler { return dirs; } - setupHomeDirectoryTask() { + public setupHomeDirectoryTask(): Task { return new Task('Setup home directory', async () => { this.setupHomeDirectory(); }); } // Config related methods: - getConfig(configName: string, flags: CommandFlag[], extraProperties: string[] = []): object { + public getConfig(configName: string, flags: CommandFlag[], extraProperties: string[] = []): object { return getConfig(this.configManager, this._configMaps, configName, flags, extraProperties); } - getUnusedConfigs(configName: string): string[] { + public getUnusedConfigs(configName: string): string[] { return this._configMaps.get(configName).getUnusedConfigs(); } } From aa5dc2069f34058d96797934627bdf1dffe1e3e6 Mon Sep 17 00:00:00 2001 From: Ivo Yankov Date: Tue, 28 Jan 2025 12:22:17 +0200 Subject: [PATCH 11/14] chore: code cleanup Signed-off-by: Ivo Yankov --- test/unit/commands/cluster.test.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/test/unit/commands/cluster.test.ts b/test/unit/commands/cluster.test.ts index 11e837f1f..ded8cff7e 100644 --- a/test/unit/commands/cluster.test.ts +++ b/test/unit/commands/cluster.test.ts @@ -242,18 +242,9 @@ describe('ClusterCommand unit tests', () => { remoteConfigManager: remoteConfigManagerStub, } as Opts; - // stubDependencies([Object.values(options)]); - return options; }; - function stubDependencies(deps: any[]) { - for (const dep of deps) { - container.unregister(dep.constructor); - container.registerInstance(dep.constructor, dep); - } - } - describe('updateLocalConfig', () => { async function runUpdateLocalConfigTask(opts) { command = new ClusterCommand(opts); From 7d86901a0100934ddcc4492aec95cd2aafefab0b Mon Sep 17 00:00:00 2001 From: Ivo Yankov Date: Thu, 30 Jan 2025 16:16:25 +0200 Subject: [PATCH 12/14] chore: resolve conflicts Signed-off-by: Ivo Yankov --- src/core/command_handler.ts | 15 +-------------- src/core/config_builder.ts | 15 +-------------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/src/core/command_handler.ts b/src/core/command_handler.ts index 550d5cb40..7cd9dd1b8 100644 --- a/src/core/command_handler.ts +++ b/src/core/command_handler.ts @@ -1,18 +1,5 @@ /** - * 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. - * + * SPDX-License-Identifier: Apache-2.0 */ import {inject, injectable} from 'tsyringe-neo'; import {SoloLogger} from './logging.js'; diff --git a/src/core/config_builder.ts b/src/core/config_builder.ts index 1ecfc6dda..bfc517e93 100644 --- a/src/core/config_builder.ts +++ b/src/core/config_builder.ts @@ -1,18 +1,5 @@ /** - * 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. - * + * SPDX-License-Identifier: Apache-2.0 */ import {type ConfigManager} from './config_manager.js'; import {type CommandFlag} from '../types/flag_types.js'; From 39f9091d24339d7fd2b8e1dae63c82917dab1e9c Mon Sep 17 00:00:00 2001 From: Ivo Yankov Date: Thu, 30 Jan 2025 16:22:13 +0200 Subject: [PATCH 13/14] nit: add scopes Signed-off-by: Ivo Yankov --- src/commands/base.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/commands/base.ts b/src/commands/base.ts index 61a2d385e..d3ab7de93 100644 --- a/src/commands/base.ts +++ b/src/commands/base.ts @@ -101,14 +101,14 @@ export abstract class BaseCommand extends ShellRunner { * Setup home directories * @param dirs a list of directories that need to be created in sequence */ - setupHomeDirectory( + public setupHomeDirectory( dirs: string[] = [ constants.SOLO_HOME_DIR, constants.SOLO_LOGS_DIR, constants.SOLO_CACHE_DIR, constants.SOLO_VALUES_DIR, ], - ) { + ): string[] { const self = this; try { @@ -126,7 +126,7 @@ export abstract class BaseCommand extends ShellRunner { return dirs; } - setupHomeDirectoryTask() { + public setupHomeDirectoryTask(): Task { return new Task('Setup home directory', async () => { this.setupHomeDirectory(); }); From f408ec0bfcd38d479b3b13160252120f61e16bf7 Mon Sep 17 00:00:00 2001 From: Ivo Yankov Date: Fri, 7 Feb 2025 12:20:36 +0200 Subject: [PATCH 14/14] chore: resolve conflicts Signed-off-by: Ivo Yankov --- src/commands/cluster/handlers.ts | 7 ++++--- src/commands/cluster/tasks.ts | 4 ++-- src/commands/explorer.ts | 1 - src/commands/node/handlers.ts | 8 ++++---- src/commands/node/tasks.ts | 7 ++++--- test/e2e/e2e_node_util.ts | 4 +++- test/unit/commands/cluster.test.ts | 4 ++-- 7 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/commands/cluster/handlers.ts b/src/commands/cluster/handlers.ts index a6aac5444..f590c8270 100644 --- a/src/commands/cluster/handlers.ts +++ b/src/commands/cluster/handlers.ts @@ -11,7 +11,8 @@ import {connectConfigBuilder, resetConfigBuilder, setupConfigBuilder} from './co import {SoloError} from '../../core/errors.js'; import {inject, injectable} from 'tsyringe-neo'; import {patchInject} from '../../core/container_helper.js'; -import {K8} from '../../core/k8.js'; +import {K8Client} from '../../core/kube/k8_client.js'; +import {type K8} from '../../core/kube/k8.js'; import {CommandHandler} from '../../core/command_handler.js'; import {LocalConfig} from '../../core/config/local_config.js'; import {ChartManager} from '../../core/chart_manager.js'; @@ -22,14 +23,14 @@ export class ClusterCommandHandlers extends CommandHandler { @inject(ClusterCommandTasks) private readonly tasks: ClusterCommandTasks, @inject(RemoteConfigManager) private readonly remoteConfigManager: RemoteConfigManager, @inject(LocalConfig) private readonly localConfig: LocalConfig, - @inject(K8) private readonly k8: K8, + @inject(K8Client) private readonly k8: K8, @inject(ChartManager) private readonly chartManager: ChartManager, ) { super(); this.tasks = patchInject(tasks, ClusterCommandTasks, this.constructor.name); this.remoteConfigManager = patchInject(remoteConfigManager, RemoteConfigManager, this.constructor.name); - this.k8 = patchInject(k8, K8, this.constructor.name); + this.k8 = patchInject(k8, K8Client, this.constructor.name); this.localConfig = patchInject(localConfig, LocalConfig, this.constructor.name); this.chartManager = patchInject(chartManager, ChartManager, this.constructor.name); } diff --git a/src/commands/cluster/tasks.ts b/src/commands/cluster/tasks.ts index 490f228ad..7b97dae5c 100644 --- a/src/commands/cluster/tasks.ts +++ b/src/commands/cluster/tasks.ts @@ -48,7 +48,7 @@ export class ClusterCommandTasks { @inject(LeaseManager) private readonly leaseManager: LeaseManager, @inject(Helm) private readonly helm: Helm, ) { - this.k8 = patchInject(k8, K8, this.constructor.name); + this.k8 = patchInject(k8, K8Client, this.constructor.name); this.configManager = patchInject(configManager, ConfigManager, this.constructor.name); this.remoteConfigManager = patchInject(remoteConfigManager, RemoteConfigManager, this.constructor.name); this.localConfig = patchInject(localConfig, LocalConfig, this.constructor.name); @@ -272,7 +272,7 @@ export class ClusterCommandTasks { /** Show list of installed chart */ private async showInstalledChartList(clusterSetupNamespace: NamespaceName) { - this.logger.showList('Installed Charts', await this.chartManager.getInstalledCharts(clusterSetupNamespace)); + this.logger.showList('Installed Charts', await this.chartManager.getInstalledCharts(clusterSetupNamespace)); } public selectContext(): SoloListrTask { diff --git a/src/commands/explorer.ts b/src/commands/explorer.ts index 5fb07844e..fb869fd4a 100644 --- a/src/commands/explorer.ts +++ b/src/commands/explorer.ts @@ -14,7 +14,6 @@ import {type Opts} from '../types/command_types.js'; import {ListrLease} from '../core/lease/listr_lease.js'; import {ComponentType} from '../core/config/remote/enumerations.js'; import {MirrorNodeExplorerComponent} from '../core/config/remote/components/mirror_node_explorer_component.js'; -import type {SoloListrTask} from '../types/index.js'; import {prepareChartPath, prepareValuesFiles} from '../core/helpers.js'; import {type SoloListrTask} from '../types/index.js'; import {type NamespaceName} from '../core/kube/namespace_name.js'; diff --git a/src/commands/node/handlers.ts b/src/commands/node/handlers.ts index bb66cd201..a39d6ddae 100644 --- a/src/commands/node/handlers.ts +++ b/src/commands/node/handlers.ts @@ -22,12 +22,12 @@ import { import * as constants from '../../core/constants.js'; import {AccountManager} from '../../core/account_manager.js'; import {PlatformInstaller} from '../../core/platform_installer.js'; -import {K8} from '../../core/k8.js'; +import {K8Client} from '../../core/kube/k8_client.js'; +import {type K8} from '../../core/kube/k8.js'; import {LeaseManager} from '../../core/lease/lease_manager.js'; import {RemoteConfigManager} from '../../core/config/remote/remote_config_manager.js'; import {SoloError} from '../../core/errors.js'; import {ComponentType, ConsensusNodeStates} from '../../core/config/remote/enumerations.js'; -import {type NodeCommandTasks} from './tasks.js'; import {type Lease} from '../../core/lease/lease.js'; import {NodeCommandTasks} from './tasks.js'; import {NodeSubcommandType} from '../../core/enumerations.js'; @@ -49,7 +49,7 @@ export class NodeCommandHandlers extends CommandHandler { constructor( @inject(AccountManager) private readonly accountManager: AccountManager, - @inject(K8) private readonly k8: K8, + @inject(K8Client) private readonly k8: K8, @inject(PlatformInstaller) private readonly platformInstaller: PlatformInstaller, @inject(LeaseManager) private readonly leaseManager: LeaseManager, @inject(RemoteConfigManager) private readonly remoteConfigManager: RemoteConfigManager, @@ -58,7 +58,7 @@ export class NodeCommandHandlers extends CommandHandler { super(); this.accountManager = patchInject(accountManager, AccountManager, this.constructor.name); - this.k8 = patchInject(k8, K8, this.constructor.name); + this.k8 = patchInject(k8, K8Client, this.constructor.name); this.platformInstaller = patchInject(platformInstaller, PlatformInstaller, this.constructor.name); this.leaseManager = patchInject(leaseManager, LeaseManager, this.constructor.name); this.remoteConfigManager = patchInject(remoteConfigManager, RemoteConfigManager, this.constructor.name); diff --git a/src/commands/node/tasks.ts b/src/commands/node/tasks.ts index 2bfe4c585..fe364ca8e 100644 --- a/src/commands/node/tasks.ts +++ b/src/commands/node/tasks.ts @@ -6,7 +6,8 @@ import {ConfigManager} from '../../core/config_manager.js'; import {KeyManager} from '../../core/key_manager.js'; import {ProfileManager} from '../../core/profile_manager.js'; import {PlatformInstaller} from '../../core/platform_installer.js'; -import {K8} from '../../core/kube/k8.js'; +import {K8Client} from '../../core/kube/k8_client.js'; +import {type K8} from '../../core/kube/k8.js'; import {ChartManager} from '../../core/chart_manager.js'; import {CertificateManager} from '../../core/certificate_manager.js'; import {Zippy} from '../../core/zippy.js'; @@ -76,7 +77,7 @@ export class NodeCommandTasks { @inject(SoloLogger) private readonly logger: SoloLogger, @inject(AccountManager) private readonly accountManager: AccountManager, @inject(ConfigManager) private readonly configManager: ConfigManager, - @inject(K8) private readonly k8: K8, + @inject(K8Client) private readonly k8: K8, @inject(PlatformInstaller) private readonly platformInstaller: PlatformInstaller, @inject(KeyManager) private readonly keyManager: KeyManager, @inject(ProfileManager) private readonly profileManager: ProfileManager, @@ -86,7 +87,7 @@ export class NodeCommandTasks { this.logger = patchInject(logger, SoloLogger, this.constructor.name); this.accountManager = patchInject(accountManager, AccountManager, this.constructor.name); this.configManager = patchInject(configManager, ConfigManager, this.constructor.name); - this.k8 = patchInject(k8, K8, this.constructor.name); + this.k8 = patchInject(k8, K8Client, this.constructor.name); this.platformInstaller = patchInject(platformInstaller, PlatformInstaller, this.constructor.name); this.keyManager = patchInject(keyManager, KeyManager, this.constructor.name); this.profileManager = patchInject(profileManager, ProfileManager, this.constructor.name); diff --git a/test/e2e/e2e_node_util.ts b/test/e2e/e2e_node_util.ts index fff53ca11..e70620f14 100644 --- a/test/e2e/e2e_node_util.ts +++ b/test/e2e/e2e_node_util.ts @@ -127,7 +127,9 @@ export function e2eNodeKeyRefreshTest(testName: string, mode: string, releaseTag it(`${nodeAlias} should be running`, async () => { try { const nodeTasks = container.resolve(NodeCommandTasks); - expect((await nodeTasks.checkNetworkNodePod(namespace, nodeAlias)).podName.name).to.equal(`network-${nodeAlias}-0`); + expect((await nodeTasks.checkNetworkNodePod(namespace, nodeAlias)).podName.name).to.equal( + `network-${nodeAlias}-0`, + ); } catch (e) { nodeCmd.logger.showUserError(e); expect.fail(); diff --git a/test/unit/commands/cluster.test.ts b/test/unit/commands/cluster.test.ts index 74eecc3ea..57aa5504b 100644 --- a/test/unit/commands/cluster.test.ts +++ b/test/unit/commands/cluster.test.ts @@ -196,8 +196,8 @@ describe('ClusterCommand unit tests', () => { container.unregister(RemoteConfigManager); container.registerInstance(RemoteConfigManager, remoteConfigManagerStub); - container.unregister(K8); - container.registerInstance(K8, k8Stub); + container.unregister(K8Client); + container.registerInstance(K8Client, k8Stub); const localConfig = new LocalConfig(filePath); container.unregister(LocalConfig);