Skip to content

Commit

Permalink
feat(infra): Add script to check warp route pod status (#5335)
Browse files Browse the repository at this point in the history
### Description

<!--
What's included in this PR?
-->

- Add script to check warp route monitor status by getting the pod using
a given `warpRouteId`
- The script will also return logs equal to the amount determined by the
`LOG_AMOUNT` constant
- Logs a link to the grafana dashboard with the given `warpRouteId` 
- Updated `withWarpRouteId` function to enforce choices for
`WarpRouteIds`

### Drive-by changes

<!--
Are there any minor or drive-by changes also included?
-->
No

### Related issues

<!--
- Fixes #[issue number here]
-->
fixes #5247 

### Backward compatibility

<!--
Are these changes backward compatible? Are there any infrastructure
implications, e.g. changes that would prohibit deploying older commits
using this infra tooling?

Yes/No
-->

Yes
### Testing

<!--
What kind of testing have these changes undergone?

None/Manual/Unit Tests
-->
Manual


![image](https://github.com/user-attachments/assets/5de7c2ff-29d7-40c0-a442-c895577076e7)
  • Loading branch information
Xaroz authored Jan 30, 2025
1 parent 57d22cf commit d2ba3de
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 1 deletion.
5 changes: 4 additions & 1 deletion typescript/infra/scripts/agent-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,10 @@ export function withOutputFile<T>(args: Argv<T>) {
}

export function withWarpRouteId<T>(args: Argv<T>) {
return args.describe('warpRouteId', 'warp route id').string('warpRouteId');
return args
.describe('warpRouteId', 'warp route id')
.string('warpRouteId')
.choices('warpRouteId', Object.values(WarpRouteIds));
}

export function withWarpRouteIdRequired<T>(args: Argv<T>) {
Expand Down
106 changes: 106 additions & 0 deletions typescript/infra/scripts/warp-routes/monitor/status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import chalk from 'chalk';

import {
LogFormat,
LogLevel,
configureRootLogger,
rootLogger,
} from '@hyperlane-xyz/utils';

import { HelmManager } from '../../../src/utils/helm.js';
import { WarpRouteMonitorHelmManager } from '../../../src/warp/helm.js';
import {
assertCorrectKubeContext,
getArgs,
withWarpRouteIdRequired,
} from '../../agent-utils.js';
import { getEnvironmentConfig } from '../../core-utils.js';

const orange = chalk.hex('#FFA500');
const GRAFANA_LINK =
'https://abacusworks.grafana.net/d/ddz6ma94rnzswc/warp-routes?orgId=1&var-warp_route_id=';
const LOG_AMOUNT = 5;

async function main() {
configureRootLogger(LogFormat.Pretty, LogLevel.Info);
const { environment, warpRouteId } = await withWarpRouteIdRequired(
getArgs(),
).parse();

const config = getEnvironmentConfig(environment);
await assertCorrectKubeContext(config);

try {
const podWarpRouteId = `${WarpRouteMonitorHelmManager.getHelmReleaseName(
warpRouteId,
)}-0`;

rootLogger.info(chalk.grey.italic(`Fetching pod status...`));
const pod = HelmManager.runK8sCommand(
'get pod',
podWarpRouteId,
environment,
);
rootLogger.info(chalk.green(pod));

rootLogger.info(chalk.gray.italic(`Fetching latest logs...`));
const latestLogs = HelmManager.runK8sCommand(
'logs',
podWarpRouteId,
environment,
[`--tail=${LOG_AMOUNT}`],
);
formatAndPrintLogs(latestLogs);

rootLogger.info(
orange.bold(`Grafana Dashboard Link: ${GRAFANA_LINK}${warpRouteId}`),
);
} catch (error) {
rootLogger.error(error);
process.exit(1);
}
}

function formatAndPrintLogs(rawLogs: string) {
try {
const logs = rawLogs
.trim()
.split('\n')
.map((line) => JSON.parse(line));
logs.forEach((log) => {
const { time, module, msg, labels, balance, valueUSD } = log;
const timestamp = new Date(time).toISOString();
const chain = labels?.chain_name || 'Unknown Chain';
const token = labels?.token_name || 'Unknown Token';
const warpRoute = labels?.warp_route_id || 'Unknown Warp Route';
const tokenStandard = labels?.token_standard || 'Unknown Standard';
const tokenAddress = labels?.token_address || 'Unknown Token Address';
const walletAddress = labels?.wallet_address || 'Unknown Wallet';

let logMessage =
chalk.gray(`[${timestamp}] `) + chalk.white(`[${module}] `);
logMessage += chalk.blue(`${warpRoute} `);
logMessage += chalk.green(`${chain} `);
logMessage += chalk.blue.italic(`Token: ${token} (${tokenAddress}) `);
logMessage += chalk.green.italic(`${tokenStandard} `);
logMessage += chalk.blue.italic(`Wallet: ${walletAddress} `);

if (balance) {
logMessage += chalk.yellow.italic(`Balance: ${balance} `);
}
if (valueUSD) {
logMessage += chalk.green.italic(`Value (USD): ${valueUSD} `);
}
logMessage += chalk.white(`→ ${msg}\n`);

rootLogger.info(logMessage);
});
} catch (error) {
rootLogger.error(`Failed to parse logs: ${error}`);
}
}

main().catch((err) => {
rootLogger.error('Error in main:', err);
process.exit(1);
});
17 changes: 17 additions & 0 deletions typescript/infra/src/utils/helm.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { execSync } from 'child_process';

import { DockerConfig } from '../config/agent/agent.js';
import {
HelmChartConfig,
Expand Down Expand Up @@ -211,4 +213,19 @@ export abstract class HelmManager<T = HelmValues> {
// Split on new lines and remove empty strings
return output.split('\n').filter(Boolean);
}

static runK8sCommand(
command: string,
podId: string,
namespace: string,
args: string[] = [],
) {
const argsString = args.join(' ');
return execSync(
`kubectl ${command} ${podId} -n ${namespace} ${argsString}`,
{
encoding: 'utf-8',
},
);
}
}

0 comments on commit d2ba3de

Please sign in to comment.