Skip to content

Commit e73114c

Browse files
authored
feat(multi-cluster): 'solo relay deploy' to handle cluster-ref value (#1394)
Signed-off-by: instamenta <[email protected]>
1 parent 2dca095 commit e73114c

File tree

5 files changed

+63
-37
lines changed

5 files changed

+63
-37
lines changed

src/commands/node/tasks.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ export class NodeCommandTasks {
265265

266266
const self = this;
267267

268-
const k8 = context ? self.k8Factory.getK8(context) : self.k8Factory.default();
268+
const k8 = self.k8Factory.getK8(context);
269269

270270
subTasks.push({
271271
title: `Copy local build to Node: ${chalk.yellow(nodeAlias)} from ${localDataLibBuildPath}`,
@@ -882,7 +882,7 @@ export class NodeCommandTasks {
882882
const podRef = PodRef.of(namespace, podName);
883883

884884
try {
885-
const k8 = context ? this.k8Factory.getK8(context) : this.k8Factory.default();
885+
const k8 = this.k8Factory.getK8(context);
886886

887887
await k8
888888
.pods()

src/commands/relay.ts

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ import {RelayComponent} from '../core/config/remote/components/relay_component.j
1717
import {ComponentType} from '../core/config/remote/enumerations.js';
1818
import * as Base64 from 'js-base64';
1919
import {NamespaceName} from '../core/kube/resources/namespace/namespace_name.js';
20-
import {type DeploymentName} from '../core/config/remote/types.js';
20+
import {type ClusterRef, type DeploymentName} from '../core/config/remote/types.js';
21+
import {type Optional} from '../types/index.js';
2122

2223
export class RelayCommand extends BaseCommand {
2324
private readonly profileManager: ProfileManager;
@@ -42,6 +43,7 @@ export class RelayCommand extends BaseCommand {
4243
flags.chainId,
4344
flags.chartDirectory,
4445
flags.deployment,
46+
flags.clusterRef,
4547
flags.nodeAliasesUnparsed,
4648
flags.operatorId,
4749
flags.operatorKey,
@@ -67,6 +69,7 @@ export class RelayCommand extends BaseCommand {
6769
operatorID: string,
6870
operatorKey: string,
6971
namespace: NamespaceName,
72+
context?: Optional<string>,
7073
) {
7174
let valuesArg = '';
7275

@@ -104,10 +107,9 @@ export class RelayCommand extends BaseCommand {
104107
try {
105108
const deploymentName = this.configManager.getFlag<DeploymentName>(flags.deployment);
106109
const namespace = NamespaceName.of(this.localConfig.deployments[deploymentName].namespace);
107-
const secrets = await this.k8Factory
108-
.default()
109-
.secrets()
110-
.list(namespace, [`solo.hedera.com/account-id=${operatorIdUsing}`]);
110+
111+
const k8 = this.k8Factory.getK8(context);
112+
const secrets = await k8.secrets().list(namespace, [`solo.hedera.com/account-id=${operatorIdUsing}`]);
111113
if (secrets.length === 0) {
112114
this.logger.info(`No k8s secret found for operator account id ${operatorIdUsing}, use default one`);
113115
valuesArg += ` --set config.OPERATOR_KEY_MAIN=${constants.OPERATOR_KEY}`;
@@ -116,7 +118,7 @@ export class RelayCommand extends BaseCommand {
116118
const operatorKeyFromK8 = Base64.decode(secrets[0].data.privateKey);
117119
valuesArg += ` --set config.OPERATOR_KEY_MAIN=${operatorKeyFromK8}`;
118120
}
119-
} catch (e: Error | any) {
121+
} catch (e) {
120122
throw new SoloError(`Error getting operator key: ${e.message}`, e);
121123
}
122124
}
@@ -198,6 +200,8 @@ export class RelayCommand extends BaseCommand {
198200
nodeAliases: NodeAliases;
199201
releaseName: string;
200202
valuesArg: string;
203+
clusterRef: Optional<ClusterRef>;
204+
context: Optional<string>;
201205
getUnusedConfigs: () => string[];
202206
}
203207

@@ -215,7 +219,7 @@ export class RelayCommand extends BaseCommand {
215219

216220
self.configManager.update(argv);
217221

218-
flags.disablePrompts([flags.operatorId, flags.operatorKey]);
222+
flags.disablePrompts([flags.operatorId, flags.operatorKey, flags.clusterRef]);
219223

220224
await self.configManager.executePrompt(task, RelayCommand.DEPLOY_FLAGS_LIST);
221225

@@ -227,9 +231,16 @@ export class RelayCommand extends BaseCommand {
227231
ctx.config.namespace = await resolveNamespaceFromDeployment(this.localConfig, this.configManager, task);
228232
ctx.config.nodeAliases = helpers.parseNodeAliases(ctx.config.nodeAliasesUnparsed);
229233
ctx.config.releaseName = self.prepareReleaseName(ctx.config.nodeAliases);
234+
235+
if (ctx.config.clusterRef) {
236+
const context = self.getClusterRefs()[ctx.config.clusterRef];
237+
if (context) ctx.config.context = context;
238+
}
239+
230240
ctx.config.isChartInstalled = await self.chartManager.isChartInstalled(
231241
ctx.config.namespace,
232242
ctx.config.releaseName,
243+
ctx.config.context,
233244
);
234245

235246
self.logger.debug('Initialized config', {config: ctx.config});
@@ -250,6 +261,7 @@ export class RelayCommand extends BaseCommand {
250261
ctx.config.namespace,
251262
self.getClusterRefs(),
252263
self.configManager.getFlag<DeploymentName>(flags.deployment),
264+
ctx.config.context,
253265
);
254266
config.valuesArg = await self.prepareValuesArg(
255267
config.valuesFile,
@@ -260,6 +272,7 @@ export class RelayCommand extends BaseCommand {
260272
config.operatorId,
261273
config.operatorKey,
262274
config.namespace,
275+
config.context,
263276
);
264277
},
265278
},
@@ -268,17 +281,19 @@ export class RelayCommand extends BaseCommand {
268281
task: async ctx => {
269282
const config = ctx.config;
270283

284+
const k8 = self.k8Factory.getK8(config.context);
285+
const kubeContext = k8.contexts().readCurrent();
286+
271287
await self.chartManager.install(
272288
config.namespace,
273289
config.releaseName,
274290
config.chartPath,
275291
'',
276292
config.valuesArg,
277-
this.k8Factory.default().contexts().readCurrent(),
293+
kubeContext,
278294
);
279295

280-
await self.k8Factory
281-
.default()
296+
await k8
282297
.pods()
283298
.waitForRunningPhase(
284299
config.namespace,
@@ -295,17 +310,17 @@ export class RelayCommand extends BaseCommand {
295310
title: 'Check relay is ready',
296311
task: async ctx => {
297312
const config = ctx.config;
313+
const k8 = self.k8Factory.getK8(config.context);
298314
try {
299-
await self.k8Factory
300-
.default()
315+
await k8
301316
.pods()
302317
.waitForReadyStatus(
303318
config.namespace,
304319
['app=hedera-json-rpc-relay', `app.kubernetes.io/instance=${config.releaseName}`],
305320
constants.RELAY_PODS_READY_MAX_ATTEMPTS,
306321
constants.RELAY_PODS_READY_DELAY,
307322
);
308-
} catch (e: Error | any) {
323+
} catch (e) {
309324
throw new SoloError(`Relay ${config.releaseName} is not ready: ${e.message}`, e);
310325
}
311326
},
@@ -320,7 +335,7 @@ export class RelayCommand extends BaseCommand {
320335

321336
try {
322337
await tasks.run();
323-
} catch (e: Error | any) {
338+
} catch (e) {
324339
throw new SoloError('Error installing relays', e);
325340
} finally {
326341
await lease.release();

src/core/account_manager.ts

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import path from 'path';
2929

3030
import {type SoloLogger} from './logging.js';
3131
import {type K8Factory} from './kube/k8_factory.js';
32-
import {type AccountIdWithKeyPairObject, type ExtendedNetServer} from '../types/index.js';
32+
import {type AccountIdWithKeyPairObject, type ExtendedNetServer, type Optional} from '../types/index.js';
3333
import {type NodeAlias, type SdkNetworkEndpoint} from '../types/aliases.js';
3434
import {PodName} from './kube/resources/pod/pod_name.js';
3535
import {isNumeric, sleep} from './helpers.js';
@@ -71,14 +71,17 @@ export class AccountManager {
7171
/**
7272
* Gets the account keys from the Kubernetes secret from which it is stored
7373
* @param accountId - the account ID for which we want its keys
74-
* @param namespace - the namespace that is storing the secret
74+
* @param namespace - the namespace storing the secret
75+
* @param [context]
7576
*/
76-
async getAccountKeysFromSecret(accountId: string, namespace: NamespaceName): Promise<AccountIdWithKeyPairObject> {
77+
async getAccountKeysFromSecret(
78+
accountId: string,
79+
namespace: NamespaceName,
80+
context?: Optional<string>,
81+
): Promise<AccountIdWithKeyPairObject> {
7782
try {
78-
const secrets = await this.k8Factory
79-
.default()
80-
.secrets()
81-
.list(namespace, [Templates.renderAccountKeySecretLabelSelector(accountId)]);
83+
const k8 = this.k8Factory.getK8(context);
84+
const secrets = await k8.secrets().list(namespace, [Templates.renderAccountKeySecretLabelSelector(accountId)]);
8285

8386
if (secrets.length > 0) {
8487
const secret = secrets[0];
@@ -107,10 +110,11 @@ export class AccountManager {
107110
* returns the Genesis private key, then will return an AccountInfo object with the
108111
* accountId, ed25519PrivateKey, publicKey
109112
* @param namespace - the namespace that the secret is in
113+
* @param [context]
110114
*/
111-
async getTreasuryAccountKeys(namespace: NamespaceName) {
115+
async getTreasuryAccountKeys(namespace: NamespaceName, context?: Optional<string>) {
112116
// check to see if the treasure account is in the secrets
113-
return await this.getAccountKeysFromSecret(constants.TREASURY_ACCOUNT_ID, namespace);
117+
return await this.getAccountKeysFromSecret(constants.TREASURY_ACCOUNT_ID, namespace, context);
114118
}
115119

116120
/**
@@ -165,8 +169,14 @@ export class AccountManager {
165169
* @param namespace - the namespace of the network
166170
* @param clusterRefs
167171
* @param deployment
172+
* @param context
168173
*/
169-
async loadNodeClient(namespace: NamespaceName, clusterRefs?: ClusterRefs, deployment?: DeploymentName) {
174+
async loadNodeClient(
175+
namespace: NamespaceName,
176+
clusterRefs?: ClusterRefs,
177+
deployment?: DeploymentName,
178+
context?: Optional<string>,
179+
) {
170180
try {
171181
this.logger.debug(
172182
`loading node client: [!this._nodeClient=${!this._nodeClient}, this._nodeClient.isClientShutDown=${this._nodeClient?.isClientShutDown}]`,
@@ -175,15 +185,15 @@ export class AccountManager {
175185
this.logger.debug(
176186
`refreshing node client: [!this._nodeClient=${!this._nodeClient}, this._nodeClient.isClientShutDown=${this._nodeClient?.isClientShutDown}]`,
177187
);
178-
await this.refreshNodeClient(namespace, undefined, clusterRefs, deployment);
188+
await this.refreshNodeClient(namespace, undefined, clusterRefs, deployment, context);
179189
} else {
180190
try {
181191
if (!constants.SKIP_NODE_PING) {
182192
await this._nodeClient.ping(this._nodeClient.operatorAccountId);
183193
}
184194
} catch {
185195
this.logger.debug('node client ping failed, refreshing node client');
186-
await this.refreshNodeClient(namespace, undefined, clusterRefs, deployment);
196+
await this.refreshNodeClient(namespace, undefined, clusterRefs, deployment, context);
187197
}
188198
}
189199

@@ -199,16 +209,21 @@ export class AccountManager {
199209
* loads and initializes the Node Client, throws a SoloError if anything fails
200210
* @param namespace - the namespace of the network
201211
* @param skipNodeAlias - the node alias to skip
212+
* @param [clusterRefs]
213+
* @param [deployment]
214+
* @param [context]
202215
*/
203216
async refreshNodeClient(
204217
namespace: NamespaceName,
205218
skipNodeAlias?: NodeAlias,
206219
clusterRefs?: ClusterRefs,
207220
deployment?: DeploymentName,
221+
context?: Optional<string>,
208222
) {
209223
try {
210224
await this.close();
211-
const treasuryAccountInfo = await this.getTreasuryAccountKeys(namespace);
225+
226+
const treasuryAccountInfo = await this.getTreasuryAccountKeys(namespace, context);
212227
const networkNodeServicesMap = await this.getNodeServiceMap(namespace, clusterRefs, deployment);
213228

214229
this._nodeClient = await this._getNodeClient(
@@ -541,7 +556,7 @@ export class AccountManager {
541556
serviceBuilder.withHaProxyPodName(PodName.of(podList[0].metadata.name));
542557
}
543558

544-
for (const [clusterRef, context] of Object.entries(clusterRefs)) {
559+
for (const [_, context] of Object.entries(clusterRefs)) {
545560
// get the pod name of the network node
546561
const pods: V1Pod[] = await this.k8Factory
547562
.getK8(context)

src/core/helpers.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ import {type Optional} from '../types/index.js';
2121
import {type Version} from './config/remote/types.js';
2222
import {fileURLToPath} from 'url';
2323
import {type NamespaceName} from './kube/resources/namespace/namespace_name.js';
24-
import {type K8Factory} from './kube/k8_factory.js';
25-
import {type Context} from './config/remote/types.js';
2624

2725
export function getInternalIp(releaseVersion: semver.SemVer, namespaceName: NamespaceName, nodeAlias: NodeAlias) {
2826
//? Explanation: for v0.59.x the internal IP address is set to 127.0.0.1 to avoid an ISS

src/core/platform_installer.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ export class PlatformInstaller {
100100
const extractScript = path.join(constants.HEDERA_USER_HOME_DIR, scriptName); // inside the container
101101
const containerRef = ContainerRef.of(podRef, constants.ROOT_CONTAINER);
102102

103-
const k8Containers = context ? this.k8Factory.getK8(context).containers() : this.k8Factory.default().containers();
103+
const k8Containers = this.k8Factory.getK8(context).containers();
104104

105105
await k8Containers.readByRef(containerRef).execContainer(`chmod +x ${extractScript}`);
106106
await k8Containers.readByRef(containerRef).execContainer([extractScript, tag]);
@@ -139,9 +139,7 @@ export class PlatformInstaller {
139139
throw new SoloError(`file does not exist: ${srcPath}`);
140140
}
141141

142-
const k8Containers = context
143-
? this.k8Factory.getK8(context).containers()
144-
: this.k8Factory.default().containers();
142+
const k8Containers = this.k8Factory.getK8(context).containers();
145143

146144
if (!(await k8Containers.readByRef(containerRef).hasDir(destDir))) {
147145
await k8Containers.readByRef(containerRef).mkdir(destDir);
@@ -263,7 +261,7 @@ export class PlatformInstaller {
263261

264262
const recursiveFlag = recursive ? '-R' : '';
265263

266-
const k8Containers = context ? this.k8Factory.getK8(context).containers() : this.k8Factory.default().containers();
264+
const k8Containers = this.k8Factory.getK8(context).containers();
267265

268266
await k8Containers
269267
.readByRef(containerRef)

0 commit comments

Comments
 (0)