Skip to content

Commit 77b769f

Browse files
authored
fix: update RemoteConfig to handle multi-cluster networking (#1348)
Signed-off-by: Lenin Mehedy <[email protected]>
1 parent 757156a commit 77b769f

20 files changed

+337
-106
lines changed

src/commands/deployment.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as constants from '../core/constants.js';
99
import chalk from 'chalk';
1010
import {ListrRemoteConfig} from '../core/config/remote/listr_config_tasks.js';
1111
import {ClusterCommandTasks} from './cluster/tasks.js';
12-
import {type DeploymentName, type NamespaceNameAsString, type Cluster} from '../core/config/remote/types.js';
12+
import {type DeploymentName, type NamespaceNameAsString, type ClusterRef} from '../core/config/remote/types.js';
1313
import {type CommandFlag} from '../types/flag_types.js';
1414
import {type CommandBuilder} from '../types/aliases.js';
1515
import {type SoloListrTask} from '../types/index.js';
@@ -168,7 +168,7 @@ export class DeploymentCommand extends BaseCommand {
168168
const self = this;
169169

170170
interface Config {
171-
clusterName: Cluster;
171+
clusterName: ClusterRef;
172172
}
173173

174174
interface Context {
@@ -186,7 +186,7 @@ export class DeploymentCommand extends BaseCommand {
186186
await self.configManager.executePrompt(task, [flags.clusterName]);
187187

188188
ctx.config = {
189-
clusterName: self.configManager.getFlag<Cluster>(flags.clusterName),
189+
clusterName: self.configManager.getFlag<ClusterRef>(flags.clusterName),
190190
} as Config;
191191

192192
self.logger.debug('Prepared config', {config: ctx.config, cachedConfig: self.configManager.config});

src/commands/network.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,13 @@ export class NetworkCommand extends BaseCommand {
964964
for (const nodeAlias of nodeAliases) {
965965
remoteConfig.components.add(
966966
nodeAlias,
967-
new ConsensusNodeComponent(nodeAlias, cluster, namespace.name, ConsensusNodeStates.INITIALIZED),
967+
new ConsensusNodeComponent(
968+
nodeAlias,
969+
cluster,
970+
namespace.name,
971+
ConsensusNodeStates.INITIALIZED,
972+
Templates.nodeIdFromNodeAlias(nodeAlias),
973+
),
968974
);
969975

970976
remoteConfig.components.add(

src/commands/node/handlers.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ import {type Listr, type ListrTask} from 'listr2';
4040
import chalk from 'chalk';
4141
import {type ComponentsDataWrapper} from '../../core/config/remote/components_data_wrapper.js';
4242
import {type Optional} from '../../types/index.js';
43-
import {type NamespaceNameAsString} from '../../core/config/remote/types.js';
4443
import {type NamespaceName} from '../../core/kube/resources/namespace/namespace_name.js';
44+
import {Templates} from '../../core/templates.js';
4545

4646
export class NodeCommandHandlers implements CommandHandlers {
4747
private readonly accountManager: AccountManager;
@@ -879,7 +879,13 @@ export class NodeCommandHandlers implements CommandHandlers {
879879
for (const nodeAlias of nodeAliases) {
880880
remoteConfig.components.edit(
881881
nodeAlias,
882-
new ConsensusNodeComponent(nodeAlias, cluster, namespace.name, state),
882+
new ConsensusNodeComponent(
883+
nodeAlias,
884+
cluster,
885+
namespace.name,
886+
state,
887+
Templates.nodeIdFromNodeAlias(nodeAlias),
888+
),
883889
);
884890
}
885891
});

src/core/config/local_config_data.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* SPDX-License-Identifier: Apache-2.0
33
*/
44
import {
5-
type Cluster,
5+
type ClusterRef,
66
type Context,
77
type EmailAddress,
88
type NamespaceNameAsString,
@@ -11,11 +11,11 @@ import {
1111

1212
export interface DeploymentStructure {
1313
// A list of clusters on which the deployment is deployed
14-
clusters: Cluster[];
14+
clusters: ClusterRef[];
1515
namespace: NamespaceNameAsString;
1616
}
1717

18-
export type ClusterContextMapping = Record<Cluster, Context>;
18+
export type ClusterContextMapping = Record<ClusterRef, Context>;
1919

2020
export type Deployments = Record<DeploymentName, DeploymentStructure>;
2121

src/core/config/remote/cluster.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/**
2+
* SPDX-License-Identifier: Apache-2.0
3+
*/
4+
import {type ToObject} from '../../../types/index.js';
5+
import {type ClusterRef, type ICluster, type NamespaceNameAsString} from './types.js';
6+
import {SoloError} from '../../errors.js';
7+
8+
export class Cluster implements ICluster, ToObject<ICluster> {
9+
private readonly _name: string;
10+
private readonly _namespace: string;
11+
private readonly _dnsBaseDomain: string = 'cluster.local'; // example: 'us-west-2.gcp.charlie.sphere'`
12+
private readonly _dnsConsensusNodePattern: string = 'network-${nodeAlias}-svc.${namespace}.svc'; // example: '${nodeId}.consensus.prod'`
13+
14+
public constructor(
15+
name: string,
16+
namespace: NamespaceNameAsString,
17+
dnsBaseDomain?: string,
18+
dnsConsensusNodePattern?: string,
19+
) {
20+
if (!name) {
21+
throw new SoloError('name is required');
22+
}
23+
24+
if (typeof name !== 'string') {
25+
throw new SoloError(`Invalid type for name: ${typeof name}`);
26+
}
27+
28+
if (!namespace) {
29+
throw new SoloError('namespace is required');
30+
}
31+
32+
if (typeof namespace !== 'string') {
33+
throw new SoloError(`Invalid type for namespace: ${typeof namespace}`);
34+
}
35+
36+
this._name = name;
37+
this._namespace = namespace;
38+
39+
if (dnsBaseDomain) {
40+
this._dnsBaseDomain = dnsBaseDomain;
41+
}
42+
43+
if (dnsConsensusNodePattern) {
44+
this._dnsConsensusNodePattern = dnsConsensusNodePattern;
45+
}
46+
}
47+
48+
public get name(): string {
49+
return this._name;
50+
}
51+
52+
public get namespace(): string {
53+
return this._namespace;
54+
}
55+
56+
public get dnsBaseDomain(): string {
57+
return this._dnsBaseDomain;
58+
}
59+
60+
public get dnsConsensusNodePattern(): string {
61+
return this._dnsConsensusNodePattern;
62+
}
63+
64+
public toObject(): ICluster {
65+
return {
66+
name: this.name,
67+
namespace: this.namespace,
68+
dnsBaseDomain: this.dnsBaseDomain,
69+
dnsConsensusNodePattern: this.dnsConsensusNodePattern,
70+
};
71+
}
72+
73+
public static fromObject(cluster: ICluster) {
74+
return new Cluster(cluster.name, cluster.namespace, cluster.dnsBaseDomain, cluster.dnsConsensusNodePattern);
75+
}
76+
77+
public static toClustersMapObject(clustersMap: Record<ClusterRef, Cluster>) {
78+
const entries = Object.entries(clustersMap).map(([ref, cluster]) => [ref, cluster.toObject()]);
79+
return Object.fromEntries(entries);
80+
}
81+
82+
public static fromClustersMapObject(obj: any): Record<ClusterRef, Cluster> {
83+
const clusters: Record<ClusterRef, Cluster> = {};
84+
85+
for (const [ref, cluster] of Object.entries(obj)) {
86+
clusters[ref] = Cluster.fromObject(cluster as ICluster);
87+
}
88+
89+
return clusters;
90+
}
91+
}

src/core/config/remote/components/base_component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44
import {ComponentType} from '../enumerations.js';
55
import {SoloError} from '../../../errors.js';
6-
import {type Cluster, type Component, type ComponentName, type NamespaceNameAsString} from '../types.js';
6+
import {type ClusterRef, type Component, type ComponentName, type NamespaceNameAsString} from '../types.js';
77
import {type ToObject, type Validate} from '../../../../types/index.js';
88

99
/**
@@ -20,7 +20,7 @@ export abstract class BaseComponent implements Component, Validate, ToObject<Com
2020
protected constructor(
2121
public readonly type: ComponentType,
2222
public readonly name: ComponentName,
23-
public readonly cluster: Cluster,
23+
public readonly cluster: ClusterRef,
2424
public readonly namespace: NamespaceNameAsString,
2525
) {}
2626

src/core/config/remote/components/consensus_node_component.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44
import {ComponentType, ConsensusNodeStates} from '../enumerations.js';
55
import {BaseComponent} from './base_component.js';
66
import {SoloError} from '../../../errors.js';
7-
import {type Cluster, type IConsensusNodeComponent, type ComponentName, type NamespaceNameAsString} from '../types.js';
7+
import {
8+
type ClusterRef,
9+
type ComponentName,
10+
type IConsensusNodeComponent,
11+
type NamespaceNameAsString,
12+
} from '../types.js';
813
import {type ToObject} from '../../../../types/index.js';
914

1015
/**
@@ -19,15 +24,17 @@ export class ConsensusNodeComponent
1924
{
2025
/**
2126
* @param name - the name to distinguish components.
27+
* @param nodeId - node id of the consensus node
2228
* @param cluster - associated to component
2329
* @param namespace - associated to component
2430
* @param state - of the consensus node
2531
*/
2632
public constructor(
2733
name: ComponentName,
28-
cluster: Cluster,
34+
cluster: ClusterRef,
2935
namespace: NamespaceNameAsString,
3036
public readonly state: ConsensusNodeStates,
37+
public readonly nodeId: number,
3138
) {
3239
super(ComponentType.ConsensusNode, name, cluster, namespace);
3340

@@ -38,8 +45,8 @@ export class ConsensusNodeComponent
3845

3946
/** Handles creating instance of the class from plain object. */
4047
public static fromObject(component: IConsensusNodeComponent): ConsensusNodeComponent {
41-
const {name, cluster, namespace, state} = component;
42-
return new ConsensusNodeComponent(name, cluster, namespace, state);
48+
const {name, cluster, namespace, state, nodeId} = component;
49+
return new ConsensusNodeComponent(name, cluster, namespace, state, nodeId);
4350
}
4451

4552
public validate(): void {
@@ -48,12 +55,21 @@ export class ConsensusNodeComponent
4855
if (!Object.values(ConsensusNodeStates).includes(this.state)) {
4956
throw new SoloError(`Invalid consensus node state: ${this.state}`);
5057
}
58+
59+
if (typeof this.nodeId !== 'number') {
60+
throw new SoloError(`Invalid node id. It must be a number: ${this.nodeId}`);
61+
}
62+
63+
if (this.nodeId < 0) {
64+
throw new SoloError(`Invalid node id. It cannot be negative: ${this.nodeId}`);
65+
}
5166
}
5267

5368
public toObject(): IConsensusNodeComponent {
5469
return {
5570
...super.toObject(),
5671
state: this.state,
72+
nodeId: this.nodeId,
5773
};
5874
}
5975
}

src/core/config/remote/enumerations.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export enum ComponentType {
1212
EnvoyProxy = 'envoyProxies',
1313
MirrorNode = 'mirrorNodes',
1414
MirrorNodeExplorer = 'mirrorNodeExplorers',
15-
Relay = 'replays',
15+
Relay = 'relays',
1616
}
1717

1818
/**

src/core/config/remote/listr_config_tasks.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44
import chalk from 'chalk';
55
import {type BaseCommand} from '../../../commands/base.js';
6-
import {type Cluster, type Context} from './types.js';
6+
import {type ClusterRef, type Context} from './types.js';
77
import {type SoloListrTask} from '../../../types/index.js';
88
import {type AnyObject} from '../../../types/aliases.js';
99
import {type NamespaceName} from '../../kube/resources/namespace/namespace_name.js';
@@ -41,15 +41,15 @@ export class ListrRemoteConfig {
4141
*/
4242
public static createRemoteConfig(
4343
command: BaseCommand,
44-
cluster: Cluster,
44+
clusterRef: ClusterRef,
4545
context: Context,
4646
namespace: NamespaceName,
4747
argv: AnyObject,
4848
): SoloListrTask<any> {
4949
return {
50-
title: `Create remote config in cluster: ${chalk.cyan(cluster)}`,
50+
title: `Create remote config in cluster: ${chalk.cyan(clusterRef)}`,
5151
task: async (): Promise<void> => {
52-
await command.getRemoteConfigManager().createAndValidate(cluster, context, namespace.name, argv);
52+
await command.getRemoteConfigManager().createAndValidate(clusterRef, context, namespace.name, argv);
5353
},
5454
};
5555
}
@@ -66,11 +66,11 @@ export class ListrRemoteConfig {
6666
task: async (ctx, task) => {
6767
const subTasks: SoloListrTask<Context>[] = [];
6868

69-
for (const cluster of command.localConfig.deployments[ctx.config.deployment].clusters) {
70-
const context = command.localConfig.clusterContextMapping?.[cluster];
69+
for (const clusterRef of command.localConfig.deployments[ctx.config.deployment].clusters) {
70+
const context = command.localConfig.clusterContextMapping?.[clusterRef];
7171
if (!context) continue;
7272

73-
subTasks.push(ListrRemoteConfig.createRemoteConfig(command, cluster, context, ctx.config.namespace, argv));
73+
subTasks.push(ListrRemoteConfig.createRemoteConfig(command, clusterRef, context, ctx.config.namespace, argv));
7474
}
7575

7676
return task.newListr(subTasks, {

src/core/config/remote/remote_config_data.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
import {type RemoteConfigMetadata} from './metadata.js';
55
import {type ComponentsDataWrapper} from './components_data_wrapper.js';
66
import {type CommonFlagsDataWrapper} from './common_flags_data_wrapper.js';
7-
import {type Cluster, type NamespaceNameAsString} from './types.js';
7+
import {type ClusterRef} from './types.js';
8+
import {type Cluster} from './cluster.js';
89

910
export interface RemoteConfigData {
1011
metadata: RemoteConfigMetadata;
11-
clusters: Record<Cluster, NamespaceNameAsString>;
12+
clusters: Record<ClusterRef, Cluster>;
1213
components: ComponentsDataWrapper;
1314
lastExecutedCommand: string;
1415
commandHistory: string[];

0 commit comments

Comments
 (0)