Skip to content

Commit

Permalink
feat: inspect existing cluster resources during cluster setup (#1094)
Browse files Browse the repository at this point in the history
Signed-off-by: instamenta <[email protected]>
Signed-off-by: Jeromy Cannon <[email protected]>
Co-authored-by: Jeromy Cannon <[email protected]>
  • Loading branch information
instamenta and jeromy-cannon authored Jan 8, 2025
1 parent a064954 commit 808516c
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 64 deletions.
1 change: 1 addition & 0 deletions src/commands/cluster/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export const resetConfigBuilder = async function (argv, ctx, task) {
});

if (!confirm) {
// eslint-disable-next-line n/no-process-exit
process.exit(0);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/commands/cluster/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class ClusterCommand extends BaseCommand {
constructor(opts: Opts) {
super(opts);

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

getCommandDefinition() {
Expand Down
69 changes: 64 additions & 5 deletions src/commands/cluster/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,16 @@ import * as constants from '../../core/constants.js';
import path from 'path';
import chalk from 'chalk';
import {ListrLease} from '../../core/lease/listr_lease.js';
import {type K8} from '../../core/k8.js';
import {ListrEnquirerPromptAdapter} from '@listr2/prompt-adapter-enquirer';

export class ClusterCommandTasks {
private readonly parent: BaseCommand;

constructor(parent) {
constructor(
parent,
private readonly k8: K8,
) {
this.parent = parent;
}

Expand Down Expand Up @@ -131,9 +136,9 @@ export class ClusterCommandTasks {
let valuesArg = chartDir ? `-f ${path.join(chartDir, 'solo-cluster-setup', 'values.yaml')}` : '';

valuesArg += ` --set cloud.prometheusStack.enabled=${prometheusStackEnabled}`;
valuesArg += ` --set cloud.minio.enabled=${minioEnabled}`;
valuesArg += ` --set cloud.certManager.enabled=${certManagerEnabled}`;
valuesArg += ` --set cert-manager.installCRDs=${certManagerCrdsEnabled}`;
valuesArg += ` --set cloud.minio.enabled=${minioEnabled}`;

if (certManagerEnabled && !certManagerCrdsEnabled) {
this.parent.logger.showUser(
Expand Down Expand Up @@ -246,13 +251,15 @@ export class ClusterCommandTasks {
const cluster = this.parent.getK8().getKubeConfig().getCurrentCluster();
this.parent.logger.showJSON(`Cluster Information (${cluster.name})`, cluster);
this.parent.logger.showUser('\n');
} catch (e: Error | any) {
} catch (e: Error | unknown) {
this.parent.logger.showUserError(e);
}
});
}

prepareChartValues(argv) {
const self = this;

return new Task(
'Prepare chart values',
async (ctx: any, task: ListrTaskWrapper<any, any, any>) => {
Expand All @@ -261,6 +268,40 @@ export class ClusterCommandTasks {
constants.SOLO_TESTING_CHART_URL,
constants.SOLO_CLUSTER_SETUP_CHART,
);

// if minio is already present, don't deploy it
if (ctx.config.deployMinio && (await self.k8.isMinioInstalled(ctx.config.clusterSetupNamespace))) {
ctx.config.deployMinio = false;
}

// if prometheus is found, don't deploy it
if (
ctx.config.deployPrometheusStack &&
!(await self.k8.isPrometheusInstalled(ctx.config.clusterSetupNamespace))
) {
ctx.config.deployPrometheusStack = false;
}

// if cert manager is installed, don't deploy it
if (
(ctx.config.deployCertManager || ctx.config.deployCertManagerCrds) &&
(await self.k8.isCertManagerInstalled())
) {
ctx.config.deployCertManager = false;
ctx.config.deployCertManagerCrds = false;
}

// If all are already present or not wanted, skip installation
if (
!ctx.config.deployPrometheusStack &&
!ctx.config.deployMinio &&
!ctx.config.deployCertManager &&
!ctx.config.deployCertManagerCrds
) {
ctx.isChartInstalled = true;
return;
}

ctx.valuesArg = this.prepareValuesArg(
ctx.config.chartDir,
ctx.config.deployPrometheusStack,
Expand All @@ -287,15 +328,15 @@ export class ClusterCommandTasks {
await parent
.getChartManager()
.install(clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART, ctx.chartPath, version, valuesArg);
} catch (e: Error | any) {
} catch (e: Error | unknown) {
// if error, uninstall the chart and rethrow the error
parent.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);
} catch (ex) {
} catch {
// ignore error during uninstall since we are doing the best-effort uninstall here
}

Expand All @@ -319,10 +360,28 @@ export class ClusterCommandTasks {

uninstallClusterChart(argv) {
const parent = this.parent;
const self = this;

return new Task(
`Uninstall '${constants.SOLO_CLUSTER_SETUP_CHART}' chart`,
async (ctx: any, task: ListrTaskWrapper<any, any, any>) => {
const clusterSetupNamespace = ctx.config.clusterSetupNamespace;

if (!argv.force && (await self.k8.isRemoteConfigPresentInAnyNamespace())) {
const confirm = await task.prompt(ListrEnquirerPromptAdapter).run({
type: 'toggle',
default: false,
message:
'There is remote config for one of the deployments' +
'Are you sure you would like to uninstall the cluster?',
});

if (!confirm) {
// eslint-disable-next-line n/no-process-exit
process.exit(0);
}
}

await parent.getChartManager().uninstall(clusterSetupNamespace, constants.SOLO_CLUSTER_SETUP_CHART);
if (argv.dev) {
await this.showInstalledChartList(clusterSetupNamespace);
Expand Down
46 changes: 19 additions & 27 deletions src/commands/mirror_node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,46 +128,38 @@ export class MirrorNodeCommand extends BaseCommand {
/**
* @param config
* @param config.tlsClusterIssuerType - must be one of - acme-staging, acme-prod, or self-signed
* @param config.enableHederaExplorerTls
* @param config.namespace - used for classname ingress class name prefix
* @param config.hederaExplorerTlsLoadBalancerIp - can be an empty string
* @param config.hederaExplorerTlsHostName
*/
private prepareSoloChartSetupValuesArg(config: MirrorNodeDeployConfigClass) {
if (!config.enableHederaExplorerTls) return '';

const {
tlsClusterIssuerType,
enableHederaExplorerTls,
namespace,
hederaExplorerTlsLoadBalancerIp,
hederaExplorerTlsHostName,
} = config;
private async prepareSoloChartSetupValuesArg(config: MirrorNodeDeployConfigClass) {
const {tlsClusterIssuerType, namespace, hederaExplorerTlsLoadBalancerIp, hederaExplorerTlsHostName} = config;

let valuesArg = '';

if (enableHederaExplorerTls) {
if (!['acme-staging', 'acme-prod', 'self-signed'].includes(tlsClusterIssuerType)) {
throw new Error(
`Invalid TLS cluster issuer type: ${tlsClusterIssuerType}, must be one of: "acme-staging", "acme-prod", or "self-signed"`,
);
}
if (!['acme-staging', 'acme-prod', 'self-signed'].includes(tlsClusterIssuerType)) {
throw new Error(
`Invalid TLS cluster issuer type: ${tlsClusterIssuerType}, must be one of: "acme-staging", "acme-prod", or "self-signed"`,
);
}

// Install ingress controller only if it's not already present
if (!(await this.k8.isIngressControllerInstalled())) {
valuesArg += ' --set ingress.enabled=true';
valuesArg += ' --set haproxyIngressController.enabled=true';
valuesArg += ` --set ingressClassName=${namespace}-hedera-explorer-ingress-class`;
valuesArg += ` --set-json 'ingress.hosts[0]={"host":"${hederaExplorerTlsHostName}","paths":[{"path":"/","pathType":"Prefix"}]}'`;
}

if (hederaExplorerTlsLoadBalancerIp !== '') {
valuesArg += ` --set haproxy-ingress.controller.service.loadBalancerIP=${hederaExplorerTlsLoadBalancerIp}`;
}
if (hederaExplorerTlsLoadBalancerIp !== '') {
valuesArg += ` --set haproxy-ingress.controller.service.loadBalancerIP=${hederaExplorerTlsLoadBalancerIp}`;
}

if (tlsClusterIssuerType === 'self-signed') {
valuesArg += ' --set selfSignedClusterIssuer.enabled=true';
} else {
valuesArg += ' --set acmeClusterIssuer.enabled=true';
valuesArg += ` --set certClusterIssuerType=${tlsClusterIssuerType}`;
}
if (tlsClusterIssuerType === 'self-signed') {
valuesArg += ' --set selfSignedClusterIssuer.enabled=true';
} else {
valuesArg += ' --set acmeClusterIssuer.enabled=true';
valuesArg += ` --set certClusterIssuerType=${tlsClusterIssuerType}`;
}

return valuesArg;
Expand Down Expand Up @@ -314,7 +306,7 @@ export class MirrorNodeCommand extends BaseCommand {
constants.SOLO_CLUSTER_SETUP_CHART,
);

const soloChartSetupValuesArg = self.prepareSoloChartSetupValuesArg(config);
const soloChartSetupValuesArg = await self.prepareSoloChartSetupValuesArg(config);
await self.chartManager.upgrade(
clusterSetupNamespace,
constants.SOLO_CLUSTER_SETUP_CHART,
Expand Down
2 changes: 1 addition & 1 deletion src/core/config/remote/remote_config_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ export class RemoteConfigManager {
* @returns the remote configuration data.
* @throws {@link SoloError} if the ConfigMap could not be read and the error is not a 404 status.
*/
private async getConfigMap(): Promise<k8s.V1ConfigMap> {
public async getConfigMap(): Promise<k8s.V1ConfigMap> {
try {
return await this.k8.getNamespacedConfigMap(constants.SOLO_REMOTE_CONFIGMAP_NAME);
} catch (error: any) {
Expand Down
1 change: 1 addition & 0 deletions src/core/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const ROOT_CONTAINER = 'root-container';
export const SOLO_REMOTE_CONFIGMAP_NAME = 'solo-remote-config';
export const SOLO_REMOTE_CONFIGMAP_LABELS = {'solo.hedera.com/type': 'remote-config'};
export const SOLO_REMOTE_CONFIG_MAX_COMMAND_IN_HISTORY = 50;
export const SOLO_REMOTE_CONFIGMAP_LABEL_SELECTOR = 'solo.hedera.com/type=remote-config';

// --------------- Hedera network and node related constants --------------------------------------------------------------------
export const HEDERA_CHAIN_ID = process.env.SOLO_CHAIN_ID || '298';
Expand Down
Loading

0 comments on commit 808516c

Please sign in to comment.