Skip to content

Commit 4618a43

Browse files
authored
feat(multi-cluster): Update solo node setup to support multiple clusters (#1368)
Signed-off-by: instamenta <[email protected]>
1 parent c35c7a5 commit 4618a43

File tree

7 files changed

+120
-41
lines changed

7 files changed

+120
-41
lines changed

src/commands/base.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import * as constants from '../core/constants.js';
2222
import fs from 'fs';
2323
import {Task} from '../core/task.js';
2424
import {ConsensusNode} from '../core/model/consensus_node.js';
25+
import {type NodeAlias} from '../types/aliases.js';
2526

2627
export interface CommandHandlers {
2728
parent: BaseCommand;
@@ -254,11 +255,17 @@ export abstract class BaseCommand extends ShellRunner {
254255
public getConsensusNodes(): ConsensusNode[] {
255256
const consensusNodes: ConsensusNode[] = [];
256257

258+
try {
259+
if (!this.getRemoteConfigManager()?.components?.consensusNodes) return [];
260+
} catch {
261+
return [];
262+
}
263+
257264
// using the remoteConfigManager to get the consensus nodes
258265
Object.values(this.getRemoteConfigManager().components.consensusNodes).forEach(node => {
259266
consensusNodes.push(
260267
new ConsensusNode(
261-
node.name,
268+
node.name as NodeAlias,
262269
node.nodeId,
263270
node.namespace,
264271
node.cluster,

src/commands/node/configs.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {type NodeAddConfigClass} from './node_add_config.js';
1818
import {type NamespaceName} from '../../core/kube/resources/namespace/namespace_name.js';
1919
import {type PodRef} from '../../core/kube/resources/pod/pod_ref.js';
2020
import {type K8Factory} from '../../core/kube/k8_factory.js';
21+
import {type ConsensusNode} from '../../core/model/consensus_node.js';
2122

2223
export const PREPARE_UPGRADE_CONFIGS_NAME = 'prepareUpgradeConfig';
2324
export const DOWNLOAD_GENERATED_FILES_CONFIGS_NAME = 'downloadGeneratedFilesConfig';
@@ -353,6 +354,7 @@ export const setupConfigBuilder = async function (argv, ctx, task) {
353354

354355
config.namespace = await resolveNamespaceFromDeployment(this.parent.localConfig, this.configManager, task);
355356
config.nodeAliases = helpers.parseNodeAliases(config.nodeAliasesUnparsed);
357+
config.consensusNodes = this.parent.getConsensusNodes();
356358

357359
await initializeSetup(config, this.k8Factory);
358360

@@ -448,6 +450,10 @@ export interface NodeSetupConfigClass {
448450
releaseTag: string;
449451
nodeAliases: NodeAliases;
450452
podRefs: Record<NodeAlias, PodRef>;
453+
consensusNodes: ConsensusNode[];
454+
skipStop?: boolean;
455+
keysDir: string;
456+
stagingDir: string;
451457
getUnusedConfigs: () => string[];
452458
}
453459

src/commands/node/handlers.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {type ComponentsDataWrapper} from '../../core/config/remote/components_da
4242
import {type Optional} from '../../types/index.js';
4343
import {type NamespaceName} from '../../core/kube/resources/namespace/namespace_name.js';
4444
import {Templates} from '../../core/templates.js';
45+
import {type CommandFlag} from '../../types/flag_types.js';
4546

4647
export class NodeCommandHandlers implements CommandHandlers {
4748
private readonly accountManager: AccountManager;
@@ -53,7 +54,7 @@ export class NodeCommandHandlers implements CommandHandlers {
5354
private readonly leaseManager: LeaseManager;
5455
public readonly remoteConfigManager: RemoteConfigManager;
5556

56-
private getConfig: any;
57+
public getConfig: (configName: string, flags: CommandFlag[], extraProperties?: string[]) => object;
5758
private prepareChartPath: any;
5859

5960
public readonly parent: BaseCommand;

src/commands/node/tasks.ts

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,12 @@ import {type Listr, type ListrTaskWrapper} from 'listr2';
5454
import {type ConfigBuilder, type NodeAlias, type NodeAliases, type SkipCheck} from '../../types/aliases.js';
5555
import {PodName} from '../../core/kube/resources/pod/pod_name.js';
5656
import {NodeStatusCodes, NodeStatusEnums, NodeSubcommandType} from '../../core/enumerations.js';
57-
import {type NodeDeleteConfigClass, type NodeRefreshConfigClass, type NodeUpdateConfigClass} from './configs.js';
57+
import {
58+
type NodeDeleteConfigClass,
59+
type NodeRefreshConfigClass,
60+
type NodeSetupConfigClass,
61+
type NodeUpdateConfigClass,
62+
} from './configs.js';
5863
import {type Lease} from '../../core/lease/lease.js';
5964
import {ListrLease} from '../../core/lease/listr_lease.js';
6065
import {Duration} from '../../core/time/duration.js';
@@ -68,6 +73,8 @@ import {ContainerRef} from '../../core/kube/resources/container/container_ref.js
6873
import {NetworkNodes} from '../../core/network_nodes.js';
6974
import {container} from 'tsyringe-neo';
7075
import * as helpers from '../../core/helpers.js';
76+
import {type Optional, type SoloListrTask, type SoloListrTaskWrapper} from '../../types/index.js';
77+
import {type ConsensusNode} from '../../core/model/consensus_node.js';
7178

7279
export class NodeCommandTasks {
7380
private readonly accountManager: AccountManager;
@@ -196,6 +203,7 @@ export class NodeCommandTasks {
196203
podRefs: Record<NodeAlias, PodRef>,
197204
task: ListrTaskWrapper<any, any, any>,
198205
localBuildPath: string,
206+
consensusNodes: Optional<ConsensusNode[]>,
199207
) {
200208
const subTasks = [];
201209

@@ -216,6 +224,7 @@ export class NodeCommandTasks {
216224
let localDataLibBuildPath: string;
217225
for (const nodeAlias of nodeAliases) {
218226
const podRef = podRefs[nodeAlias];
227+
const context = helpers.extractContextFromConsensusNodes(nodeAlias, consensusNodes);
219228
if (buildPathMap.has(nodeAlias)) {
220229
localDataLibBuildPath = buildPathMap.get(nodeAlias);
221230
} else {
@@ -227,24 +236,25 @@ export class NodeCommandTasks {
227236
}
228237

229238
const self = this;
239+
240+
const k8 = context ? self.k8Factory.getK8(context) : self.k8Factory.default();
241+
230242
subTasks.push({
231243
title: `Copy local build to Node: ${chalk.yellow(nodeAlias)} from ${localDataLibBuildPath}`,
232244
task: async () => {
233245
// filter the data/config and data/keys to avoid failures due to config and secret mounts
234246
const filterFunction = (path, stat) => {
235247
return !(path.includes('data/keys') || path.includes('data/config'));
236248
};
237-
await self.k8Factory
238-
.default()
249+
await k8
239250
.containers()
240251
.readByRef(ContainerRef.of(podRef, constants.ROOT_CONTAINER))
241252
.copyTo(localDataLibBuildPath, `${constants.HEDERA_HAPI_PATH}`, filterFunction);
242253
if (self.configManager.getFlag<string>(flags.appConfig)) {
243254
const testJsonFiles: string[] = this.configManager.getFlag<string>(flags.appConfig)!.split(',');
244255
for (const jsonFile of testJsonFiles) {
245256
if (fs.existsSync(jsonFile)) {
246-
await self.k8Factory
247-
.default()
257+
await k8
248258
.containers()
249259
.readByRef(ContainerRef.of(podRef, constants.ROOT_CONTAINER))
250260
.copyTo(jsonFile, `${constants.HEDERA_HAPI_PATH}`);
@@ -267,13 +277,15 @@ export class NodeCommandTasks {
267277
releaseTag: string,
268278
task: ListrTaskWrapper<any, any, any>,
269279
platformInstaller: PlatformInstaller,
280+
consensusNodes?: Optional<ConsensusNode[]>,
270281
) {
271282
const subTasks = [];
272283
for (const nodeAlias of nodeAliases) {
284+
const context = helpers.extractContextFromConsensusNodes(nodeAlias, consensusNodes);
273285
const podRef = podRefs[nodeAlias];
274286
subTasks.push({
275287
title: `Update node: ${chalk.yellow(nodeAlias)} [ platformVersion = ${releaseTag} ]`,
276-
task: async () => await platformInstaller.fetchPlatform(podRef, releaseTag),
288+
task: async () => await platformInstaller.fetchPlatform(podRef, releaseTag, context),
277289
});
278290
}
279291

@@ -797,10 +809,12 @@ export class NodeCommandTasks {
797809
if (!ctx.config) ctx.config = {};
798810

799811
ctx.config.podRefs = {};
812+
const consensusNodes: Optional<ConsensusNode[]> = ctx.config.consensusNodes;
800813

801814
const subTasks = [];
802815
const self = this;
803816
for (const nodeAlias of nodeAliases) {
817+
const context = helpers.extractContextFromConsensusNodes(nodeAlias, consensusNodes);
804818
subTasks.push({
805819
title: `Check network pod: ${chalk.yellow(nodeAlias)}`,
806820
task: async (ctx: any) => {
@@ -809,6 +823,8 @@ export class NodeCommandTasks {
809823
ctx.config.namespace,
810824
nodeAlias,
811825
maxAttempts,
826+
undefined,
827+
context,
812828
);
813829
} catch (_) {
814830
ctx.config.skipStop = true;
@@ -832,14 +848,16 @@ export class NodeCommandTasks {
832848
nodeAlias: NodeAlias,
833849
maxAttempts = constants.PODS_RUNNING_MAX_ATTEMPTS,
834850
delay = constants.PODS_RUNNING_DELAY,
851+
context?: Optional<string>,
835852
) {
836853
nodeAlias = nodeAlias.trim() as NodeAlias;
837854
const podName = Templates.renderNetworkPodName(nodeAlias);
838855
const podRef = PodRef.of(namespace, podName);
839856

840857
try {
841-
await this.k8Factory
842-
.default()
858+
const k8 = context ? this.k8Factory.getK8(context) : this.k8Factory.default();
859+
860+
await k8
843861
.pods()
844862
.waitForRunningPhase(
845863
namespace,
@@ -912,7 +930,7 @@ export class NodeCommandTasks {
912930
);
913931
}
914932

915-
identifyNetworkPods(maxAttempts = undefined) {
933+
identifyNetworkPods(maxAttempts?: number) {
916934
const self = this;
917935
return new Task('Identify network pods', (ctx: any, task: ListrTaskWrapper<any, any, any>) => {
918936
return self.taskCheckNetworkNodePods(ctx, task, ctx.config.nodeAliases, maxAttempts);
@@ -924,10 +942,22 @@ export class NodeCommandTasks {
924942
return new Task('Fetch platform software into network nodes', (ctx: any, task: ListrTaskWrapper<any, any, any>) => {
925943
const {podRefs, releaseTag, localBuildPath} = ctx.config;
926944

927-
if (localBuildPath !== '') {
928-
return self._uploadPlatformSoftware(ctx.config[aliasesField], podRefs, task, localBuildPath);
929-
}
930-
return self._fetchPlatformSoftware(ctx.config[aliasesField], podRefs, releaseTag, task, this.platformInstaller);
945+
return localBuildPath !== ''
946+
? self._uploadPlatformSoftware(
947+
ctx.config[aliasesField],
948+
podRefs,
949+
task,
950+
localBuildPath,
951+
ctx.config.consensusNodes,
952+
)
953+
: self._fetchPlatformSoftware(
954+
ctx.config[aliasesField],
955+
podRefs,
956+
releaseTag,
957+
task,
958+
this.platformInstaller,
959+
ctx.config.consensusNodes,
960+
);
931961
});
932962
}
933963

@@ -955,12 +985,14 @@ export class NodeCommandTasks {
955985

956986
await this.generateNodeOverridesJson(ctx.config.namespace, ctx.config.nodeAliases, ctx.config.stagingDir);
957987

988+
const consensusNodes = ctx.config.consensusNodes;
958989
const subTasks = [];
959990
for (const nodeAlias of ctx.config[nodeAliasesProperty]) {
960991
const podRef = ctx.config.podRefs[nodeAlias];
992+
const context = helpers.extractContextFromConsensusNodes(nodeAlias, consensusNodes);
961993
subTasks.push({
962994
title: `Node: ${chalk.yellow(nodeAlias)}`,
963-
task: () => this.platformInstaller.taskSetup(podRef, ctx.config.stagingDir, isGenesis),
995+
task: () => this.platformInstaller.taskSetup(podRef, ctx.config.stagingDir, isGenesis, context),
964996
});
965997
}
966998

src/core/helpers.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import {type CommandFlag} from '../types/flag_types.js';
1515
import {type SoloLogger} from './logging.js';
1616
import {type Duration} from './time/duration.js';
1717
import {type NodeAddConfigClass} from '../commands/node/node_add_config.js';
18+
import {type ConsensusNode} from './model/consensus_node.js';
19+
import {type Optional} from '../types/index.js';
1820

1921
export function sleep(duration: Duration) {
2022
return new Promise<void>(resolve => {
@@ -381,3 +383,18 @@ export function populateHelmArgs(valuesMapping: Record<string, string | boolean
381383

382384
return valuesArg;
383385
}
386+
387+
/**
388+
* @param nodeAlias
389+
* @param consensusNodes
390+
* @returns context of the node
391+
*/
392+
export function extractContextFromConsensusNodes(
393+
nodeAlias: NodeAlias,
394+
consensusNodes?: ConsensusNode[],
395+
): Optional<string> {
396+
if (!consensusNodes) return undefined;
397+
if (!consensusNodes.length) return undefined;
398+
const consensusNode = consensusNodes.find(node => node.name === nodeAlias);
399+
return consensusNode ? consensusNode.context : undefined;
400+
}

src/core/model/consensus_node.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
/**
22
* SPDX-License-Identifier: Apache-2.0
33
*/
4+
import {type NodeAlias} from '../../types/aliases.js';
45

56
export class ConsensusNode {
67
constructor(
7-
public readonly name: string,
8+
public readonly name: NodeAlias,
89
public readonly nodeId: number,
910
public readonly namespace: string,
1011
public readonly cluster: string,

0 commit comments

Comments
 (0)