Skip to content

Commit 01a0a18

Browse files
authoredFeb 18, 2025··
Added check to events-to-s3 for label canary (#40)
Signed-off-by: Brandon Shien <bshien@amazon.com>
1 parent 3b1ecd9 commit 01a0a18

File tree

5 files changed

+218
-3
lines changed

5 files changed

+218
-3
lines changed
 

‎configs/operations/github-events-to-s3.yml

+7
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,12 @@ events:
55
- all
66

77
tasks:
8+
- name: Github Label Canary Monitor
9+
call: github-label-canary-monitor@default
10+
args:
11+
nameSpace: GitHubLabelCanary
12+
metricName: AutomationApp_EventDataLake
13+
value: '1'
14+
unit: Count
815
- name: Github Events To S3 Operation
916
call: github-events-to-s3@default

‎package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "opensearch-automation-app",
3-
"version": "0.3.5",
3+
"version": "0.3.6",
44
"description": "An Automation App that handles all your GitHub Repository Activities",
55
"author": "Peter Zhu",
66
"homepage": "https://github.com/opensearch-project/automation-app",
+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* The OpenSearch Contributors require contributions made to
6+
* this file be licensed under the Apache-2.0 license or a
7+
* compatible open source license.
8+
*/
9+
10+
// Name : githubLabelCanaryMonitor
11+
// Description : Handle canary event by sending CloudWatch Metrics for monitoring purposes
12+
// Arguments :
13+
// - nameSpace: (string) The namespace of the CloudWatch Metric you want to send data to.
14+
// - metricName: (string) The metric name of the CloudWatch Metric you want to send data to.
15+
// - value: (string) The value of the CloudWatch Metric you want to send.
16+
// - unit: (string) The unit of the CloudWatch Metric you want to send.
17+
18+
import { Probot } from 'probot';
19+
import { CloudWatchClient, PutMetricDataCommand, StandardUnit } from '@aws-sdk/client-cloudwatch';
20+
import { Resource } from '../service/resource/resource';
21+
22+
export interface LabelCanaryMonitorParams {
23+
nameSpace: string;
24+
metricName: string;
25+
value: string;
26+
unit: string;
27+
}
28+
29+
export default async function githubLabelCanaryMonitor(
30+
app: Probot,
31+
context: any,
32+
resource: Resource,
33+
{ nameSpace, metricName, value, unit }: LabelCanaryMonitorParams,
34+
): Promise<void> {
35+
// Removed validateResourceConfig to let this function listen on all repos, and filter for only the repos that are public.
36+
// This is done so when a new repo is made public, this app can automatically start processing its events.
37+
//
38+
// This is only for the s3 data lake specific case, everything else should still specify repos required to be listened in resource config.
39+
//
40+
// if (!(await validateResourceConfig(app, context, resource))) return;
41+
//
42+
const repoName = context.payload.repository?.name;
43+
if (context.payload.repository?.private === false) {
44+
// Handle canary event for monitoring purposes
45+
if (repoName === 'opensearch-metrics' && context.name === 'label' && context.payload.label?.name === 's3-data-lake-app-canary-label') {
46+
// Ignore if label was created
47+
if (context.payload.action === 'deleted') {
48+
try {
49+
const cloudWatchClient = new CloudWatchClient({ region: String(process.env.REGION) });
50+
const putMetricDataCommand = new PutMetricDataCommand({
51+
Namespace: nameSpace,
52+
MetricData: [
53+
{
54+
MetricName: metricName,
55+
Value: Number(value),
56+
Unit: unit as StandardUnit,
57+
},
58+
],
59+
});
60+
await cloudWatchClient.send(putMetricDataCommand);
61+
app.log.info('CloudWatch metric for monitoring published.');
62+
} catch (error) {
63+
app.log.error(`Error Publishing CloudWatch metric for monitoring : ${error}`);
64+
}
65+
}
66+
return; // In the future, add `exit` right here to prevent subsequent tasks from running
67+
}
68+
}
69+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* The OpenSearch Contributors require contributions made to
6+
* this file be licensed under the Apache-2.0 license or a
7+
* compatible open source license.
8+
*/
9+
10+
import { Logger, Probot } from 'probot';
11+
import githubLabelCanaryMonitor, { LabelCanaryMonitorParams } from '../../src/call/github-label-canary-monitor';
12+
import { CloudWatchClient, PutMetricDataCommand } from '@aws-sdk/client-cloudwatch';
13+
14+
jest.mock('@aws-sdk/client-cloudwatch');
15+
16+
describe('githubEventsToS3', () => {
17+
let app: Probot;
18+
let context: any;
19+
let resource: any;
20+
let mockCloudWatchClient: any;
21+
let args: LabelCanaryMonitorParams;
22+
23+
beforeEach(() => {
24+
args = {
25+
nameSpace: 'testNameSpace',
26+
metricName: 'testMetric',
27+
value: '1',
28+
unit: 'Count',
29+
};
30+
31+
app = new Probot({ appId: 1, secret: 'test', privateKey: 'test' });
32+
app.log = {
33+
info: jest.fn(),
34+
error: jest.fn(),
35+
} as unknown as Logger;
36+
37+
context = {
38+
name: 'name',
39+
id: 'id',
40+
payload: {
41+
repository: {
42+
name: 'repo',
43+
owner: { login: 'org' },
44+
private: false,
45+
},
46+
},
47+
};
48+
49+
resource = {
50+
organizations: new Map([
51+
[
52+
'org',
53+
{
54+
repositories: new Map([['repo', 'repo object']]),
55+
},
56+
],
57+
]),
58+
};
59+
60+
mockCloudWatchClient = {
61+
send: jest.fn(),
62+
};
63+
(CloudWatchClient as jest.Mock).mockImplementation(() => mockCloudWatchClient);
64+
});
65+
66+
afterEach(() => {
67+
jest.clearAllMocks();
68+
});
69+
70+
it('should publish CloudWatch metric if event is label canary', async () => {
71+
context = {
72+
name: 'label',
73+
id: 'id',
74+
payload: {
75+
action: 'deleted',
76+
label: {
77+
name: 's3-data-lake-app-canary-label',
78+
},
79+
repository: {
80+
name: 'opensearch-metrics',
81+
private: false,
82+
},
83+
},
84+
};
85+
86+
mockCloudWatchClient.send.mockResolvedValue({});
87+
88+
await githubLabelCanaryMonitor(app, context, resource, args);
89+
90+
expect(mockCloudWatchClient.send).toHaveBeenCalledWith(expect.any(PutMetricDataCommand));
91+
expect(app.log.info).toHaveBeenCalledWith('CloudWatch metric for monitoring published.');
92+
});
93+
94+
it('should not publish CloudWatch metric if event is not label canary', async () => {
95+
context = {
96+
name: 'label',
97+
id: 'id',
98+
payload: {
99+
label: {
100+
name: 'normal-label',
101+
},
102+
repository: {
103+
name: 'opensearch-metrics',
104+
private: false,
105+
},
106+
},
107+
};
108+
109+
mockCloudWatchClient.send.mockResolvedValue({});
110+
111+
await githubLabelCanaryMonitor(app, context, resource, args);
112+
113+
expect(mockCloudWatchClient.send).not.toHaveBeenCalledWith(expect.any(PutMetricDataCommand));
114+
expect(app.log.info).not.toHaveBeenCalledWith('CloudWatch metric for monitoring published.');
115+
});
116+
117+
it('should log an error if CloudWatch metric publishing fails', async () => {
118+
context = {
119+
name: 'label',
120+
id: 'id',
121+
payload: {
122+
action: 'deleted',
123+
label: {
124+
name: 's3-data-lake-app-canary-label',
125+
},
126+
repository: {
127+
name: 'opensearch-metrics',
128+
private: false,
129+
},
130+
},
131+
};
132+
133+
mockCloudWatchClient.send.mockRejectedValue(new Error('CloudWatch error'));
134+
135+
await githubLabelCanaryMonitor(app, context, resource, args);
136+
137+
expect(app.log.error).toHaveBeenCalledWith('Error Publishing CloudWatch metric for monitoring : Error: CloudWatch error');
138+
});
139+
});

0 commit comments

Comments
 (0)
Please sign in to comment.