Skip to content
This repository was archived by the owner on Jan 16, 2025. It is now read-only.

Commit 985e722

Browse files
npalmGuptaNavdeep1983rootnavdeepg2021
authored
feat: Experimental feature - Duplicate workflow job event to extra queue (#2268)
feat: Experimental feature - Duplicate workflow job event to extra queue (#2268) * Update variables.tf * Update main.tf * feat: Changes to publish gh actions event to second queue for monitoring. * feat: Changes to publish gh actions event to second queue for monitoring. * feat: Changes to publish gh actions event to second queue for monitoring. * Update index.ts * feat: Changes to publish gh actions event to second queue for monitoring. * feat: reverted * Added test cases. * fixed test case name. * fix: formatting * Review comments * Review comments * fixed output. * feat: Few more changes. * Update README.md * Additional review comments. * fixed formatting. * prettified * Changed secondary queue config to a single object * declared the object type. * fixed style issues * fixed formatting * fixed linting errors * fix: fixed warnings. * Changed the name of the queue to workflow_job_queue. * fix: formatting. * fix:formatting. * Updated as per the comments. Co-authored-by: Niek Palm <[email protected]> * fix: review comments. * fix: comments * fix: formatting * fix: addressed review comments. * fix: reverted. * fix: formatting. * fix: updated tests. * Update README.md Co-authored-by: Niek Palm <[email protected]> * Update README.md Co-authored-by: Niek Palm <[email protected]> * Update README.md Co-authored-by: Niek Palm <[email protected]> * Update README.md Co-authored-by: Niek Palm <[email protected]> * fix: addressed review comments. * Update variables.tf Co-authored-by: Niek Palm <[email protected]> * Update main.tf Co-authored-by: Niek Palm <[email protected]> * fix: formatting. * fix: cross reference. * fix: formatting. Co-authored-by: Niek Palm <[email protected]> Co-authored-by: root <[email protected]> Co-authored-by: navdeepg2021 <[email protected]> Co-authored-by: GuptaNavdeep1983 <[email protected]> Co-authored-by: root <[email protected]> Co-authored-by: navdeepg2021 <[email protected]>
1 parent ffc2e38 commit 985e722

File tree

15 files changed

+180
-17
lines changed

15 files changed

+180
-17
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
* Update ubuntu example to fix /opt/hostedtoolcache ([#2302](https://github.com/philips-labs/terraform-aws-github-runner/issues/2302)) ([8eea748](https://github.com/philips-labs/terraform-aws-github-runner/commit/8eea74817a9817ca386b77f1b90ae9ef721e250e))
100100
* Webhook lambda misleading log ([#2291](https://github.com/philips-labs/terraform-aws-github-runner/issues/2291)) ([c6275f9](https://github.com/philips-labs/terraform-aws-github-runner/commit/c6275f9d5a68c962e32596e4abf77b1fda6dd18f))
101101

102+
102103
## [1.5.0](https://github.com/philips-labs/terraform-aws-github-runner/compare/v1.4.1...v1.5.0) (2022-07-08)
103104

104105

README.md

+18-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ This [Terraform](https://www.terraform.io/) module creates the required infrastr
2222
- [Idle runners](#idle-runners)
2323
- [Ephemeral runners](#ephemeral-runners)
2424
- [Prebuilt Images](#prebuilt-images)
25+
- [Experimental - Optional queue to publish GitHub workflow job events](#experimental---optional-queue-to-publish-github-workflow-job-events)
2526
- [Examples](#examples)
2627
- [Sub modules](#sub-modules)
2728
- [ARM64 configuration for submodules](#arm64-configuration-for-submodules)
@@ -310,7 +311,23 @@ The example for [ephemeral runners](./examples/ephemeral) is based on the [defau
310311

311312
### Prebuilt Images
312313

313-
This module also allows you to run agents from a prebuilt AMI to gain faster startup times. You can find more information in [the image README.md](/images/README.md). When the GitHub runner is part of the AMI you can disable the binary syncer by setting `enable_runner_binaries_syncer = false`.
314+
This module also allows you to run agents from a prebuilt AMI to gain faster startup times. You can find more information in [the image README.md](/images/README.md)
315+
316+
### Experimental - Optional queue to publish GitHub workflow job events
317+
318+
This queue is an experimental feature to allow you to receive a copy of the wokflow_jobs events sent by the GItHub App. For example to calculate matrix or monitor the system.
319+
320+
To enable the feature set `enable_workflow_job_events_queue = true`. Be-aware the feature in experimental!
321+
322+
Messages received on the queue are using the same format as published by GitHub wrapped in a property `workflowJobEvent`.
323+
324+
```
325+
export interface GithubWorkflowEvent {
326+
workflowJobEvent: WorkflowJobEvent;
327+
}
328+
```
329+
This extendible format allows to add more fields to be added if needed.
330+
You can configure the queue by setting properties to `workflow_job_events_queue_config`
314331

315332
## Examples
316333

examples/arm64/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,4 @@ You can receive the webhook details by running:
2828
terraform output -raw webhook_secret
2929
```
3030

31-
Be-aware some shells will print some end of line character `%`.
31+
Be-aware some shells will print some end of line character `%`.

examples/default/main.tf

+2
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,6 @@ module "runners" {
8383

8484
# override scaling down
8585
scale_down_schedule_expression = "cron(* * * * ? *)"
86+
# enable this flag to publish webhook events to workflow job queue
87+
# enable_workflow_job_events_queue = true
8688
}

main.tf

+29-5
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ resource "aws_sqs_queue_policy" "build_queue_policy" {
4949
policy = data.aws_iam_policy_document.deny_unsecure_transport.json
5050
}
5151

52+
resource "aws_sqs_queue_policy" "webhook_events_workflow_job_queue_policy" {
53+
count = var.enable_workflow_job_events_queue ? 1 : 0
54+
queue_url = aws_sqs_queue.webhook_events_workflow_job_queue[0].id
55+
policy = data.aws_iam_policy_document.deny_unsecure_transport.json
56+
}
57+
5258
resource "aws_sqs_queue" "queued_builds" {
5359
name = "${var.prefix}-queued-builds${var.fifo_build_queue ? ".fifo" : ""}"
5460
delay_seconds = var.delay_webhook_event
@@ -69,6 +75,24 @@ resource "aws_sqs_queue" "queued_builds" {
6975
tags = var.tags
7076
}
7177

78+
resource "aws_sqs_queue" "webhook_events_workflow_job_queue" {
79+
count = var.enable_workflow_job_events_queue ? 1 : 0
80+
name = "${var.prefix}-webhook_events_workflow_job_queue"
81+
delay_seconds = var.workflow_job_queue_configuration.delay_seconds
82+
visibility_timeout_seconds = var.workflow_job_queue_configuration.visibility_timeout_seconds
83+
message_retention_seconds = var.workflow_job_queue_configuration.message_retention_seconds
84+
fifo_queue = false
85+
receive_wait_time_seconds = 0
86+
content_based_deduplication = false
87+
redrive_policy = null
88+
89+
sqs_managed_sse_enabled = var.queue_encryption.sqs_managed_sse_enabled
90+
kms_master_key_id = var.queue_encryption.kms_master_key_id
91+
kms_data_key_reuse_period_seconds = var.queue_encryption.kms_data_key_reuse_period_seconds
92+
93+
tags = var.tags
94+
}
95+
7296
resource "aws_sqs_queue_policy" "build_queue_dlq_policy" {
7397
count = var.redrive_build_queue.enabled ? 1 : 0
7498
queue_url = aws_sqs_queue.queued_builds.id
@@ -98,13 +122,13 @@ module "ssm" {
98122
module "webhook" {
99123
source = "./modules/webhook"
100124

101-
aws_region = var.aws_region
102-
prefix = var.prefix
103-
tags = local.tags
104-
kms_key_arn = var.kms_key_arn
105-
125+
aws_region = var.aws_region
126+
prefix = var.prefix
127+
tags = local.tags
128+
kms_key_arn = var.kms_key_arn
106129
sqs_build_queue = aws_sqs_queue.queued_builds
107130
sqs_build_queue_fifo = var.fifo_build_queue
131+
sqs_workflow_job_queue = length(aws_sqs_queue.webhook_events_workflow_job_queue) > 0 ? aws_sqs_queue.webhook_events_workflow_job_queue[0] : null
108132
github_app_webhook_secret_arn = module.ssm.parameters.github_app_webhook_secret.arn
109133

110134
lambda_s3_bucket = var.lambda_s3_bucket

modules/runners/variables.tf

-1
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,6 @@ variable "lambda_architecture" {
565565
error_message = "`lambda_architecture` value is not valid, valid values are: `arm64` and `x86_64`."
566566
}
567567
}
568-
569568
variable "enable_runner_binaries_syncer" {
570569
description = "Option to disable the lambda to sync GitHub runner distribution, useful when using a pre-build AMI."
571570
type = bool

modules/webhook/lambdas/webhook/src/lambda.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { APIGatewayEvent, Callback, Context } from 'aws-lambda';
1+
import { APIGatewayEvent, Context } from 'aws-lambda';
22

33
import { handle } from './webhook/handler';
44
import { logger } from './webhook/logger';

modules/webhook/lambdas/webhook/src/sqs/index.test.ts

+37-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { SQS } from 'aws-sdk';
22

3-
import { ActionRequestMessage, sendActionRequest } from '.';
3+
import { ActionRequestMessage, GithubWorkflowEvent, sendActionRequest, sendWebhookEventToWorkflowJobQueue } from '.';
4+
import workflowjob_event from '../../test/resources/github_workflowjob_event.json';
45

56
const mockSQS = {
67
sendMessage: jest.fn(() => {
@@ -25,7 +26,9 @@ describe('Test sending message to SQS.', () => {
2526
QueueUrl: 'https://sqs.eu-west-1.amazonaws.com/123456789/queued-builds',
2627
MessageBody: JSON.stringify(message),
2728
};
28-
29+
afterEach(() => {
30+
jest.clearAllMocks();
31+
});
2932
it('no fifo queue, based on defaults', async () => {
3033
// Arrange
3134
process.env.SQS_URL_WEBHOOK = sqsMessage.QueueUrl;
@@ -64,3 +67,35 @@ describe('Test sending message to SQS.', () => {
6467
expect(result).resolves;
6568
});
6669
});
70+
describe('Test sending message to SQS.', () => {
71+
const message: GithubWorkflowEvent = {
72+
workflowJobEvent: JSON.parse(JSON.stringify(workflowjob_event)),
73+
};
74+
const sqsMessage: SQS.Types.SendMessageRequest = {
75+
QueueUrl: 'https://sqs.eu-west-1.amazonaws.com/123456789/webhook_events_workflow_job_queue',
76+
MessageBody: JSON.stringify(message),
77+
};
78+
afterEach(() => {
79+
jest.clearAllMocks();
80+
});
81+
it('sends webhook events to workflow job queue', async () => {
82+
// Arrange
83+
process.env.SQS_WORKFLOW_JOB_QUEUE = sqsMessage.QueueUrl;
84+
85+
// Act
86+
const result = await sendWebhookEventToWorkflowJobQueue(message);
87+
88+
// Assert
89+
expect(mockSQS.sendMessage).toBeCalledWith(sqsMessage);
90+
expect(result).resolves;
91+
});
92+
it('Does not send webhook events to workflow job event copy queue', async () => {
93+
// Arrange
94+
process.env.SQS_WORKFLOW_JOB_QUEUE = '';
95+
// Act
96+
await sendWebhookEventToWorkflowJobQueue(message);
97+
98+
// Assert
99+
expect(mockSQS.sendMessage).not.toBeCalledWith(sqsMessage);
100+
});
101+
});

modules/webhook/lambdas/webhook/src/sqs/index.ts

+25
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { WorkflowJobEvent } from '@octokit/webhooks-types';
12
import { SQS } from 'aws-sdk';
23

34
import { LogFields, logger } from '../webhook/logger';
@@ -9,6 +10,9 @@ export interface ActionRequestMessage {
910
repositoryOwner: string;
1011
installationId: number;
1112
}
13+
export interface GithubWorkflowEvent {
14+
workflowJobEvent: WorkflowJobEvent;
15+
}
1216

1317
export const sendActionRequest = async (message: ActionRequestMessage): Promise<void> => {
1418
const sqs = new SQS({ region: process.env.AWS_REGION });
@@ -28,3 +32,24 @@ export const sendActionRequest = async (message: ActionRequestMessage): Promise<
2832

2933
await sqs.sendMessage(sqsMessage).promise();
3034
};
35+
36+
export const sendWebhookEventToWorkflowJobQueue = async (message: GithubWorkflowEvent): Promise<void> => {
37+
const webhook_events_workflow_job_queue = process.env.SQS_WORKFLOW_JOB_QUEUE || undefined;
38+
39+
if (webhook_events_workflow_job_queue != undefined) {
40+
const sqs = new SQS({ region: process.env.AWS_REGION });
41+
const sqsMessage: SQS.Types.SendMessageRequest = {
42+
QueueUrl: String(process.env.SQS_WORKFLOW_JOB_QUEUE),
43+
MessageBody: JSON.stringify(message),
44+
};
45+
logger.debug(
46+
`Sending Webhook events to the workflow job queue: ${webhook_events_workflow_job_queue}`,
47+
LogFields.print(),
48+
);
49+
try {
50+
await sqs.sendMessage(sqsMessage).promise();
51+
} catch (e) {
52+
logger.warn(`Error in sending webhook events to workflow job queue: ${(e as Error).message}`, LogFields.print());
53+
}
54+
}
55+
};

modules/webhook/lambdas/webhook/src/webhook/handler.test.ts

+17-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import nock from 'nock';
44

55
import checkrun_event from '../../test/resources/github_check_run_event.json';
66
import workflowjob_event from '../../test/resources/github_workflowjob_event.json';
7-
import { sendActionRequest } from '../sqs';
7+
import { sendActionRequest, sendWebhookEventToWorkflowJobQueue } from '../sqs';
88
import { getParameterValue } from '../ssm';
99
import { handle } from './handler';
1010

@@ -309,4 +309,20 @@ describe('handler', () => {
309309
expect(sendActionRequest).toBeCalled();
310310
});
311311
});
312+
313+
describe('Test for webhook events to be sent to workflow job queue: ', () => {
314+
beforeEach(() => {
315+
process.env.SQS_WORKFLOW_JOB_QUEUE =
316+
'https://sqs.eu-west-1.amazonaws.com/123456789/webhook_events_workflow_job_queue';
317+
});
318+
it('sends webhook events to workflow job queue', async () => {
319+
const event = JSON.stringify(workflowjob_event);
320+
const resp = await handle(
321+
{ 'X-Hub-Signature': await webhooks.sign(event), 'X-GitHub-Event': 'workflow_job' },
322+
event,
323+
);
324+
expect(resp.statusCode).toBe(201);
325+
expect(sendWebhookEventToWorkflowJobQueue).toBeCalled();
326+
});
327+
});
312328
});

modules/webhook/lambdas/webhook/src/webhook/handler.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { CheckRunEvent, WorkflowJobEvent } from '@octokit/webhooks-types';
33
import { IncomingHttpHeaders } from 'http';
44

55
import { Response } from '../lambda';
6-
import { sendActionRequest } from '../sqs';
6+
import { sendActionRequest, sendWebhookEventToWorkflowJobQueue } from '../sqs';
77
import { getParameterValue } from '../ssm';
88
import { LogFields, logger as rootLogger } from './logger';
99

@@ -63,19 +63,26 @@ export async function handle(headers: IncomingHttpHeaders, body: string): Promis
6363
logger.info(`Processing Github event`, LogFields.print());
6464

6565
if (githubEvent == 'workflow_job') {
66+
const workflowEventPayload = payload as WorkflowJobEvent;
6667
response = await handleWorkflowJob(
67-
payload as WorkflowJobEvent,
68+
workflowEventPayload,
6869
githubEvent,
6970
enableWorkflowLabelCheck,
7071
workflowLabelCheckAll,
7172
runnerLabels,
7273
);
74+
await sendWorkflowJobEvents(githubEvent, workflowEventPayload);
7375
} else if (githubEvent == 'check_run') {
7476
response = await handleCheckRun(payload as CheckRunEvent, githubEvent);
7577
}
7678

7779
return response;
7880
}
81+
async function sendWorkflowJobEvents(githubEvent: string, workflowEventPayload: WorkflowJobEvent) {
82+
await sendWebhookEventToWorkflowJobQueue({
83+
workflowJobEvent: workflowEventPayload,
84+
});
85+
}
7986

8087
function readEnvironmentVariables() {
8188
const environment = process.env.ENVIRONMENT;

modules/webhook/variables.tf

+8-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,14 @@ variable "sqs_build_queue" {
3737
arn = string
3838
})
3939
}
40-
40+
variable "sqs_workflow_job_queue" {
41+
description = "SQS queue to monitor github events."
42+
type = object({
43+
id = string
44+
arn = string
45+
})
46+
default = null
47+
}
4148
variable "lambda_zip" {
4249
description = "File location of the lambda zip file."
4350
type = string

modules/webhook/webhook.tf

+10
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ resource "aws_lambda_function" "webhook" {
2222
RUNNER_LABELS = jsonencode(split(",", lower(var.runner_labels)))
2323
SQS_URL_WEBHOOK = var.sqs_build_queue.id
2424
SQS_IS_FIFO = var.sqs_build_queue_fifo
25+
SQS_WORKFLOW_JOB_QUEUE = try(var.sqs_workflow_job_queue, null) != null ? var.sqs_workflow_job_queue.id : ""
2526
}
2627
}
2728

@@ -78,6 +79,15 @@ resource "aws_iam_role_policy" "webhook_sqs" {
7879
sqs_resource_arn = var.sqs_build_queue.arn
7980
})
8081
}
82+
resource "aws_iam_role_policy" "webhook_workflow_job_sqs" {
83+
count = var.sqs_workflow_job_queue != null ? 1 : 0
84+
name = "${var.prefix}-lambda-webhook-publish-workflow-job-sqs-policy"
85+
role = aws_iam_role.webhook_lambda.name
86+
87+
policy = templatefile("${path.module}/policies/lambda-publish-sqs-policy.json", {
88+
sqs_resource_arn = var.sqs_workflow_job_queue.arn
89+
})
90+
}
8191

8292
resource "aws_iam_role_policy" "webhook_ssm" {
8393
name = "${var.prefix}-lambda-webhook-publish-ssm-policy"

outputs.tf

+3-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ output "ssm_parameters" {
3939
output "queues" {
4040
description = "SQS queues."
4141
value = {
42-
build_queue_arn = aws_sqs_queue.queued_builds.arn
43-
build_queue_dlq_arn = var.redrive_build_queue.enabled ? aws_sqs_queue.queued_builds_dlq[0].arn : null
42+
build_queue_arn = aws_sqs_queue.queued_builds.arn
43+
build_queue_dlq_arn = var.redrive_build_queue.enabled ? aws_sqs_queue.queued_builds_dlq[0].arn : null
44+
webhook_workflow_job_queue = try(aws_sqs_queue.webhook_events_workflow_job_queue[0], null) != null ? aws_sqs_queue.webhook_events_workflow_job_queue[0].arn : ""
4445
}
4546
}

variables.tf

+19
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,25 @@ variable "lambda_architecture" {
702702
}
703703
}
704704

705+
variable "enable_workflow_job_events_queue" {
706+
description = "Enabling this experimental feature will create a secondory sqs queue to wich a copy of the workflow_job event will be delivered."
707+
type = bool
708+
default = false
709+
}
710+
711+
variable "workflow_job_queue_configuration" {
712+
description = "Configuration options for workflow job queue which is only applicable if the flag enable_workflow_job_events_queue is set to true."
713+
type = object({
714+
delay_seconds = number
715+
visibility_timeout_seconds = number
716+
message_retention_seconds = number
717+
})
718+
default = {
719+
"delay_seconds" : null,
720+
"visibility_timeout_seconds" : null,
721+
"message_retention_seconds" : null
722+
}
723+
}
705724
variable "enable_runner_binaries_syncer" {
706725
description = "Option to disable the lambda to sync GitHub runner distribution, useful when using a pre-build AMI."
707726
type = bool

0 commit comments

Comments
 (0)