@cloudsnorkel/cdk-github-runners 0.9.4 → 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/.gitattributes +5 -3
  2. package/.jsii +332 -284
  3. package/API.md +55 -19
  4. package/README.md +135 -65
  5. package/assets/{providers/image-builders → image-builders}/aws-image-builder/delete-ami.lambda/index.js +2 -2
  6. package/assets/{providers/image-builders → image-builders}/aws-image-builder/filter-failed-builds.lambda/index.js +1 -1
  7. package/assets/image-builders/aws-image-builder/reaper.lambda/index.js +163 -0
  8. package/assets/{providers/image-builders → image-builders}/aws-image-builder/versioner.lambda/index.js +2 -2
  9. package/cdk.json +10 -0
  10. package/lib/access.js +1 -1
  11. package/lib/image-builders/api.js +47 -0
  12. package/lib/{providers/image-builders → image-builders}/aws-image-builder/ami.d.ts +2 -3
  13. package/lib/image-builders/aws-image-builder/ami.js +93 -0
  14. package/lib/{providers/image-builders → image-builders}/aws-image-builder/builder.d.ts +10 -3
  15. package/lib/image-builders/aws-image-builder/builder.js +568 -0
  16. package/lib/image-builders/aws-image-builder/common.js +46 -0
  17. package/lib/{providers/image-builders → image-builders}/aws-image-builder/container.d.ts +1 -1
  18. package/lib/image-builders/aws-image-builder/container.js +63 -0
  19. package/lib/{providers/image-builders → image-builders}/aws-image-builder/delete-ami-function.d.ts +1 -1
  20. package/lib/image-builders/aws-image-builder/delete-ami-function.js +23 -0
  21. package/lib/image-builders/aws-image-builder/delete-ami.lambda.js +87 -0
  22. package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/ami.d.ts +4 -4
  23. package/lib/image-builders/aws-image-builder/deprecated/ami.js +240 -0
  24. package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/common.d.ts +1 -1
  25. package/lib/image-builders/aws-image-builder/deprecated/common.js +144 -0
  26. package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/container.d.ts +3 -3
  27. package/lib/image-builders/aws-image-builder/deprecated/container.js +222 -0
  28. package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/index.js +1 -1
  29. package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/linux-components.d.ts +1 -1
  30. package/lib/image-builders/aws-image-builder/deprecated/linux-components.js +172 -0
  31. package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/windows-components.d.ts +1 -1
  32. package/lib/image-builders/aws-image-builder/deprecated/windows-components.js +126 -0
  33. package/lib/{providers/image-builders → image-builders}/aws-image-builder/filter-failed-builds-function.d.ts +1 -1
  34. package/lib/image-builders/aws-image-builder/filter-failed-builds-function.js +23 -0
  35. package/lib/image-builders/aws-image-builder/filter-failed-builds.lambda.js +18 -0
  36. package/lib/{providers/image-builders → image-builders}/aws-image-builder/index.js +1 -1
  37. package/lib/image-builders/aws-image-builder/reaper-function.d.ts +13 -0
  38. package/lib/image-builders/aws-image-builder/reaper-function.js +23 -0
  39. package/lib/image-builders/aws-image-builder/reaper.lambda.d.ts +1 -0
  40. package/lib/image-builders/aws-image-builder/reaper.lambda.js +149 -0
  41. package/lib/{providers/image-builders → image-builders}/aws-image-builder/versioner-function.d.ts +1 -1
  42. package/lib/image-builders/aws-image-builder/versioner-function.js +23 -0
  43. package/lib/image-builders/aws-image-builder/versioner.lambda.js +96 -0
  44. package/lib/{providers/image-builders → image-builders}/codebuild-deprecated.d.ts +5 -5
  45. package/lib/image-builders/codebuild-deprecated.js +373 -0
  46. package/lib/{providers/image-builders → image-builders}/codebuild.d.ts +2 -2
  47. package/lib/image-builders/codebuild.js +289 -0
  48. package/lib/{providers/image-builders → image-builders}/common.d.ts +6 -4
  49. package/lib/{providers/image-builders → image-builders}/common.js +1 -1
  50. package/lib/{providers/image-builders → image-builders}/components.d.ts +8 -2
  51. package/lib/image-builders/components.js +568 -0
  52. package/lib/{providers/image-builders → image-builders}/index.js +1 -1
  53. package/lib/{providers/image-builders → image-builders}/static.d.ts +1 -1
  54. package/lib/image-builders/static.js +58 -0
  55. package/lib/providers/codebuild.d.ts +1 -1
  56. package/lib/providers/codebuild.js +4 -4
  57. package/lib/providers/common.js +3 -3
  58. package/lib/providers/ec2.d.ts +2 -2
  59. package/lib/providers/ec2.js +4 -4
  60. package/lib/providers/ecs.d.ts +1 -1
  61. package/lib/providers/ecs.js +3 -3
  62. package/lib/providers/fargate.d.ts +1 -1
  63. package/lib/providers/fargate.js +4 -4
  64. package/lib/providers/index.d.ts +1 -1
  65. package/lib/providers/index.js +2 -2
  66. package/lib/providers/lambda.d.ts +1 -1
  67. package/lib/providers/lambda.js +4 -4
  68. package/lib/runner.d.ts +3 -3
  69. package/lib/runner.js +5 -5
  70. package/lib/secrets.js +1 -1
  71. package/package.json +12 -10
  72. package/lib/providers/image-builders/api.js +0 -47
  73. package/lib/providers/image-builders/aws-image-builder/ami.js +0 -81
  74. package/lib/providers/image-builders/aws-image-builder/builder.js +0 -520
  75. package/lib/providers/image-builders/aws-image-builder/common.js +0 -46
  76. package/lib/providers/image-builders/aws-image-builder/container.js +0 -63
  77. package/lib/providers/image-builders/aws-image-builder/delete-ami-function.js +0 -23
  78. package/lib/providers/image-builders/aws-image-builder/delete-ami.lambda.js +0 -87
  79. package/lib/providers/image-builders/aws-image-builder/deprecated/ami.js +0 -240
  80. package/lib/providers/image-builders/aws-image-builder/deprecated/common.js +0 -144
  81. package/lib/providers/image-builders/aws-image-builder/deprecated/container.js +0 -222
  82. package/lib/providers/image-builders/aws-image-builder/deprecated/linux-components.js +0 -172
  83. package/lib/providers/image-builders/aws-image-builder/deprecated/windows-components.js +0 -129
  84. package/lib/providers/image-builders/aws-image-builder/filter-failed-builds-function.js +0 -23
  85. package/lib/providers/image-builders/aws-image-builder/filter-failed-builds.lambda.js +0 -18
  86. package/lib/providers/image-builders/aws-image-builder/versioner-function.js +0 -23
  87. package/lib/providers/image-builders/aws-image-builder/versioner.lambda.js +0 -96
  88. package/lib/providers/image-builders/codebuild-deprecated.js +0 -373
  89. package/lib/providers/image-builders/codebuild.js +0 -287
  90. package/lib/providers/image-builders/components.js +0 -535
  91. package/lib/providers/image-builders/static.js +0 -58
  92. /package/lib/{providers/image-builders → image-builders}/api.d.ts +0 -0
  93. /package/lib/{providers/image-builders → image-builders}/aws-image-builder/common.d.ts +0 -0
  94. /package/lib/{providers/image-builders → image-builders}/aws-image-builder/delete-ami.lambda.d.ts +0 -0
  95. /package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/index.d.ts +0 -0
  96. /package/lib/{providers/image-builders → image-builders}/aws-image-builder/filter-failed-builds.lambda.d.ts +0 -0
  97. /package/lib/{providers/image-builders → image-builders}/aws-image-builder/index.d.ts +0 -0
  98. /package/lib/{providers/image-builders → image-builders}/aws-image-builder/versioner.lambda.d.ts +0 -0
  99. /package/lib/{providers/image-builders → image-builders}/index.d.ts +0 -0
