Skip to content

Commit a89d584

Browse files
committed
feat(infra): add CronJob secret refresh to RPC rotation
CronJobs (KeyFunder, Kathy) now get their secrets refreshed during RPC rotation, but without pod restart. They pick up new secrets on next run.
1 parent 34f61aa commit a89d584

1 file changed

Lines changed: 74 additions & 7 deletions

File tree

typescript/infra/src/utils/rpcUrls.ts

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { ethers } from 'ethers';
66
import { ChainName } from '@hyperlane-xyz/sdk';
77
import { ProtocolType, timeout } from '@hyperlane-xyz/utils';
88

9+
import { Contexts } from '../../config/contexts.js';
910
import { getChain } from '../../config/registry.js';
1011
import { getEnvironmentConfig } from '../../scripts/core-utils.js';
1112
import {
@@ -18,6 +19,8 @@ import {
1819
setSecretRpcEndpoints,
1920
} from '../agents/index.js';
2021
import { DeployEnvironment } from '../config/environment.js';
22+
import { KeyFunderHelmManager } from '../funding/key-funder.js';
23+
import { KathyHelmManager } from '../helloworld/kathy.js';
2124
import { WarpRouteMonitorHelmManager } from '../warp-monitor/helm.js';
2225

2326
import { disableGCPSecretVersion } from './gcloud.js';
@@ -270,7 +273,8 @@ async function updateSecretAndDisablePrevious(
270273

271274
/**
272275
* Interactively refreshes dependent k8s resources for the given chain in the given environment.
273-
* Prompts for core infrastructure and warp monitors separately, then executes all refreshes together.
276+
* Prompts for core infrastructure, warp monitors, and CronJobs separately, then executes refreshes.
277+
* CronJobs only get secret refresh (no pod restart) - they pick up new secrets on next run.
274278
* @param environment The environment to refresh resources in
275279
* @param chain The chain to refresh resources for
276280
*/
@@ -286,15 +290,29 @@ async function refreshDependentK8sResourcesInteractive(
286290
return;
287291
}
288292

289-
// Collect selections from both prompts
293+
// Collect selections from all prompts
290294
const coreManagers = await selectCoreInfrastructure(environment, chain);
291295
const warpManagers = await selectWarpMonitors(environment, chain);
296+
const cronjobManagers = await selectCronJobs(environment);
292297

293-
// Execute all refreshes together
294-
const allManagers = [...coreManagers, ...warpManagers];
295-
if (allManagers.length > 0) {
296-
await refreshK8sResources(allManagers, K8sResourceType.SECRET, environment);
297-
await refreshK8sResources(allManagers, K8sResourceType.POD, environment);
298+
// Services get both secret and pod refresh
299+
const serviceManagers = [...coreManagers, ...warpManagers];
300+
// CronJobs only get secret refresh (they pick up new secrets on next scheduled run)
301+
const allManagersForSecrets = [...serviceManagers, ...cronjobManagers];
302+
303+
if (allManagersForSecrets.length > 0) {
304+
await refreshK8sResources(
305+
allManagersForSecrets,
306+
K8sResourceType.SECRET,
307+
environment,
308+
);
309+
}
310+
if (serviceManagers.length > 0) {
311+
await refreshK8sResources(
312+
serviceManagers,
313+
K8sResourceType.POD,
314+
environment,
315+
);
298316
}
299317
}
300318

@@ -409,6 +427,55 @@ async function selectWarpMonitors(
409427
return warpMonitorManagers.filter((_, i) => selection.includes(i));
410428
}
411429

430+
async function selectCronJobs(
431+
environment: DeployEnvironment,
432+
): Promise<HelmManager<any>[]> {
433+
const cronjobManagers: [string, HelmManager<any>][] = [];
434+
435+
try {
436+
const keyFunder = KeyFunderHelmManager.forEnvironment(environment);
437+
cronjobManagers.push(['Key Funder', keyFunder]);
438+
} catch (e) {
439+
// Environment may not have key funder configured
440+
}
441+
442+
try {
443+
const kathy = KathyHelmManager.forEnvironment(
444+
environment,
445+
Contexts.Hyperlane,
446+
);
447+
cronjobManagers.push(['Kathy', kathy]);
448+
} catch (e) {
449+
// Environment may not have kathy configured
450+
}
451+
452+
if (cronjobManagers.length === 0) {
453+
console.log('No CronJobs to refresh');
454+
return [];
455+
}
456+
457+
console.log(
458+
`Found ${cronjobManagers.length} CronJobs (secrets only, no pod restart):`,
459+
);
460+
for (const [name, manager] of cronjobManagers) {
461+
console.log(` - ${manager.helmReleaseName} (${name})`);
462+
}
463+
464+
const selection = await checkbox({
465+
message:
466+
'Select CronJobs to refresh secrets (pods pick up changes on next run)',
467+
choices: cronjobManagers.map(([name, manager], i) => ({
468+
name: `${manager.helmReleaseName} (${name})`,
469+
value: i,
470+
checked: true,
471+
})),
472+
});
473+
474+
return cronjobManagers
475+
.map(([_, m]) => m)
476+
.filter((_, i) => selection.includes(i));
477+
}
478+
412479
/**
413480
* Test the provider at the given URL, returning false if the provider is unhealthy
414481
* or related to a different chain. No-op for non-Ethereum chains.

0 commit comments

Comments
 (0)