Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: inspect existing cluster resources during cluster setup #1094

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading