Skip to content

Commit 7035467

Browse files
committed
feat: introduce periodic logging healthcheck
This helps us to better understand the status of the snyk-monitor, for example, whether accessing the Sysdig integration is possible.
1 parent 902bed7 commit 7035467

File tree

3 files changed

+77
-8
lines changed

3 files changed

+77
-8
lines changed

src/data-scraper/index.ts

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,57 @@ import { IRuntimeImagesResponse } from '../transmitter/types';
77
import { NeedleOptions } from 'needle';
88
import { Agent as HttpsAgent } from 'https';
99

10+
const httpsAgent = new HttpsAgent({
11+
keepAlive: true,
12+
// We agreed with Sysdig to skip TLS certificates validation for HTTPS connection.
13+
rejectUnauthorized: false,
14+
});
15+
16+
function getSysdigUrl(): string {
17+
return config.SYSDIG_ENDPOINT + '/v1/runtimeimages';
18+
}
19+
20+
function getSysdigAuthHeader(): string {
21+
return `Bearer ${config.SYSDIG_TOKEN}`;
22+
}
23+
1024
function isSuccessStatusCode(statusCode: number | undefined): boolean {
1125
return statusCode !== undefined && statusCode >= 200 && statusCode < 300;
1226
}
1327

28+
/** NOTE: This function can throw, so the caller should handle errors. */
29+
export async function validateConnectivity(): Promise<void> {
30+
const url = getSysdigUrl();
31+
const header = getSysdigAuthHeader();
32+
const reqOptions: NeedleOptions = {
33+
agent: httpsAgent,
34+
headers: {
35+
authorization: header,
36+
},
37+
timeout: 10_000,
38+
};
39+
40+
const limit: number = 1;
41+
const cursor: string = '';
42+
const { response } = await retryRequest(
43+
'get',
44+
`${url}?limit=${limit}&cursor=${cursor}`,
45+
{},
46+
reqOptions,
47+
);
48+
if (!isSuccessStatusCode(response.statusCode)) {
49+
throw new Error(`${response.statusCode} ${response.statusMessage}`);
50+
}
51+
}
52+
1453
export async function scrapeData(): Promise<void> {
15-
const base: string = config.SYSDIG_ENDPOINT;
16-
const header: string = `Bearer ${config.SYSDIG_TOKEN}`;
54+
const url = getSysdigUrl();
55+
const header = getSysdigAuthHeader();
1756

18-
const url: string = base + '/v1/runtimeimages';
1957
// limit: min 1, max 500, default 250
2058
const limit: number = 10;
2159
const reqOptions: NeedleOptions = {
22-
agent: new HttpsAgent({
23-
keepAlive: true,
24-
// We agreed with Sysdig to skip TLS certificates validation for HTTPS connection.
25-
rejectUnauthorized: false,
26-
}),
60+
agent: httpsAgent,
2761
headers: {
2862
authorization: header,
2963
},

src/healthcheck.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { config } from './common/config';
2+
import { logger } from './common/logger';
3+
import { state } from './state';
4+
5+
import * as dataScraper from './data-scraper';
6+
7+
export async function setupHealthCheck(): Promise<void> {
8+
const interval = 1 * 60 * 1000; // 1 minute in milliseconds
9+
setInterval(healthCheck, interval).unref();
10+
}
11+
12+
async function healthCheck(): Promise<void> {
13+
const imagesAlreadyScanned = state.imagesAlreadyScanned.values().length;
14+
const workloadsAlreadyScanned = state.workloadsAlreadyScanned.values().length;
15+
logger.debug(
16+
{ imagesAlreadyScanned, workloadsAlreadyScanned },
17+
'cache size report',
18+
);
19+
20+
await sysdigHealthCheck();
21+
}
22+
23+
async function sysdigHealthCheck(): Promise<void> {
24+
if (!config.SYSDIG_ENDPOINT || !config.SYSDIG_TOKEN) {
25+
return;
26+
}
27+
28+
try {
29+
await dataScraper.validateConnectivity();
30+
} catch (error) {
31+
logger.error({ error }, 'could not connect to the Sysdig integration');
32+
}
33+
}

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { loadAndSendWorkloadEventsPolicy } from './common/policy';
1111
import { sendClusterMetadata } from './transmitter';
1212
import { setSnykMonitorAgentId } from './supervisor/agent';
1313
import { scrapeData } from './data-scraper';
14+
import { setupHealthCheck } from './healthcheck';
1415

1516
process.on('uncaughtException', (err) => {
1617
if (state.shutdownInProgress) {
@@ -86,4 +87,5 @@ setImmediate(async function setUpAndMonitor(): Promise<void> {
8687
await loadAndSendWorkloadEventsPolicy();
8788
await monitor();
8889
await setupSysdigIntegration();
90+
await setupHealthCheck();
8991
});

0 commit comments

Comments
 (0)