Skip to content

Commit

Permalink
fix: update RemoteConfig to handle multi-cluster networking and add s…
Browse files Browse the repository at this point in the history
…upport for CusterRef type

Signed-off-by: Lenin Mehedy <[email protected]>
  • Loading branch information
leninmehedy committed Feb 11, 2025
1 parent 757156a commit 55494a2
Show file tree
Hide file tree
Showing 19 changed files with 336 additions and 105 deletions.
6 changes: 3 additions & 3 deletions src/commands/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import * as constants from '../core/constants.js';
import chalk from 'chalk';
import {ListrRemoteConfig} from '../core/config/remote/listr_config_tasks.js';
import {ClusterCommandTasks} from './cluster/tasks.js';
import {type DeploymentName, type NamespaceNameAsString, type Cluster} from '../core/config/remote/types.js';
import {type DeploymentName, type NamespaceNameAsString, type ClusterRef} from '../core/config/remote/types.js';
import {type CommandFlag} from '../types/flag_types.js';
import {type CommandBuilder} from '../types/aliases.js';
import {type SoloListrTask} from '../types/index.js';
Expand Down Expand Up @@ -168,7 +168,7 @@ export class DeploymentCommand extends BaseCommand {
const self = this;

interface Config {
clusterName: Cluster;
clusterName: ClusterRef;
}

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

ctx.config = {
clusterName: self.configManager.getFlag<Cluster>(flags.clusterName),
clusterName: self.configManager.getFlag<ClusterRef>(flags.clusterName),
} as Config;

self.logger.debug('Prepared config', {config: ctx.config, cachedConfig: self.configManager.config});
Expand Down
8 changes: 7 additions & 1 deletion src/commands/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,13 @@ export class NetworkCommand extends BaseCommand {
for (const nodeAlias of nodeAliases) {
remoteConfig.components.add(
nodeAlias,
new ConsensusNodeComponent(nodeAlias, cluster, namespace.name, ConsensusNodeStates.INITIALIZED),
new ConsensusNodeComponent(
nodeAlias,
cluster,
namespace.name,
ConsensusNodeStates.INITIALIZED,
Templates.nodeIdFromNodeAlias(nodeAlias),
),

Check warning on line 973 in src/commands/network.ts

View check run for this annotation

Codecov / codecov/patch

src/commands/network.ts#L967-L973

Added lines #L967 - L973 were not covered by tests
);

remoteConfig.components.add(
Expand Down
10 changes: 8 additions & 2 deletions src/commands/node/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ import {type Listr, type ListrTask} from 'listr2';
import chalk from 'chalk';
import {type ComponentsDataWrapper} from '../../core/config/remote/components_data_wrapper.js';
import {type Optional} from '../../types/index.js';
import {type NamespaceNameAsString} from '../../core/config/remote/types.js';
import {type NamespaceName} from '../../core/kube/resources/namespace/namespace_name.js';
import {Templates} from '../../core/templates.js';

export class NodeCommandHandlers implements CommandHandlers {
private readonly accountManager: AccountManager;
Expand Down Expand Up @@ -879,7 +879,13 @@ export class NodeCommandHandlers implements CommandHandlers {
for (const nodeAlias of nodeAliases) {
remoteConfig.components.edit(
nodeAlias,
new ConsensusNodeComponent(nodeAlias, cluster, namespace.name, state),
new ConsensusNodeComponent(
nodeAlias,
cluster,
namespace.name,
state,
Templates.nodeIdFromNodeAlias(nodeAlias),
),

Check warning on line 888 in src/commands/node/handlers.ts

View check run for this annotation

Codecov / codecov/patch

src/commands/node/handlers.ts#L882-L888

Added lines #L882 - L888 were not covered by tests
);
}
});
Expand Down
6 changes: 3 additions & 3 deletions src/core/config/local_config_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import {
type Cluster,
type ClusterRef,
type Context,
type EmailAddress,
type NamespaceNameAsString,
Expand All @@ -11,11 +11,11 @@ import {

export interface DeploymentStructure {
// A list of clusters on which the deployment is deployed
clusters: Cluster[];
clusters: ClusterRef[];
namespace: NamespaceNameAsString;
}

export type ClusterContextMapping = Record<Cluster, Context>;
export type ClusterContextMapping = Record<ClusterRef, Context>;

export type Deployments = Record<DeploymentName, DeploymentStructure>;

Expand Down
91 changes: 91 additions & 0 deletions src/core/config/remote/cluster.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/**
* SPDX-License-Identifier: Apache-2.0
*/
import {type ToObject} from '../../../types/index.js';
import {type ClusterRef, type ICluster, type NamespaceNameAsString} from './types.js';
import {SoloError} from '../../errors.js';

export class Cluster implements ICluster, ToObject<ICluster> {
private readonly _name: string;
private readonly _namespace: string;
private readonly _dnsBaseDomain: string = 'cluster.local'; // example: 'us-west-2.gcp.charlie.sphere'`
private readonly _dnsConsensusNodePattern: string = 'network-${nodeAlias}-svc.${namespace}.svc'; // example: '${nodeId}.consensus.prod'`

public constructor(
name: string,
namespace: NamespaceNameAsString,
dnsBaseDomain?: string,
dnsConsensusNodePattern?: string,
) {
if (!name) {
throw new SoloError('name is required');
}

if (typeof name !== 'string') {
throw new SoloError(`Invalid type for name: ${typeof name}`);
}

if (!namespace) {
throw new SoloError('namespace is required');
}

if (typeof namespace !== 'string') {
throw new SoloError(`Invalid type for namespace: ${typeof namespace}`);
}

this._name = name;
this._namespace = namespace;

if (dnsBaseDomain) {
this._dnsBaseDomain = dnsBaseDomain;
}

if (dnsConsensusNodePattern) {
this._dnsConsensusNodePattern = dnsConsensusNodePattern;
}
}

public get name(): string {
return this._name;
}

public get namespace(): string {
return this._namespace;
}

public get dnsBaseDomain(): string {
return this._dnsBaseDomain;
}

public get dnsConsensusNodePattern(): string {
return this._dnsConsensusNodePattern;
}

public toObject(): ICluster {
return {
name: this.name,
namespace: this.namespace,
dnsBaseDomain: this.dnsBaseDomain,
dnsConsensusNodePattern: this.dnsConsensusNodePattern,
};
}

public static fromObject(cluster: ICluster) {
return new Cluster(cluster.name, cluster.namespace, cluster.dnsBaseDomain, cluster.dnsConsensusNodePattern);
}

public static toClustersMapObject(clustersMap: Record<ClusterRef, Cluster>) {
const entries = Object.entries(clustersMap).map(([ref, cluster]) => [ref, cluster.toObject()]);
return Object.fromEntries(entries);
}

public static fromClustersMapObject(obj: any): Record<ClusterRef, Cluster> {
const clusters: Record<ClusterRef, Cluster> = {};

for (const [ref, cluster] of Object.entries(obj)) {
clusters[ref] = Cluster.fromObject(cluster as ICluster);
}

return clusters;
}
}
4 changes: 2 additions & 2 deletions src/core/config/remote/components/base_component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/
import {ComponentType} from '../enumerations.js';
import {SoloError} from '../../../errors.js';
import {type Cluster, type Component, type ComponentName, type NamespaceNameAsString} from '../types.js';
import {type ClusterRef, type Component, type ComponentName, type NamespaceNameAsString} from '../types.js';
import {type ToObject, type Validate} from '../../../../types/index.js';

/**
Expand All @@ -20,7 +20,7 @@ export abstract class BaseComponent implements Component, Validate, ToObject<Com
protected constructor(
public readonly type: ComponentType,
public readonly name: ComponentName,
public readonly cluster: Cluster,
public readonly cluster: ClusterRef,
public readonly namespace: NamespaceNameAsString,
) {}

Expand Down
24 changes: 20 additions & 4 deletions src/core/config/remote/components/consensus_node_component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
import {ComponentType, ConsensusNodeStates} from '../enumerations.js';
import {BaseComponent} from './base_component.js';
import {SoloError} from '../../../errors.js';
import {type Cluster, type IConsensusNodeComponent, type ComponentName, type NamespaceNameAsString} from '../types.js';
import {
type ClusterRef,
type ComponentName,
type IConsensusNodeComponent,
type NamespaceNameAsString,
} from '../types.js';
import {type ToObject} from '../../../../types/index.js';

/**
Expand All @@ -19,15 +24,17 @@ export class ConsensusNodeComponent
{
/**
* @param name - the name to distinguish components.
* @param nodeId - node id of the consensus node
* @param cluster - associated to component
* @param namespace - associated to component
* @param state - of the consensus node
*/
public constructor(
name: ComponentName,
cluster: Cluster,
cluster: ClusterRef,
namespace: NamespaceNameAsString,
public readonly state: ConsensusNodeStates,
public readonly nodeId: number,
) {
super(ComponentType.ConsensusNode, name, cluster, namespace);

Expand All @@ -38,8 +45,8 @@ export class ConsensusNodeComponent

/** Handles creating instance of the class from plain object. */
public static fromObject(component: IConsensusNodeComponent): ConsensusNodeComponent {
const {name, cluster, namespace, state} = component;
return new ConsensusNodeComponent(name, cluster, namespace, state);
const {name, cluster, namespace, state, nodeId} = component;
return new ConsensusNodeComponent(name, cluster, namespace, state, nodeId);
}

public validate(): void {
Expand All @@ -48,12 +55,21 @@ export class ConsensusNodeComponent
if (!Object.values(ConsensusNodeStates).includes(this.state)) {
throw new SoloError(`Invalid consensus node state: ${this.state}`);
}

if (typeof this.nodeId !== 'number') {
throw new SoloError(`Invalid node id. It must be a number: ${this.nodeId}`);
}

if (this.nodeId < 0) {
throw new SoloError(`Invalid node id. It cannot be negative: ${this.nodeId}`);
}
}

public toObject(): IConsensusNodeComponent {
return {
...super.toObject(),
state: this.state,
nodeId: this.nodeId,
};
}
}
14 changes: 7 additions & 7 deletions src/core/config/remote/listr_config_tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/
import chalk from 'chalk';
import {type BaseCommand} from '../../../commands/base.js';
import {type Cluster, type Context} from './types.js';
import {type ClusterRef, type Context} from './types.js';
import {type SoloListrTask} from '../../../types/index.js';
import {type AnyObject} from '../../../types/aliases.js';
import {type NamespaceName} from '../../kube/resources/namespace/namespace_name.js';
Expand Down Expand Up @@ -41,15 +41,15 @@ export class ListrRemoteConfig {
*/
public static createRemoteConfig(
command: BaseCommand,
cluster: Cluster,
clusterRef: ClusterRef,

Check warning on line 44 in src/core/config/remote/listr_config_tasks.ts

View check run for this annotation

Codecov / codecov/patch

src/core/config/remote/listr_config_tasks.ts#L44

Added line #L44 was not covered by tests
context: Context,
namespace: NamespaceName,
argv: AnyObject,
): SoloListrTask<any> {
return {
title: `Create remote config in cluster: ${chalk.cyan(cluster)}`,
title: `Create remote config in cluster: ${chalk.cyan(clusterRef)}`,

Check warning on line 50 in src/core/config/remote/listr_config_tasks.ts

View check run for this annotation

Codecov / codecov/patch

src/core/config/remote/listr_config_tasks.ts#L50

Added line #L50 was not covered by tests
task: async (): Promise<void> => {
await command.getRemoteConfigManager().createAndValidate(cluster, context, namespace.name, argv);
await command.getRemoteConfigManager().createAndValidate(clusterRef, context, namespace.name, argv);

Check warning on line 52 in src/core/config/remote/listr_config_tasks.ts

View check run for this annotation

Codecov / codecov/patch

src/core/config/remote/listr_config_tasks.ts#L52

Added line #L52 was not covered by tests
},
};
}
Expand All @@ -66,11 +66,11 @@ export class ListrRemoteConfig {
task: async (ctx, task) => {
const subTasks: SoloListrTask<Context>[] = [];

for (const cluster of command.localConfig.deployments[ctx.config.deployment].clusters) {
const context = command.localConfig.clusterContextMapping?.[cluster];
for (const clusterRef of command.localConfig.deployments[ctx.config.deployment].clusters) {
const context = command.localConfig.clusterContextMapping?.[clusterRef];

Check warning on line 70 in src/core/config/remote/listr_config_tasks.ts

View check run for this annotation

Codecov / codecov/patch

src/core/config/remote/listr_config_tasks.ts#L69-L70

Added lines #L69 - L70 were not covered by tests
if (!context) continue;

subTasks.push(ListrRemoteConfig.createRemoteConfig(command, cluster, context, ctx.config.namespace, argv));
subTasks.push(ListrRemoteConfig.createRemoteConfig(command, clusterRef, context, ctx.config.namespace, argv));

Check warning on line 73 in src/core/config/remote/listr_config_tasks.ts

View check run for this annotation

Codecov / codecov/patch

src/core/config/remote/listr_config_tasks.ts#L73

Added line #L73 was not covered by tests
}

return task.newListr(subTasks, {
Expand Down
5 changes: 3 additions & 2 deletions src/core/config/remote/remote_config_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
import {type RemoteConfigMetadata} from './metadata.js';
import {type ComponentsDataWrapper} from './components_data_wrapper.js';
import {type CommonFlagsDataWrapper} from './common_flags_data_wrapper.js';
import {type Cluster, type NamespaceNameAsString} from './types.js';
import {type ClusterRef} from './types.js';
import {type Cluster} from './cluster.js';

export interface RemoteConfigData {
metadata: RemoteConfigMetadata;
clusters: Record<Cluster, NamespaceNameAsString>;
clusters: Record<ClusterRef, Cluster>;
components: ComponentsDataWrapper;
lastExecutedCommand: string;
commandHistory: string[];
Expand Down
Loading

0 comments on commit 55494a2

Please sign in to comment.