Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Experimental feature - Duplicate workflow job event to extra queue #2268

Merged
merged 53 commits into from
Oct 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
6e73dce
Update variables.tf
GuptaNavdeep1983 Jul 14, 2022
e4ba04d
Update main.tf
GuptaNavdeep1983 Jul 20, 2022
34c37c0
feat: Changes to publish gh actions event to second queue for monito…
GuptaNavdeep1983 Jul 20, 2022
a77e4ce
feat: Changes to publish gh actions event to second queue for monitor…
GuptaNavdeep1983 Jul 20, 2022
4aaf416
feat: Changes to publish gh actions event to second queue for monito…
GuptaNavdeep1983 Jul 20, 2022
86d40aa
Update index.ts
GuptaNavdeep1983 Jul 20, 2022
16c9d15
feat: Changes to publish gh actions event to second queue for monitor…
GuptaNavdeep1983 Jul 20, 2022
ecdc2b1
feat: reverted
GuptaNavdeep1983 Jul 20, 2022
054fdab
Added test cases.
GuptaNavdeep1983 Jul 20, 2022
3625127
fixed test case name.
GuptaNavdeep1983 Jul 20, 2022
a844894
fix: formatting
GuptaNavdeep1983 Jul 20, 2022
091e2aa
Review comments
GuptaNavdeep1983 Jul 20, 2022
cdceda3
Review comments
GuptaNavdeep1983 Jul 20, 2022
174efbd
fixed output.
GuptaNavdeep1983 Jul 20, 2022
813706f
feat: Few more changes.
GuptaNavdeep1983 Jul 20, 2022
97669e4
Update README.md
GuptaNavdeep1983 Jul 22, 2022
930bba1
Additional review comments.
GuptaNavdeep1983 Jul 22, 2022
6379245
Merge branch 'features/monitoring' of https://github.com/GuptaNavdeep…
GuptaNavdeep1983 Jul 22, 2022
8182874
fixed formatting.
GuptaNavdeep1983 Jul 22, 2022
818dd6f
prettified
GuptaNavdeep1983 Jul 22, 2022
d6c9c0f
Changed secondary queue config to a single object
GuptaNavdeep1983 Jul 22, 2022
26316f0
declared the object type.
GuptaNavdeep1983 Jul 22, 2022
ea50c90
fixed style issues
GuptaNavdeep1983 Jul 25, 2022
d5a51bf
fixed formatting
GuptaNavdeep1983 Jul 25, 2022
48469b9
fixed linting errors
GuptaNavdeep1983 Jul 25, 2022
56032d5
fix: fixed warnings.
GuptaNavdeep1983 Jul 25, 2022
5ab532e
Changed the name of the queue to workflow_job_queue.
GuptaNavdeep1983 Aug 12, 2022
6a01177
fix: formatting.
GuptaNavdeep1983 Aug 12, 2022
9ca014f
Merge branch 'develop' into features/monitoring
GuptaNavdeep1983 Aug 12, 2022
4008358
fix:formatting.
GuptaNavdeep1983 Aug 12, 2022
7627756
Merge branch 'features/monitoring' of https://github.com/GuptaNavdeep…
GuptaNavdeep1983 Aug 12, 2022
c3f2cdf
Updated as per the comments.
GuptaNavdeep1983 Aug 15, 2022
5cf5957
Merge branch 'develop' into features/monitoring
GuptaNavdeep1983 Aug 15, 2022
137f17a
fix: review comments.
GuptaNavdeep1983 Aug 22, 2022
30f750e
fix: comments
GuptaNavdeep1983 Aug 22, 2022
fa8a141
Merge branch 'main' into features/monitoring
Aug 22, 2022
a6f99d8
fix: formatting
GuptaNavdeep1983 Aug 23, 2022
3ae709a
Merge branch 'develop' into features/monitoring
GuptaNavdeep1983 Oct 4, 2022
428da8d
fix: addressed review comments.
navdeepg2021 Oct 4, 2022
e74f0f9
fix: reverted.
navdeepg2021 Oct 4, 2022
9efeb47
fix: formatting.
navdeepg2021 Oct 4, 2022
deed33a
fix: updated tests.
navdeepg2021 Oct 4, 2022
8e8f9de
Update README.md
GuptaNavdeep1983 Oct 5, 2022
9e271b0
Update README.md
GuptaNavdeep1983 Oct 5, 2022
6a42643
Update README.md
GuptaNavdeep1983 Oct 5, 2022
897a697
Update README.md
GuptaNavdeep1983 Oct 5, 2022
545d37c
fix: addressed review comments.
navdeepg2021 Oct 5, 2022
aed8c4d
Update variables.tf
GuptaNavdeep1983 Oct 6, 2022
19b9210
Update main.tf
GuptaNavdeep1983 Oct 6, 2022
71df24b
fix: formatting.
navdeepg2021 Oct 6, 2022
d780028
fix: cross reference.
navdeepg2021 Oct 7, 2022
ddea5f1
fix: formatting.
navdeepg2021 Oct 10, 2022
e2f68bb
Merge branch 'develop' into features/monitoring
npalm Oct 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Changelog

