Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
0b649fc
save
JeffreyDallas Jul 28, 2025
90348e9
save
JeffreyDallas Jul 28, 2025
c2b4f53
save
JeffreyDallas Jul 28, 2025
e45cf4a
Update src/core/network/port-utilities.ts
JeffreyDallas Jul 28, 2025
13f106c
Update src/integration/kube/k8-client/resources/pod/k8-client-pod.ts
JeffreyDallas Jul 28, 2025
9222359
add delay
JeffreyDallas Jul 28, 2025
47f95a6
Merge branch '02300-D-tcp-port' of https://github.com/hiero-ledger/so…
JeffreyDallas Jul 28, 2025
43f559d
Update src/integration/kube/k8-client/resources/pod/k8-client-pod.ts
JeffreyDallas Jul 28, 2025
c29c721
Update src/core/network/port-utilities.ts
JeffreyDallas Jul 28, 2025
6d07e40
Update src/core/network/port-utilities.ts
JeffreyDallas Jul 28, 2025
1abca60
save
JeffreyDallas Jul 28, 2025
1d26487
Merge commit 'e12938ffd0d09302beaf28a5ec1f7cf964145afa' into 02300-D-…
JeffreyDallas Jul 28, 2025
2f89138
fix the portForward signatore
JeffreyDallas Jul 29, 2025
ed640bc
save
JeffreyDallas Jul 29, 2025
eb3b023
Merge commit 'de2b994441cb71fb9c4cee2c9330a12360b5a36c' into 02300-D-…
JeffreyDallas Jul 29, 2025
b1d6598
Update src/integration/kube/k8-client/resources/pod/k8-client-pod.ts
JeffreyDallas Jul 29, 2025
2c033d8
Update src/integration/kube/k8-client/resources/pod/k8-client-pod.ts
JeffreyDallas Jul 29, 2025
a39e958
Update src/commands/explorer.ts
JeffreyDallas Jul 29, 2025
28e3623
Update src/commands/relay.ts
JeffreyDallas Jul 29, 2025
f90af36
Update src/commands/mirror-node.ts
JeffreyDallas Jul 29, 2025
6359b46
Update src/integration/kube/k8-client/resources/pod/k8-client-pod.ts
JeffreyDallas Jul 29, 2025
e643df9
Update src/commands/node/tasks.ts
JeffreyDallas Jul 29, 2025
234679c
Merge branch '02300-D-tcp-port' of https://github.com/hiero-ledger/so…
JeffreyDallas Jul 29, 2025
8c313aa
save
JeffreyDallas Jul 29, 2025
596dd7d
save
JeffreyDallas Jul 30, 2025
bc124a8
save
JeffreyDallas Jul 30, 2025
4856699
save
JeffreyDallas Jul 30, 2025
4046b1f
add nodeid for portforward
JeffreyDallas Jul 30, 2025
fb59a34
save
JeffreyDallas Jul 30, 2025
4c9236c
save
JeffreyDallas Jul 30, 2025
d94eeee
save
JeffreyDallas Jul 30, 2025
7f52658
save
JeffreyDallas Jul 30, 2025
04a5f11
save
JeffreyDallas Aug 1, 2025
64d8526
save
JeffreyDallas Aug 1, 2025
1440648
save
JeffreyDallas Aug 1, 2025
8ad27a0
Merge commit '6c40c9ad9908fe22f0c9a42f54b6f27b7d7ad708' into 02300-D-…
JeffreyDallas Aug 1, 2025
09fc940
save
JeffreyDallas Aug 1, 2025
262b5a1
save
JeffreyDallas Aug 1, 2025
dced32a
Update src/core/network/port-utilities.ts
JeffreyDallas Aug 3, 2025
124499e
Update src/core/config/remote/components-data-wrapper.ts
JeffreyDallas Aug 3, 2025
f43a740
Update src/integration/kube/k8-client/resources/pod/k8-client-pod.ts
JeffreyDallas Aug 3, 2025
3bd39c3
save
JeffreyDallas Aug 3, 2025
ed0120d
save
JeffreyDallas Aug 4, 2025
0a5dded
Merge commit '66d9f90a108d78a6a747bdd7394e26561af50fbe' into 02300-D-…
JeffreyDallas Aug 4, 2025
464e295
Merge branch 'main' into 02300-D-tcp-port
JeffreyDallas Aug 5, 2025
d115a13
Update src/integration/kube/k8-client/resources/pod/k8-client-pod.ts
JeffreyDallas Aug 8, 2025
679183b
Update src/integration/kube/k8-client/resources/pod/k8-client-pod.ts
JeffreyDallas Aug 8, 2025
63da2ec
add migrationv2
JeffreyDallas Aug 8, 2025
1214642
Merge branch '02300-D-tcp-port' of https://github.com/hiero-ledger/so…
JeffreyDallas Aug 8, 2025
cad9b34
move portforward check function
JeffreyDallas Aug 10, 2025
b7c1019
test migration
JeffreyDallas Aug 11, 2025
2ba30ee
save
JeffreyDallas Aug 11, 2025
c65a33d
Merge commit '89910ccb2b86db143248b3965e8a14b4eca3fd31' into 02300-D-…
JeffreyDallas Aug 11, 2025
e79aecd
save
JeffreyDallas Aug 11, 2025
177514e
fix unit test
JeffreyDallas Aug 11, 2025
c7e3b99
Merge branch 'main' into 02300-D-tcp-port
JeffreyDallas Aug 12, 2025
ca5328c
update
JeffreyDallas Aug 12, 2025
eadad52
fix check
JeffreyDallas Aug 12, 2025
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
4 changes: 2 additions & 2 deletions .github/workflows/script/launch_network.sh
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ if ! grep -q "schemaVersion: 2" ./local-config-after.yaml; then
fi

# check remote-config-after.yaml should contains 'schemaVersion: 1'
if ! grep -q "schemaVersion: 1" ./remote-config-after.yaml; then
echo "schemaVersion: 1 not found in remote-config-after.yaml"
if ! grep -q "schemaVersion: 2" ./remote-config-after.yaml; then
echo "schemaVersion: 2 not found in remote-config-after.yaml"
exit 1
fi
echo "::endgroup::"
Expand Down
82 changes: 82 additions & 0 deletions src/business/utils/port-utilities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: Apache-2.0

import net from 'node:net';
import * as constants from '../../core/constants.js';
import {type SoloLogger} from '../../core/logging/solo-logger.js';

/**
* Utility class for port-related operations
*/
export class PortUtilities {
/**
* Check if a TCP port is available on the local machine
* @param port Port number to check
* @returns Promise that resolves to true if port is available, false otherwise
*/
public static async isPortAvailable(port: number): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {

Check warning on line 17 in src/business/utils/port-utilities.ts

View workflow job for this annotation

GitHub Actions / Code Style / Standard

Missing return type on function
const server: net.Server = net.createServer();
const timeout = setTimeout(() => {
server.close();
reject(new Error(`Timeout while checking port ${port}`));
}, 5000); // 5-second timeout

server.once('error', error => {
clearTimeout(timeout);
if ((error as NodeJS.ErrnoException).code === 'EADDRINUSE') {
// Port is in use
resolve(false);
} else {
// Unexpected error
reject(error);
}
});

server.once('listening', () => {
clearTimeout(timeout);
// Port is available
server.close(() => {
resolve(true);
});
});
server.listen(port, constants.LOCAL_HOST);
});
}

/**
* Find an available port starting from the given port
* @param startPort Port number to start checking from
* @param timeoutMs Timeout in milliseconds before giving up (default: 30000)
* @param logger logger for debug messages
* @returns Promise that resolves to the first available port or throws an error if timeout is reached
* @throws Error if no available port is found within the timeout period
*/
public static async findAvailablePort(
startPort: number,
timeoutMs: number = 30_000,
logger: SoloLogger,
): Promise<number> {
if (!Number.isInteger(startPort) || startPort < 1 || startPort > 65_535) {
throw new Error(`Invalid startPort: ${startPort}. Must be an integer between 1 and 65535.`);
}
let port: number = startPort;
let attempts: number = 0;
const startTime: number = Date.now();

while (!(await this.isPortAvailable(port))) {
logger.debug(`Port ${port} is not available, trying ${port + 1}`);
port++;
attempts++;

if (Date.now() - startTime > timeoutMs) {
const errorMessage: string = `Failed to find an available port after ${timeoutMs}ms timeout, starting from port ${startPort}`;
logger.error(errorMessage);
throw new Error(errorMessage);
}
}

return port;
}
}

