Skip to content

Commit

Permalink
feat(remote-config): save reusable solo flags in remoteconfig (#1191)
Browse files Browse the repository at this point in the history
Signed-off-by: instamenta <[email protected]>
Signed-off-by: Jeromy Cannon <[email protected]>
Signed-off-by: Jan Milenkov <[email protected]>
Co-authored-by: Jeromy Cannon <[email protected]>
  • Loading branch information
instamenta and jeromy-cannon authored Jan 27, 2025
1 parent 7877d92 commit 809d0ab
Show file tree
Hide file tree
Showing 14 changed files with 273 additions and 114 deletions.
35 changes: 5 additions & 30 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"license": "Apache2.0",
"dependencies": {
"@hashgraph/sdk": "^2.56.0",
"@inquirer/prompts": "^7.2.3",
"@kubernetes/client-node": "^0.22.3",
"@listr2/prompt-adapter-enquirer": "^2.0.12",
"@peculiar/x509": "^1.12.3",
Expand All @@ -57,12 +58,10 @@
"class-validator": "^0.14.1",
"dot-object": "^2.1.5",
"dotenv": "^16.4.7",
"enquirer": "^2.4.1",
"esm": "^3.2.25",
"figlet": "^1.8.0",
"got": "^14.4.5",
"http-status-codes": "^2.3.0",
"inquirer": "^12.3.2",
"ip": "^2.0.1",
"js-base64": "^3.7.7",
"listr2": "^8.2.5",
Expand Down
2 changes: 1 addition & 1 deletion src/commands/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export class DeploymentCommand extends BaseCommand {
});
},
},
ListrRemoteConfig.createRemoteConfigInMultipleClusters(this),
ListrRemoteConfig.createRemoteConfigInMultipleClusters(this, argv),
],
{
concurrent: false,
Expand Down
2 changes: 1 addition & 1 deletion src/commands/mirror_node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ export class MirrorNodeCommand extends BaseCommand {
await tasks.run();
self.logger.debug('mirror node destruction has completed');
} catch (e) {
throw new SoloError(`Error destrong mirror node: ${e.message}`, e);
throw new SoloError(`Error destroying mirror node: ${e.message}`, e);
} finally {
await lease.release();
await self.accountManager.close();
Expand Down
124 changes: 124 additions & 0 deletions src/core/config/remote/common_flags_data_wrapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/**
* Copyright (C) 2024 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the ""License"");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an ""AS IS"" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import {Flags as flags} from '../../../commands/flags.js';
import type {ToObject} from '../../../types/index.js';
import type {RemoteConfigCommonFlagsStruct} from './types.js';
import type {ConfigManager} from '../../config_manager.js';
import type {CommandFlag} from '../../../types/flag_types.js';
import type {AnyObject} from '../../../types/aliases.js';
import {select} from '@inquirer/prompts';

export class CommonFlagsDataWrapper implements ToObject<RemoteConfigCommonFlagsStruct> {
private static readonly COMMON_FLAGS: CommandFlag[] = [
flags.releaseTag,
flags.chartDirectory,
flags.relayReleaseTag,
flags.soloChartVersion,
flags.mirrorNodeVersion,
flags.nodeAliasesUnparsed,
flags.hederaExplorerVersion,
];

private constructor(
private readonly configManager: ConfigManager,
private readonly flags: RemoteConfigCommonFlagsStruct,
) {}

/**
* Updates the flags or populates them inside the remote config
*/
public async handleFlags(argv: AnyObject): Promise<void> {
for (const flag of CommonFlagsDataWrapper.COMMON_FLAGS) {
await this.handleFlag(flag, argv);
}
}

private async handleFlag(flag: CommandFlag, argv: AnyObject): Promise<void> {
const detectFlagMismatch = async () => {
const oldValue = this.flags[flag.constName] as string;
const newValue = this.configManager.getFlag<string>(flag);

// if the old value is not present, override it with the new one
if (!oldValue && newValue) {
this.flags[flag.constName] = newValue;
return;
}

// if its present but there is a mismatch warn user
else if (oldValue && oldValue !== newValue) {
const isQuiet = this.configManager.getFlag<boolean>(flags.quiet);
const isForced = this.configManager.getFlag<boolean>(flags.force);

// if the quiet or forced flag is passed don't prompt the user
if (isQuiet === true || isForced === true) return;

const answer = await select<string>({
message: 'Value in remote config differs with the one you are passing, choose which you want to use',
choices: [
{
name: `[old value] ${oldValue}`,
value: oldValue,
},
{
name: `[new value] ${newValue}`,
value: newValue,
},
],
});

// Override if user chooses new the new value, else override and keep the old one
if (answer === newValue) {
this.flags[flag.constName] = newValue;
} else {
this.configManager.setFlag(flag, oldValue);
argv[flag.constName] = oldValue;
}
}
};

// if the flag is set, inspect the value
if (this.configManager.hasFlag(flag)) {
await detectFlagMismatch();
}

// use remote config value if no user supplied value
else if (this.flags[flag.constName]) {
argv[flag.constName] = this.flags[flag.constName];
this.configManager.setFlag(flag, this.flags[flag.constName]);
}
}

public static async initialize(configManager: ConfigManager, argv: AnyObject): Promise<CommonFlagsDataWrapper> {
const commonFlagsDataWrapper = new CommonFlagsDataWrapper(configManager, {});
await commonFlagsDataWrapper.handleFlags(argv);
return commonFlagsDataWrapper;
}

public static fromObject(configManager: ConfigManager, data: RemoteConfigCommonFlagsStruct): CommonFlagsDataWrapper {
return new CommonFlagsDataWrapper(configManager, data);
}

public toObject(): RemoteConfigCommonFlagsStruct {
return {
nodeAliasesUnparsed: this.flags.nodeAliasesUnparsed,
releaseTag: this.flags.releaseTag,
relayReleaseTag: this.flags.relayReleaseTag,
hederaExplorerVersion: this.flags.hederaExplorerVersion,
mirrorNodeVersion: this.flags.mirrorNodeVersion,
};
}
}
24 changes: 6 additions & 18 deletions src/core/config/remote/components_data_wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,14 @@ import {MirrorNodeComponent} from './components/mirror_node_component.js';
import {EnvoyProxyComponent} from './components/envoy_proxy_component.js';
import {ConsensusNodeComponent} from './components/consensus_node_component.js';
import {MirrorNodeExplorerComponent} from './components/mirror_node_explorer_component.js';
import {
type Component,
type ComponentsDataStructure,
type IConsensusNodeComponent,
type IRelayComponent,
type ComponentName,
type Cluster,
type Namespace,
import type {
Component,
ComponentsDataStructure,
IConsensusNodeComponent,
IRelayComponent,
ComponentName,
} from './types.js';
import type {ToObject, Validate} from '../../../types/index.js';
import type {RemoteConfigMetadata} from './metadata.js';

export interface RemoteConfigData {
metadata: RemoteConfigMetadata;
clusters: Record<Cluster, Namespace>;
components: ComponentsDataWrapper;
lastExecutedCommand: string;
commandHistory: string[];
}

/**
* Represent the components in the remote config and handles:
Expand Down Expand Up @@ -166,7 +155,6 @@ export class ComponentsDataWrapper implements Validate, ToObject<ComponentsDataS
case ComponentType.Relay:
callback(this.relays);
break;

case ComponentType.HaProxy:
callback(this.haProxies);
break;
Expand Down
12 changes: 5 additions & 7 deletions src/core/config/remote/listr_config_tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,21 +50,18 @@ export class ListrRemoteConfig {

/**
* Create remoteConfig and save it to the provided cluster.
* @param command
* @param cluster
* @param context
* @param namespace
*/
public static createRemoteConfig(
command: BaseCommand,
cluster: Cluster,
context: Context,
namespace: Namespace,
argv: AnyObject,
): SoloListrTask<any> {
return {
title: `Create remote config in cluster: ${chalk.cyan(cluster)}`,
task: async (): Promise<void> => {
await command.getRemoteConfigManager().createAndValidate(cluster, context, namespace);
await command.getRemoteConfigManager().createAndValidate(cluster, context, namespace, argv);
},
};
}
Expand All @@ -73,8 +70,9 @@ export class ListrRemoteConfig {
* Create a remoteConfig object and save it to multiple clusters, read from ctx config
*
* @param command - the BaseCommand object on which an action will be performed
* @param argv
*/
public static createRemoteConfigInMultipleClusters(command: BaseCommand): SoloListrTask<any> {
public static createRemoteConfigInMultipleClusters(command: BaseCommand, argv: AnyObject): SoloListrTask<any> {
return {
title: 'Create remoteConfig in clusters',
task: async (ctx, task) => {
Expand All @@ -84,7 +82,7 @@ export class ListrRemoteConfig {
const context = command.localConfig.clusterContextMapping?.[cluster];
if (!context) continue;

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

return task.newListr(subTasks, {
Expand Down
9 changes: 1 addition & 8 deletions src/core/config/remote/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,9 @@
import {Migration} from './migration.js';
import {SoloError} from '../../errors.js';
import * as k8s from '@kubernetes/client-node';
import type {EmailAddress, Namespace, Version} from './types.js';
import type {EmailAddress, Namespace, RemoteConfigMetadataStructure, Version} from './types.js';
import type {Optional, ToObject, Validate} from '../../../types/index.js';

export interface RemoteConfigMetadataStructure {
name: Namespace;
lastUpdatedAt: Date;
lastUpdateBy: EmailAddress;
migration?: Migration;
}

/**
* Represent the remote config metadata object and handles:
* - Validation
Expand Down
29 changes: 29 additions & 0 deletions src/core/config/remote/remote_config_data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Copyright (C) 2024 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the ""License"");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an ""AS IS"" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
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 Namespace} from './types.js';

export interface RemoteConfigData {
metadata: RemoteConfigMetadata;
clusters: Record<Cluster, Namespace>;
components: ComponentsDataWrapper;
lastExecutedCommand: string;
commandHistory: string[];
flags: CommonFlagsDataWrapper;
}
Loading

0 comments on commit 809d0ab

Please sign in to comment.