diff --git a/src/commands/base.ts b/src/commands/base.ts index 8b2a7860f..4d453990d 100644 --- a/src/commands/base.ts +++ b/src/commands/base.ts @@ -47,7 +47,7 @@ export abstract class BaseCommand extends ShellRunner { protected readonly depManager: DependencyManager; protected readonly leaseManager: LeaseManager; protected readonly _configMaps = new Map<string, any>(); - protected readonly localConfig: LocalConfig; + public readonly localConfig: LocalConfig; protected readonly remoteConfigManager: RemoteConfigManager; constructor(opts: Opts) { diff --git a/src/commands/cluster/tasks.ts b/src/commands/cluster/tasks.ts index 224b91de9..62fdaf95d 100644 --- a/src/commands/cluster/tasks.ts +++ b/src/commands/cluster/tasks.ts @@ -282,6 +282,12 @@ export class ClusterCommandTasks { // If one or more contexts are provided, use the first one if (contexts.length) { selectedContext = contexts[0]; + + if (clusters.length) { + selectedCluster = clusters[0]; + } else if (localConfig.deployments[deploymentName]) { + selectedCluster = localConfig.deployments[deploymentName].clusters[0]; + } } // If one or more clusters are provided, use the first one to determine the context @@ -335,7 +341,7 @@ export class ClusterCommandTasks { const connectionValid = await this.parent.getK8().testClusterConnection(selectedContext, selectedCluster); if (!connectionValid) { - throw new SoloError(ErrorMessages.INVALID_CONTEXT_FOR_CLUSTER(selectedContext)); + throw new SoloError(ErrorMessages.INVALID_CONTEXT_FOR_CLUSTER(selectedContext, selectedCluster)); } this.parent.getK8().setCurrentContext(selectedContext); this.parent.getConfigManager().setFlag(flags.context, selectedContext); diff --git a/src/commands/deployment.ts b/src/commands/deployment.ts index 2f7c888f3..87614643f 100644 --- a/src/commands/deployment.ts +++ b/src/commands/deployment.ts @@ -19,16 +19,14 @@ import {SoloError} from '../core/errors.js'; 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 chalk from 'chalk'; import {ListrRemoteConfig} from '../core/config/remote/listr_config_tasks.js'; import {ClusterCommandTasks} from './cluster/tasks.js'; import type {Namespace} from '../core/config/remote/types.js'; -import type {ContextClusterStructure} from '../types/config_types.js'; 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 type {Opts} from '../types/command_types.js'; export class DeploymentCommand extends BaseCommand { readonly tasks: ClusterCommandTasks; @@ -44,9 +42,9 @@ export class DeploymentCommand extends BaseCommand { flags.quiet, flags.context, flags.namespace, + flags.clusterName, flags.userEmailAddress, flags.deploymentClusters, - flags.contextClusterUnparsed, ]; } @@ -56,9 +54,8 @@ export class DeploymentCommand extends BaseCommand { interface Config { context: string; namespace: Namespace; - contextClusterUnparsed: string; - contextCluster: ContextClusterStructure; } + interface Context { config: Config; } @@ -71,19 +68,12 @@ export class DeploymentCommand extends BaseCommand { self.configManager.update(argv); self.logger.debug('Updated config with argv', {config: self.configManager.config}); - await self.configManager.executePrompt(task, [ - flags.contextClusterUnparsed, - flags.namespace, - flags.deploymentClusters, - ]); + await self.configManager.executePrompt(task, [flags.namespace]); ctx.config = { - contextClusterUnparsed: self.configManager.getFlag<string>(flags.contextClusterUnparsed), namespace: self.configManager.getFlag<Namespace>(flags.namespace), } as Config; - ctx.config.contextCluster = Templates.parseContextCluster(ctx.config.contextClusterUnparsed); - self.logger.debug('Prepared config', {config: ctx.config, cachedConfig: self.configManager.config}); }, }, @@ -112,13 +102,16 @@ export class DeploymentCommand extends BaseCommand { task: async (ctx, task) => { const subTasks: SoloListrTask<Context>[] = []; - for (const context of Object.keys(ctx.config.contextCluster)) { - const cluster = ctx.config.contextCluster[context]; + for (const cluster of self.localConfig.deployments[ctx.config.namespace].clusters) { + const context = self.localConfig.clusterContextMapping?.[cluster]; + if (!context) continue; + subTasks.push({ title: `Testing connection to cluster: ${chalk.cyan(cluster)}`, task: async (_, task) => { if (!(await self.k8.testClusterConnection(context, cluster))) { task.title = `${task.title} - ${chalk.red('Cluster connection failed')}`; + throw new SoloError(`Cluster connection failed for: ${cluster}`); } }, diff --git a/src/commands/flags.ts b/src/commands/flags.ts index d1dbbc5b1..c3bc3febc 100644 --- a/src/commands/flags.ts +++ b/src/commands/flags.ts @@ -1576,27 +1576,6 @@ export class Flags { prompt: undefined, }; - static readonly contextClusterUnparsed: CommandFlag = { - constName: 'contextClusterUnparsed', - name: 'context-cluster', - definition: { - describe: - 'Context cluster mapping where context is key = value is cluster and comma delimited if more than one, ' + - '(e.g.: --context-cluster kind-solo=kind-solo,kind-solo-2=kind-solo-2)', - type: 'string', - }, - prompt: async function promptContextCluster(task: ListrTaskWrapper<any, any, any>, input: any) { - return await Flags.promptText( - task, - input, - null, - 'Enter context cluster mapping: ', - 'context-cluster cannot be empty', - Flags.contextClusterUnparsed.name, - ); - }, - }; - static readonly haproxyIps: CommandFlag = { constName: 'haproxyIps', name: 'haproxy-ips', @@ -1725,7 +1704,6 @@ export class Flags { Flags.clusterName, Flags.clusterSetupNamespace, Flags.context, - Flags.contextClusterUnparsed, Flags.createAmount, Flags.debugNodeAlias, Flags.deletePvcs, diff --git a/src/commands/mirror_node.ts b/src/commands/mirror_node.ts index d7a60335a..75c70203f 100644 --- a/src/commands/mirror_node.ts +++ b/src/commands/mirror_node.ts @@ -570,7 +570,7 @@ export class MirrorNodeCommand extends BaseCommand { } /** Removes the mirror node components from remote config. */ - public removeMirrorNodeComponents(): SoloListrTask<object> { + public removeMirrorNodeComponents(): SoloListrTask<any> { return { title: 'Remove mirror node from remote config', skip: (): boolean => !this.remoteConfigManager.isLoaded(), @@ -583,7 +583,7 @@ export class MirrorNodeCommand extends BaseCommand { } /** Adds the mirror node components to remote config. */ - public addMirrorNodeComponents(): SoloListrTask<{config: {namespace: Namespace}}> { + public addMirrorNodeComponents(): SoloListrTask<any> { return { title: 'Add mirror node to remote config', skip: (): boolean => !this.remoteConfigManager.isLoaded(), diff --git a/src/commands/network.ts b/src/commands/network.ts index 2aead3e95..2642230e3 100644 --- a/src/commands/network.ts +++ b/src/commands/network.ts @@ -952,7 +952,7 @@ export class NetworkCommand extends BaseCommand { } /** Adds the consensus node, envoy and haproxy components to remote config. */ - public addNodesAndProxies(): SoloListrTask<{config: {namespace: Namespace; nodeAliases: NodeAliases}}> { + public addNodesAndProxies(): SoloListrTask<any> { return { title: 'Add node and proxies to remote config', skip: (): boolean => !this.remoteConfigManager.isLoaded(), diff --git a/src/core/config/local_config.ts b/src/core/config/local_config.ts index e9b465e93..97f626c3d 100644 --- a/src/core/config/local_config.ts +++ b/src/core/config/local_config.ts @@ -34,7 +34,8 @@ import {type K8} from '../k8.js'; import {splitFlagInput} from '../helpers.js'; import {inject, injectable} from 'tsyringe-neo'; import {patchInject} from '../container_helper.js'; -import type {SoloListrTask, SoloListrTaskWrapper} from '../../types/index.js'; +import type {SoloListrTask} from '../../types/index.js'; +import type {AnyObject} from '../../types/aliases.js'; @injectable() export class LocalConfig implements LocalConfigData { @@ -168,7 +169,7 @@ export class LocalConfig implements LocalConfigData { return { title: 'Prompt local configuration', skip: this.skipPromptTask, - task: async (_: any, task: SoloListrTaskWrapper<any>): Promise<void> => { + task: async (_, task): Promise<void> => { if (self.configFileExists()) { self.configManager.setFlag(flags.userEmailAddress, self.userEmailAddress); } diff --git a/src/core/config/remote/listr_config_tasks.ts b/src/core/config/remote/listr_config_tasks.ts index 91d967301..f687ee9a7 100644 --- a/src/core/config/remote/listr_config_tasks.ts +++ b/src/core/config/remote/listr_config_tasks.ts @@ -14,10 +14,11 @@ * limitations under the License. * */ -import type {ListrTask} from 'listr2'; +import chalk from 'chalk'; import type {BaseCommand} from '../../../commands/base.js'; -import {type Cluster, type Context, type Namespace} from './types.js'; +import type {Cluster, Context, Namespace} from './types.js'; import type {SoloListrTask} from '../../../types/index.js'; +import type {AnyObject} from '../../../types/aliases.js'; /** * Static class that handles all tasks related to remote config used by other commands. @@ -38,10 +39,10 @@ export class ListrRemoteConfig { * @param command - the BaseCommand object on which an action will be performed * @param argv - used to update the last executed command and command history */ - public static loadRemoteConfig(command: BaseCommand, argv: any): ListrTask<any, any, any> { + public static loadRemoteConfig(command: BaseCommand, argv: {_: string[]} & AnyObject): SoloListrTask<any> { return { title: 'Load remote config', - task: async (_, task): Promise<void> => { + task: async (): Promise<void> => { await command.getRemoteConfigManager().loadAndValidate(argv); }, }; @@ -59,10 +60,10 @@ export class ListrRemoteConfig { cluster: Cluster, context: Context, namespace: Namespace, - ): ListrTask<any, any, any> { + ): SoloListrTask<any> { return { - title: `Create remote config in cluster: ${cluster}`, - task: async (_, task): Promise<void> => { + title: `Create remote config in cluster: ${chalk.cyan(cluster)}`, + task: async (): Promise<void> => { await command.getRemoteConfigManager().createAndValidate(cluster, context, namespace); }, }; @@ -73,14 +74,16 @@ export class ListrRemoteConfig { * * @param command - the BaseCommand object on which an action will be performed */ - public static createRemoteConfigInMultipleClusters(command: BaseCommand): ListrTask<any, any, any> { + public static createRemoteConfigInMultipleClusters(command: BaseCommand): SoloListrTask<any> { return { title: 'Create remoteConfig in clusters', task: async (ctx, task) => { const subTasks: SoloListrTask<Context>[] = []; - for (const context of Object.keys(ctx.config.contextCluster)) { - const cluster = ctx.config.contextCluster[context]; + for (const cluster of command.localConfig.deployments[ctx.config.namespace].clusters) { + const context = command.localConfig.clusterContextMapping?.[cluster]; + if (!context) continue; + subTasks.push(ListrRemoteConfig.createRemoteConfig(command, cluster, context, ctx.config.namespace)); } diff --git a/src/core/config/remote/remote_config_manager.ts b/src/core/config/remote/remote_config_manager.ts index a905dd8b9..b05fb6743 100644 --- a/src/core/config/remote/remote_config_manager.ts +++ b/src/core/config/remote/remote_config_manager.ts @@ -29,16 +29,16 @@ import {SoloLogger} from '../../logging.js'; import {ConfigManager} from '../../config_manager.js'; import {LocalConfig} from '../local_config.js'; import type {DeploymentStructure} from '../local_config_data.js'; -import {type ContextClusterStructure} from '../../../types/config_types.js'; -import {type EmptyContextConfig, type Optional, type SoloListrTask} from '../../../types/index.js'; +import type {Optional} from '../../../types/index.js'; import type * as k8s from '@kubernetes/client-node'; import {StatusCodes} from 'http-status-codes'; import {inject, injectable} from 'tsyringe-neo'; import {patchInject} from '../../container_helper.js'; import {ErrorMessages} from '../../error_messages.js'; +import {type AnyObject} from '../../../types/aliases.js'; interface ListrContext { - config: {contextCluster: ContextClusterStructure}; + config: object; } /** @@ -189,7 +189,7 @@ export class RemoteConfigManager { * * @param argv - arguments containing command input for historical reference. */ - public async loadAndValidate(argv: {_: string[]}) { + public async loadAndValidate(argv: {_: string[]} & AnyObject) { const self = this; try { self.setDefaultNamespaceIfNotSet(); diff --git a/src/core/templates.ts b/src/core/templates.ts index a8bdf4a35..9fb0fcbce 100644 --- a/src/core/templates.ts +++ b/src/core/templates.ts @@ -22,8 +22,7 @@ import * as constants from './constants.js'; import {type AccountId} from '@hashgraph/sdk'; import type {IP, NodeAlias, NodeId, PodName} from '../types/aliases.js'; import {GrpcProxyTlsEnums} from './enumerations.js'; -import {type ContextClusterStructure} from '../types/config_types.js'; -import type {Cluster, Context, Namespace} from './config/remote/types.js'; +import type {Namespace} from './config/remote/types.js'; import {HEDERA_PLATFORM_VERSION} from '../../version.js'; export class Templates { @@ -228,35 +227,6 @@ export class Templates { } } - /** - * Parsed and validates the unparsed value of flag clusterMappings - * - * @param unparsed - value of flag clusterMappings - */ - public static parseContextCluster(unparsed: string): ContextClusterStructure { - const mapping = {}; - const errorMessage = - 'Invalid context in context-cluster, expected structure where context' + - ' is key = value is cluster and comma delimited if more than one, ' + - '(e.g.: --context-cluster kind-solo=kind-solo,kind-solo-2=kind-solo-2)'; - - unparsed.split(',').forEach(data => { - const [context, cluster] = data.split('=') as [Context, Cluster]; - - if (!context || typeof context !== 'string') { - throw new SoloError(errorMessage, null, {data}); - } - - if (!cluster || typeof cluster !== 'string') { - throw new SoloError(errorMessage, null, {data}); - } - - mapping[context] = cluster; - }); - - return mapping; - } - public static renderEnvoyProxyName(nodeAlias: NodeAlias): string { return `envoy-proxy-${nodeAlias}`; } diff --git a/src/types/config_types.ts b/src/types/config_types.ts deleted file mode 100644 index d9780e120..000000000 --- a/src/types/config_types.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * 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 {Cluster, Context} from '../core/config/remote/types.js'; - -export type ContextClusterStructure = Record<Context, Cluster>;