Skip to content

Commit

Permalink
feat: add factory and injection logic (#1352)
Browse files Browse the repository at this point in the history
Signed-off-by: Jeromy Cannon <[email protected]>
  • Loading branch information
jeromy-cannon authored Feb 11, 2025
1 parent 6405d67 commit c794610
Show file tree
Hide file tree
Showing 65 changed files with 932 additions and 536 deletions.
13 changes: 8 additions & 5 deletions src/commands/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export class AccountCommand extends BaseCommand {
const namespace = await resolveNamespaceFromDeployment(this.localConfig, this.configManager, task);
const config = {namespace};

if (!(await this.k8.namespaces().has(namespace))) {
if (!(await this.k8Factory.default().namespaces().has(namespace))) {
throw new SoloError(`namespace ${namespace.name} does not exist`);
}

Expand All @@ -191,7 +191,10 @@ export class AccountCommand extends BaseCommand {
title: 'Prepare for account key updates',
task: async ctx => {
const namespace = await resolveNamespaceFromDeployment(this.localConfig, this.configManager, task);
const secrets = await self.k8.secrets().list(namespace, ['solo.hedera.com/account-id']);
const secrets = await self.k8Factory
.default()
.secrets()
.list(namespace, ['solo.hedera.com/account-id']);
ctx.updateSecrets = secrets.length > 0;

ctx.accountsBatchedSet = self.accountManager.batchAccounts(this.systemAccounts);
Expand Down Expand Up @@ -334,7 +337,7 @@ export class AccountCommand extends BaseCommand {
config.amount = flags.amount.definition.defaultValue as number;
}

if (!(await this.k8.namespaces().has(config.namespace))) {
if (!(await this.k8Factory.default().namespaces().has(config.namespace))) {
throw new SoloError(`namespace ${config.namespace} does not exist`);
}

Expand Down Expand Up @@ -412,7 +415,7 @@ export class AccountCommand extends BaseCommand {
ed25519PrivateKey: self.configManager.getFlag<string>(flags.ed25519PrivateKey) as string,
};

if (!(await this.k8.namespaces().has(config.namespace))) {
if (!(await this.k8Factory.default().namespaces().has(config.namespace))) {
throw new SoloError(`namespace ${config.namespace} does not exist`);
}

Expand Down Expand Up @@ -494,7 +497,7 @@ export class AccountCommand extends BaseCommand {
privateKey: self.configManager.getFlag<boolean>(flags.privateKey) as boolean,
};

if (!(await this.k8.namespaces().has(config.namespace))) {
if (!(await this.k8Factory.default().namespaces().has(config.namespace))) {
throw new SoloError(`namespace ${config.namespace} does not exist`);
}

Expand Down
12 changes: 6 additions & 6 deletions src/commands/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {type LeaseManager} from '../core/lease/lease_manager.js';
import {type LocalConfig} from '../core/config/local_config.js';
import {type RemoteConfigManager} from '../core/config/remote/remote_config_manager.js';
import {type Helm} from '../core/helm.js';
import {type K8} from '../core/kube/k8.js';
import {type K8Factory} from '../core/kube/k8_factory.js';
import {type ChartManager} from '../core/chart_manager.js';
import {type ConfigManager} from '../core/config_manager.js';
import {type DependencyManager} from '../core/dependency_managers/index.js';
Expand All @@ -28,7 +28,7 @@ export interface CommandHandlers {

export abstract class BaseCommand extends ShellRunner {
protected readonly helm: Helm;
protected readonly k8: K8;
protected readonly k8Factory: K8Factory;
protected readonly chartManager: ChartManager;
protected readonly configManager: ConfigManager;
protected readonly depManager: DependencyManager;
Expand All @@ -39,7 +39,7 @@ export abstract class BaseCommand extends ShellRunner {

constructor(opts: Opts) {
if (!opts || !opts.helm) throw new Error('An instance of core/Helm is required');
if (!opts || !opts.k8) throw new Error('An instance of core/K8 is required');
if (!opts || !opts.k8Factory) throw new Error('An instance of core/K8Factory is required');
if (!opts || !opts.chartManager) throw new Error('An instance of core/ChartManager is required');
if (!opts || !opts.configManager) throw new Error('An instance of core/ConfigManager is required');
if (!opts || !opts.depManager) throw new Error('An instance of core/DependencyManager is required');
Expand All @@ -49,7 +49,7 @@ export abstract class BaseCommand extends ShellRunner {
super();

this.helm = opts.helm;
this.k8 = opts.k8;
this.k8Factory = opts.k8Factory;
this.chartManager = opts.chartManager;
this.configManager = opts.configManager;
this.depManager = opts.depManager;
Expand Down Expand Up @@ -177,8 +177,8 @@ export abstract class BaseCommand extends ShellRunner {
return this._configMaps.get(configName).getUnusedConfigs();
}

getK8() {
return this.k8;
getK8Factory() {
return this.k8Factory;
}

getLocalConfig() {
Expand Down
2 changes: 1 addition & 1 deletion src/commands/cluster/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class ClusterCommandHandlers implements CommandHandlers {
[
this.tasks.initialize(argv, connectConfigBuilder.bind(this)),
this.parent.setupHomeDirectoryTask(),
this.parent.getLocalConfig().promptLocalConfigTask(this.parent.getK8()),
this.parent.getLocalConfig().promptLocalConfigTask(this.parent.getK8Factory()),
this.tasks.selectContext(),
ListrRemoteConfig.loadRemoteConfig(this.parent, argv),
this.tasks.readClustersFromRemoteConfig(argv),
Expand Down
6 changes: 5 additions & 1 deletion src/commands/cluster/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ export class ClusterCommand extends BaseCommand {
constructor(opts: Opts) {
super(opts);

this.handlers = new ClusterCommandHandlers(this, new ClusterCommandTasks(this, this.k8), this.remoteConfigManager);
this.handlers = new ClusterCommandHandlers(
this,
new ClusterCommandTasks(this, this.k8Factory),
this.remoteConfigManager,
);
}

getCommandDefinition() {
Expand Down
34 changes: 19 additions & 15 deletions src/commands/cluster/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ 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/kube/k8.js';
import {type K8Factory} from '../../core/kube/k8_factory.js';
import {type SoloListrTask, type SoloListrTaskWrapper} from '../../types/index.js';
import {type SelectClusterContextContext} from './configs.js';
import {type DeploymentName} from '../../core/config/remote/types.js';
Expand All @@ -32,7 +32,7 @@ export class ClusterCommandTasks {

constructor(
parent,
private readonly k8: K8,
private readonly k8Factory: K8Factory,
) {
this.parent = parent;
}
Expand All @@ -46,14 +46,14 @@ export class ClusterCommandTasks {
if (!context) {
const isQuiet = self.parent.getConfigManager().getFlag(flags.quiet);
if (isQuiet) {
context = self.parent.getK8().contexts().readCurrent();
context = self.parent.getK8Factory().default().contexts().readCurrent();
} else {
context = await self.promptForContext(parentTask, cluster);
}

localConfig.clusterRefs[cluster] = context;
}
if (!(await self.parent.getK8().contexts().testContextConnection(context))) {
if (!(await self.parent.getK8Factory().default().contexts().testContextConnection(context))) {
subTask.title = `${subTask.title} - ${chalk.red('Cluster connection failed')}`;
throw new SoloError(`${ErrorMessages.INVALID_CONTEXT_FOR_CLUSTER_DETAILED(context, cluster)}`);
}
Expand All @@ -72,7 +72,7 @@ export class ClusterCommandTasks {
title: `Pull and validate remote configuration for cluster: ${chalk.cyan(cluster)}`,
task: async (_, subTask: ListrTaskWrapper<any, any, any>) => {
const context = localConfig.clusterRefs[cluster];
self.parent.getK8().contexts().updateCurrent(context);
self.parent.getK8Factory().default().contexts().updateCurrent(context);
const remoteConfigFromOtherCluster = await self.parent.getRemoteConfigManager().get();
if (!RemoteConfigManager.compare(currentRemoteConfig, remoteConfigFromOtherCluster)) {
throw new SoloError(ErrorMessages.REMOTE_CONFIGS_DO_NOT_MATCH(currentClusterName, cluster));
Expand All @@ -87,7 +87,7 @@ export class ClusterCommandTasks {
title: 'Read clusters from remote config',
task: async (ctx, task) => {
const localConfig = this.parent.getLocalConfig();
const currentClusterName = this.parent.getK8().clusters().readCurrent();
const currentClusterName = this.parent.getK8Factory().default().clusters().readCurrent();
const currentRemoteConfig: RemoteConfigDataWrapper = await this.parent.getRemoteConfigManager().get();
const subTasks = [];
const remoteConfigClusters = Object.keys(currentRemoteConfig.clusters);
Expand Down Expand Up @@ -161,7 +161,7 @@ export class ClusterCommandTasks {
} else if (!localConfig.clusterRefs[cluster]) {
// In quiet mode, use the currently selected context to update the mapping
if (isQuiet) {
localConfig.clusterRefs[cluster] = this.parent.getK8().contexts().readCurrent();
localConfig.clusterRefs[cluster] = this.parent.getK8Factory().default().contexts().readCurrent();
}

// Prompt the user to select a context if mapping value is missing
Expand All @@ -184,7 +184,7 @@ export class ClusterCommandTasks {
) {
let selectedContext;
if (isQuiet) {
selectedContext = this.parent.getK8().contexts().readCurrent();
selectedContext = this.parent.getK8Factory().default().contexts().readCurrent();
} else {
selectedContext = await this.promptForContext(task, selectedCluster);
localConfig.clusterRefs[selectedCluster] = selectedContext;
Expand All @@ -193,7 +193,7 @@ export class ClusterCommandTasks {
}

private async promptForContext(task: SoloListrTaskWrapper<SelectClusterContextContext>, cluster: string) {
const kubeContexts = this.parent.getK8().contexts().list();
const kubeContexts = this.parent.getK8Factory().default().contexts().list();
return flags.context.prompt(task, kubeContexts, cluster);
}

Expand Down Expand Up @@ -305,8 +305,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().contexts().readCurrent();
selectedCluster = this.parent.getK8().clusters().readCurrent();
selectedContext = this.parent.getK8Factory().default().contexts().readCurrent();
selectedCluster = this.parent.getK8Factory().default().clusters().readCurrent();
localConfig.deployments[deploymentName] = {
clusters: [selectedCluster],
namespace: namespace ? namespace.name : '',
Expand Down Expand Up @@ -334,11 +334,15 @@ export class ClusterCommandTasks {
}
}

const connectionValid = await this.parent.getK8().contexts().testContextConnection(selectedContext);
const connectionValid = await this.parent
.getK8Factory()
.default()
.contexts()
.testContextConnection(selectedContext);
if (!connectionValid) {
throw new SoloError(ErrorMessages.INVALID_CONTEXT_FOR_CLUSTER(selectedContext, selectedCluster));
}
this.parent.getK8().contexts().updateCurrent(selectedContext);
this.parent.getK8Factory().default().contexts().updateCurrent(selectedContext);
this.parent.getConfigManager().setFlag(flags.context, selectedContext);
},
};
Expand All @@ -360,14 +364,14 @@ export class ClusterCommandTasks {

showClusterList() {
return new Task('List all available clusters', async (ctx: any, task: ListrTaskWrapper<any, any, any>) => {
this.parent.logger.showList('Clusters', this.parent.getK8().clusters().list());
this.parent.logger.showList('Clusters', this.parent.getK8Factory().default().clusters().list());
});
}

getClusterInfo() {
return new Task('Get cluster info', async (ctx: any, task: ListrTaskWrapper<any, any, any>) => {
try {
const clusterName = this.parent.getK8().clusters().readCurrent();
const clusterName = this.parent.getK8Factory().default().clusters().readCurrent();
this.parent.logger.showUser(`Cluster Name (${clusterName})`);
this.parent.logger.showUser('\n');
} catch (e: Error | unknown) {
Expand Down
12 changes: 6 additions & 6 deletions src/commands/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class DeploymentCommand extends BaseCommand {
constructor(opts: Opts) {
super(opts);

this.tasks = new ClusterCommandTasks(this, this.k8);
this.tasks = new ClusterCommandTasks(this, this.k8Factory);
}

private static get DEPLOY_FLAGS_LIST(): CommandFlag[] {
Expand Down Expand Up @@ -88,7 +88,7 @@ export class DeploymentCommand extends BaseCommand {
},
},
this.setupHomeDirectoryTask(),
this.localConfig.promptLocalConfigTask(self.k8),
this.localConfig.promptLocalConfigTask(self.k8Factory),
{
title: 'Add new deployment to local config',
task: async (ctx, task) => {
Expand All @@ -107,7 +107,7 @@ export class DeploymentCommand extends BaseCommand {
title: 'Validate context',
task: async (ctx, task) => {
ctx.config.context = ctx.config.context ?? self.configManager.getFlag<string>(flags.context);
const availableContexts = self.k8.contexts().list();
const availableContexts = self.k8Factory.default().contexts().list();

if (availableContexts.includes(ctx.config.context)) {
task.title += chalk.green(`- validated context ${ctx.config.context}`);
Expand All @@ -132,7 +132,7 @@ export class DeploymentCommand extends BaseCommand {
subTasks.push({
title: `Testing connection to cluster: ${chalk.cyan(cluster)}`,
task: async (_, task) => {
if (!(await self.k8.contexts().testContextConnection(context))) {
if (!(await self.k8Factory.default().contexts().testContextConnection(context))) {
task.title = `${task.title} - ${chalk.red('Cluster connection failed')}`;

throw new SoloError(`Cluster connection failed for: ${cluster}`);
Expand Down Expand Up @@ -199,9 +199,9 @@ export class DeploymentCommand extends BaseCommand {

const context = self.localConfig.clusterRefs[clusterName];

self.k8.contexts().updateCurrent(context);
self.k8Factory.default().contexts().updateCurrent(context);

const namespaces = await self.k8.namespaces().list();
const namespaces = await self.k8Factory.default().namespaces().list();
const namespacesWithRemoteConfigs: NamespaceNameAsString[] = [];

for (const namespace of namespaces) {
Expand Down
44 changes: 27 additions & 17 deletions src/commands/explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ export class ExplorerCommand extends BaseCommand {

ctx.config.valuesArg += await self.prepareValuesArg(ctx.config);

if (!(await self.k8.namespaces().has(ctx.config.namespace))) {
if (!(await self.k8Factory.default().namespaces().has(ctx.config.namespace))) {
throw new SoloError(`namespace ${ctx.config.namespace} does not exist`);
}

Expand Down Expand Up @@ -226,7 +226,8 @@ export class ExplorerCommand extends BaseCommand {
}

// wait cert-manager to be ready to proceed, otherwise may get error of "failed calling webhook"
await self.k8
await self.k8Factory
.default()
.pods()
.waitForReadyStatus(
constants.DEFAULT_CERT_MANAGER_NAMESPACE,
Expand All @@ -251,14 +252,18 @@ export class ExplorerCommand extends BaseCommand {

if (config.enableIngress) {
// patch ingressClassName of mirror ingress so it can be recognized by haproxy ingress controller
await this.k8.ingresses().update(config.namespace, constants.MIRROR_NODE_RELEASE_NAME, {
spec: {
ingressClassName: `${config.namespace}-hedera-explorer-ingress-class`,
},
});
await this.k8Factory
.default()
.ingresses()
.update(config.namespace, constants.MIRROR_NODE_RELEASE_NAME, {
spec: {
ingressClassName: `${config.namespace}-hedera-explorer-ingress-class`,
},
});

// to support GRPC over HTTP/2
await this.k8
await this.k8Factory
.default()
.configMaps()
.update(clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART + '-haproxy-ingress', {
'backend-protocol': 'h2',
Expand Down Expand Up @@ -286,19 +291,23 @@ export class ExplorerCommand extends BaseCommand {

// patch explorer ingress to use h1 protocol, haproxy ingress controller default backend protocol is h2
// to support grpc over http/2
await this.k8.ingresses().update(config.namespace, constants.HEDERA_EXPLORER_RELEASE_NAME, {
metadata: {
annotations: {
'haproxy-ingress.github.io/backend-protocol': 'h1',
await this.k8Factory
.default()
.ingresses()
.update(config.namespace, constants.HEDERA_EXPLORER_RELEASE_NAME, {
metadata: {
annotations: {
'haproxy-ingress.github.io/backend-protocol': 'h1',
},
},
},
});
});
},
},
{
title: 'Check explorer pod is ready',
task: async ctx => {
await self.k8
await self.k8Factory
.default()
.pods()
.waitForReadyStatus(
ctx.config.namespace,
Expand All @@ -311,7 +320,8 @@ export class ExplorerCommand extends BaseCommand {
{
title: 'Check haproxy ingress controller pod is ready',
task: async () => {
await self.k8
await self.k8Factory
.default()
.pods()
.waitForReadyStatus(
constants.SOLO_SETUP_NAMESPACE,
Expand Down Expand Up @@ -378,7 +388,7 @@ export class ExplorerCommand extends BaseCommand {
self.configManager.update(argv);
const namespace = await resolveNamespaceFromDeployment(this.localConfig, this.configManager, task);

if (!(await self.k8.namespaces().has(namespace))) {
if (!(await self.k8Factory.default().namespaces().has(namespace))) {
throw new SoloError(`namespace ${namespace} does not exist`);
}

Expand Down
Loading

0 comments on commit c794610

Please sign in to comment.