// The managePortForward function has been moved to components-data-wrapper.ts
26 changes: 16 additions & 10 deletions src/commands/explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,9 @@ export class ExplorerCommand extends BaseCommand {
]) as ExplorerDeployConfigClass;

context_.config.valuesArg += await self.prepareValuesArg(context_.config);
context_.config.clusterReference =
(this.configManager.getFlag<string>(flags.clusterRef) as string) ??
this.k8Factory.default().clusters().readCurrent();
context_.config.clusterContext = context_.config.clusterRef
? this.localConfig.configuration.clusterRefs.get(context_.config.clusterRef)?.toString()
: this.k8Factory.default().contexts().readCurrent();
Expand Down Expand Up @@ -450,7 +453,7 @@ export class ExplorerCommand extends BaseCommand {
},
this.addMirrorNodeExplorerComponents(),
{
title: 'Enable port forwarding',
title: 'Enable port forwarding for explorer',
skip: context_ => !context_.config.forcePortForward,
task: async context_ => {
const pods: Pod[] = await this.k8Factory
Expand All @@ -461,16 +464,19 @@ export class ExplorerCommand extends BaseCommand {
throw new SoloError('No Hiero Explorer pod found');
}
const podReference: PodReference = pods[0].podReference;
const clusterReference: ClusterReferenceName = context_.config.clusterReference;

await this.k8Factory
.getK8(context_.config.clusterContext)
.pods()
.readByReference(podReference)
.portForward(constants.EXPLORER_PORT, constants.EXPLORER_PORT, true);
this.logger.addMessageGroup(constants.PORT_FORWARDING_MESSAGE_GROUP, 'Port forwarding enabled');
this.logger.addMessageGroupMessage(
constants.PORT_FORWARDING_MESSAGE_GROUP,
`Explorer port forward enabled on http://localhost:${constants.EXPLORER_PORT}`,
await this.remoteConfig.configuration.components.managePortForward(
clusterReference,
podReference,
constants.EXPLORER_PORT, // Pod port
constants.EXPLORER_PORT, // Local port
this.k8Factory.getK8(context_.config.clusterContext),
this.logger,
ComponentTypes.Explorers,

'Explorer',
context_.config.isChartInstalled, // Reuse existing port if chart is already installed
);
},
},
Expand Down
29 changes: 19 additions & 10 deletions src/commands/mirror-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {Base64} from 'js-base64';
import {Lock} from '../core/lock/lock.js';
import {Version} from '../business/utils/version.js';
import {IngressClass} from '../integration/kube/resources/ingress-class/ingress-class.js';
// Port forwarding is now a method on the components object

interface MirrorNodeDeployConfigClass {
isChartInstalled: boolean;
Expand Down Expand Up @@ -614,6 +615,10 @@ export class MirrorNodeCommand extends BaseCommand {
title: 'Check Monitor',
labels: ['app.kubernetes.io/component=monitor', 'app.kubernetes.io/name=monitor'],
},
{
title: 'Check Web3',
labels: ['app.kubernetes.io/component=web3', 'app.kubernetes.io/name=web3'],
},
{
title: 'Check Importer',
labels: ['app.kubernetes.io/component=importer', 'app.kubernetes.io/name=importer'],
Expand Down Expand Up @@ -771,7 +776,7 @@ export class MirrorNodeCommand extends BaseCommand {
},
this.addMirrorNodeComponents(),
{
title: 'Enable port forwarding',
title: 'Enable port forwarding for mirror ingress controller',
skip: context_ => !context_.config.forcePortForward || !context_.config.enableIngress,
task: async context_ => {
const pods: Pod[] = await this.k8Factory
Expand All @@ -789,15 +794,19 @@ export class MirrorNodeCommand extends BaseCommand {
}
}

await this.k8Factory
.getK8(context_.config.clusterContext)
.pods()
.readByReference(podReference)
.portForward(constants.MIRROR_NODE_PORT, 80, true);
this.logger.addMessageGroup(constants.PORT_FORWARDING_MESSAGE_GROUP, 'Port forwarding enabled');
this.logger.addMessageGroupMessage(
constants.PORT_FORWARDING_MESSAGE_GROUP,
`Mirror Node port forward enabled on localhost:${constants.MIRROR_NODE_PORT}`,
const clusterReference: ClusterReferenceName = context_.config.clusterReference;

await this.remoteConfig.configuration.components.managePortForward(
clusterReference,
podReference,
80, // Pod port
constants.MIRROR_NODE_PORT, // Local port
this.k8Factory.getK8(context_.config.clusterContext),
this.logger,
ComponentTypes.MirrorNode,

'Mirror ingress controller',
context_.config.isChartInstalled, // Reuse existing port if chart is already installed
);
},
},
Expand Down
24 changes: 14 additions & 10 deletions src/commands/node/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1573,7 +1573,7 @@ export class NodeCommandTasks {

public enablePortForwarding(enablePortForwardHaProxy: boolean = false) {
return {
title: 'Enable port forwarding',
title: 'Enable port forwarding for debug port and/or GRPC port',
task: async context_ => {
const nodeAlias: NodeAlias = context_.config.debugNodeAlias || 'node1';
const context = helpers.extractContextFromConsensusNodes(nodeAlias, context_.config.consensusNodes);
Expand All @@ -1600,15 +1600,19 @@ export class NodeCommandTasks {
throw new SoloError(`No HAProxy pod found for node alias: ${nodeAlias}`);
}
const podReference: PodReference = pods[0].podReference;
await this.k8Factory
.getK8(context)
.pods()
.readByReference(podReference)
.portForward(constants.GRPC_PORT, constants.GRPC_PORT, true);
this.logger.addMessageGroup(constants.PORT_FORWARDING_MESSAGE_GROUP, 'Port forwarding enabled');
this.logger.addMessageGroupMessage(
constants.PORT_FORWARDING_MESSAGE_GROUP,
`Consensus Node gRPC port forward enabled on localhost:${constants.GRPC_PORT}`,
const nodeId: number = Templates.nodeIdFromNodeAlias(nodeAlias);
await this.remoteConfig.configuration.components.managePortForward(
undefined,
podReference,
constants.GRPC_PORT, // Pod port
constants.GRPC_PORT, // Local port
this.k8Factory.getK8(context_.config.clusterContext),
this.logger,
ComponentTypes.ConsensusNode,

'Consensus Node gRPC',
context_.config.isChartInstalled, // Reuse existing port if chart is already installed
nodeId,
);
}
},
Expand Down
54 changes: 36 additions & 18 deletions src/commands/relay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ export class RelayCommand extends BaseCommand {
},
this.addRelayComponent(),
{
title: 'Enable port forwarding',
title: 'Enable port forwarding for relay node',
task: async (context_): Promise<void> => {
const pods: Pod[] = await this.k8Factory
.getK8(context_.config.clusterContext)
Expand All @@ -430,15 +430,21 @@ export class RelayCommand extends BaseCommand {
throw new SoloError('No Relay pod found');
}
const podReference: PodReference = pods[0].podReference;
await this.k8Factory
.getK8(context_.config.context)
.pods()
.readByReference(podReference)
.portForward(constants.JSON_RPC_RELAY_PORT, constants.JSON_RPC_RELAY_PORT, true);
this.logger.addMessageGroup(constants.PORT_FORWARDING_MESSAGE_GROUP, 'Port forwarding enabled');
this.logger.addMessageGroupMessage(
constants.PORT_FORWARDING_MESSAGE_GROUP,
`JSON RPC Relay forward enabled on localhost:${constants.JSON_RPC_RELAY_PORT}`,
const clusterReference: string =
(this.configManager.getFlag<string>(flags.clusterRef) as string) ??
this.k8Factory.default().clusters().readCurrent();

await this.remoteConfig.configuration.components.managePortForward(
clusterReference,
podReference,
constants.JSON_RPC_RELAY_PORT, // Pod port
constants.JSON_RPC_RELAY_PORT, // Local port
this.k8Factory.getK8(context_.config.clusterContext),
this.logger,
ComponentTypes.RelayNodes,

'JSON RPC Relay',
context_.config.isChartInstalled, // Reuse existing port if chart is already installed
);
},
skip: context_ => !context_.config.forcePortForward,
Expand Down Expand Up @@ -626,12 +632,14 @@ export class RelayCommand extends BaseCommand {
title: 'Add relay component in remote config',
skip: context_ => !this.remoteConfig.isLoaded() || context_.config.isChartInstalled,
task: async (context_): Promise<void> => {
const {namespace, nodeAliases, clusterRef} = context_.config;
const {namespace, nodeAliases} = context_.config;

const nodeIds: NodeId[] = nodeAliases.map((nodeAlias: NodeAlias) => Templates.nodeIdFromNodeAlias(nodeAlias));

const clusterReference: string =
(this.configManager.getFlag<string>(flags.clusterRef) as string) ??
this.k8Factory.default().clusters().readCurrent();
this.remoteConfig.configuration.components.addNewComponent(
this.componentFactory.createNewRelayComponent(clusterRef, namespace, nodeIds),
this.componentFactory.createNewRelayComponent(clusterReference, namespace, nodeIds),
ComponentTypes.RelayNodes,
);

Expand All @@ -648,12 +656,22 @@ export class RelayCommand extends BaseCommand {
task: async (context_): Promise<void> => {
const clusterReference: ClusterReferenceName = context_.config.clusterRef;

const relayComponents: RelayNodeStateSchema[] =
this.remoteConfig.configuration.components.getComponentsByClusterReference<RelayNodeStateSchema>(
ComponentTypes.RelayNodes,
clusterReference,
);
// if clusterReference not defined then we will remove all relay nodes
const relayComponents: RelayNodeStateSchema[] = clusterReference
? this.remoteConfig.configuration.components.getComponentsByClusterReference<RelayNodeStateSchema>(
ComponentTypes.RelayNodes,
clusterReference,
)
: this.remoteConfig.configuration.components.getComponentByType<RelayNodeStateSchema>(
ComponentTypes.RelayNodes,
);

if (relayComponents.length === 0) {
this.logger.showUser(
`Did not find any relay node in remote config to be removed, clusterReference = ${clusterReference}`,
);
return;
}
for (const relayComponent of relayComponents) {
this.remoteConfig.configuration.components.removeComponent(
relayComponent.metadata.id,
Expand Down
15 changes: 7 additions & 8 deletions src/core/account-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,16 +427,15 @@ export class AccountManager {
const targetPort: number = localPort;

if (this._portForwards.length < totalNodes) {
this._portForwards.push(
await this.k8Factory
.getK8(networkNodeService.context)
.pods()
.readByReference(PodReference.of(networkNodeService.namespace, networkNodeService.haProxyPodName))
.portForward(localPort, port),
);
const portForward: ExtendedNetServer = await this.k8Factory
.getK8(networkNodeService.context)
.pods()
.readByReference(PodReference.of(networkNodeService.namespace, networkNodeService.haProxyPodName))
.portForward(localPort, port);
this._portForwards.push(portForward);
this.logger.debug(`using local host port forward: ${host}:${portForward.localPort}`);
}

this.logger.debug(`using local host port forward: ${host}:${targetPort}`);
object[`${host}:${targetPort}`] = accountId;

await this.testNodeClientConnection(object, accountId);
Expand Down
3 changes: 2 additions & 1 deletion src/core/config/remote/api/component-factory-api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0

import {type ClusterReferenceName} from '../../../../types/index.js';
import {type ClusterReferenceName, type portForwardConfig} from '../../../../types/index.js';
import {type NodeId} from '../../../../types/aliases.js';
import {type NamespaceName} from '../../../../types/namespace/namespace-name.js';
import {type DeploymentPhase} from '../../../../data/schema/model/remote/deployment-phase.js';
Expand Down Expand Up @@ -34,6 +34,7 @@ export interface ComponentFactoryApi {
clusterReference: ClusterReferenceName,
namespace: NamespaceName,
phase: DeploymentPhase.REQUESTED | DeploymentPhase.STARTED,
portForwardConfigs?: portForwardConfig[],
): ConsensusNodeStateSchema;

createConsensusNodeComponentsFromNodeIds(
Expand Down
Loading
Loading