package/API.md CHANGED
@@ -29,8 +29,8 @@ builder.addComponent(new ImageBuilderComponent(scope, id, {
29
29
  'apt-get install p7zip',
30
30
  ],
31
31
  }));
32
- new Ec2Runner(this, 'EC2 provider', {
33
- label: 'custom-ec2',
32
+ new Ec2RunnerProvider(this, 'EC2 provider', {
33
+ labels: ['custom-ec2'],
34
34
  amiBuilder: builder,
35
35
  });
36
36
  ```
@@ -240,13 +240,13 @@ For example, to set a specific runner version, rebuild the image every 2 weeks,
240
240
 
241
241
  ```
242
242
  const builder = new CodeBuildImageBuilder(this, 'Builder', {
243
- dockerfilePath: FargateProvider.LINUX_X64_DOCKERFILE_PATH,
243
+ dockerfilePath: FargateRunnerProvider.LINUX_X64_DOCKERFILE_PATH,
244
244
  runnerVersion: RunnerVersion.specific('2.293.0'),
245
245
  rebuildInterval: Duration.days(14),
246
246
  });
247
247
  builder.setBuildArg('EXTRA_PACKAGES', 'nginx xz-utils');
248
- new FargateRunner(this, 'Fargate provider', {
249
- label: 'customized-fargate',
248
+ new FargateRunnerProvider(this, 'Fargate provider', {
249
+ labels: ['customized-fargate'],
250
250
  imageBuilder: builder,
251
251
  });
252
252
  ```
@@ -1221,8 +1221,8 @@ const builder = new ContainerImageBuilder(this, 'Builder', {
1221
1221
  runnerVersion: RunnerVersion.specific('2.293.0'),
1222
1222
  rebuildInterval: Duration.days(14),
1223
1223
  });
1224
- new CodeBuildRunner(this, 'CodeBuild provider', {
1225
- label: 'custom-codebuild',
1224
+ new CodeBuildRunnerProvider(this, 'CodeBuild provider', {
1225
+ labels: ['custom-codebuild'],
1226
1226
  imageBuilder: builder,
1227
1227
  });
1228
1228
  ```
@@ -3039,12 +3039,12 @@ const dbSg = ec2.SecurityGroup.fromSecurityGroupId(this, 'database security grou
3039
3039
  const bucket = new s3.Bucket(this, 'runner bucket');
3040
3040
 
3041
3041
  // create a custom CodeBuild provider
3042
- const myProvider = new CodeBuildRunner(
3042
+ const myProvider = new CodeBuildRunnerProvider(
3043
3043
  this, 'codebuild runner',
3044
3044
  {
3045
- label: 'my-codebuild',
3045
+ labels: ['my-codebuild'],
3046
3046
  vpc: vpc,
3047
- securityGroup: runnerSg,
3047
+ securityGroups: [runnerSg],
3048
3048
  },
3049
3049
  );
3050
3050
  // grant some permissions to the provider
@@ -3294,7 +3294,8 @@ new ImageBuilderComponent(this, 'AWS CLI', {
3294
3294
  displayName: 'AWS CLI',
3295
3295
  description: 'Install latest version of AWS CLI',
3296
3296
  commands: [
3297
- 'Start-Process msiexec.exe -Wait -ArgumentList \'/i https://awscli.amazonaws.com/AWSCLIV2.msi /qn\'',
3297
+ '$p = Start-Process msiexec.exe -PassThru -Wait -ArgumentList \'/i https://awscli.amazonaws.com/AWSCLIV2.msi /qn\'',
3298
+ 'if ($p.ExitCode -ne 0) { throw "Exit code is $p.ExitCode" }',
3298
3299
  ],
3299
3300
  }
3300
3301
  ```
@@ -4666,8 +4667,6 @@ public readonly installDocker: boolean;
4666
4667
 
4667
4668
  Install Docker inside the image, so it can be used by the runner.
4668
4669
 
4669
- You may want to disable this if you are building a Windows image and don't have a Docker Desktop license.
4670
-
4671
4670
  ---
4672
4671
 
4673
4672
  ##### `instanceType`<sup>Optional</sup> <a name="instanceType" id="@cloudsnorkel/cdk-github-runners.AmiBuilderProps.property.instanceType"></a>
@@ -4975,7 +4974,7 @@ public readonly buildImage: IBuildImage;
4975
4974
  ```
4976
4975
 
4977
4976
  - *Type:* aws-cdk-lib.aws_codebuild.IBuildImage
4978
- - *Default:* Ubuntu 20.04 for x64 and Amazon Linux 2 for ARM64
4977
+ - *Default:* Ubuntu 22.04 for x64 and Amazon Linux 2 for ARM64
4979
4978
 
4980
4979
  Build image to use in CodeBuild.
4981
4980
 
@@ -5159,7 +5158,7 @@ public readonly buildImage: IBuildImage;
5159
5158
  ```
5160
5159
 
5161
5160
  - *Type:* aws-cdk-lib.aws_codebuild.IBuildImage
5162
- - *Default:* Ubuntu 20.04 for x64 and Amazon Linux 2 for ARM64
5161
+ - *Default:* Ubuntu 22.04 for x64 and Amazon Linux 2 for ARM64
5163
5162
 
5164
5163
  Build image to use in CodeBuild.
5165
5164
 
@@ -5694,7 +5693,7 @@ public readonly imageBuilder: IRunnerImageBuilder;
5694
5693
  ```
5695
5694
 
5696
5695
  - *Type:* <a href="#@cloudsnorkel/cdk-github-runners.IRunnerImageBuilder">IRunnerImageBuilder</a>
5697
- - *Default:* Ec2ProviderProps.imageBuilder()
5696
+ - *Default:* Ec2RunnerProvider.imageBuilder()
5698
5697
 
5699
5698
  Runner image builder used to build AMI containing GitHub Runner and all requirements.
5700
5699
 
@@ -6700,6 +6699,7 @@ const imageBuilderComponentProperties: ImageBuilderComponentProperties = { ... }
6700
6699
  | <code><a href="#@cloudsnorkel/cdk-github-runners.ImageBuilderComponentProperties.property.displayName">displayName</a></code> | <code>string</code> | Component display name. |
6701
6700
  | <code><a href="#@cloudsnorkel/cdk-github-runners.ImageBuilderComponentProperties.property.platform">platform</a></code> | <code>string</code> | Component platform. |
6702
6701
  | <code><a href="#@cloudsnorkel/cdk-github-runners.ImageBuilderComponentProperties.property.assets">assets</a></code> | <code><a href="#@cloudsnorkel/cdk-github-runners.ImageBuilderAsset">ImageBuilderAsset</a>[]</code> | Optional assets to add to the built image. |
6702
+ | <code><a href="#@cloudsnorkel/cdk-github-runners.ImageBuilderComponentProperties.property.reboot">reboot</a></code> | <code>boolean</code> | Require a reboot after installing this component. |
6703
6703
 
6704
6704
  ---
6705
6705
 
@@ -6767,6 +6767,19 @@ Optional assets to add to the built image.
6767
6767
 
6768
6768
  ---
6769
6769
 
6770
+ ##### `reboot`<sup>Optional</sup> <a name="reboot" id="@cloudsnorkel/cdk-github-runners.ImageBuilderComponentProperties.property.reboot"></a>
6771
+
6772
+ ```typescript
6773
+ public readonly reboot: boolean;
6774
+ ```
6775
+
6776
+ - *Type:* boolean
6777
+ - *Default:* false
6778
+
6779
+ Require a reboot after installing this component.
6780
+
6781
+ ---
6782
+
6770
6783
  ### LambdaRunnerProviderProps <a name="LambdaRunnerProviderProps" id="@cloudsnorkel/cdk-github-runners.LambdaRunnerProviderProps"></a>
6771
6784
 
6772
6785
  #### Initializer <a name="Initializer" id="@cloudsnorkel/cdk-github-runners.LambdaRunnerProviderProps.Initializer"></a>
@@ -7432,10 +7445,12 @@ public readonly baseAmi: string;
7432
7445
  ```
7433
7446
 
7434
7447
  - *Type:* string
7435
- - *Default:* latest Ubuntu 20.04 AMI for Os.LINUX_UBUNTU, latest Amazon Linux 2 AMI for Os.LINUX_AMAZON_2, latest Windows Server 2022 AMI for Os.WINDOWS
7448
+ - *Default:* latest Ubuntu 22.04 AMI for Os.LINUX_UBUNTU, latest Amazon Linux 2 AMI for Os.LINUX_AMAZON_2, latest Windows Server 2022 AMI for Os.WINDOWS
7436
7449
 
7437
7450
  Base AMI from which runner AMIs will be built.
7438
7451
 
7452
+ This can be an actual AMI or an AWS Image Builder ARN that points to the latest AMI. For example `arn:aws:imagebuilder:us-east-1:aws:image/ubuntu-server-22-lts-x86/x.x.x` would always use the latest version of Ubuntu 22.04 in each build. If you want a specific version, you can replace `x.x.x` with that version.
7453
+
7439
7454
  ---
7440
7455
 
7441
7456
  ##### `baseDockerImage`<sup>Optional</sup> <a name="baseDockerImage" id="@cloudsnorkel/cdk-github-runners.RunnerImageBuilderProps.property.baseDockerImage"></a>
@@ -7530,7 +7545,7 @@ public readonly os: Os;
7530
7545
  ```
7531
7546
 
7532
7547
  - *Type:* <a href="#@cloudsnorkel/cdk-github-runners.Os">Os</a>
7533
- - *Default:* OS.LINUX
7548
+ - *Default:* OS.LINUX_UBUNTU
7534
7549
 
7535
7550
  Image OS.
7536
7551
 
@@ -8443,6 +8458,7 @@ new RunnerImageComponent()
8443
8458
  | <code><a href="#@cloudsnorkel/cdk-github-runners.RunnerImageComponent.getAssets">getAssets</a></code> | Returns assets to copy into the built image. |
8444
8459
  | <code><a href="#@cloudsnorkel/cdk-github-runners.RunnerImageComponent.getCommands">getCommands</a></code> | Returns commands to run to in built image. |
8445
8460
  | <code><a href="#@cloudsnorkel/cdk-github-runners.RunnerImageComponent.getDockerCommands">getDockerCommands</a></code> | Returns Docker commands to run to in built image. |
8461
+ | <code><a href="#@cloudsnorkel/cdk-github-runners.RunnerImageComponent.shouldReboot">shouldReboot</a></code> | Returns true if the image builder should be rebooted after this component is installed. |
8446
8462
 
8447
8463
  ---
8448
8464
 
@@ -8514,6 +8530,26 @@ Docker commands are added after assets and normal commands.
8514
8530
 
8515
8531
  ---
8516
8532
 
8533
+ ##### `shouldReboot` <a name="shouldReboot" id="@cloudsnorkel/cdk-github-runners.RunnerImageComponent.shouldReboot"></a>
8534
+
8535
+ ```typescript
8536
+ public shouldReboot(_os: Os, _architecture: Architecture): boolean
8537
+ ```
8538
+
8539
+ Returns true if the image builder should be rebooted after this component is installed.
8540
+
8541
+ ###### `_os`<sup>Required</sup> <a name="_os" id="@cloudsnorkel/cdk-github-runners.RunnerImageComponent.shouldReboot.parameter._os"></a>
8542
+
8543
+ - *Type:* <a href="#@cloudsnorkel/cdk-github-runners.Os">Os</a>
8544
+
8545
+ ---
8546
+
8547
+ ###### `_architecture`<sup>Required</sup> <a name="_architecture" id="@cloudsnorkel/cdk-github-runners.RunnerImageComponent.shouldReboot.parameter._architecture"></a>
8548
+
8549
+ - *Type:* <a href="#@cloudsnorkel/cdk-github-runners.Architecture">Architecture</a>
8550
+
8551
+ ---
8552
+
8517
8553
  #### Static Functions <a name="Static Functions" id="Static Functions"></a>
8518
8554
 
8519
8555
  | **Name** | **Description** |
@@ -8574,7 +8610,7 @@ RunnerImageComponent.docker()
8574
8610
 
8575
8611
  A component to install Docker.
8576
8612
 
8577
- On Windows this installs Docker Desktop.
8613
+ On Windows this sets up dockerd for Windows containers without Docker Desktop. If you need Linux containers on Windows, you'll need to install Docker Desktop which doesn't seem to play well with servers (PRs welcome).
8578
8614
 
8579
8615
  ##### `dockerInDocker` <a name="dockerInDocker" id="@cloudsnorkel/cdk-github-runners.RunnerImageComponent.dockerInDocker"></a>
8580
8616
 
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![NPM](https://img.shields.io/npm/v/@cloudsnorkel/cdk-github-runners?label=npm&logo=npm)][7]
4
4
  [![PyPI](https://img.shields.io/pypi/v/cloudsnorkel.cdk-github-runners?label=pypi&logo=pypi)][6]
5
- [![Maven Central](https://img.shields.io/maven-central/v/com.cloudsnorkel/cdk.github.runners.svg?label=Maven%20Central&logo=java)][8]
5
+ [![Maven Central](https://img.shields.io/maven-central/v/com.cloudsnorkel/cdk.github.runners.svg?label=Maven%20Central&logo=apachemaven)][8]
6
6
  [![Go](https://img.shields.io/github/v/tag/CloudSnorkel/cdk-github-runners?color=red&label=go&logo=go)][11]
7
7
  [![Nuget](https://img.shields.io/nuget/v/CloudSnorkel.Cdk.Github.Runners?color=red&&logo=nuget)][12]
8
8
  [![Release](https://github.com/CloudSnorkel/cdk-github-runners/actions/workflows/release.yml/badge.svg)](https://github.com/CloudSnorkel/cdk-github-runners/actions/workflows/release.yml)
@@ -21,6 +21,7 @@ Self-hosted runners in AWS are useful when:
21
21
  * You need easy access to internal resources in your actions
22
22
  * You want to pre-install some software for your actions
23
23
  * You want to provide some basic AWS API access (but [aws-actions/configure-aws-credentials][2] has more security controls)
24
+ * You are using GitHub Enterprise Server
24
25
 
25
26
  Ephemeral (or on-demand) runners are the [recommended way by GitHub][14] for auto-scaling, and they make sure all jobs run with a clean image. Runners are started on-demand. You don't pay unless a job is running.
26
27
 
@@ -54,39 +55,96 @@ You can also create your own provider by implementing `IRunnerProvider`.
54
55
 
55
56
  ## Installation
56
57
 
57
- 1. Confirm you're using CDK v2
58
- 2. Install the appropriate package
59
- 1. [Python][6]
60
- ```
61
- pip install cloudsnorkel.cdk-github-runners
62
- ```
63
- 2. [TypeScript or JavaScript][7]
64
- ```
65
- npm i @cloudsnorkel/cdk-github-runners
66
- ```
67
- 3. [Java][8]
68
- ```xml
69
- <dependency>
58
+ 1. Install and use the appropriate package
59
+ <details><summary>Python</summary>
60
+
61
+ ### Install
62
+ Available on [PyPI][6].
63
+ ```bash
64
+ pip install cloudsnorkel.cdk-github-runners
65
+ ```
66
+ ### Use
67
+ ```python
68
+ from cloudsnorkel.cdk_github_runners import GitHubRunners
69
+
70
+ GitHubRunners(self, "runners")
71
+ ```
72
+ </details>
73
+ <details><summary>TypeScript or JavaScript</summary>
74
+
75
+ ### Install
76
+ Available on [npm][7].
77
+ ```bash
78
+ npm i @cloudsnorkel/cdk-github-runners
79
+ ```
80
+ ### Use
81
+ ```typescript
82
+ import { GitHubRunners } from '@cloudsnorkel/cdk-github-runners';
83
+
84
+ new GitHubRunners(this, "runners");
85
+ ```
86
+ </details>
87
+ <details><summary>Java</summary>
88
+
89
+ ### Install
90
+ Available on [Maven][8].
91
+ ```xml
92
+ <dependency>
70
93
  <groupId>com.cloudsnorkel</groupId>
71
94
  <artifactId>cdk.github.runners</artifactId>
72
- </dependency>
73
- ```
74
- 4. [Go][11]
75
- ```
76
- go get github.com/CloudSnorkel/cdk-github-runners-go/cloudsnorkelcdkgithubrunners
77
- ```
78
- 5. [.NET][12]
79
- ```
80
- dotnet add package CloudSnorkel.Cdk.Github.Runners
81
- ```
82
- 3. Use `GitHubRunners` construct in your code (starting with default arguments is fine)
83
- 4. Deploy your stack
84
- 5. Look for the status command output similar to `aws --region us-east-1 lambda invoke --function-name status-XYZ123 status.json`
85
- 6. Execute the status command (you may need to specify `--profile` too) and open the resulting `status.json` file
86
- 7. Open the URL in `github.setup.url` from `status.json` or [manually setup GitHub](SETUP_GITHUB.md) integration as an app or with personal access token
87
- 8. Run status command again to confirm `github.auth.status` and `github.webhook.status` are OK
88
- 9. Trigger a GitHub action that has a `self-hosted` label with `runs-on: [self-hosted, linux, codebuild]` or similar
89
- 10. If the action is not successful, see [troubleshooting](#Troubleshooting)
95
+ </dependency>
96
+ ```
97
+ ### Use
98
+ ```java
99
+ import com.cloudsnorkel.cdk.github.runners.GitHubRunners;
100
+
101
+ GitHubRunners.Builder.create(this, "runners").build();
102
+ ```
103
+ </details>
104
+ <details><summary>Go</summary>
105
+
106
+ ### Install
107
+ Available on [GitHub][11].
108
+ ```bash
109
+ go get github.com/CloudSnorkel/cdk-github-runners-go/cloudsnorkelcdkgithubrunners
110
+ ```
111
+ ### Use
112
+ ```go
113
+ import "github.com/CloudSnorkel/cdk-github-runners-go/cloudsnorkelcdkgithubrunners"
114
+
115
+ NewGitHubRunners(this, jsii.String("runners"))
116
+ ```
117
+ </details>
118
+ <details><summary>.NET</summary>
119
+
120
+ ### Install
121
+ Available on [Nuget][12].
122
+ ```bash
123
+ dotnet add package CloudSnorkel.Cdk.Github.Runners
124
+ ```
125
+ ### Use
126
+ ```csharp
127
+ using CloudSnorkel;
128
+
129
+ new GitHubRunners(this, "runners");
130
+ ```
131
+ </details>
132
+ 2. Use `GitHubRunners` construct in your code (starting with default arguments is fine)
133
+ 3. Deploy your stack
134
+ 4. Look for the status command output similar to `aws --region us-east-1 lambda invoke --function-name status-XYZ123 status.json`
135
+ ```
136
+ ✅ github-runners-test
137
+
138
+ ✨ Deployment time: 260.01s
139
+
140
+ Outputs:
141
+ github-runners-test.runnersstatuscommand4A30F0F5 = aws --region us-east-1 lambda invoke --function-name github-runners-test-runnersstatus1A5771C0-mvttg8oPQnQS status.json
142
+ ```
143
+ 5. Execute the status command (you may need to specify `--profile` too) and open the resulting `status.json` file
144
+ 6. Open the URL in `github.setup.url` from `status.json` or [manually setup GitHub](SETUP_GITHUB.md) integration as an app or with personal access token
145
+ 7. Run status command again to confirm `github.auth.status` and `github.webhook.status` are OK
146
+ 8. Trigger a GitHub action that has a `self-hosted` label with `runs-on: [self-hosted, linux, codebuild]` or similar
147
+ 9. If the action is not successful, see [troubleshooting](#Troubleshooting)
90
148
 
91
149
  [![Demo](demo-thumbnail.jpg)](https://youtu.be/wlyv_3V8lIw)
92
150
 
@@ -103,10 +161,10 @@ let dbSg: ec2.SecurityGroup;
103
161
  let bucket: s3.Bucket;
104
162
 
105
163
  // create a custom CodeBuild provider
106
- const myProvider = new CodeBuildRunnerProvider(this, 'codebuild runner', {
107
- label: 'my-codebuild',
108
- vpc: vpc,
109
- securityGroup: runnerSg,
164
+ const myProvider = new CodeBuildRunnerProvider(this, 'codebuild runner', {
165
+ labels: ['my-codebuild'],
166
+ vpc: vpc,
167
+ securityGroups: [runnerSg],
110
168
  });
111
169
  // grant some permissions to the provider
112
170
  bucket.grantReadWrite(myProvider);
@@ -131,9 +189,9 @@ myBuilder.addComponent(
131
189
  );
132
190
 
133
191
  const myProvider = new FargateRunnerProvider(this, 'fargate runner', {
134
- label: 'customized-fargate',
192
+ labels: ['customized-fargate'],
135
193
  vpc: vpc,
136
- securityGroup: runnerSg,
194
+ securityGroups: [runnerSg],
137
195
  imageBuilder: myBuilder,
138
196
  });
139
197
 
@@ -159,31 +217,31 @@ Windows images can also be customized the same way.
159
217
 
160
218
  ```typescript
161
219
  const myWindowsBuilder = FargateRunnerProvider.imageBuilder(this, 'Windows image builder', {
162
- architecture: Architecture.X86_64,
163
- os: Os.WINDOWS,
164
- runnerVersion: RunnerVersion.specific('2.291.0'),
165
- rebuildInterval: Duration.days(14),
220
+ architecture: Architecture.X86_64,
221
+ os: Os.WINDOWS,
222
+ runnerVersion: RunnerVersion.specific('2.291.0'),
223
+ rebuildInterval: Duration.days(14),
166
224
  });
167
225
  myWindowsBuilder.addComponent(
168
- RunnerImageComponent.custom({
169
- name: 'Ninja',
170
- commands: [
171
- 'Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/ninja-build/ninja/releases/download/v1.11.1/ninja-win.zip" -OutFile ninja.zip',
172
- 'Expand-Archive ninja.zip -DestinationPath C:\\actions',
173
- 'del ninja.zip',
174
- ],
175
- })
226
+ RunnerImageComponent.custom({
227
+ name: 'Ninja',
228
+ commands: [
229
+ 'Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/ninja-build/ninja/releases/download/v1.11.1/ninja-win.zip" -OutFile ninja.zip',
230
+ 'Expand-Archive ninja.zip -DestinationPath C:\\actions',
231
+ 'del ninja.zip',
232
+ ],
233
+ })
176
234
  );
177
235
 
178
236
  const myProvider = new FargateRunnerProvider(this, 'fargate runner', {
179
- label: 'customized-windows-fargate',
180
- vpc: vpc,
181
- securityGroup: runnerSg,
182
- imageBuidler: myWindowsBuilder,
237
+ labels: ['customized-windows-fargate'],
238
+ vpc: vpc,
239
+ securityGroups: [runnerSg],
240
+ imageBuidler: myWindowsBuilder,
183
241
  });
184
242
 
185
243
  new GitHubRunners(this, 'runners', {
186
- providers: [myProvider],
244
+ providers: [myProvider],
187
245
  });
188
246
  ```
189
247
 
@@ -191,15 +249,15 @@ The runner OS and architecture is determined by the image it is set to use. For
191
249
 
192
250
  ```typescript
193
251
  new GitHubRunners(this, 'runners', {
194
- providers: [
195
- new FargateRunnerProvider(this, 'fargate runner', {
196
- labels: ['arm64', 'fargate'],
197
- imageBuidler: FargateRunnerProvider.imageBuilder(this, 'image builder', {
198
- architecture: Architecture.ARM64,
199
- os: Os.LINUX,
252
+ providers: [
253
+ new FargateRunnerProvider(this, 'fargate runner', {
254
+ labels: ['arm64', 'fargate'],
255
+ imageBuidler: FargateRunnerProvider.imageBuilder(this, 'image builder', {
256
+ architecture: Architecture.ARM64,
257
+ os: Os.LINUX_UBUNTU,
258
+ }),
200
259
  }),
201
- }),
202
- ],
260
+ ],
203
261
  });
204
262
  ```
205
263
 
@@ -212,7 +270,7 @@ new GitHubRunners(this, 'runners', {
212
270
  1. Always start with the status function, make sure no errors are reported, and confirm all status codes are OK
213
271
  2. If jobs are stuck on pending:
214
272
  1. Make sure `runs-on` in the workflow matches the expected labels set in the runner provider
215
- 2. If it happens every time, cancel the job and start it again
273
+ 2. If jobs get stuck often and take a long time to start, cancel the pending jobs and start them again
216
274
  4. Confirm the webhook Lambda was called by visiting the URL in `troubleshooting.webhookHandlerUrl` from `status.json`
217
275
  1. If it's not called or logs errors, confirm the webhook settings on the GitHub side
218
276
  2. If you see too many errors, make sure you're only sending `workflow_job` events
@@ -221,6 +279,18 @@ new GitHubRunners(this, 'runners', {
221
279
  1. Use the details tab to find the specific execution of the provider (Lambda, CodeBuild, Fargate, etc.)
222
280
  2. Every step function execution should be successful, even if the runner action inside it failed
223
281
 
282
+ ## Monitoring
283
+
284
+ There are two important ways to monitor your runners:
285
+
286
+ 1. Make sure runners don't fail to start. When that happens, jobs may sit and wait. Use `GitHubRunners.metricFailed()` to get a metric for the number of failed runner starts. You should use this metric to trigger an alarm.
287
+ 2. Make sure runner images don't fail to build. Failed runner image builds mean you will get stuck with out-of-date software on your runners. It may lead to security vulnerabilities, or it may lead to slower runner start-ups as the runner software itself needs to be updated. Use `GitHubRunners.failedImageBuildsTopic()` to get SNS topic that gets notified of failed runner image builds. You should subscribe to this topic.
288
+
289
+ Other useful metrics to track:
290
+
291
+ 1. Use `GitHubRunners.metricJobCompleted()` to get a metric for the number of completed jobs broken down by labels and job success.
292
+ 2. Use `GitHubRunners.metricTime()` to get a metric for the total time a runner is running. This includes the overhead of starting the runner.
293
+
224
294
  ## Other Options
225
295
 
226
296
  1. [philips-labs/terraform-aws-github-runner][3] if you're using Terraform
@@ -234,7 +304,7 @@ new GitHubRunners(this, 'runners', {
234
304
  [5]: https://github.com/actions/runner
235
305
  [6]: https://pypi.org/project/cloudsnorkel.cdk-github-runners
236
306
  [7]: https://www.npmjs.com/package/@cloudsnorkel/cdk-github-runners
237
- [8]: https://search.maven.org/search?q=g:%22com.cloudsnorkel%22%20AND%20a:%22cdk.github.runners%22
307
+ [8]: https://central.sonatype.com/artifact/com.cloudsnorkel/cdk.github.runners/
238
308
  [9]: https://docs.github.com/en/developers/apps/getting-started-with-apps/about-apps
239
309
  [10]: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token
240
310
  [11]: https://pkg.go.dev/github.com/CloudSnorkel/cdk-github-runners-go/cloudsnorkelcdkgithubrunners
@@ -22,7 +22,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
22
22
  mod
23
23
  ));
24
24
 
25
- // src/providers/image-builders/aws-image-builder/delete-ami.lambda.ts
25
+ // src/image-builders/aws-image-builder/delete-ami.lambda.ts
26
26
  var AWS2 = __toESM(require("aws-sdk"));
27
27
 
28
28
  // src/lambda-helpers.ts
@@ -62,7 +62,7 @@ async function customResourceRespond(event, responseStatus, reason, physicalReso
62
62
  });
63
63
  }
64
64
 
65
- // src/providers/image-builders/aws-image-builder/delete-ami.lambda.ts
65
+ // src/image-builders/aws-image-builder/delete-ami.lambda.ts
66
66
  var ec2 = new AWS2.EC2();
67
67
  async function deleteAmis(launchTemplateId, stackName, builderName, deleteAll) {
68
68
  var _a;
@@ -22,7 +22,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
22
22
  mod
23
23
  ));
24
24
 
25
- // src/providers/image-builders/aws-image-builder/filter-failed-builds.lambda.ts
25
+ // src/image-builders/aws-image-builder/filter-failed-builds.lambda.ts
26
26
  var AWS = __toESM(require("aws-sdk"));
27
27
  var sns = new AWS.SNS();
28
28
  exports.handler = async function(event) {
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+
25
+ // src/image-builders/aws-image-builder/reaper.lambda.ts
26
+ var AWS = __toESM(require("aws-sdk"));
27
+ var ec2 = new AWS.EC2();
28
+ var ecr = new AWS.ECR();
29
+ var ib = new AWS.Imagebuilder();
30
+ async function iterateImageVersions(imageName) {
31
+ let result = [];
32
+ let params = {
33
+ owner: "Self",
34
+ filters: [
35
+ {
36
+ name: "name",
37
+ values: [imageName]
38
+ }
39
+ ]
40
+ };
41
+ while (true) {
42
+ const response = await ib.listImages(params).promise();
43
+ if (response.imageVersionList) {
44
+ for (const imageVersion of response.imageVersionList) {
45
+ if (imageVersion.arn) {
46
+ result.push(imageVersion.arn);
47
+ }
48
+ }
49
+ }
50
+ if (!response.nextToken) {
51
+ break;
52
+ }
53
+ params.nextToken = response.nextToken;
54
+ }
55
+ return result;
56
+ }
57
+ async function iterateImageBuildVersions(imageVersionArn) {
58
+ var _a;
59
+ let result = [];
60
+ let params = {
61
+ imageVersionArn
62
+ };
63
+ while (true) {
64
+ const response = await ib.listImageBuildVersions(params).promise();
65
+ if (response.imageSummaryList) {
66
+ for (const imageBuildVersion of response.imageSummaryList) {
67
+ if (((_a = imageBuildVersion.state) == null ? void 0 : _a.status) !== "AVAILABLE") {
68
+ console.log(`${imageBuildVersion.arn} is still being created, so we can't delete it`);
69
+ continue;
70
+ }
71
+ result.push(imageBuildVersion);
72
+ }
73
+ }
74
+ if (!response.nextToken) {
75
+ break;
76
+ }
77
+ params.nextToken = response.nextToken;
78
+ }
79
+ return result;
80
+ }
81
+ async function amisGone(amis) {
82
+ var _a;
83
+ if (!amis) {
84
+ console.log("No AMIs found, so we can delete the image version build");
85
+ return true;
86
+ }
87
+ for (const ami of amis) {
88
+ console.log(`Checking if ${ami.image} exists`);
89
+ if (!ami.image) {
90
+ console.log("No AMI, so we can delete it");
91
+ continue;
92
+ }
93
+ try {
94
+ const response = await ec2.describeImages({
95
+ ImageIds: [ami.image]
96
+ }).promise();
97
+ if (((_a = response.Images) == null ? void 0 : _a.length) ?? 0 > 0) {
98
+ console.log("AMI still available, so we can't delete it");
99
+ return false;
100
+ }
101
+ } catch (e) {
102
+ if (e.code != "InvalidAMIID.NotFound") {
103
+ console.error(`Unknown exception while checking if ${ami.image} exists:`, e);
104
+ return false;
105
+ }
106
+ }
107
+ }
108
+ console.log("All AMIs are gone, so we can delete the image version build");
109
+ return true;
110
+ }
111
+ async function dockerImagesGone(dockerImages) {
112
+ var _a;
113
+ if (!dockerImages) {
114
+ console.log("No docker images, so we can delete the image version build");
115
+ return true;
116
+ }
117
+ for (const images of dockerImages) {
118
+ for (const image of images.imageUris ?? []) {
119
+ const [repo, version] = image.split(":", 2);
120
+ const [_, repoName] = repo.split("/", 2);
121
+ if (version === "latest") {
122
+ continue;
123
+ }
124
+ console.log(`Checking if ${repoName}:${version} exists`);
125
+ try {
126
+ const response = await ecr.describeImages({
127
+ repositoryName: repoName,
128
+ imageIds: [{ imageTag: version }]
129
+ }).promise();
130
+ if (response.imageDetails && response.imageDetails.length > 0) {
131
+ if ((_a = response.imageDetails[0].imageTags) == null ? void 0 : _a.includes("latest")) {
132
+ console.log(`Docker image ${repoName}:${version} still available and tagged latest, so we can't delete it`);
133
+ return false;
134
+ }
135
+ }
136
+ } catch (e) {
137
+ if (e.code != "RepositoryNotFoundException" && e.code != "ImageNotFoundException") {
138
+ console.error(`Unknown exception while checking if ${repoName}:${version} exists:`, e);
139
+ return false;
140
+ }
141
+ }
142
+ }
143
+ }
144
+ console.log("All Docker images are gone, so we can delete the image version build");
145
+ return true;
146
+ }
147
+ exports.handler = async function(event, _context) {
148
+ var _a, _b;
149
+ for (const imageVersion of await iterateImageVersions(event.RecipeName)) {
150
+ for (const imageBuildVersion of await iterateImageBuildVersions(imageVersion)) {
151
+ if (!imageBuildVersion.arn) {
152
+ continue;
153
+ }
154
+ console.log(`Checking ${imageBuildVersion.name}/${imageBuildVersion.version}`);
155
+ if (await amisGone((_a = imageBuildVersion.outputResources) == null ? void 0 : _a.amis) && await dockerImagesGone((_b = imageBuildVersion.outputResources) == null ? void 0 : _b.containers)) {
156
+ console.log("Deleting image version build", imageBuildVersion.arn);
157
+ await ib.deleteImage({
158
+ imageBuildVersionArn: imageBuildVersion.arn
159
+ }).promise();
160
+ }
161
+ }
162
+ }
163
+ };