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(multi-cluster): Update solo node setup to support multiple clusters #1368

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
9 changes: 8 additions & 1 deletion src/commands/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import * as constants from '../core/constants.js';
import fs from 'fs';
import {Task} from '../core/task.js';
import {ConsensusNode} from '../core/model/consensus_node.js';
import {type NodeAlias} from '../types/aliases.js';

export interface CommandHandlers {
parent: BaseCommand;
Expand Down Expand Up @@ -254,11 +255,17 @@ export abstract class BaseCommand extends ShellRunner {
public getConsensusNodes(): ConsensusNode[] {
const consensusNodes: ConsensusNode[] = [];

try {
if (!this.getRemoteConfigManager()?.components?.consensusNodes) return [];
} catch {
return [];
}

// using the remoteConfigManager to get the consensus nodes
Object.values(this.getRemoteConfigManager().components.consensusNodes).forEach(node => {
consensusNodes.push(
new ConsensusNode(
node.name,
node.name as NodeAlias,
node.nodeId,
node.namespace,
node.cluster,
Expand Down
6 changes: 6 additions & 0 deletions src/commands/node/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {type NodeAddConfigClass} from './node_add_config.js';
import {type NamespaceName} from '../../core/kube/resources/namespace/namespace_name.js';
import {type PodRef} from '../../core/kube/resources/pod/pod_ref.js';
import {type K8Factory} from '../../core/kube/k8_factory.js';
import {type ConsensusNode} from '../../core/model/consensus_node.js';

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

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

await initializeSetup(config, this.k8Factory);

Expand Down Expand Up @@ -448,6 +450,10 @@ export interface NodeSetupConfigClass {
releaseTag: string;
nodeAliases: NodeAliases;
podRefs: Record<NodeAlias, PodRef>;
consensusNodes: ConsensusNode[];
skipStop?: boolean;
keysDir: string;
stagingDir: string;
getUnusedConfigs: () => string[];
}

Expand Down
3 changes: 2 additions & 1 deletion src/commands/node/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {type ComponentsDataWrapper} from '../../core/config/remote/components_da
import {type Optional} from '../../types/index.js';
import {type NamespaceName} from '../../core/kube/resources/namespace/namespace_name.js';
import {Templates} from '../../core/templates.js';
import {type CommandFlag} from '../../types/flag_types.js';

export class NodeCommandHandlers implements CommandHandlers {
private readonly accountManager: AccountManager;
Expand All @@ -53,7 +54,7 @@ export class NodeCommandHandlers implements CommandHandlers {
private readonly leaseManager: LeaseManager;
public readonly remoteConfigManager: RemoteConfigManager;

private getConfig: any;
public getConfig: (configName: string, flags: CommandFlag[], extraProperties?: string[]) => object;
private prepareChartPath: any;

public readonly parent: BaseCommand;
Expand Down
60 changes: 46 additions & 14 deletions src/commands/node/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,12 @@ import {type Listr, type ListrTaskWrapper} from 'listr2';
import {type ConfigBuilder, type NodeAlias, type NodeAliases, type SkipCheck} from '../../types/aliases.js';
import {PodName} from '../../core/kube/resources/pod/pod_name.js';
import {NodeStatusCodes, NodeStatusEnums, NodeSubcommandType} from '../../core/enumerations.js';
import {type NodeDeleteConfigClass, type NodeRefreshConfigClass, type NodeUpdateConfigClass} from './configs.js';
import {
type NodeDeleteConfigClass,
type NodeRefreshConfigClass,
type NodeSetupConfigClass,
type NodeUpdateConfigClass,
} from './configs.js';
import {type Lease} from '../../core/lease/lease.js';
import {ListrLease} from '../../core/lease/listr_lease.js';
import {Duration} from '../../core/time/duration.js';
Expand All @@ -68,6 +73,8 @@ import {ContainerRef} from '../../core/kube/resources/container/container_ref.js
import {NetworkNodes} from '../../core/network_nodes.js';
import {container} from 'tsyringe-neo';
import * as helpers from '../../core/helpers.js';
import {type Optional, type SoloListrTask, type SoloListrTaskWrapper} from '../../types/index.js';
import {type ConsensusNode} from '../../core/model/consensus_node.js';

export class NodeCommandTasks {
private readonly accountManager: AccountManager;
Expand Down Expand Up @@ -196,6 +203,7 @@ export class NodeCommandTasks {
podRefs: Record<NodeAlias, PodRef>,
task: ListrTaskWrapper<any, any, any>,
localBuildPath: string,
consensusNodes: Optional<ConsensusNode[]>,
) {
const subTasks = [];

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

const self = this;

const k8 = context ? self.k8Factory.getK8(context) : self.k8Factory.default();

subTasks.push({
title: `Copy local build to Node: ${chalk.yellow(nodeAlias)} from ${localDataLibBuildPath}`,
task: async () => {
// filter the data/config and data/keys to avoid failures due to config and secret mounts
const filterFunction = (path, stat) => {
return !(path.includes('data/keys') || path.includes('data/config'));
};
await self.k8Factory
.default()
await k8
.containers()
.readByRef(ContainerRef.of(podRef, constants.ROOT_CONTAINER))
.copyTo(localDataLibBuildPath, `${constants.HEDERA_HAPI_PATH}`, filterFunction);
if (self.configManager.getFlag<string>(flags.appConfig)) {
const testJsonFiles: string[] = this.configManager.getFlag<string>(flags.appConfig)!.split(',');
for (const jsonFile of testJsonFiles) {
if (fs.existsSync(jsonFile)) {
await self.k8Factory
.default()
await k8
.containers()
.readByRef(ContainerRef.of(podRef, constants.ROOT_CONTAINER))
.copyTo(jsonFile, `${constants.HEDERA_HAPI_PATH}`);
Expand All @@ -267,13 +277,15 @@ export class NodeCommandTasks {
releaseTag: string,
task: ListrTaskWrapper<any, any, any>,
platformInstaller: PlatformInstaller,
consensusNodes?: Optional<ConsensusNode[]>,
) {
const subTasks = [];
for (const nodeAlias of nodeAliases) {
const context = helpers.extractContextFromConsensusNodes(nodeAlias, consensusNodes);
const podRef = podRefs[nodeAlias];
subTasks.push({
title: `Update node: ${chalk.yellow(nodeAlias)} [ platformVersion = ${releaseTag} ]`,
task: async () => await platformInstaller.fetchPlatform(podRef, releaseTag),
task: async () => await platformInstaller.fetchPlatform(podRef, releaseTag, context),
});
}

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

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

const subTasks = [];
const self = this;
for (const nodeAlias of nodeAliases) {
const context = helpers.extractContextFromConsensusNodes(nodeAlias, consensusNodes);
subTasks.push({
title: `Check network pod: ${chalk.yellow(nodeAlias)}`,
task: async (ctx: any) => {
Expand All @@ -809,6 +823,8 @@ export class NodeCommandTasks {
ctx.config.namespace,
nodeAlias,
maxAttempts,
undefined,
context,
);
} catch (_) {
ctx.config.skipStop = true;
Expand All @@ -832,14 +848,16 @@ export class NodeCommandTasks {
nodeAlias: NodeAlias,
maxAttempts = constants.PODS_RUNNING_MAX_ATTEMPTS,
delay = constants.PODS_RUNNING_DELAY,
context?: Optional<string>,
) {
nodeAlias = nodeAlias.trim() as NodeAlias;
const podName = Templates.renderNetworkPodName(nodeAlias);
const podRef = PodRef.of(namespace, podName);

try {
await this.k8Factory
.default()
const k8 = context ? this.k8Factory.getK8(context) : this.k8Factory.default();

await k8
.pods()
.waitForRunningPhase(
namespace,
Expand Down Expand Up @@ -912,7 +930,7 @@ export class NodeCommandTasks {
);
}

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

if (localBuildPath !== '') {
return self._uploadPlatformSoftware(ctx.config[aliasesField], podRefs, task, localBuildPath);
}
return self._fetchPlatformSoftware(ctx.config[aliasesField], podRefs, releaseTag, task, this.platformInstaller);
return localBuildPath !== ''
? self._uploadPlatformSoftware(
ctx.config[aliasesField],
podRefs,
task,
localBuildPath,
ctx.config.consensusNodes,
)
: self._fetchPlatformSoftware(
ctx.config[aliasesField],
podRefs,
releaseTag,
task,
this.platformInstaller,
ctx.config.consensusNodes,
);
});
}

Expand Down Expand Up @@ -955,12 +985,14 @@ export class NodeCommandTasks {

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

const consensusNodes = ctx.config.consensusNodes;
const subTasks = [];
for (const nodeAlias of ctx.config[nodeAliasesProperty]) {
const podRef = ctx.config.podRefs[nodeAlias];
const context = helpers.extractContextFromConsensusNodes(nodeAlias, consensusNodes);
subTasks.push({
title: `Node: ${chalk.yellow(nodeAlias)}`,
task: () => this.platformInstaller.taskSetup(podRef, ctx.config.stagingDir, isGenesis),
task: () => this.platformInstaller.taskSetup(podRef, ctx.config.stagingDir, isGenesis, context),
});
}

Expand Down
17 changes: 17 additions & 0 deletions src/core/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import {type SoloLogger} from './logging.js';
import {type Duration} from './time/duration.js';
import {type NodeAddConfigClass} from '../commands/node/node_add_config.js';
import {type ConsensusNode} from './model/consensus_node.js';
import {type Optional} from '../types/index.js';

export function sleep(duration: Duration) {
return new Promise<void>(resolve => {
Expand Down Expand Up @@ -381,3 +383,18 @@

return valuesArg;
}

/**
* @param nodeAlias
* @param consensusNodes
* @returns context of the node
*/
export function extractContextFromConsensusNodes(
nodeAlias: NodeAlias,
consensusNodes?: ConsensusNode[],
): Optional<string> {
if (!consensusNodes) return undefined;
if (!consensusNodes.length) return undefined;
const consensusNode = consensusNodes.find(node => node.name === nodeAlias);
return consensusNode ? consensusNode.context : undefined;

Check warning on line 399 in src/core/helpers.ts

View check run for this annotation

Codecov / codecov/patch

src/core/helpers.ts#L399

Added line #L399 was not covered by tests
}
3 changes: 2 additions & 1 deletion src/core/model/consensus_node.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
/**
* SPDX-License-Identifier: Apache-2.0
*/
import {type NodeAlias} from '../../types/aliases.js';

export class ConsensusNode {
constructor(
public readonly name: string,
public readonly name: NodeAlias,
public readonly nodeId: number,
public readonly namespace: string,
public readonly cluster: string,
Expand Down
Loading
Loading