From a250b96b58c91e35ad64e3cbd8c00c3aa4475900 Mon Sep 17 00:00:00 2001 From: Nathaniel McAuliffe Date: Wed, 3 Nov 2021 17:41:55 -0400 Subject: [PATCH] feat: add option to format logging in JSON for lambdas (#1228) * feat(log): Adding Support for JSON logging * Passing in log_type to other lambdas * Casting e as Error * Add log_level variable, fix formatting * Correcting failed resolution * Using latest releases for testing * Passing in log_level to sub-modules * Update terraform.yml * Manually removing `node-fetch` * Moving logger object to new file * Resolving merge from develop Wouldn't be a conflict resolve without a miss * Logging when job is not queued * Updating handler names --- .github/workflows/terraform.yml | 9 +- README.md | 160 +++++++++--------- main.tf | 9 + modules/runner-binaries-syncer/README.md | 36 ++-- .../runner-binaries-syncer/package.json | 3 +- .../runner-binaries-syncer/src/lambda.ts | 3 + .../src/syncer/handler.ts | 15 +- .../src/syncer/logger.ts | 10 ++ .../src/syncer/modules.d.ts | 6 + .../runner-binaries-syncer/tsconfig.json | 14 +- .../lambdas/runner-binaries-syncer/yarn.lock | 11 +- .../runner-binaries-syncer.tf | 6 +- modules/runner-binaries-syncer/variables.tf | 32 ++++ modules/runners/README.md | 2 + modules/runners/lambdas/runners/package.json | 1 + modules/runners/lambdas/runners/src/lambda.ts | 28 +-- .../runners/src/scale-runners/gh-auth.ts | 4 + .../runners/src/scale-runners/logger.ts | 11 ++ .../runners/src/scale-runners/modules.d.ts | 10 +- .../runners/src/scale-runners/runners.ts | 9 +- .../runners/src/scale-runners/scale-down.ts | 37 ++-- .../runners/src/scale-runners/scale-up.ts | 21 ++- modules/runners/lambdas/runners/tsconfig.json | 5 +- modules/runners/lambdas/runners/yarn.lock | 15 ++ modules/runners/scale-down.tf | 11 +- modules/runners/scale-up.tf | 11 +- modules/runners/variables.tf | 34 +++- modules/webhook/README.md | 78 ++++----- modules/webhook/lambdas/webhook/package.json | 3 +- modules/webhook/lambdas/webhook/src/lambda.ts | 4 +- .../webhook/src/webhook/handler.test.ts | 1 + .../lambdas/webhook/src/webhook/handler.ts | 19 ++- .../lambdas/webhook/src/webhook/logger.ts | 10 ++ .../lambdas/webhook/src/webhook/modules.d.ts | 9 + modules/webhook/lambdas/webhook/tsconfig.json | 14 +- modules/webhook/lambdas/webhook/yarn.lock | 11 +- modules/webhook/variables.tf | 34 +++- modules/webhook/webhook.tf | 4 +- modules/webhook/yarn.lock | 28 +++ variables.tf | 32 ++++ 40 files changed, 532 insertions(+), 228 deletions(-) create mode 100644 modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/src/syncer/logger.ts create mode 100644 modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/src/syncer/modules.d.ts create mode 100644 modules/runners/lambdas/runners/src/scale-runners/logger.ts create mode 100644 modules/webhook/lambdas/webhook/src/webhook/logger.ts create mode 100644 modules/webhook/lambdas/webhook/src/webhook/modules.d.ts create mode 100644 modules/webhook/yarn.lock diff --git a/.github/workflows/terraform.yml b/.github/workflows/terraform.yml index 194019e5f5..450976e2e1 100644 --- a/.github/workflows/terraform.yml +++ b/.github/workflows/terraform.yml @@ -13,12 +13,11 @@ env: tf_working_dir: "." AWS_REGION: eu-west-1 jobs: - verify_module: name: Verify module strategy: matrix: - terraform: [1.0.8] + terraform: [1.0.8] runs-on: ubuntu-latest container: image: hashicorp/terraform:${{ matrix.terraform }} @@ -43,7 +42,7 @@ jobs: strategy: fail-fast: false matrix: - terraform: [0.14.1, 0.15.0, 1.0.8] + terraform: [0.14.3, 0.15.5, 1.0.8] example: ["default", "ubuntu"] defaults: run: @@ -51,7 +50,7 @@ jobs: runs-on: ubuntu-latest container: image: hashicorp/terraform:${{ matrix.terraform }} - steps: + steps: - uses: actions/checkout@v2 - name: terraform init run: terraform init -get -backend=false -input=false @@ -61,5 +60,3 @@ jobs: continue-on-error: true - name: validate terraform run: terraform validate - - diff --git a/README.md b/README.md index 532f0d6d2f..d7e3d77de4 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ This [Terraform](https://www.terraform.io/) module creates the required infrastr - [Providers](#providers) - [Modules](#modules) - [Resources](#resources) +- [Modules](#modules-1) +- [Resources](#resources-1) - [Inputs](#inputs) - [Outputs](#outputs) - [Contribution](#contribution) @@ -332,107 +334,109 @@ In case the setup does not work as intended follow the trace of events: | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 0.14.1 | -| [aws](#requirement\_aws) | >= 3.38 | +| terraform | >= 0.14.1 | +| aws | >= 3.38 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 3.38 | -| [random](#provider\_random) | n/a | +| aws | >= 3.38 | +| random | n/a | ## Modules | Name | Source | Version | |------|--------|---------| -| [runner\_binaries](#module\_runner\_binaries) | ./modules/runner-binaries-syncer | n/a | -| [runners](#module\_runners) | ./modules/runners | n/a | -| [ssm](#module\_ssm) | ./modules/ssm | n/a | -| [webhook](#module\_webhook) | ./modules/webhook | n/a | +| runner_binaries | ./modules/runner-binaries-syncer | | +| runners | ./modules/runners | | +| ssm | ./modules/ssm | | +| webhook | ./modules/webhook | | ## Resources -| Name | Type | -|------|------| -| [aws_resourcegroups_group.resourcegroups_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/resourcegroups_group) | resource | -| [aws_sqs_queue.queued_builds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sqs_queue) | resource | -| [random_string.random](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource | +| Name | +|------| +| [aws_resourcegroups_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/resourcegroups_group) | +| [aws_sqs_queue](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sqs_queue) | +| [random_string](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [ami\_filter](#input\_ami\_filter) | List of maps used to create the AMI filter for the action runner AMI. By default amazon linux 2 is used. | `map(list(string))` | `{}` | no | -| [ami\_owners](#input\_ami\_owners) | The list of owners used to select the AMI of action runner instances. | `list(string)` |
[
"amazon"
]
| no | -| [aws\_region](#input\_aws\_region) | AWS region. | `string` | n/a | yes | -| [block\_device\_mappings](#input\_block\_device\_mappings) | The EC2 instance block device configuration. Takes the following keys: `device_name`, `delete_on_termination`, `volume_type`, `volume_size`, `encrypted`, `iops` | `map(string)` | `{}` | no | -| [cloudwatch\_config](#input\_cloudwatch\_config) | (optional) Replaces the module default cloudwatch log config. See https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-Configuration-File-Details.html for details. | `string` | `null` | no | -| [create\_service\_linked\_role\_spot](#input\_create\_service\_linked\_role\_spot) | (optional) create the serviced linked role for spot instances that is required by the scale-up lambda. | `bool` | `false` | no | -| [delay\_webhook\_event](#input\_delay\_webhook\_event) | The number of seconds the event accepted by the webhook is invisible on the queue before the scale up lambda will receive the event. | `number` | `30` | no | -| [disable\_check\_wokflow\_job\_labels](#input\_disable\_check\_wokflow\_job\_labels) | Disable the the check of workflow labels for received workflow job events. | `bool` | `false` | no | -| [enable\_cloudwatch\_agent](#input\_enable\_cloudwatch\_agent) | Enabling the cloudwatch agent on the ec2 runner instances, the runner contains default config. Configuration can be overridden via `cloudwatch_config`. | `bool` | `true` | no | -| [enable\_organization\_runners](#input\_enable\_organization\_runners) | Register runners to organization, instead of repo level | `bool` | `false` | no | -| [enable\_ssm\_on\_runners](#input\_enable\_ssm\_on\_runners) | Enable to allow access the runner instances for debugging purposes via SSM. Note that this adds additional permissions to the runner instances. | `bool` | `false` | no | -| [environment](#input\_environment) | A name that identifies the environment, used as prefix and for tagging. | `string` | n/a | yes | -| [ghes\_ssl\_verify](#input\_ghes\_ssl\_verify) | GitHub Enterprise SSL verification. Set to 'false' when custom certificate (chains) is used for GitHub Enterprise Server (insecure). | `bool` | `true` | no | -| [ghes\_url](#input\_ghes\_url) | GitHub Enterprise Server URL. Example: https://github.internal.co - DO NOT SET IF USING PUBLIC GITHUB | `string` | `null` | no | -| [github\_app](#input\_github\_app) | GitHub app parameters, see your github app. Ensure the key is the base64-encoded `.pem` file (the output of `base64 app.private-key.pem`, not the content of `private-key.pem`). |
object({
key_base64 = string
id = string
webhook_secret = string
})
| n/a | yes | -| [idle\_config](#input\_idle\_config) | List of time period that can be defined as cron expression to keep a minimum amount of runners active instead of scaling down to 0. By defining this list you can ensure that in time periods that match the cron expression within 5 seconds a runner is kept idle. |
list(object({
cron = string
timeZone = string
idleCount = number
}))
| `[]` | no | -| [instance\_profile\_path](#input\_instance\_profile\_path) | The path that will be added to the instance\_profile, if not set the environment name will be used. | `string` | `null` | no | -| [instance\_type](#input\_instance\_type) | [DEPRECATED] See instance\_types. | `string` | `"m5.large"` | no | -| [instance\_types](#input\_instance\_types) | List of instance types for the action runner. | `list(string)` | `null` | no | -| [key\_name](#input\_key\_name) | Key pair name | `string` | `null` | no | -| [kms\_key\_arn](#input\_kms\_key\_arn) | Optional CMK Key ARN to be used for Parameter Store. This key must be in the current account. | `string` | `null` | no | -| [lambda\_s3\_bucket](#input\_lambda\_s3\_bucket) | S3 bucket from which to specify lambda functions. This is an alternative to providing local files directly. | `any` | `null` | no | -| [lambda\_security\_group\_ids](#input\_lambda\_security\_group\_ids) | List of security group IDs associated with the Lambda function. | `list(string)` | `[]` | no | -| [lambda\_subnet\_ids](#input\_lambda\_subnet\_ids) | List of subnets in which the action runners will be launched, the subnets needs to be subnets in the `vpc_id`. | `list(string)` | `[]` | no | -| [logging\_retention\_in\_days](#input\_logging\_retention\_in\_days) | Specifies the number of days you want to retain log events for the lambda log group. Possible values are: 0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653. | `number` | `180` | no | -| [market\_options](#input\_market\_options) | Market options for the action runner instances. Setting the value to `null` let the scaler create on-demand instances instead of spot instances. | `string` | `"spot"` | no | -| [minimum\_running\_time\_in\_minutes](#input\_minimum\_running\_time\_in\_minutes) | The time an ec2 action runner should be running at minimum before terminated if not busy. | `number` | `5` | no | -| [repository\_white\_list](#input\_repository\_white\_list) | List of repositories allowed to use the github app | `list(string)` | `[]` | no | -| [role\_path](#input\_role\_path) | The path that will be added to role path for created roles, if not set the environment name will be used. | `string` | `null` | no | -| [role\_permissions\_boundary](#input\_role\_permissions\_boundary) | Permissions boundary that will be added to the created roles. | `string` | `null` | no | -| [runner\_additional\_security\_group\_ids](#input\_runner\_additional\_security\_group\_ids) | (optional) List of additional security groups IDs to apply to the runner | `list(string)` | `[]` | no | -| [runner\_allow\_prerelease\_binaries](#input\_runner\_allow\_prerelease\_binaries) | Allow the runners to update to prerelease binaries. | `bool` | `false` | no | -| [runner\_as\_root](#input\_runner\_as\_root) | Run the action runner under the root user. | `bool` | `false` | no | -| [runner\_binaries\_syncer\_lambda\_timeout](#input\_runner\_binaries\_syncer\_lambda\_timeout) | Time out of the binaries sync lambda in seconds. | `number` | `300` | no | -| [runner\_binaries\_syncer\_lambda\_zip](#input\_runner\_binaries\_syncer\_lambda\_zip) | File location of the binaries sync lambda zip file. | `string` | `null` | no | -| [runner\_boot\_time\_in\_minutes](#input\_runner\_boot\_time\_in\_minutes) | The minimum time for an EC2 runner to boot and register as a runner. | `number` | `5` | no | -| [runner\_egress\_rules](#input\_runner\_egress\_rules) | List of egress rules for the GitHub runner instances. |
list(object({
cidr_blocks = list(string)
ipv6_cidr_blocks = list(string)
prefix_list_ids = list(string)
from_port = number
protocol = string
security_groups = list(string)
self = bool
to_port = number
description = string
}))
|
[
{
"cidr_blocks": [
"0.0.0.0/0"
],
"description": null,
"from_port": 0,
"ipv6_cidr_blocks": [
"::/0"
],
"prefix_list_ids": null,
"protocol": "-1",
"security_groups": null,
"self": null,
"to_port": 0
}
]
| no | -| [runner\_extra\_labels](#input\_runner\_extra\_labels) | Extra labels for the runners (GitHub). Separate each label by a comma | `string` | `""` | no | -| [runner\_group\_name](#input\_runner\_group\_name) | Name of the runner group. | `string` | `"Default"` | no | -| [runner\_iam\_role\_managed\_policy\_arns](#input\_runner\_iam\_role\_managed\_policy\_arns) | Attach AWS or customer-managed IAM policies (by ARN) to the runner IAM role | `list(string)` | `[]` | no | -| [runner\_log\_files](#input\_runner\_log\_files) | (optional) Replaces the module default cloudwatch log config. See https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-Configuration-File-Details.html for details. |
list(object({
log_group_name = string
prefix_log_group = bool
file_path = string
log_stream_name = string
}))
|
[
{
"file_path": "/var/log/messages",
"log_group_name": "messages",
"log_stream_name": "{instance_id}",
"prefix_log_group": true
},
{
"file_path": "/var/log/user-data.log",
"log_group_name": "user_data",
"log_stream_name": "{instance_id}",
"prefix_log_group": true
},
{
"file_path": "/home/ec2-user/actions-runner/_diag/Runner_**.log",
"log_group_name": "runner",
"log_stream_name": "{instance_id}",
"prefix_log_group": true
}
]
| no | -| [runners\_lambda\_s3\_key](#input\_runners\_lambda\_s3\_key) | S3 key for runners lambda function. Required if using S3 bucket to specify lambdas. | `any` | `null` | no | -| [runners\_lambda\_s3\_object\_version](#input\_runners\_lambda\_s3\_object\_version) | S3 object version for runners lambda function. Useful if S3 versioning is enabled on source bucket. | `any` | `null` | no | -| [runners\_lambda\_zip](#input\_runners\_lambda\_zip) | File location of the lambda zip file for scaling runners. | `string` | `null` | no | -| [runners\_maximum\_count](#input\_runners\_maximum\_count) | The maximum number of runners that will be created. | `number` | `3` | no | -| [runners\_scale\_down\_lambda\_timeout](#input\_runners\_scale\_down\_lambda\_timeout) | Time out for the scale down lambda in seconds. | `number` | `60` | no | -| [runners\_scale\_up\_lambda\_timeout](#input\_runners\_scale\_up\_lambda\_timeout) | Time out for the scale up lambda in seconds. | `number` | `180` | no | -| [scale\_down\_schedule\_expression](#input\_scale\_down\_schedule\_expression) | Scheduler expression to check every x for scale down. | `string` | `"cron(*/5 * * * ? *)"` | no | -| [subnet\_ids](#input\_subnet\_ids) | List of subnets in which the action runners will be launched, the subnets needs to be subnets in the `vpc_id`. | `list(string)` | n/a | yes | -| [syncer\_lambda\_s3\_key](#input\_syncer\_lambda\_s3\_key) | S3 key for syncer lambda function. Required if using S3 bucket to specify lambdas. | `any` | `null` | no | -| [syncer\_lambda\_s3\_object\_version](#input\_syncer\_lambda\_s3\_object\_version) | S3 object version for syncer lambda function. Useful if S3 versioning is enabled on source bucket. | `any` | `null` | no | -| [tags](#input\_tags) | Map of tags that will be added to created resources. By default resources will be tagged with name and environment. | `map(string)` | `{}` | no | -| [userdata\_post\_install](#input\_userdata\_post\_install) | Script to be ran after the GitHub Actions runner is installed on the EC2 instances | `string` | `""` | no | -| [userdata\_pre\_install](#input\_userdata\_pre\_install) | Script to be ran before the GitHub Actions runner is installed on the EC2 instances | `string` | `""` | no | -| [userdata\_template](#input\_userdata\_template) | Alternative user-data template, replacing the default template. By providing your own user\_data you have to take care of installing all required software, including the action runner. Variables userdata\_pre/post\_install are ignored. | `string` | `null` | no | -| [volume\_size](#input\_volume\_size) | Size of runner volume | `number` | `30` | no | -| [vpc\_id](#input\_vpc\_id) | The VPC for security groups of the action runners. | `string` | n/a | yes | -| [webhook\_lambda\_s3\_key](#input\_webhook\_lambda\_s3\_key) | S3 key for webhook lambda function. Required if using S3 bucket to specify lambdas. | `any` | `null` | no | -| [webhook\_lambda\_s3\_object\_version](#input\_webhook\_lambda\_s3\_object\_version) | S3 object version for webhook lambda function. Useful if S3 versioning is enabled on source bucket. | `any` | `null` | no | -| [webhook\_lambda\_timeout](#input\_webhook\_lambda\_timeout) | Time out of the webhook lambda in seconds. | `number` | `10` | no | -| [webhook\_lambda\_zip](#input\_webhook\_lambda\_zip) | File location of the webhook lambda zip file. | `string` | `null` | no | +| ami\_filter | List of maps used to create the AMI filter for the action runner AMI. By default amazon linux 2 is used. | `map(list(string))` | `{}` | no | +| ami\_owners | The list of owners used to select the AMI of action runner instances. | `list(string)` |
[
"amazon"
]
| no | +| aws\_region | AWS region. | `string` | n/a | yes | +| block\_device\_mappings | The EC2 instance block device configuration. Takes the following keys: `device_name`, `delete_on_termination`, `volume_type`, `volume_size`, `encrypted`, `iops` | `map(string)` | `{}` | no | +| cloudwatch\_config | (optional) Replaces the module default cloudwatch log config. See https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-Configuration-File-Details.html for details. | `string` | `null` | no | +| create\_service\_linked\_role\_spot | (optional) create the serviced linked role for spot instances that is required by the scale-up lambda. | `bool` | `false` | no | +| delay\_webhook\_event | The number of seconds the event accepted by the webhook is invisible on the queue before the scale up lambda will receive the event. | `number` | `30` | no | +| disable\_check\_wokflow\_job\_labels | Disable the the check of workflow labels for received workflow job events. | `bool` | `false` | no | +| enable\_cloudwatch\_agent | Enabling the cloudwatch agent on the ec2 runner instances, the runner contains default config. Configuration can be overridden via `cloudwatch_config`. | `bool` | `true` | no | +| enable\_organization\_runners | Register runners to organization, instead of repo level | `bool` | `false` | no | +| enable\_ssm\_on\_runners | Enable to allow access the runner instances for debugging purposes via SSM. Note that this adds additional permissions to the runner instances. | `bool` | `false` | no | +| environment | A name that identifies the environment, used as prefix and for tagging. | `string` | n/a | yes | +| ghes\_ssl\_verify | GitHub Enterprise SSL verification. Set to 'false' when custom certificate (chains) is used for GitHub Enterprise Server (insecure). | `bool` | `true` | no | +| ghes\_url | GitHub Enterprise Server URL. Example: https://github.internal.co - DO NOT SET IF USING PUBLIC GITHUB | `string` | `null` | no | +| github\_app | GitHub app parameters, see your github app. Ensure the key is the base64-encoded `.pem` file (the output of `base64 app.private-key.pem`, not the content of `private-key.pem`). |
object({
key_base64 = string
id = string
webhook_secret = string
})
| n/a | yes | +| idle\_config | List of time period that can be defined as cron expression to keep a minimum amount of runners active instead of scaling down to 0. By defining this list you can ensure that in time periods that match the cron expression within 5 seconds a runner is kept idle. |
list(object({
cron = string
timeZone = string
idleCount = number
}))
| `[]` | no | +| instance\_profile\_path | The path that will be added to the instance\_profile, if not set the environment name will be used. | `string` | `null` | no | +| instance\_type | [DEPRECATED] See instance\_types. | `string` | `"m5.large"` | no | +| instance\_types | List of instance types for the action runner. | `list(string)` | `null` | no | +| key\_name | Key pair name | `string` | `null` | no | +| kms\_key\_arn | Optional CMK Key ARN to be used for Parameter Store. This key must be in the current account. | `string` | `null` | no | +| lambda\_s3\_bucket | S3 bucket from which to specify lambda functions. This is an alternative to providing local files directly. | `any` | `null` | no | +| lambda\_security\_group\_ids | List of security group IDs associated with the Lambda function. | `list(string)` | `[]` | no | +| lambda\_subnet\_ids | List of subnets in which the action runners will be launched, the subnets needs to be subnets in the `vpc_id`. | `list(string)` | `[]` | no | +| log\_level | Logging level for lambda logging. Valid values are 'silly', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'. | `string` | `"info"` | no | +| log\_type | Logging format for lambda logging. Valid values are 'json', 'pretty', 'hidden'. | `string` | `"pretty"` | no | +| logging\_retention\_in\_days | Specifies the number of days you want to retain log events for the lambda log group. Possible values are: 0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653. | `number` | `180` | no | +| market\_options | Market options for the action runner instances. Setting the value to `null` let the scaler create on-demand instances instead of spot instances. | `string` | `"spot"` | no | +| minimum\_running\_time\_in\_minutes | The time an ec2 action runner should be running at minimum before terminated if not busy. | `number` | `5` | no | +| repository\_white\_list | List of repositories allowed to use the github app | `list(string)` | `[]` | no | +| role\_path | The path that will be added to role path for created roles, if not set the environment name will be used. | `string` | `null` | no | +| role\_permissions\_boundary | Permissions boundary that will be added to the created roles. | `string` | `null` | no | +| runner\_additional\_security\_group\_ids | (optional) List of additional security groups IDs to apply to the runner | `list(string)` | `[]` | no | +| runner\_allow\_prerelease\_binaries | Allow the runners to update to prerelease binaries. | `bool` | `false` | no | +| runner\_as\_root | Run the action runner under the root user. | `bool` | `false` | no | +| runner\_binaries\_syncer\_lambda\_timeout | Time out of the binaries sync lambda in seconds. | `number` | `300` | no | +| runner\_binaries\_syncer\_lambda\_zip | File location of the binaries sync lambda zip file. | `string` | `null` | no | +| runner\_boot\_time\_in\_minutes | The minimum time for an EC2 runner to boot and register as a runner. | `number` | `5` | no | +| runner\_egress\_rules | List of egress rules for the GitHub runner instances. |
list(object({
cidr_blocks = list(string)
ipv6_cidr_blocks = list(string)
prefix_list_ids = list(string)
from_port = number
protocol = string
security_groups = list(string)
self = bool
to_port = number
description = string
}))
|
[
{
"cidr_blocks": [
"0.0.0.0/0"
],
"description": null,
"from_port": 0,
"ipv6_cidr_blocks": [
"::/0"
],
"prefix_list_ids": null,
"protocol": "-1",
"security_groups": null,
"self": null,
"to_port": 0
}
]
| no | +| runner\_extra\_labels | Extra labels for the runners (GitHub). Separate each label by a comma | `string` | `""` | no | +| runner\_group\_name | Name of the runner group. | `string` | `"Default"` | no | +| runner\_iam\_role\_managed\_policy\_arns | Attach AWS or customer-managed IAM policies (by ARN) to the runner IAM role | `list(string)` | `[]` | no | +| runner\_log\_files | (optional) Replaces the module default cloudwatch log config. See https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-Configuration-File-Details.html for details. |
list(object({
log_group_name = string
prefix_log_group = bool
file_path = string
log_stream_name = string
}))
|
[
{
"file_path": "/var/log/messages",
"log_group_name": "messages",
"log_stream_name": "{instance_id}",
"prefix_log_group": true
},
{
"file_path": "/var/log/user-data.log",
"log_group_name": "user_data",
"log_stream_name": "{instance_id}",
"prefix_log_group": true
},
{
"file_path": "/home/ec2-user/actions-runner/_diag/Runner_**.log",
"log_group_name": "runner",
"log_stream_name": "{instance_id}",
"prefix_log_group": true
}
]
| no | +| runners\_lambda\_s3\_key | S3 key for runners lambda function. Required if using S3 bucket to specify lambdas. | `any` | `null` | no | +| runners\_lambda\_s3\_object\_version | S3 object version for runners lambda function. Useful if S3 versioning is enabled on source bucket. | `any` | `null` | no | +| runners\_lambda\_zip | File location of the lambda zip file for scaling runners. | `string` | `null` | no | +| runners\_maximum\_count | The maximum number of runners that will be created. | `number` | `3` | no | +| runners\_scale\_down\_lambda\_timeout | Time out for the scale down lambda in seconds. | `number` | `60` | no | +| runners\_scale\_up\_lambda\_timeout | Time out for the scale up lambda in seconds. | `number` | `180` | no | +| scale\_down\_schedule\_expression | Scheduler expression to check every x for scale down. | `string` | `"cron(*/5 * * * ? *)"` | no | +| subnet\_ids | List of subnets in which the action runners will be launched, the subnets needs to be subnets in the `vpc_id`. | `list(string)` | n/a | yes | +| syncer\_lambda\_s3\_key | S3 key for syncer lambda function. Required if using S3 bucket to specify lambdas. | `any` | `null` | no | +| syncer\_lambda\_s3\_object\_version | S3 object version for syncer lambda function. Useful if S3 versioning is enabled on source bucket. | `any` | `null` | no | +| tags | Map of tags that will be added to created resources. By default resources will be tagged with name and environment. | `map(string)` | `{}` | no | +| userdata\_post\_install | Script to be ran after the GitHub Actions runner is installed on the EC2 instances | `string` | `""` | no | +| userdata\_pre\_install | Script to be ran before the GitHub Actions runner is installed on the EC2 instances | `string` | `""` | no | +| userdata\_template | Alternative user-data template, replacing the default template. By providing your own user\_data you have to take care of installing all required software, including the action runner. Variables userdata\_pre/post\_install are ignored. | `string` | `null` | no | +| volume\_size | Size of runner volume | `number` | `30` | no | +| vpc\_id | The VPC for security groups of the action runners. | `string` | n/a | yes | +| webhook\_lambda\_s3\_key | S3 key for webhook lambda function. Required if using S3 bucket to specify lambdas. | `any` | `null` | no | +| webhook\_lambda\_s3\_object\_version | S3 object version for webhook lambda function. Useful if S3 versioning is enabled on source bucket. | `any` | `null` | no | +| webhook\_lambda\_timeout | Time out of the webhook lambda in seconds. | `number` | `10` | no | +| webhook\_lambda\_zip | File location of the webhook lambda zip file. | `string` | `null` | no | ## Outputs | Name | Description | |------|-------------| -| [binaries\_syncer](#output\_binaries\_syncer) | n/a | -| [runners](#output\_runners) | n/a | -| [ssm\_parameters](#output\_ssm\_parameters) | n/a | -| [webhook](#output\_webhook) | n/a | +| binaries\_syncer | n/a | +| runners | n/a | +| ssm\_parameters | n/a | +| webhook | n/a | ## Contribution diff --git a/main.tf b/main.tf index 673ea30c52..a2cd335fc0 100644 --- a/main.tf +++ b/main.tf @@ -64,6 +64,9 @@ module "webhook" { role_path = var.role_path role_permissions_boundary = var.role_permissions_boundary repository_white_list = var.repository_white_list + + log_type = var.log_type + log_level = var.log_level } module "runners" { @@ -133,6 +136,9 @@ module "runners" { ghes_ssl_verify = var.ghes_ssl_verify kms_key_arn = var.kms_key_arn + + log_type = var.log_type + log_level = var.log_level } module "runner_binaries" { @@ -156,6 +162,9 @@ module "runner_binaries" { role_path = var.role_path role_permissions_boundary = var.role_permissions_boundary + + log_type = var.log_type + log_level = var.log_level } resource "aws_resourcegroups_group" "resourcegroups_group" { diff --git a/modules/runner-binaries-syncer/README.md b/modules/runner-binaries-syncer/README.md index 9ca3f470f1..a2ff43177e 100644 --- a/modules/runner-binaries-syncer/README.md +++ b/modules/runner-binaries-syncer/README.md @@ -75,23 +75,25 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [aws\_region](#input\_aws\_region) | AWS region. | `string` | n/a | yes | -| [distribution\_bucket\_name](#input\_distribution\_bucket\_name) | Bucket for storing the action runner distribution. | `string` | n/a | yes | -| [environment](#input\_environment) | A name that identifies the environment, used as prefix and for tagging. | `string` | n/a | yes | -| [lambda\_s3\_bucket](#input\_lambda\_s3\_bucket) | S3 bucket from which to specify lambda functions. This is an alternative to providing local files directly. | `any` | `null` | no | -| [lambda\_schedule\_expression](#input\_lambda\_schedule\_expression) | Scheduler expression for action runner binary syncer. | `string` | `"cron(27 * * * ? *)"` | no | -| [lambda\_security\_group\_ids](#input\_lambda\_security\_group\_ids) | List of security group IDs associated with the Lambda function. | `list(string)` | `[]` | no | -| [lambda\_subnet\_ids](#input\_lambda\_subnet\_ids) | List of subnets in which the action runners will be launched, the subnets needs to be subnets in the `vpc_id`. | `list(string)` | `[]` | no | -| [lambda\_timeout](#input\_lambda\_timeout) | Time out of the lambda in seconds. | `number` | `300` | no | -| [lambda\_zip](#input\_lambda\_zip) | File location of the lambda zip file. | `string` | `null` | no | -| [logging\_retention\_in\_days](#input\_logging\_retention\_in\_days) | Specifies the number of days you want to retain log events for the lambda log group. Possible values are: 0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653. | `number` | `7` | no | -| [role\_path](#input\_role\_path) | The path that will be added to the role, if not set the environment name will be used. | `string` | `null` | no | -| [role\_permissions\_boundary](#input\_role\_permissions\_boundary) | Permissions boundary that will be added to the created role for the lambda. | `string` | `null` | no | -| [runner\_allow\_prerelease\_binaries](#input\_runner\_allow\_prerelease\_binaries) | Allow the runners to update to prerelease binaries. | `bool` | `false` | no | -| [runner\_architecture](#input\_runner\_architecture) | The platform architecture for the runner instance (x64, arm64), defaults to 'x64' | `string` | `"x64"` | no | -| [syncer\_lambda\_s3\_key](#input\_syncer\_lambda\_s3\_key) | S3 key for syncer lambda function. Required if using S3 bucket to specify lambdas. | `any` | `null` | no | -| [syncer\_lambda\_s3\_object\_version](#input\_syncer\_lambda\_s3\_object\_version) | S3 object version for syncer lambda function. Useful if S3 versioning is enabled on source bucket. | `any` | `null` | no | -| [tags](#input\_tags) | Map of tags that will be added to created resources. By default resources will be tagged with name and environment. | `map(string)` | `{}` | no | +| aws\_region | AWS region. | `string` | n/a | yes | +| distribution\_bucket\_name | Bucket for storing the action runner distribution. | `string` | n/a | yes | +| environment | A name that identifies the environment, used as prefix and for tagging. | `string` | n/a | yes | +| lambda\_s3\_bucket | S3 bucket from which to specify lambda functions. This is an alternative to providing local files directly. | `any` | `null` | no | +| lambda\_schedule\_expression | Scheduler expression for action runner binary syncer. | `string` | `"cron(27 * * * ? *)"` | no | +| lambda\_security\_group\_ids | List of security group IDs associated with the Lambda function. | `list(string)` | `[]` | no | +| lambda\_subnet\_ids | List of subnets in which the action runners will be launched, the subnets needs to be subnets in the `vpc_id`. | `list(string)` | `[]` | no | +| lambda\_timeout | Time out of the lambda in seconds. | `number` | `300` | no | +| lambda\_zip | File location of the lambda zip file. | `string` | `null` | no | +| log\_level | Logging level for lambda logging. Valid values are 'silly', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'. | `string` | `"info"` | no | +| log\_type | Logging format for lambda logging. Valid values are 'json', 'pretty', 'hidden'. | `string` | `"pretty"` | no | +| logging\_retention\_in\_days | Specifies the number of days you want to retain log events for the lambda log group. Possible values are: 0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653. | `number` | `7` | no | +| role\_path | The path that will be added to the role, if not set the environment name will be used. | `string` | `null` | no | +| role\_permissions\_boundary | Permissions boundary that will be added to the created role for the lambda. | `string` | `null` | no | +| runner\_allow\_prerelease\_binaries | Allow the runners to update to prerelease binaries. | `bool` | `false` | no | +| runner\_architecture | The platform architecture for the runner instance (x64, arm64), defaults to 'x64' | `string` | `"x64"` | no | +| syncer\_lambda\_s3\_key | S3 key for syncer lambda function. Required if using S3 bucket to specify lambdas. | `any` | `null` | no | +| syncer\_lambda\_s3\_object\_version | S3 object version for syncer lambda function. Useful if S3 versioning is enabled on source bucket. | `any` | `null` | no | +| tags | Map of tags that will be added to created resources. By default resources will be tagged with name and environment. | `map(string)` | `{}` | no | ## Outputs diff --git a/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/package.json b/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/package.json index 44a614e1cb..f5d5a7d2e9 100644 --- a/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/package.json +++ b/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/package.json @@ -32,6 +32,7 @@ "typescript": "^4.4.4" }, "dependencies": { + "tslog": "^3.2.2", "axios": "^0.24.0" } -} \ No newline at end of file +} diff --git a/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/src/lambda.ts b/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/src/lambda.ts index 85ea9622bd..b835538009 100644 --- a/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/src/lambda.ts +++ b/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/src/lambda.ts @@ -1,7 +1,10 @@ import { handle } from './syncer/handler'; +import { logger } from './syncer/logger'; // eslint-disable-next-line export const handler = async (event: any, context: any, callback: any): Promise => { + logger.setSettings({ requestId: context.awsRequestId }); + logger.debug(JSON.stringify(event)); try { await handle(); callback(null); diff --git a/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/src/syncer/handler.ts b/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/src/syncer/handler.ts index 223e51c71d..c330ed5e03 100644 --- a/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/src/syncer/handler.ts +++ b/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/src/syncer/handler.ts @@ -3,6 +3,9 @@ import { PassThrough } from 'stream'; import { S3 } from 'aws-sdk'; import AWS from 'aws-sdk'; import axios from 'axios'; +import { logger as rootLogger } from './logger'; + +const logger = rootLogger.getChildLogger(); const versionKey = 'name'; @@ -22,7 +25,7 @@ async function getCachedVersion(s3: S3, cacheObject: CacheObject): Promise t.Key === versionKey); return versions.length === 1 ? versions[0].Value : undefined; } catch (e) { - console.debug('No tags found'); + logger.debug('No tags found'); return undefined; } } @@ -73,7 +76,7 @@ async function uploadToS3(s3: S3, cacheObject: CacheObject, actionRunnerReleaseA }) .promise(); - console.debug('Start downloading %s and uploading to S3.', actionRunnerReleaseAsset.name); + logger.debug('Start downloading %s and uploading to S3.', actionRunnerReleaseAsset.name); const readPromise = new Promise((resolve, reject) => { axios @@ -93,9 +96,9 @@ async function uploadToS3(s3: S3, cacheObject: CacheObject, actionRunnerReleaseA }); await Promise.all([readPromise, writePromise]) - .then(() => console.info(`The new distribution is uploaded to S3.`)) + .then(() => logger.info(`The new distribution is uploaded to S3.`)) .catch((error) => { - console.error(`Uploading of the new distribution to S3 failed: ${error}`); + logger.error(`Uploading of the new distribution to S3 failed: ${error}`); throw error; }); } @@ -120,10 +123,10 @@ export const handle = async (): Promise => { } const currentVersion = await getCachedVersion(s3, cacheObject); - console.debug('latest: ' + currentVersion); + logger.debug('latest: ' + currentVersion); if (currentVersion === undefined || currentVersion != actionRunnerReleaseAsset.name) { uploadToS3(s3, cacheObject, actionRunnerReleaseAsset); } else { - console.debug('Distribution is up-to-date, no action.'); + logger.debug('Distribution is up-to-date, no action.'); } }; diff --git a/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/src/syncer/logger.ts b/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/src/syncer/logger.ts new file mode 100644 index 0000000000..ebae043deb --- /dev/null +++ b/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/src/syncer/logger.ts @@ -0,0 +1,10 @@ +import { Logger } from 'tslog'; + +export const logger = new Logger({ + colorizePrettyLogs: false, + displayInstanceName: false, + minLevel: process.env.LOG_LEVEL || 'info', + name: 'runner-binaries-syncer', + overwriteConsole: true, + type: process.env.LOG_TYPE || 'pretty', +}); diff --git a/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/src/syncer/modules.d.ts b/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/src/syncer/modules.d.ts new file mode 100644 index 0000000000..cff03913cb --- /dev/null +++ b/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/src/syncer/modules.d.ts @@ -0,0 +1,6 @@ +declare namespace NodeJS { + export interface ProcessEnv { + LOG_LEVEL: 'silly' | 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'; + LOG_TYPE: 'json' | 'pretty' | 'hidden'; + } +} diff --git a/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/tsconfig.json b/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/tsconfig.json index 64a2b54f25..764f2f6ae0 100644 --- a/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/tsconfig.json +++ b/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/tsconfig.json @@ -1,10 +1,13 @@ { "compilerOptions": { /* Basic Options */ - "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */, + "target": "es2019" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */, "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, "outDir": "build", - "lib": ["es2020", "DOM"] /* Specify library files to be included in the compilation. */, + "lib": [ + "es2020", + "DOM" + ] /* Specify library files to be included in the compilation. */, "allowJs": true /* Allow javascript files to be compiled. */, // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ @@ -54,7 +57,10 @@ /* Experimental Options */ "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */, - "resolveJsonModule": true + "resolveJsonModule": true, + "sourceMap": true }, - "include": ["src/**/*"] + "include": [ + "src/**/*" + ] } diff --git a/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/yarn.lock b/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/yarn.lock index ee41e5339e..5e1eafbe03 100644 --- a/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/yarn.lock +++ b/modules/runner-binaries-syncer/lambdas/runner-binaries-syncer/yarn.lock @@ -3148,10 +3148,10 @@ source-map-support@^0.5.12, source-map-support@^0.5.17: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-support@^0.5.6: +source-map-support@^0.5.19, source-map-support@^0.5.6: version "0.5.20" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" - integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== + integrity sha1-EhZgifj15ejFaSazd2Mzkt0stsk= dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -3421,6 +3421,13 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslog@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.2.2.tgz#5bbaa1fab685c4273e59b38064227321a69a0694" + integrity sha1-W7qh+raFxCc+WbOAZCJzIaaaBpQ= + dependencies: + source-map-support "^0.5.19" + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" diff --git a/modules/runner-binaries-syncer/runner-binaries-syncer.tf b/modules/runner-binaries-syncer/runner-binaries-syncer.tf index 4dfd726f4d..04f2cd0c47 100644 --- a/modules/runner-binaries-syncer/runner-binaries-syncer.tf +++ b/modules/runner-binaries-syncer/runner-binaries-syncer.tf @@ -18,10 +18,12 @@ resource "aws_lambda_function" "syncer" { environment { variables = { - S3_BUCKET_NAME = aws_s3_bucket.action_dist.id - S3_OBJECT_KEY = local.action_runner_distribution_object_key GITHUB_RUNNER_ARCHITECTURE = var.runner_architecture GITHUB_RUNNER_ALLOW_PRERELEASE_BINARIES = var.runner_allow_prerelease_binaries + LOG_LEVEL = var.log_level + LOG_TYPE = var.log_type + S3_BUCKET_NAME = aws_s3_bucket.action_dist.id + S3_OBJECT_KEY = local.action_runner_distribution_object_key } } dynamic "vpc_config" { diff --git a/modules/runner-binaries-syncer/variables.tf b/modules/runner-binaries-syncer/variables.tf index b4320ee531..79cb10c293 100644 --- a/modules/runner-binaries-syncer/variables.tf +++ b/modules/runner-binaries-syncer/variables.tf @@ -98,3 +98,35 @@ variable "lambda_security_group_ids" { type = list(string) default = [] } + +variable "log_type" { + description = "Logging format for lambda logging. Valid values are 'json', 'pretty', 'hidden'. " + type = string + default = "pretty" + validation { + condition = anytrue([ + var.log_type == "json", + var.log_type == "pretty", + var.log_type == "hidden", + ]) + error_message = "`log_type` value not valid. Valid values are 'json', 'pretty', 'hidden'." + } +} + +variable "log_level" { + description = "Logging level for lambda logging. Valid values are 'silly', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'." + type = string + default = "info" + validation { + condition = anytrue([ + var.log_level == "silly", + var.log_level == "trace", + var.log_level == "debug", + var.log_level == "info", + var.log_level == "warn", + var.log_level == "error", + var.log_level == "fatal", + ]) + error_message = "`log_level` value not valid. Valid values are 'silly', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'." + } +} diff --git a/modules/runners/README.md b/modules/runners/README.md index 7cd06682ea..b7d52ff17e 100644 --- a/modules/runners/README.md +++ b/modules/runners/README.md @@ -132,6 +132,8 @@ No modules. | [lambda\_timeout\_scale\_down](#input\_lambda\_timeout\_scale\_down) | Time out for the scale down lambda in seconds. | `number` | `60` | no | | [lambda\_timeout\_scale\_up](#input\_lambda\_timeout\_scale\_up) | Time out for the scale up lambda in seconds. | `number` | `60` | no | | [lambda\_zip](#input\_lambda\_zip) | File location of the lambda zip file. | `string` | `null` | no | +| [log\_level](#input\_log\_level) | Logging level for lambda logging. Valid values are 'silly', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'. | `string` | `"info"` | no | +| [log\_type](#input\_log\_type) | Logging format for lambda logging. Valid values are 'json', 'pretty', 'hidden'. | `string` | `"pretty"` | no | | [logging\_retention\_in\_days](#input\_logging\_retention\_in\_days) | Specifies the number of days you want to retain log events for the lambda log group. Possible values are: 0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653. | `number` | `180` | no | | [market\_options](#input\_market\_options) | Market options for the action runner instances. | `string` | `"spot"` | no | | [minimum\_running\_time\_in\_minutes](#input\_minimum\_running\_time\_in\_minutes) | The time an ec2 action runner should be running at minimum before terminated if non busy. | `number` | `5` | no | diff --git a/modules/runners/lambdas/runners/package.json b/modules/runners/lambdas/runners/package.json index 88de7dc162..eb28c1e838 100644 --- a/modules/runners/lambdas/runners/package.json +++ b/modules/runners/lambdas/runners/package.json @@ -43,6 +43,7 @@ "@types/node": "^16.11.6", "aws-sdk": "^2.1019.0", "cron-parser": "^4.1.0", + "tslog": "^3.2.2", "typescript": "^4.4.4" } } diff --git a/modules/runners/lambdas/runners/src/lambda.ts b/modules/runners/lambdas/runners/src/lambda.ts index 848bda9c66..a784c0d059 100644 --- a/modules/runners/lambdas/runners/src/lambda.ts +++ b/modules/runners/lambdas/runners/src/lambda.ts @@ -1,27 +1,31 @@ -import { scaleUp as scaleUpAction } from './scale-runners/scale-up'; -import { scaleDown as scaleDownAction } from './scale-runners/scale-down'; -import { SQSEvent, ScheduledEvent, Context } from 'aws-lambda'; +import { scaleUp } from './scale-runners/scale-up'; +import { scaleDown } from './scale-runners/scale-down'; +import { SQSEvent, ScheduledEvent, Context, Callback } from 'aws-lambda'; +import { logger } from './scale-runners/logger'; +import 'source-map-support/register'; -export const scaleUp = async (event: SQSEvent, context: Context, callback: any): Promise => { - console.debug(JSON.stringify(event)); +export async function scaleUpHandler(event: SQSEvent, context: Context, callback: Callback): Promise { + logger.setSettings({ requestId: context.awsRequestId }); + logger.debug(JSON.stringify(event)); try { for (const e of event.Records) { - await scaleUpAction(e.eventSource, JSON.parse(e.body)); + await scaleUp(e.eventSource, JSON.parse(e.body)); } callback(null); } catch (e) { - console.error(e); + logger.error(e); callback('Failed handling SQS event'); } -}; +} -export const scaleDown = async (event: ScheduledEvent, context: Context, callback: any): Promise => { +export async function scaleDownHandler(event: ScheduledEvent, context: Context, callback: Callback): Promise { + logger.setSettings({ requestId: context.awsRequestId }); try { - await scaleDownAction(); + await scaleDown(); callback(null); } catch (e) { - console.error(e); + logger.error(e); callback('Failed'); } -}; +} diff --git a/modules/runners/lambdas/runners/src/scale-runners/gh-auth.ts b/modules/runners/lambdas/runners/src/scale-runners/gh-auth.ts index 297edd0b27..d60d4bebc1 100644 --- a/modules/runners/lambdas/runners/src/scale-runners/gh-auth.ts +++ b/modules/runners/lambdas/runners/src/scale-runners/gh-auth.ts @@ -11,6 +11,9 @@ import { } from '@octokit/auth-app/dist-types/types'; import { OctokitOptions } from '@octokit/core/dist-types/types'; import { getParameterValue } from './ssm'; +import { logger as rootLogger } from './logger'; + +const logger = rootLogger.getChildLogger(); export async function createOctoClient(token: string, ghesApiUrl = ''): Promise { const ocktokitOptions: OctokitOptions = { @@ -52,6 +55,7 @@ async function createAuth(installationId: number | undefined, ghesApiUrl: string }; if (installationId) authOptions = { ...authOptions, installationId }; + logger.debug(`GHES API URL: ${ghesApiUrl}`); if (ghesApiUrl) { authOptions.request = request.defaults({ baseUrl: ghesApiUrl, diff --git a/modules/runners/lambdas/runners/src/scale-runners/logger.ts b/modules/runners/lambdas/runners/src/scale-runners/logger.ts new file mode 100644 index 0000000000..fcf2fda8b1 --- /dev/null +++ b/modules/runners/lambdas/runners/src/scale-runners/logger.ts @@ -0,0 +1,11 @@ +import { Logger } from 'tslog'; + +export const logger = new Logger({ + colorizePrettyLogs: false, + displayInstanceName: false, + maskAnyRegEx: ['--token [A-Z0-9]*'], + minLevel: process.env.LOG_LEVEL || 'info', + name: 'scale-up', + overwriteConsole: true, + type: process.env.LOG_TYPE || 'pretty', +}); diff --git a/modules/runners/lambdas/runners/src/scale-runners/modules.d.ts b/modules/runners/lambdas/runners/src/scale-runners/modules.d.ts index 0710eb74a5..6b11e1a626 100644 --- a/modules/runners/lambdas/runners/src/scale-runners/modules.d.ts +++ b/modules/runners/lambdas/runners/src/scale-runners/modules.d.ts @@ -1,15 +1,17 @@ declare namespace NodeJS { export interface ProcessEnv { + AWS_REGION: string; ENVIRONMENT: string; - SUBNET_IDS: string; GHES_URL: string; - SCALE_DOWN_CONFIG: string; - MINIMUM_RUNNING_TIME_IN_MINUTES: string; LAUNCH_TEMPLATE_NAME: string; - AWS_REGION: string; + LOG_LEVEL: 'silly' | 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'; + LOG_TYPE: 'json' | 'pretty' | 'hidden'; + MINIMUM_RUNNING_TIME_IN_MINUTES: string; PARAMETER_GITHUB_APP_CLIENT_ID_NAME: string; PARAMETER_GITHUB_APP_CLIENT_SECRET_NAME: string; PARAMETER_GITHUB_APP_ID_NAME: string; PARAMETER_GITHUB_APP_KEY_BASE64_NAME: string; + SCALE_DOWN_CONFIG: string; + SUBNET_IDS: string; } } diff --git a/modules/runners/lambdas/runners/src/scale-runners/runners.ts b/modules/runners/lambdas/runners/src/scale-runners/runners.ts index cef470dc76..9d152d9007 100644 --- a/modules/runners/lambdas/runners/src/scale-runners/runners.ts +++ b/modules/runners/lambdas/runners/src/scale-runners/runners.ts @@ -1,4 +1,7 @@ import { EC2, SSM } from 'aws-sdk'; +import { logger as rootLogger } from './logger'; + +const logger = rootLogger.getChildLogger(); export interface RunnerList { instanceId: string; @@ -72,16 +75,16 @@ export async function terminateRunner(instanceId: string): Promise { InstanceIds: [instanceId], }) .promise(); - console.info(`Runner ${instanceId} has been terminated.`); + logger.info(`Runner ${instanceId} has been terminated.`); } export async function createRunner(runnerParameters: RunnerInputParameters, launchTemplateName: string): Promise { - console.debug('Runner configuration: ' + JSON.stringify(runnerParameters)); + logger.debug('Runner configuration: ' + JSON.stringify(runnerParameters)); const ec2 = new EC2(); const runInstancesResponse = await ec2 .runInstances(getInstanceParams(launchTemplateName, runnerParameters)) .promise(); - console.info('Created instance(s): ', runInstancesResponse.Instances?.map((i) => i.InstanceId).join(',')); + logger.info('Created instance(s): ', runInstancesResponse.Instances?.map((i) => i.InstanceId).join(',')); const ssm = new SSM(); runInstancesResponse.Instances?.forEach(async (i: EC2.Instance) => { await ssm diff --git a/modules/runners/lambdas/runners/src/scale-runners/scale-down.ts b/modules/runners/lambdas/runners/src/scale-runners/scale-down.ts index 3bafa35182..6d81e43c9b 100644 --- a/modules/runners/lambdas/runners/src/scale-runners/scale-down.ts +++ b/modules/runners/lambdas/runners/src/scale-runners/scale-down.ts @@ -4,17 +4,20 @@ import { listEC2Runners, RunnerInfo, RunnerList, terminateRunner } from './runne import { getIdleRunnerCount, ScalingDownConfig } from './scale-down-config'; import { createOctoClient, createGithubAppAuth, createGithubInstallationAuth } from './gh-auth'; import { githubCache, GhRunners } from './cache'; +import { logger as rootLogger } from './logger'; + +const logger = rootLogger.getChildLogger(); async function getOrCreateOctokit(runner: RunnerInfo): Promise { const key = runner.owner; const cachedOctokit = githubCache.clients.get(key); if (cachedOctokit) { - console.debug(`[createGitHubClientForRunner] Cache hit for ${key}`); + logger.debug(`[createGitHubClientForRunner] Cache hit for ${key}`); return cachedOctokit; } - console.debug(`[createGitHubClientForRunner] Cache miss for ${key}`); + logger.debug(`[createGitHubClientForRunner] Cache miss for ${key}`); const ghesBaseUrl = process.env.GHES_URL; let ghesApiUrl = ''; if (ghesBaseUrl) { @@ -47,11 +50,11 @@ async function listGitHubRunners(runner: RunnerInfo): Promise { const key = runner.owner as string; const cachedRunners = githubCache.runners.get(key); if (cachedRunners) { - console.debug(`[listGithubRunners] Cache hit for ${key}`); + logger.debug(`[listGithubRunners] Cache hit for ${key}`); return cachedRunners; } - console.debug(`[listGithubRunners] Cache miss for ${key}`); + logger.debug(`[listGithubRunners] Cache miss for ${key}`); const client = await getOrCreateOctokit(runner); const runners = runner.type === 'Org' @@ -99,12 +102,12 @@ async function removeRunner(ec2runner: RunnerInfo, ghRunnerId: number): Promise< if (result.status == 204) { await terminateRunner(ec2runner.instanceId); - console.info(`AWS runner instance '${ec2runner.instanceId}' is terminated and GitHub runner is de-registered.`); + logger.info(`AWS runner instance '${ec2runner.instanceId}' is terminated and GitHub runner is de-registered.`); } else { - console.error(`Failed to de-register GitHub runner: ${result.status}`); + logger.error(`Failed to de-register GitHub runner: ${result.status}`); } } catch (e) { - console.info(`Runner '${ec2runner.instanceId}' cannot be de-registered, most likely the runner is active.`); + logger.info(`Runner '${ec2runner.instanceId}' cannot be de-registered, most likely the runner is active.`); } } @@ -117,7 +120,7 @@ async function evaluateAndRemoveRunners( for (const ownerTag of ownerTags) { const ec2RunnersFiltered = ec2Runners.filter((runner) => runner.owner === ownerTag); - console.info(`Found: '${ec2RunnersFiltered.length}' active GitHub runners with owner tag: '${ownerTag}'`); + logger.debug(`Found: '${ec2RunnersFiltered.length}' active GitHub runners with owner tag: '${ownerTag}'`); for (const ec2Runner of ec2RunnersFiltered) { const ghRunners = await listGitHubRunners(ec2Runner); const ghRunner = ghRunners.find((runner) => runner.name === ec2Runner.instanceId); @@ -125,18 +128,18 @@ async function evaluateAndRemoveRunners( if (runnerMinimumTimeExceeded(ec2Runner)) { if (idleCounter > 0) { idleCounter--; - console.info(`Runner '${ec2Runner.instanceId}' will kept idle.`); + logger.info(`Runner '${ec2Runner.instanceId}' will kept idle.`); } else { - console.info(`Runner '${ec2Runner.instanceId}' will be terminated.`); + logger.info(`Runner '${ec2Runner.instanceId}' will be terminated.`); await removeRunner(ec2Runner, ghRunner.id); } } } else { if (bootTimeExceeded(ec2Runner)) { - console.info(`Runner '${ec2Runner.instanceId}' is orphaned and will be removed.`); + logger.info(`Runner '${ec2Runner.instanceId}' is orphaned and will be removed.`); terminateOrphan(ec2Runner.instanceId); } else { - console.debug(`Runner ${ec2Runner.instanceId} has not yet booted.`); + logger.debug(`Runner ${ec2Runner.instanceId} has not yet booted.`); } } } @@ -147,7 +150,7 @@ async function terminateOrphan(instanceId: string): Promise { try { await terminateRunner(instanceId); } catch (e) { - console.debug(`Orphan runner '${instanceId}' cannot be removed.`); + logger.debug(`Orphan runner '${instanceId}' cannot be removed.`); } } @@ -192,19 +195,19 @@ export async function scaleDown(): Promise { // list and sort runners, newest first. This ensure we keep the newest runners longer. const ec2Runners = await listAndSortRunners(environment); const activeEc2RunnersCount = ec2Runners.length; - console.info(`Found: '${activeEc2RunnersCount}' active GitHub EC2 runner instances before clean-up.`); + logger.info(`Found: '${activeEc2RunnersCount}' active GitHub EC2 runner instances before clean-up.`); if (activeEc2RunnersCount === 0) { - console.debug(`No active runners found for environment: '${environment}'`); + logger.debug(`No active runners found for environment: '${environment}'`); return; } const legacyRunners = filterLegacyRunners(ec2Runners); - console.debug(JSON.stringify(legacyRunners)); + logger.debug(JSON.stringify(legacyRunners)); const runners = filterRunners(ec2Runners); await evaluateAndRemoveRunners(runners, scaleDownConfigs); await evaluateAndRemoveRunners(legacyRunners, scaleDownConfigs); const activeEc2RunnersCountAfter = (await listAndSortRunners(environment)).length; - console.info(`Found: '${activeEc2RunnersCountAfter}' active GitHub EC2 runners instances after clean-up.`); + logger.info(`Found: '${activeEc2RunnersCountAfter}' active GitHub EC2 runners instances after clean-up.`); } diff --git a/modules/runners/lambdas/runners/src/scale-runners/scale-up.ts b/modules/runners/lambdas/runners/src/scale-runners/scale-up.ts index 33c7a81a68..81da1e8794 100644 --- a/modules/runners/lambdas/runners/src/scale-runners/scale-up.ts +++ b/modules/runners/lambdas/runners/src/scale-runners/scale-up.ts @@ -2,6 +2,9 @@ import { listEC2Runners, createRunner, RunnerInputParameters } from './runners'; import { createOctoClient, createGithubAppAuth, createGithubInstallationAuth } from './gh-auth'; import yn from 'yn'; import { Octokit } from '@octokit/rest'; +import { logger as rootLogger } from './logger'; + +const logger = rootLogger.getChildLogger(); export interface ActionRequestMessage { id: number; @@ -11,7 +14,7 @@ export interface ActionRequestMessage { installationId: number; } -export const scaleUp = async (eventSource: string, payload: ActionRequestMessage): Promise => { +export async function scaleUp(eventSource: string, payload: ActionRequestMessage): Promise { if (eventSource !== 'aws:sqs') throw Error('Cannot handle non-SQS events!'); const enableOrgLevel = yn(process.env.ENABLE_ORGANIZATION_RUNNERS, { default: true }); const maximumRunners = parseInt(process.env.RUNNERS_MAXIMUM_COUNT || '3'); @@ -57,7 +60,7 @@ export const scaleUp = async (eventSource: string, payload: ActionRequestMessage runnerType, runnerOwner, }); - console.info(`${runnerType} ${runnerOwner} has ${currentRunners.length}/${maximumRunners} runners`); + logger.info(`${runnerType} ${runnerOwner} has ${currentRunners.length}/${maximumRunners} runners`); if (currentRunners.length < maximumRunners) { console.info(`Attempting to launch a new runner`); @@ -84,10 +87,10 @@ export const scaleUp = async (eventSource: string, payload: ActionRequestMessage runnerType, }); } else { - console.warn('No runner created: maximum number of runners reached.'); + logger.info('No runner will be created, maximum number of runners reached.'); } } -}; +} async function getJobStatus(githubInstallationClient: Octokit, payload: ActionRequestMessage): Promise { let isQueued = false; @@ -108,7 +111,9 @@ async function getJobStatus(githubInstallationClient: Octokit, payload: ActionRe } else { throw Error(`Event ${payload.eventType} is not supported`); } - console.info(`Job ${payload.id} is ${isQueued ? 'queued' : 'not queued'}`); + if (!isQueued) { + logger.info(`Job ${payload.id} is not queued`); + } return isQueued; } @@ -116,14 +121,14 @@ export async function createRunnerLoop(runnerParameters: RunnerInputParameters): const launchTemplateNames = process.env.LAUNCH_TEMPLATE_NAME?.split(',') as string[]; let launched = false; for (let i = 0; i < launchTemplateNames.length; i++) { - console.info(`Attempt '${i}' to launch instance using ${launchTemplateNames[i]}.`); + logger.info(`Attempt '${i}' to launch instance using ${launchTemplateNames[i]}.`); try { await createRunner(runnerParameters, launchTemplateNames[i]); launched = true; break; } catch (error) { - console.warn(`Attempt '${i}' to launch instance using ${launchTemplateNames[i]} FAILED.`); - console.error(error); + logger.debug(`Attempt '${i}' to launch instance using ${launchTemplateNames[i]} FAILED.`); + logger.error(error); } } if (launched == false) { diff --git a/modules/runners/lambdas/runners/tsconfig.json b/modules/runners/lambdas/runners/tsconfig.json index 71f5cd6a47..764f2f6ae0 100644 --- a/modules/runners/lambdas/runners/tsconfig.json +++ b/modules/runners/lambdas/runners/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { /* Basic Options */ - "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */, + "target": "es2019" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */, "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, "outDir": "build", "lib": [ @@ -57,7 +57,8 @@ /* Experimental Options */ "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */, - "resolveJsonModule": true + "resolveJsonModule": true, + "sourceMap": true }, "include": [ "src/**/*" diff --git a/modules/runners/lambdas/runners/yarn.lock b/modules/runners/lambdas/runners/yarn.lock index ab5c75535c..66d7aee052 100644 --- a/modules/runners/lambdas/runners/yarn.lock +++ b/modules/runners/lambdas/runners/yarn.lock @@ -4025,6 +4025,14 @@ source-map-support@^0.5.12, source-map-support@^0.5.17, source-map-support@^0.5. buffer-from "^1.0.0" source-map "^0.6.0" +source-map-support@^0.5.19: + version "0.5.20" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" + integrity sha1-EhZgifj15ejFaSazd2Mzkt0stsk= + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map@^0.5.0: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -4302,6 +4310,13 @@ tslib@^2.3.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== +tslog@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.2.2.tgz#5bbaa1fab685c4273e59b38064227321a69a0694" + integrity sha1-W7qh+raFxCc+WbOAZCJzIaaaBpQ= + dependencies: + source-map-support "^0.5.19" + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" diff --git a/modules/runners/scale-down.tf b/modules/runners/scale-down.tf index 341d7d6e2d..d3cb5beb37 100644 --- a/modules/runners/scale-down.tf +++ b/modules/runners/scale-down.tf @@ -6,21 +6,24 @@ resource "aws_lambda_function" "scale_down" { source_code_hash = var.lambda_s3_bucket == null ? filebase64sha256(local.lambda_zip) : null function_name = "${var.environment}-scale-down" role = aws_iam_role.scale_down.arn - handler = "index.scaleDown" + handler = "index.scaleDownHandler" runtime = "nodejs14.x" timeout = var.lambda_timeout_scale_down tags = local.tags + memory_size = 512 environment { variables = { ENVIRONMENT = var.environment - MINIMUM_RUNNING_TIME_IN_MINUTES = var.minimum_running_time_in_minutes - RUNNER_BOOT_TIME_IN_MINUTES = var.runner_boot_time_in_minutes - SCALE_DOWN_CONFIG = jsonencode(var.idle_config) GHES_URL = var.ghes_url + LOG_LEVEL = var.log_level + LOG_TYPE = var.log_type + MINIMUM_RUNNING_TIME_IN_MINUTES = var.minimum_running_time_in_minutes NODE_TLS_REJECT_UNAUTHORIZED = var.ghes_url != null && !var.ghes_ssl_verify ? 0 : 1 PARAMETER_GITHUB_APP_ID_NAME = var.github_app_parameters.id.name PARAMETER_GITHUB_APP_KEY_BASE64_NAME = var.github_app_parameters.key_base64.name + RUNNER_BOOT_TIME_IN_MINUTES = var.runner_boot_time_in_minutes + SCALE_DOWN_CONFIG = jsonencode(var.idle_config) } } diff --git a/modules/runners/scale-up.tf b/modules/runners/scale-up.tf index f67c9661b2..cb61dde66a 100644 --- a/modules/runners/scale-up.tf +++ b/modules/runners/scale-up.tf @@ -6,10 +6,11 @@ resource "aws_lambda_function" "scale_up" { source_code_hash = var.lambda_s3_bucket == null ? filebase64sha256(local.lambda_zip) : null function_name = "${var.environment}-scale-up" role = aws_iam_role.scale_up.arn - handler = "index.scaleUp" + handler = "index.scaleUpHandler" runtime = "nodejs14.x" timeout = var.lambda_timeout_scale_up reserved_concurrent_executions = 1 + memory_size = 512 tags = local.tags environment { @@ -17,14 +18,16 @@ resource "aws_lambda_function" "scale_up" { ENABLE_ORGANIZATION_RUNNERS = var.enable_organization_runners ENVIRONMENT = var.environment GHES_URL = var.ghes_url + LAUNCH_TEMPLATE_NAME = join(",", [for template in aws_launch_template.runner : template.name]) + LOG_LEVEL = var.log_level + LOG_TYPE = var.log_type NODE_TLS_REJECT_UNAUTHORIZED = var.ghes_url != null && !var.ghes_ssl_verify ? 0 : 1 + PARAMETER_GITHUB_APP_ID_NAME = var.github_app_parameters.id.name + PARAMETER_GITHUB_APP_KEY_BASE64_NAME = var.github_app_parameters.key_base64.name RUNNER_EXTRA_LABELS = var.runner_extra_labels RUNNER_GROUP_NAME = var.runner_group_name RUNNERS_MAXIMUM_COUNT = var.runners_maximum_count - LAUNCH_TEMPLATE_NAME = join(",", [for template in aws_launch_template.runner : template.name]) SUBNET_IDS = join(",", var.subnet_ids) - PARAMETER_GITHUB_APP_ID_NAME = var.github_app_parameters.id.name - PARAMETER_GITHUB_APP_KEY_BASE64_NAME = var.github_app_parameters.key_base64.name } } diff --git a/modules/runners/variables.tf b/modules/runners/variables.tf index 3a7b27f27e..f8c444c856 100644 --- a/modules/runners/variables.tf +++ b/modules/runners/variables.tf @@ -369,8 +369,40 @@ variable "egress_rules" { }] } +variable "log_type" { + description = "Logging format for lambda logging. Valid values are 'json', 'pretty', 'hidden'. " + type = string + default = "pretty" + validation { + condition = anytrue([ + var.log_type == "json", + var.log_type == "pretty", + var.log_type == "hidden", + ]) + error_message = "`log_type` value not valid. Valid values are 'json', 'pretty', 'hidden'." + } +} + +variable "log_level" { + description = "Logging level for lambda logging. Valid values are 'silly', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'." + type = string + default = "info" + validation { + condition = anytrue([ + var.log_level == "silly", + var.log_level == "trace", + var.log_level == "debug", + var.log_level == "info", + var.log_level == "warn", + var.log_level == "error", + var.log_level == "fatal", + ]) + error_message = "`log_level` value not valid. Valid values are 'silly', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'." + } +} + variable "runner_ec2_tags" { description = "Map of tags that will be added to the launch template instance tag specificatons." type = map(string) default = {} -} \ No newline at end of file +} diff --git a/modules/webhook/README.md b/modules/webhook/README.md index 26480f8f12..ad9beca0b1 100644 --- a/modules/webhook/README.md +++ b/modules/webhook/README.md @@ -38,66 +38,66 @@ yarn run dist | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 0.14.1 | -| [aws](#requirement\_aws) | >= 3.38 | +| terraform | >= 0.14.1 | +| aws | >= 3.38 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 3.38 | +| aws | >= 3.38 | ## Modules -No modules. +No Modules. ## Resources -| Name | Type | -|------|------| -| [aws_apigatewayv2_api.webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_api) | resource | -| [aws_apigatewayv2_integration.webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_integration) | resource | -| [aws_apigatewayv2_route.webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_route) | resource | -| [aws_apigatewayv2_stage.webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_stage) | resource | -| [aws_cloudwatch_log_group.webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | -| [aws_iam_role.webhook_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | -| [aws_iam_role_policy.webhook_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | -| [aws_iam_role_policy.webhook_sqs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | -| [aws_iam_role_policy.webhook_ssm](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | -| [aws_lambda_function.webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource | -| [aws_lambda_permission.webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource | -| [aws_iam_policy_document.lambda_assume_role_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| Name | +|------| +| [aws_apigatewayv2_api](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_api) | +| [aws_apigatewayv2_integration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_integration) | +| [aws_apigatewayv2_route](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_route) | +| [aws_apigatewayv2_stage](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_stage) | +| [aws_cloudwatch_log_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | +| [aws_iam_policy_document](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | +| [aws_iam_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | +| [aws_iam_role_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | +| [aws_lambda_function](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | +| [aws_lambda_permission](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [aws\_region](#input\_aws\_region) | AWS region. | `string` | n/a | yes | -| [disable\_check\_wokflow\_job\_labels](#input\_disable\_check\_wokflow\_job\_labels) | Disable the the check of workflow labels. | `bool` | `false` | no | -| [environment](#input\_environment) | A name that identifies the environment, used as prefix and for tagging. | `string` | n/a | yes | -| [github\_app\_webhook\_secret\_arn](#input\_github\_app\_webhook\_secret\_arn) | n/a | `string` | n/a | yes | -| [kms\_key\_arn](#input\_kms\_key\_arn) | Optional CMK Key ARN to be used for Parameter Store. | `string` | `null` | no | -| [lambda\_s3\_bucket](#input\_lambda\_s3\_bucket) | S3 bucket from which to specify lambda functions. This is an alternative to providing local files directly. | `any` | `null` | no | -| [lambda\_timeout](#input\_lambda\_timeout) | Time out of the lambda in seconds. | `number` | `10` | no | -| [lambda\_zip](#input\_lambda\_zip) | File location of the lambda zip file. | `string` | `null` | no | -| [logging\_retention\_in\_days](#input\_logging\_retention\_in\_days) | Specifies the number of days you want to retain log events for the lambda log group. Possible values are: 0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653. | `number` | `7` | no | -| [repository\_white\_list](#input\_repository\_white\_list) | List of repositories allowed to use the github app | `list(string)` | `[]` | no | -| [role\_path](#input\_role\_path) | The path that will be added to the role; if not set, the environment name will be used. | `string` | `null` | no | -| [role\_permissions\_boundary](#input\_role\_permissions\_boundary) | Permissions boundary that will be added to the created role for the lambda. | `string` | `null` | no | -| [runner\_extra\_labels](#input\_runner\_extra\_labels) | Extra labels for the runners (GitHub). Separate each label by a comma | `string` | `""` | no | -| [sqs\_build\_queue](#input\_sqs\_build\_queue) | SQS queue to publish accepted build events. |
object({
id = string
arn = string
})
| n/a | yes | -| [tags](#input\_tags) | Map of tags that will be added to created resources. By default resources will be tagged with name and environment. | `map(string)` | `{}` | no | -| [webhook\_lambda\_s3\_key](#input\_webhook\_lambda\_s3\_key) | S3 key for webhook lambda function. Required if using S3 bucket to specify lambdas. | `any` | `null` | no | -| [webhook\_lambda\_s3\_object\_version](#input\_webhook\_lambda\_s3\_object\_version) | S3 object version for webhook lambda function. Useful if S3 versioning is enabled on source bucket. | `any` | `null` | no | +| aws\_region | AWS region. | `string` | n/a | yes | +| disable\_check\_wokflow\_job\_labels | Disable the the check of workflow labels. | `bool` | `false` | no | +| environment | A name that identifies the environment, used as prefix and for tagging. | `string` | n/a | yes | +| github\_app\_webhook\_secret\_arn | n/a | `string` | n/a | yes | +| kms\_key\_arn | Optional CMK Key ARN to be used for Parameter Store. | `string` | `null` | no | +| lambda\_s3\_bucket | S3 bucket from which to specify lambda functions. This is an alternative to providing local files directly. | `any` | `null` | no | +| lambda\_timeout | Time out of the lambda in seconds. | `number` | `10` | no | +| lambda\_zip | File location of the lambda zip file. | `string` | `null` | no | +| log\_level | Logging level for lambda logging. Valid values are 'silly', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'. | `string` | `"info"` | no | +| log\_type | Logging format for lambda logging. Valid values are 'json', 'pretty', 'hidden'. | `string` | `"pretty"` | no | +| logging\_retention\_in\_days | Specifies the number of days you want to retain log events for the lambda log group. Possible values are: 0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653. | `number` | `7` | no | +| repository\_white\_list | List of repositories allowed to use the github app | `list(string)` | `[]` | no | +| role\_path | The path that will be added to the role; if not set, the environment name will be used. | `string` | `null` | no | +| role\_permissions\_boundary | Permissions boundary that will be added to the created role for the lambda. | `string` | `null` | no | +| runner\_extra\_labels | Extra labels for the runners (GitHub). Separate each label by a comma | `string` | `""` | no | +| sqs\_build\_queue | SQS queue to publish accepted build events. |
object({
id = string
arn = string
})
| n/a | yes | +| tags | Map of tags that will be added to created resources. By default resources will be tagged with name and environment. | `map(string)` | `{}` | no | +| webhook\_lambda\_s3\_key | S3 key for webhook lambda function. Required if using S3 bucket to specify lambdas. | `any` | `null` | no | +| webhook\_lambda\_s3\_object\_version | S3 object version for webhook lambda function. Useful if S3 versioning is enabled on source bucket. | `any` | `null` | no | ## Outputs | Name | Description | |------|-------------| -| [endpoint\_relative\_path](#output\_endpoint\_relative\_path) | n/a | -| [gateway](#output\_gateway) | n/a | -| [lambda](#output\_lambda) | n/a | -| [role](#output\_role) | n/a | +| endpoint\_relative\_path | n/a | +| gateway | n/a | +| lambda | n/a | +| role | n/a | ## Philips Forest diff --git a/modules/webhook/lambdas/webhook/package.json b/modules/webhook/lambdas/webhook/package.json index 4f338812b5..c74efc427d 100644 --- a/modules/webhook/lambdas/webhook/package.json +++ b/modules/webhook/lambdas/webhook/package.json @@ -40,6 +40,7 @@ "@aws-sdk/client-ssm": "^3.39.0", "@octokit/rest": "^18.12.0", "@octokit/webhooks": "^9.17.0", - "aws-lambda": "^1.0.6" + "aws-lambda": "^1.0.6", + "tslog": "^3.2.2" } } \ No newline at end of file diff --git a/modules/webhook/lambdas/webhook/src/lambda.ts b/modules/webhook/lambdas/webhook/src/lambda.ts index 3c4599222e..94e10d8319 100644 --- a/modules/webhook/lambdas/webhook/src/lambda.ts +++ b/modules/webhook/lambdas/webhook/src/lambda.ts @@ -1,8 +1,10 @@ import { handle } from './webhook/handler'; import { APIGatewayEvent, Context, Callback } from 'aws-lambda'; +import { logger } from './webhook/logger'; -// eslint-disable-next-line @typescript-eslint/no-explicit-any export const githubWebhook = async (event: APIGatewayEvent, context: Context, callback: Callback): Promise => { + logger.setSettings({ requestId: context.awsRequestId }); + logger.debug(JSON.stringify(event)); try { const statusCode = await handle(event.headers, event.body as string); callback(null, { diff --git a/modules/webhook/lambdas/webhook/src/webhook/handler.test.ts b/modules/webhook/lambdas/webhook/src/webhook/handler.test.ts index 401c53d8fc..237a2da875 100644 --- a/modules/webhook/lambdas/webhook/src/webhook/handler.test.ts +++ b/modules/webhook/lambdas/webhook/src/webhook/handler.test.ts @@ -26,6 +26,7 @@ describe('handler', () => { originalError = console.error; console.error = jest.fn(); jest.clearAllMocks(); + jest.resetAllMocks(); const mockedGet = mocked(getParameterValue); mockedGet.mockResolvedValueOnce(GITHUB_APP_WEBHOOK_SECRET); diff --git a/modules/webhook/lambdas/webhook/src/webhook/handler.ts b/modules/webhook/lambdas/webhook/src/webhook/handler.ts index 5150da7e3d..f70aaca989 100644 --- a/modules/webhook/lambdas/webhook/src/webhook/handler.ts +++ b/modules/webhook/lambdas/webhook/src/webhook/handler.ts @@ -3,8 +3,11 @@ import { Webhooks } from '@octokit/webhooks'; import { sendActionRequest } from '../sqs'; import { CheckRunEvent, WorkflowJobEvent } from '@octokit/webhooks-types'; import { getParameterValue } from '../ssm'; +import { logger as rootLogger } from './logger'; -export const handle = async (headers: IncomingHttpHeaders, body: string): Promise => { +const logger = rootLogger.getChildLogger(); + +export async function handle(headers: IncomingHttpHeaders, body: string): Promise { // ensure header keys lower case since github headers can contain capitals. for (const key in headers) { headers[key.toLowerCase()] = headers[key]; @@ -17,7 +20,7 @@ export const handle = async (headers: IncomingHttpHeaders, body: string): Promis return status; } const payload = JSON.parse(body); - console.info(`Received Github event ${githubEvent} from ${payload.repository.full_name}`); + logger.info(`Received Github event ${githubEvent} from ${payload.repository.full_name}`); if (isRepoNotAllowed(payload.repository.full_name)) { console.error(`Received event from unauthorized repository ${payload.repository.full_name}`); @@ -29,15 +32,15 @@ export const handle = async (headers: IncomingHttpHeaders, body: string): Promis } else if (githubEvent == 'check_run') { status = await handleCheckRun(payload as CheckRunEvent, githubEvent); } else { - console.warn(`Ignoring unsupported event ${githubEvent}`); + logger.warn(`Ignoring unsupported event ${githubEvent}`); } return status; -}; +} async function verifySignature(githubEvent: string, signature: string, body: string): Promise { if (!signature) { - console.error("Github event doesn't have signature. This webhook requires a secret to be configured."); + logger.error("Github event doesn't have signature. This webhook requires a secret to be configured."); return 500; } @@ -47,7 +50,7 @@ async function verifySignature(githubEvent: string, signature: string, body: str secret: secret, }); if (!(await webhooks.verify(body, signature))) { - console.error('Unable to verify signature!'); + logger.error('Unable to verify signature!'); return 401; } return 200; @@ -57,7 +60,7 @@ async function handleWorkflowJob(body: WorkflowJobEvent, githubEvent: string): P const disableCheckWorkflowJobLabelsEnv = process.env.DISABLE_CHECK_WORKFLOW_JOB_LABELS || 'false'; const disableCheckWorkflowJobLabels = JSON.parse(disableCheckWorkflowJobLabelsEnv) as boolean; if (!disableCheckWorkflowJobLabels && !canRunJob(body)) { - console.error(`Received event contains runner labels '${body.workflow_job.labels}' that are not accepted.`); + logger.error(`Received event contains runner labels '${body.workflow_job.labels}' that are not accepted.`); return 403; } @@ -119,7 +122,7 @@ function canRunJob(job: WorkflowJobEvent): boolean { const runnerMatch = customWorkflowJobLabels.every((l) => runnerLabels.has(l)); - console.debug( + logger.debug( `Received workflow job event with labels: '${JSON.stringify(job.workflow_job.labels)}'. The event does ${ runnerMatch ? '' : 'NOT ' }match the configured labels: '${Array.from(runnerLabels).join(',')}'`, diff --git a/modules/webhook/lambdas/webhook/src/webhook/logger.ts b/modules/webhook/lambdas/webhook/src/webhook/logger.ts new file mode 100644 index 0000000000..b77bddf597 --- /dev/null +++ b/modules/webhook/lambdas/webhook/src/webhook/logger.ts @@ -0,0 +1,10 @@ +import { Logger } from 'tslog'; + +export const logger = new Logger({ + colorizePrettyLogs: false, + displayInstanceName: false, + minLevel: process.env.LOG_LEVEL || 'info', + name: 'webhook', + overwriteConsole: true, + type: process.env.LOG_TYPE || 'pretty', +}); diff --git a/modules/webhook/lambdas/webhook/src/webhook/modules.d.ts b/modules/webhook/lambdas/webhook/src/webhook/modules.d.ts new file mode 100644 index 0000000000..d6972fd986 --- /dev/null +++ b/modules/webhook/lambdas/webhook/src/webhook/modules.d.ts @@ -0,0 +1,9 @@ +declare namespace NodeJS { + export interface ProcessEnv { + ENVIRONMENT: string; + LOG_LEVEL: 'silly' | 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'; + LOG_TYPE: 'json' | 'pretty' | 'hidden'; + REPOSITORY_WHITE_LIST: string; + RUNNER_LABELS: string; + } +} diff --git a/modules/webhook/lambdas/webhook/tsconfig.json b/modules/webhook/lambdas/webhook/tsconfig.json index 64a2b54f25..764f2f6ae0 100644 --- a/modules/webhook/lambdas/webhook/tsconfig.json +++ b/modules/webhook/lambdas/webhook/tsconfig.json @@ -1,10 +1,13 @@ { "compilerOptions": { /* Basic Options */ - "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */, + "target": "es2019" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */, "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, "outDir": "build", - "lib": ["es2020", "DOM"] /* Specify library files to be included in the compilation. */, + "lib": [ + "es2020", + "DOM" + ] /* Specify library files to be included in the compilation. */, "allowJs": true /* Allow javascript files to be compiled. */, // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ @@ -54,7 +57,10 @@ /* Experimental Options */ "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */, - "resolveJsonModule": true + "resolveJsonModule": true, + "sourceMap": true }, - "include": ["src/**/*"] + "include": [ + "src/**/*" + ] } diff --git a/modules/webhook/lambdas/webhook/yarn.lock b/modules/webhook/lambdas/webhook/yarn.lock index cde708325d..4c10949b7b 100644 --- a/modules/webhook/lambdas/webhook/yarn.lock +++ b/modules/webhook/lambdas/webhook/yarn.lock @@ -4156,10 +4156,10 @@ source-map-support@^0.5.12, source-map-support@^0.5.17: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-support@^0.5.6: +source-map-support@^0.5.19, source-map-support@^0.5.6: version "0.5.20" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" - integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== + integrity sha1-EhZgifj15ejFaSazd2Mzkt0stsk= dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -4444,6 +4444,13 @@ tslib@^2.3.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== +tslog@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.2.2.tgz#5bbaa1fab685c4273e59b38064227321a69a0694" + integrity sha1-W7qh+raFxCc+WbOAZCJzIaaaBpQ= + dependencies: + source-map-support "^0.5.19" + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" diff --git a/modules/webhook/variables.tf b/modules/webhook/variables.tf index 29b989c04f..5a767fc1b8 100644 --- a/modules/webhook/variables.tf +++ b/modules/webhook/variables.tf @@ -89,8 +89,40 @@ variable "runner_extra_labels" { default = "" } +variable "log_type" { + description = "Logging format for lambda logging. Valid values are 'json', 'pretty', 'hidden'. " + type = string + default = "pretty" + validation { + condition = anytrue([ + var.log_type == "json", + var.log_type == "pretty", + var.log_type == "hidden", + ]) + error_message = "`log_type` value not valid. Valid values are 'json', 'pretty', 'hidden'." + } +} + +variable "log_level" { + description = "Logging level for lambda logging. Valid values are 'silly', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'." + type = string + default = "info" + validation { + condition = anytrue([ + var.log_level == "silly", + var.log_level == "trace", + var.log_level == "debug", + var.log_level == "info", + var.log_level == "warn", + var.log_level == "error", + var.log_level == "fatal", + ]) + error_message = "`log_level` value not valid. Valid values are 'silly', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'." + } +} + variable "disable_check_wokflow_job_labels" { description = "Disable the the check of workflow labels." type = bool default = false -} \ No newline at end of file +} diff --git a/modules/webhook/webhook.tf b/modules/webhook/webhook.tf index 73880aac8f..1115b985f1 100644 --- a/modules/webhook/webhook.tf +++ b/modules/webhook/webhook.tf @@ -14,9 +14,11 @@ resource "aws_lambda_function" "webhook" { variables = { DISABLE_CHECK_WORKFLOW_JOB_LABELS = var.disable_check_wokflow_job_labels ENVIRONMENT = var.environment - SQS_URL_WEBHOOK = var.sqs_build_queue.id + LOG_LEVEL = var.log_level + LOG_TYPE = var.log_type REPOSITORY_WHITE_LIST = jsonencode(var.repository_white_list) RUNNER_LABELS = jsonencode(split(",", var.runner_extra_labels)) + SQS_URL_WEBHOOK = var.sqs_build_queue.id } } diff --git a/modules/webhook/yarn.lock b/modules/webhook/yarn.lock new file mode 100644 index 0000000000..7480029b41 --- /dev/null +++ b/modules/webhook/yarn.lock @@ -0,0 +1,28 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha1-KxRqb9cugLT1XSVfNe1Zo6mkG9U= + +source-map-support@^0.5.19: + version "0.5.20" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" + integrity sha1-EhZgifj15ejFaSazd2Mzkt0stsk= + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha1-dHIq8y6WFOnCh6jQu95IteLxomM= + +tslog@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.2.2.tgz#5bbaa1fab685c4273e59b38064227321a69a0694" + integrity sha1-W7qh+raFxCc+WbOAZCJzIaaaBpQ= + dependencies: + source-map-support "^0.5.19" diff --git a/variables.tf b/variables.tf index 37a004dc14..7bb98440cc 100644 --- a/variables.tf +++ b/variables.tf @@ -401,6 +401,38 @@ variable "runner_egress_rules" { }] } +variable "log_type" { + description = "Logging format for lambda logging. Valid values are 'json', 'pretty', 'hidden'. " + type = string + default = "pretty" + validation { + condition = anytrue([ + var.log_type == "json", + var.log_type == "pretty", + var.log_type == "hidden", + ]) + error_message = "`log_type` value not valid. Valid values are 'json', 'pretty', 'hidden'." + } +} + +variable "log_level" { + description = "Logging level for lambda logging. Valid values are 'silly', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'." + type = string + default = "info" + validation { + condition = anytrue([ + var.log_level == "silly", + var.log_level == "trace", + var.log_level == "debug", + var.log_level == "info", + var.log_level == "warn", + var.log_level == "error", + var.log_level == "fatal", + ]) + error_message = "`log_level` value not valid. Valid values are 'silly', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'." + } +} + variable "disable_check_wokflow_job_labels" { description = "Disable the the check of workflow labels for received workflow job events." type = bool