=======
## [1.11.0](https://github.com/philips-labs/terraform-aws-github-runner/compare/v1.10.0...v1.11.0) (2022-10-06)


Expand Down Expand Up @@ -84,6 +85,7 @@
* 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))
* 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))


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


Expand Down
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ This [Terraform](https://www.terraform.io/) module creates the required infrastr
- [Idle runners](#idle-runners)
- [Ephemeral runners](#ephemeral-runners)
- [Prebuilt Images](#prebuilt-images)
- [Experimental - Optional queue to publish GitHub workflow job events](#experimental---optional-queue-to-publish-github-workflow-job-events)
- [Examples](#examples)
- [Sub modules](#sub-modules)
- [ARM64 configuration for submodules](#arm64-configuration-for-submodules)
Expand Down Expand Up @@ -310,7 +311,23 @@ The example for [ephemeral runners](./examples/ephemeral) is based on the [defau

### Prebuilt Images

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`.
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)

### Experimental - Optional queue to publish GitHub workflow job events

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.

To enable the feature set `enable_workflow_job_events_queue = true`. Be-aware the feature in experimental!

Messages received on the queue are using the same format as published by GitHub wrapped in a property `workflowJobEvent`.

```
export interface GithubWorkflowEvent {
workflowJobEvent: WorkflowJobEvent;
}
```
This extendible format allows to add more fields to be added if needed.
You can configure the queue by setting properties to `workflow_job_events_queue_config`

## Examples

Expand Down
2 changes: 1 addition & 1 deletion examples/arm64/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ You can receive the webhook details by running:
terraform output -raw webhook_secret
```

Be-aware some shells will print some end of line character `%`.
Be-aware some shells will print some end of line character `%`.
2 changes: 2 additions & 0 deletions examples/default/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,6 @@ module "runners" {

# override scaling down
scale_down_schedule_expression = "cron(* * * * ? *)"
# enable this flag to publish webhook events to workflow job queue
# enable_workflow_job_events_queue = true
}
34 changes: 29 additions & 5 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ resource "aws_sqs_queue_policy" "build_queue_policy" {
policy = data.aws_iam_policy_document.deny_unsecure_transport.json
}

resource "aws_sqs_queue_policy" "webhook_events_workflow_job_queue_policy" {
count = var.enable_workflow_job_events_queue ? 1 : 0
queue_url = aws_sqs_queue.webhook_events_workflow_job_queue[0].id
policy = data.aws_iam_policy_document.deny_unsecure_transport.json
}

resource "aws_sqs_queue" "queued_builds" {
name = "${var.prefix}-queued-builds${var.fifo_build_queue ? ".fifo" : ""}"
delay_seconds = var.delay_webhook_event
Expand All @@ -69,6 +75,24 @@ resource "aws_sqs_queue" "queued_builds" {
tags = var.tags
}

resource "aws_sqs_queue" "webhook_events_workflow_job_queue" {
count = var.enable_workflow_job_events_queue ? 1 : 0
name = "${var.prefix}-webhook_events_workflow_job_queue"
delay_seconds = var.workflow_job_queue_configuration.delay_seconds
visibility_timeout_seconds = var.workflow_job_queue_configuration.visibility_timeout_seconds
message_retention_seconds = var.workflow_job_queue_configuration.message_retention_seconds
fifo_queue = false
receive_wait_time_seconds = 0
content_based_deduplication = false
redrive_policy = null

sqs_managed_sse_enabled = var.queue_encryption.sqs_managed_sse_enabled
kms_master_key_id = var.queue_encryption.kms_master_key_id
kms_data_key_reuse_period_seconds = var.queue_encryption.kms_data_key_reuse_period_seconds

tags = var.tags
}

resource "aws_sqs_queue_policy" "build_queue_dlq_policy" {
count = var.redrive_build_queue.enabled ? 1 : 0
queue_url = aws_sqs_queue.queued_builds.id
Expand Down Expand Up @@ -98,13 +122,13 @@ module "ssm" {
module "webhook" {
source = "./modules/webhook"

aws_region = var.aws_region
prefix = var.prefix
tags = local.tags
kms_key_arn = var.kms_key_arn

aws_region = var.aws_region
prefix = var.prefix
tags = local.tags
kms_key_arn = var.kms_key_arn
sqs_build_queue = aws_sqs_queue.queued_builds
sqs_build_queue_fifo = var.fifo_build_queue
sqs_workflow_job_queue = length(aws_sqs_queue.webhook_events_workflow_job_queue) > 0 ? aws_sqs_queue.webhook_events_workflow_job_queue[0] : null
github_app_webhook_secret_arn = module.ssm.parameters.github_app_webhook_secret.arn

lambda_s3_bucket = var.lambda_s3_bucket
Expand Down
1 change: 0 additions & 1 deletion modules/runners/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,6 @@ variable "lambda_architecture" {
error_message = "`lambda_architecture` value is not valid, valid values are: `arm64` and `x86_64`."
}
}

variable "enable_runner_binaries_syncer" {
description = "Option to disable the lambda to sync GitHub runner distribution, useful when using a pre-build AMI."
type = bool
Expand Down
2 changes: 1 addition & 1 deletion modules/webhook/lambdas/webhook/src/lambda.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { APIGatewayEvent, Callback, Context } from 'aws-lambda';
import { APIGatewayEvent, Context } from 'aws-lambda';

import { handle } from './webhook/handler';
import { logger } from './webhook/logger';
Expand Down
39 changes: 37 additions & 2 deletions modules/webhook/lambdas/webhook/src/sqs/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { SQS } from 'aws-sdk';

import { ActionRequestMessage, sendActionRequest } from '.';
import { ActionRequestMessage, GithubWorkflowEvent, sendActionRequest, sendWebhookEventToWorkflowJobQueue } from '.';
import workflowjob_event from '../../test/resources/github_workflowjob_event.json';

const mockSQS = {
sendMessage: jest.fn(() => {
Expand All @@ -25,7 +26,9 @@ describe('Test sending message to SQS.', () => {
QueueUrl: 'https://sqs.eu-west-1.amazonaws.com/123456789/queued-builds',
MessageBody: JSON.stringify(message),
};

afterEach(() => {
jest.clearAllMocks();
});
it('no fifo queue, based on defaults', async () => {
// Arrange
process.env.SQS_URL_WEBHOOK = sqsMessage.QueueUrl;
Expand Down Expand Up @@ -64,3 +67,35 @@ describe('Test sending message to SQS.', () => {
expect(result).resolves;
});
});
describe('Test sending message to SQS.', () => {
const message: GithubWorkflowEvent = {
workflowJobEvent: JSON.parse(JSON.stringify(workflowjob_event)),
};
const sqsMessage: SQS.Types.SendMessageRequest = {
QueueUrl: 'https://sqs.eu-west-1.amazonaws.com/123456789/webhook_events_workflow_job_queue',
MessageBody: JSON.stringify(message),
};
afterEach(() => {
jest.clearAllMocks();
});
it('sends webhook events to workflow job queue', async () => {
// Arrange
process.env.SQS_WORKFLOW_JOB_QUEUE = sqsMessage.QueueUrl;

// Act
const result = await sendWebhookEventToWorkflowJobQueue(message);

// Assert
expect(mockSQS.sendMessage).toBeCalledWith(sqsMessage);
expect(result).resolves;
});
it('Does not send webhook events to workflow job event copy queue', async () => {
// Arrange
process.env.SQS_WORKFLOW_JOB_QUEUE = '';
// Act
await sendWebhookEventToWorkflowJobQueue(message);

// Assert
expect(mockSQS.sendMessage).not.toBeCalledWith(sqsMessage);
});
});
25 changes: 25 additions & 0 deletions modules/webhook/lambdas/webhook/src/sqs/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { WorkflowJobEvent } from '@octokit/webhooks-types';
import { SQS } from 'aws-sdk';

import { LogFields, logger } from '../webhook/logger';
Expand All @@ -9,6 +10,9 @@ export interface ActionRequestMessage {
repositoryOwner: string;
installationId: number;
}
export interface GithubWorkflowEvent {
GuptaNavdeep1983 marked this conversation as resolved.
Show resolved Hide resolved
workflowJobEvent: WorkflowJobEvent;
}

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

await sqs.sendMessage(sqsMessage).promise();
};

export const sendWebhookEventToWorkflowJobQueue = async (message: GithubWorkflowEvent): Promise<void> => {
const webhook_events_workflow_job_queue = process.env.SQS_WORKFLOW_JOB_QUEUE || undefined;

if (webhook_events_workflow_job_queue != undefined) {
const sqs = new SQS({ region: process.env.AWS_REGION });
const sqsMessage: SQS.Types.SendMessageRequest = {
QueueUrl: String(process.env.SQS_WORKFLOW_JOB_QUEUE),
MessageBody: JSON.stringify(message),
};
logger.debug(
`Sending Webhook events to the workflow job queue: ${webhook_events_workflow_job_queue}`,
LogFields.print(),
);
try {
await sqs.sendMessage(sqsMessage).promise();
} catch (e) {
logger.warn(`Error in sending webhook events to workflow job queue: ${(e as Error).message}`, LogFields.print());
}
}
};
18 changes: 17 additions & 1 deletion modules/webhook/lambdas/webhook/src/webhook/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import nock from 'nock';

import checkrun_event from '../../test/resources/github_check_run_event.json';
import workflowjob_event from '../../test/resources/github_workflowjob_event.json';
import { sendActionRequest } from '../sqs';
import { sendActionRequest, sendWebhookEventToWorkflowJobQueue } from '../sqs';
import { getParameterValue } from '../ssm';
import { handle } from './handler';

Expand Down Expand Up @@ -309,4 +309,20 @@ describe('handler', () => {
expect(sendActionRequest).toBeCalled();
});
});

describe('Test for webhook events to be sent to workflow job queue: ', () => {
beforeEach(() => {
process.env.SQS_WORKFLOW_JOB_QUEUE =
'https://sqs.eu-west-1.amazonaws.com/123456789/webhook_events_workflow_job_queue';
});
it('sends webhook events to workflow job queue', async () => {
const event = JSON.stringify(workflowjob_event);
const resp = await handle(
{ 'X-Hub-Signature': await webhooks.sign(event), 'X-GitHub-Event': 'workflow_job' },
event,
);
expect(resp.statusCode).toBe(201);
expect(sendWebhookEventToWorkflowJobQueue).toBeCalled();
});
});
});
11 changes: 9 additions & 2 deletions modules/webhook/lambdas/webhook/src/webhook/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { CheckRunEvent, WorkflowJobEvent } from '@octokit/webhooks-types';
import { IncomingHttpHeaders } from 'http';

import { Response } from '../lambda';
import { sendActionRequest } from '../sqs';
import { sendActionRequest, sendWebhookEventToWorkflowJobQueue } from '../sqs';
import { getParameterValue } from '../ssm';
import { LogFields, logger as rootLogger } from './logger';

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

if (githubEvent == 'workflow_job') {
const workflowEventPayload = payload as WorkflowJobEvent;
response = await handleWorkflowJob(
payload as WorkflowJobEvent,
workflowEventPayload,
githubEvent,
enableWorkflowLabelCheck,
workflowLabelCheckAll,
runnerLabels,
);
await sendWorkflowJobEvents(githubEvent, workflowEventPayload);
} else if (githubEvent == 'check_run') {
response = await handleCheckRun(payload as CheckRunEvent, githubEvent);
}

return response;
}
async function sendWorkflowJobEvents(githubEvent: string, workflowEventPayload: WorkflowJobEvent) {
await sendWebhookEventToWorkflowJobQueue({
workflowJobEvent: workflowEventPayload,
});
}

function readEnvironmentVariables() {
const environment = process.env.ENVIRONMENT;
Expand Down
9 changes: 8 additions & 1 deletion modules/webhook/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,14 @@ variable "sqs_build_queue" {
arn = string
})
}

variable "sqs_workflow_job_queue" {
description = "SQS queue to monitor github events."
type = object({
id = string
arn = string
})
default = null
}
variable "lambda_zip" {
description = "File location of the lambda zip file."
type = string
Expand Down
10 changes: 10 additions & 0 deletions modules/webhook/webhook.tf
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ resource "aws_lambda_function" "webhook" {
RUNNER_LABELS = jsonencode(split(",", lower(var.runner_labels)))
SQS_URL_WEBHOOK = var.sqs_build_queue.id
SQS_IS_FIFO = var.sqs_build_queue_fifo
SQS_WORKFLOW_JOB_QUEUE = try(var.sqs_workflow_job_queue, null) != null ? var.sqs_workflow_job_queue.id : ""
}
}

Expand Down Expand Up @@ -78,6 +79,15 @@ resource "aws_iam_role_policy" "webhook_sqs" {
sqs_resource_arn = var.sqs_build_queue.arn
})
}
resource "aws_iam_role_policy" "webhook_workflow_job_sqs" {
count = var.sqs_workflow_job_queue != null ? 1 : 0
name = "${var.prefix}-lambda-webhook-publish-workflow-job-sqs-policy"
role = aws_iam_role.webhook_lambda.name

policy = templatefile("${path.module}/policies/lambda-publish-sqs-policy.json", {
sqs_resource_arn = var.sqs_workflow_job_queue.arn
})
}

resource "aws_iam_role_policy" "webhook_ssm" {
name = "${var.prefix}-lambda-webhook-publish-ssm-policy"
Expand Down
5 changes: 3 additions & 2 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ output "ssm_parameters" {
output "queues" {
description = "SQS queues."
value = {
build_queue_arn = aws_sqs_queue.queued_builds.arn
build_queue_dlq_arn = var.redrive_build_queue.enabled ? aws_sqs_queue.queued_builds_dlq[0].arn : null
build_queue_arn = aws_sqs_queue.queued_builds.arn
build_queue_dlq_arn = var.redrive_build_queue.enabled ? aws_sqs_queue.queued_builds_dlq[0].arn : null
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 : ""
}
}
19 changes: 19 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,25 @@ variable "lambda_architecture" {
}
}

variable "enable_workflow_job_events_queue" {
description = "Enabling this experimental feature will create a secondory sqs queue to wich a copy of the workflow_job event will be delivered."
type = bool
default = false
}

variable "workflow_job_queue_configuration" {
description = "Configuration options for workflow job queue which is only applicable if the flag enable_workflow_job_events_queue is set to true."
type = object({
delay_seconds = number
visibility_timeout_seconds = number
message_retention_seconds = number
})
default = {
"delay_seconds" : null,
"visibility_timeout_seconds" : null,
"message_retention_seconds" : null
}
}
variable "enable_runner_binaries_syncer" {
description = "Option to disable the lambda to sync GitHub runner distribution, useful when using a pre-build AMI."
type = bool
Expand Down