cdk-github-microvm-runners 0.1.1__py3-none-any.whl
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.
- cdk_github_microvm_runners/__init__.py +3989 -0
- cdk_github_microvm_runners/_jsii/__init__.py +31 -0
- cdk_github_microvm_runners/_jsii/cdk-github-microvm-runners@0.1.1.jsii.tgz +0 -0
- cdk_github_microvm_runners/py.typed +1 -0
- cdk_github_microvm_runners-0.1.1.data/scripts/cdk-github-microvm-runners +20 -0
- cdk_github_microvm_runners-0.1.1.dist-info/LICENSE +202 -0
- cdk_github_microvm_runners-0.1.1.dist-info/METADATA +301 -0
- cdk_github_microvm_runners-0.1.1.dist-info/RECORD +10 -0
- cdk_github_microvm_runners-0.1.1.dist-info/WHEEL +5 -0
- cdk_github_microvm_runners-0.1.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,3989 @@
|
|
|
1
|
+
r'''
|
|
2
|
+
# cdk-github-microvm-runners
|
|
3
|
+
|
|
4
|
+
[](https://www.npmjs.com/package/cdk-github-microvm-runners) [](https://pypi.org/project/cdk-github-microvm-runners/) [](https://github.com/schuettc/cdk-github-microvm-runners/actions/workflows/ci.yml) [](LICENSE)
|
|
5
|
+
|
|
6
|
+
A CDK construct library that runs GitHub Actions jobs on
|
|
7
|
+
[AWS Lambda MicroVMs](https://docs.aws.amazon.com/lambda/latest/dg/lambda-microvms-guide.html).
|
|
8
|
+
Each job runs on its own MicroVM in your AWS account, created when the job
|
|
9
|
+
starts and removed once it finishes.
|
|
10
|
+
|
|
11
|
+
## Why this exists
|
|
12
|
+
|
|
13
|
+
AWS Lambda MicroVMs provides the ability to launch a MicroVM, but nothing that
|
|
14
|
+
connects one to GitHub Actions: there is no runner registration, no path from
|
|
15
|
+
an incoming job to a running VM, and no cleanup when a VM or a runner is left
|
|
16
|
+
behind. AWS CDK provides the individual building blocks — Lambda functions, a
|
|
17
|
+
queue, a table, IAM roles — but not an assembled system. This construct is that
|
|
18
|
+
system. It receives GitHub's `workflow_job` events, launches a MicroVM for each
|
|
19
|
+
job, registers a single-use runner, and reconciles the result afterward, so
|
|
20
|
+
that adopting per-job MicroVM runners is a matter of configuring a construct
|
|
21
|
+
rather than building and operating the surrounding machinery yourself.
|
|
22
|
+
|
|
23
|
+
Two design decisions shape the rest of the library. The runner VMs hold no AWS
|
|
24
|
+
credentials by default, because a MicroVM's instance metadata service would
|
|
25
|
+
otherwise return any attached role's credentials to the code running in the
|
|
26
|
+
job; a job that needs AWS obtains its own short-lived credentials through GitHub
|
|
27
|
+
OIDC instead. Routing is per job: a workflow job opts in by naming the runner's
|
|
28
|
+
label in its `runs-on`, and every other job continues to run on GitHub-hosted
|
|
29
|
+
runners, so a repository can be moved across one job at a time.
|
|
30
|
+
|
|
31
|
+
## How it works
|
|
32
|
+
|
|
33
|
+
A single runner set — one `GithubMicrovmRunners` in a stack — serves a GitHub
|
|
34
|
+
organization or a set of repositories. It is configured with two required
|
|
35
|
+
properties: how it authenticates to GitHub, and which organization or
|
|
36
|
+
repositories it serves.
|
|
37
|
+
|
|
38
|
+
A runner class pairs a `runs-on` label with the MicroVM size and image that
|
|
39
|
+
jobs carrying that label run on, and a runner set can define more than one.
|
|
40
|
+
Each class builds its own image and runs at its own size, so a workflow can
|
|
41
|
+
send small jobs to one class and memory-heavy jobs to a larger one by choosing
|
|
42
|
+
the matching label. The runner VMs are ARM64, so the tools and container images
|
|
43
|
+
a job pulls need arm64 builds.
|
|
44
|
+
|
|
45
|
+
<!-- sync:begin lifecycle-diagram -->
|
|
46
|
+
|
|
47
|
+
```mermaid
|
|
48
|
+
flowchart TD
|
|
49
|
+
GH["GitHub Actions — workflow_job event"] --> WH["Webhook Lambda — verifies the signature"]
|
|
50
|
+
WH --> Q["SQS job queue — launch and terminate intents"]
|
|
51
|
+
Q --> LN["Launcher Lambda — claims the job, obtains a MicroVM"]
|
|
52
|
+
LN --> VM["MicroVM — runs one job"]
|
|
53
|
+
LN -.->|registers a single-use runner| GH
|
|
54
|
+
LN <--> DB[("DynamoDB runner table")]
|
|
55
|
+
JAN["Janitor Lambda — scheduled sweep"] -.->|reaps stranded VMs, reconciles state| VM
|
|
56
|
+
JAN <--> DB
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
<!-- sync:end lifecycle-diagram -->
|
|
60
|
+
|
|
61
|
+
When GitHub sends a `workflow_job` event, the webhook handler verifies its
|
|
62
|
+
signature and places the job on an SQS queue. The launcher reads the queue,
|
|
63
|
+
records a claim so that a given job is only ever launched once, starts a
|
|
64
|
+
MicroVM (or resumes one from a warm pool, if the runner class keeps one), and
|
|
65
|
+
registers a single-use runner with GitHub. The VM runs that one job and is then
|
|
66
|
+
removed. A janitor runs on a schedule to reconcile the runner set against the
|
|
67
|
+
running VMs and GitHub's view of its runners, terminating anything that was
|
|
68
|
+
stranded and cleaning up records that are no longer needed. The
|
|
69
|
+
[architecture guide](docs/architecture.md) describes the lifecycle, the
|
|
70
|
+
idempotency model, and the checks that keep the janitor from terminating a
|
|
71
|
+
runner that is still working.
|
|
72
|
+
|
|
73
|
+
## Install
|
|
74
|
+
|
|
75
|
+
One source, compiled by jsii into two packages. The API is the same in each,
|
|
76
|
+
with names rendered in the target language's conventions.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npm install cdk-github-microvm-runners
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pip install cdk-github-microvm-runners
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Getting started
|
|
87
|
+
|
|
88
|
+
To deploy, you need an AWS account, a GitHub App connected to the runner set,
|
|
89
|
+
and the App's private key and webhook secret stored in AWS Secrets Manager. The
|
|
90
|
+
[getting-started guide](docs/getting-started.md) walks through all three, and
|
|
91
|
+
includes a helper that performs the GitHub App setup for you.
|
|
92
|
+
|
|
93
|
+
The example below is TypeScript; [API.md](API.md) carries the same surface for
|
|
94
|
+
every language.
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from aws_cdk import Environment
|
|
98
|
+
from aws_cdk import App, CfnOutput, Stack
|
|
99
|
+
from aws_cdk.aws_secretsmanager import Secret
|
|
100
|
+
from cdk_github_microvm_runners import GithubMicrovmRunners, GithubAppId, GithubAppKey, GithubAuth, RunnerScope, MicrovmSize
|
|
101
|
+
|
|
102
|
+
app = App()
|
|
103
|
+
stack = Stack(app, "Runners", env=Environment(region="us-east-1"))
|
|
104
|
+
|
|
105
|
+
# The GitHub App's ID, private key, and webhook secret are read from Secrets
|
|
106
|
+
# Manager at run time, so this stack deploys before the App is created.
|
|
107
|
+
app_id = Secret.from_secret_name_v2(stack, "AppId", "microvm-runner/dev/app-id")
|
|
108
|
+
private_key = Secret.from_secret_name_v2(stack, "AppKey", "microvm-runner/dev/app-private-key")
|
|
109
|
+
webhook_secret = Secret.from_secret_name_v2(stack, "WebhookSecret", "microvm-runner/dev/webhook-secret")
|
|
110
|
+
|
|
111
|
+
runners = GithubMicrovmRunners(stack, "Runners",
|
|
112
|
+
github=GithubAuth.app(
|
|
113
|
+
app_id=GithubAppId.from_secret(app_id),
|
|
114
|
+
private_key=GithubAppKey.from_secret(private_key),
|
|
115
|
+
webhook_secret=webhook_secret
|
|
116
|
+
),
|
|
117
|
+
scope=RunnerScope.org("my-org")
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# A runner class pairs a label with the MicroVM size it runs on. Workflows
|
|
121
|
+
# reach it through `runs-on: [self-hosted, microvm]`.
|
|
122
|
+
runners.add_runner_class("microvm", size=MicrovmSize.GB4)
|
|
123
|
+
|
|
124
|
+
CfnOutput(stack, "WebhookUrl", value=runners.webhook_url)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Once the stack is deployed, point the GitHub App's webhook at the stack's
|
|
128
|
+
`WebhookUrl` output — the setup helper reads it from the stack and wires it for
|
|
129
|
+
you, or you can set it by hand — and change a workflow job's `runs-on` to
|
|
130
|
+
`[self-hosted, microvm]`.
|
|
131
|
+
|
|
132
|
+
## Examples
|
|
133
|
+
|
|
134
|
+
The samples below extend the runner set above, and each shows only the part it
|
|
135
|
+
adds.
|
|
136
|
+
|
|
137
|
+
### A runner class with its own image
|
|
138
|
+
|
|
139
|
+
A runner class that names no image builds from the base image, which carries
|
|
140
|
+
the operating system, the Actions runner, Docker, and the AWS CLI.
|
|
141
|
+
`RunnerImage.fromOptions` describes what to add to that base: system packages,
|
|
142
|
+
setup commands, environment variables, and files.
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
runners.add_runner_class("build",
|
|
146
|
+
size=MicrovmSize.GB8,
|
|
147
|
+
image=RunnerImage.from_options(
|
|
148
|
+
system_packages=["jq", "ripgrep"],
|
|
149
|
+
setup_commands=["npm install -g pnpm@10"]
|
|
150
|
+
)
|
|
151
|
+
)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Images are built when the stack deploys, so a job that arrives later boots an
|
|
155
|
+
image that already exists. [Runner images](docs/images.md) covers the three
|
|
156
|
+
ways to describe one, including supplying a Dockerfile of your own.
|
|
157
|
+
|
|
158
|
+
### Language versions baked into the image
|
|
159
|
+
|
|
160
|
+
`actions/setup-python` and `actions/setup-node` resolve the version a job asks
|
|
161
|
+
for from the image's tool cache. A toolchain is a language runtime placed in
|
|
162
|
+
that cache when the image is built.
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
runners.add_runner_class("test",
|
|
166
|
+
size=MicrovmSize.GB4,
|
|
167
|
+
image=RunnerImage.from_options(
|
|
168
|
+
toolchains=[
|
|
169
|
+
RunnerToolchain.python("3.12.7"),
|
|
170
|
+
RunnerToolchain.node("22.11.0")
|
|
171
|
+
]
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Each toolchain pins a full three-part version, because that version names the
|
|
177
|
+
cache directory it is baked into. A workflow targeting the class then writes
|
|
178
|
+
`actions/setup-python` as it would on a GitHub-hosted runner, and
|
|
179
|
+
[Toolchains](docs/toolchains.md) covers the rest.
|
|
180
|
+
|
|
181
|
+
### Runners in your own VPC
|
|
182
|
+
|
|
183
|
+
Network egress belongs to the runner set rather than to a class, and every
|
|
184
|
+
runner class shares it. `RunnerNetwork.vpc` has the construct build a Lambda
|
|
185
|
+
runtime connector from a VPC you pass, so the VMs follow that VPC's subnets,
|
|
186
|
+
security groups, and route tables.
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
GithubMicrovmRunners(stack, "Runners",
|
|
190
|
+
github=github,
|
|
191
|
+
scope=RunnerScope.org("my-org"),
|
|
192
|
+
network=RunnerNetwork.vpc(vpc,
|
|
193
|
+
subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS)
|
|
194
|
+
)
|
|
195
|
+
)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The connector's network interfaces land in the VPC's private-with-egress
|
|
199
|
+
subnets and get a new security group unless you pass your own. The
|
|
200
|
+
[security guide](docs/security.md) covers attaching a connector you already
|
|
201
|
+
manage, and what the VPC's routing then decides for a job.
|
|
202
|
+
|
|
203
|
+
## Security
|
|
204
|
+
|
|
205
|
+
The runner VMs carry no AWS identity by default, so a compromised or malicious
|
|
206
|
+
workflow step has no credentials to read from the instance metadata service. A
|
|
207
|
+
job that needs AWS assumes a role scoped to that job through GitHub OIDC. The
|
|
208
|
+
[security guide](docs/security.md) covers the whole model, including the OIDC
|
|
209
|
+
trust-policy setup and the details that are easy to get wrong.
|
|
210
|
+
|
|
211
|
+
The webhook is served from a public Lambda Function URL, because GitHub cannot
|
|
212
|
+
sign its webhook deliveries with SigV4. The handler verifies GitHub's
|
|
213
|
+
HMAC-SHA256 signature on every request.
|
|
214
|
+
|
|
215
|
+
A single property attaches an execution role to the VMs — `vmExecutionRole` —
|
|
216
|
+
for a runner set whose jobs need a standing AWS identity. Because that role's
|
|
217
|
+
credentials become readable from inside the job, it is off by default, and the
|
|
218
|
+
construct never creates a VM identity on your behalf. Runtime console capture
|
|
219
|
+
(`consoleLogs: ConsoleLogs.enabled()`) writes its logs through that same role,
|
|
220
|
+
so it too requires `vmExecutionRole`, and you grant the role the log-write
|
|
221
|
+
actions yourself.
|
|
222
|
+
|
|
223
|
+
## Documentation
|
|
224
|
+
|
|
225
|
+
| Guide | What it covers |
|
|
226
|
+
| -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
227
|
+
| [Getting started](docs/getting-started.md) | Prerequisites, GitHub App setup, deploying, and running a first job |
|
|
228
|
+
| [Onboarding a repo](docs/onboarding.md) | Moving an existing repository's CI onto the runners |
|
|
229
|
+
| [Runner images](docs/images.md) | What an image contains, when it is built, how it changes, and the disk each size allows |
|
|
230
|
+
| [Toolchains](docs/toolchains.md) | Baking the Python and Node versions your workflows use into the image |
|
|
231
|
+
| [Security](docs/security.md) | The security model, per-job AWS access through GitHub OIDC, and the control plane |
|
|
232
|
+
| [Service quotas](docs/service-quotas.md) | Sizing for concurrency, and what to do when a quota cannot be raised |
|
|
233
|
+
| [Monitoring](docs/monitoring.md) | Opt-in CloudWatch metrics and the ready-made alarms |
|
|
234
|
+
| [Logging](docs/logging.md) | Image build logs and runtime VM console output, and the tradeoff console capture involves |
|
|
235
|
+
| [Architecture](docs/architecture.md) | The lifecycle, the idempotency model, and the checks that prevent terminating an active runner |
|
|
236
|
+
| [API reference](API.md) | Every construct, property, and default, generated from the source |
|
|
237
|
+
| [Security policy](SECURITY.md) · [Contributing](CONTRIBUTING.md) · [Changelog](CHANGELOG.md) | Reporting and project information |
|
|
238
|
+
|
|
239
|
+
## Configuration
|
|
240
|
+
|
|
241
|
+
Beyond the two required properties, every option is optional and has a
|
|
242
|
+
conservative default, so the example above deploys as written. The available
|
|
243
|
+
options include a customer-managed KMS key applied to the
|
|
244
|
+
DynamoDB table, the SQS queues, and the log groups (`encryptionKey`); a
|
|
245
|
+
permissions boundary applied to every role the construct creates
|
|
246
|
+
(`permissionsBoundary`); the removal policy, DynamoDB point-in-time recovery,
|
|
247
|
+
log retention, dead-letter retention, dead-letter redrive count, and Lambda
|
|
248
|
+
memory; and control over the VMs' network egress through `RunnerNetwork`.
|
|
249
|
+
|
|
250
|
+
## Development
|
|
251
|
+
|
|
252
|
+
Quality checks run through [`just`](https://github.com/casey/just) and are
|
|
253
|
+
enforced by [lefthook](https://github.com/evilmartians/lefthook) git hooks; CI
|
|
254
|
+
runs the same `just verify`.
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
brew install just lefthook
|
|
258
|
+
pnpm install
|
|
259
|
+
lefthook install
|
|
260
|
+
just verify
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
<!-- sync:begin branch-model -->
|
|
264
|
+
|
|
265
|
+
Feature pull requests target `dev`, which is promoted to `main` by pull
|
|
266
|
+
request.
|
|
267
|
+
|
|
268
|
+
<!-- sync:end branch-model -->
|
|
269
|
+
|
|
270
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for local setup and the full workflow.
|
|
271
|
+
|
|
272
|
+
## License
|
|
273
|
+
|
|
274
|
+
Released under the [Apache-2.0](LICENSE) license.
|
|
275
|
+
'''
|
|
276
|
+
from __future__ import annotations
|
|
277
|
+
|
|
278
|
+
from pkgutil import extend_path
|
|
279
|
+
__path__ = extend_path(__path__, __name__)
|
|
280
|
+
|
|
281
|
+
import abc
|
|
282
|
+
import builtins
|
|
283
|
+
import datetime
|
|
284
|
+
import enum
|
|
285
|
+
import typing
|
|
286
|
+
|
|
287
|
+
import jsii
|
|
288
|
+
import publication
|
|
289
|
+
import typing_extensions
|
|
290
|
+
|
|
291
|
+
from jsii._type_checking import cached_type_hints, check_type
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
from ._jsii import *
|
|
295
|
+
|
|
296
|
+
class _LazyImport:
|
|
297
|
+
def __init__(self, module_name: str) -> None:
|
|
298
|
+
self._module_name = module_name
|
|
299
|
+
self._module: typing.Any = None
|
|
300
|
+
def __getattr__(self, name: str) -> typing.Any:
|
|
301
|
+
if self._module is None:
|
|
302
|
+
import importlib
|
|
303
|
+
self._module = importlib.import_module(self._module_name)
|
|
304
|
+
return getattr(self._module, name)
|
|
305
|
+
|
|
306
|
+
if typing.TYPE_CHECKING:
|
|
307
|
+
|
|
308
|
+
import aws_cdk as _aws_cdk_ceddda9d
|
|
309
|
+
import aws_cdk.aws_cloudwatch as _aws_cdk_aws_cloudwatch_ceddda9d
|
|
310
|
+
import aws_cdk.aws_dynamodb as _aws_cdk_aws_dynamodb_ceddda9d
|
|
311
|
+
import aws_cdk.aws_ec2 as _aws_cdk_aws_ec2_ceddda9d
|
|
312
|
+
import aws_cdk.aws_iam as _aws_cdk_aws_iam_ceddda9d
|
|
313
|
+
import aws_cdk.aws_kms as _aws_cdk_aws_kms_ceddda9d
|
|
314
|
+
import aws_cdk.aws_lambda as _aws_cdk_aws_lambda_ceddda9d
|
|
315
|
+
import aws_cdk.aws_logs as _aws_cdk_aws_logs_ceddda9d
|
|
316
|
+
import aws_cdk.aws_secretsmanager as _aws_cdk_aws_secretsmanager_ceddda9d
|
|
317
|
+
import aws_cdk.aws_sqs as _aws_cdk_aws_sqs_ceddda9d
|
|
318
|
+
import constructs as _constructs_77d1e7e8
|
|
319
|
+
else:
|
|
320
|
+
|
|
321
|
+
_aws_cdk_aws_cloudwatch_ceddda9d = _LazyImport("aws_cdk.aws_cloudwatch")
|
|
322
|
+
_aws_cdk_aws_dynamodb_ceddda9d = _LazyImport("aws_cdk.aws_dynamodb")
|
|
323
|
+
_aws_cdk_aws_ec2_ceddda9d = _LazyImport("aws_cdk.aws_ec2")
|
|
324
|
+
_aws_cdk_aws_iam_ceddda9d = _LazyImport("aws_cdk.aws_iam")
|
|
325
|
+
_aws_cdk_aws_kms_ceddda9d = _LazyImport("aws_cdk.aws_kms")
|
|
326
|
+
_aws_cdk_aws_lambda_ceddda9d = _LazyImport("aws_cdk.aws_lambda")
|
|
327
|
+
_aws_cdk_aws_logs_ceddda9d = _LazyImport("aws_cdk.aws_logs")
|
|
328
|
+
_aws_cdk_aws_secretsmanager_ceddda9d = _LazyImport("aws_cdk.aws_secretsmanager")
|
|
329
|
+
_aws_cdk_aws_sqs_ceddda9d = _LazyImport("aws_cdk.aws_sqs")
|
|
330
|
+
_aws_cdk_ceddda9d = _LazyImport("aws_cdk")
|
|
331
|
+
_constructs_77d1e7e8 = _LazyImport("constructs")
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
class ConsoleLogs(
|
|
335
|
+
metaclass=jsii.JSIIMeta,
|
|
336
|
+
jsii_type="cdk-github-microvm-runners.ConsoleLogs",
|
|
337
|
+
):
|
|
338
|
+
'''Runtime console capture for a runner set: everything a VM prints while it boots, runs the runner agent, and runs the job.
|
|
339
|
+
|
|
340
|
+
Off unless you add it.
|
|
341
|
+
|
|
342
|
+
Console capture needs a VM execution role. The platform writes these logs
|
|
343
|
+
with the VM's own role, and the construct never creates a VM identity on
|
|
344
|
+
your behalf, so a runner set that turns console capture on without
|
|
345
|
+
``vmExecutionRole`` fails at synth. The two console-write actions on the group
|
|
346
|
+
are granted by you as well, since the construct does not add policy to a
|
|
347
|
+
role it did not create::
|
|
348
|
+
|
|
349
|
+
runners.vm_console_log_group.grant(role, "logs:CreateLogStream", "logs:PutLogEvents")
|
|
350
|
+
|
|
351
|
+
A MicroVM's instance metadata service serves the execution role's
|
|
352
|
+
credentials to arbitrary job code, so whatever that role can do, every job
|
|
353
|
+
running on this runner set can do. Console capture on its own needs nothing
|
|
354
|
+
beyond the two log-write actions above. Job code can also write whatever it
|
|
355
|
+
likes into the console group, so the contents are as trustworthy as the jobs
|
|
356
|
+
that produced them.
|
|
357
|
+
|
|
358
|
+
``ImageLogs`` covers the build-time counterpart and needs no role. The two are
|
|
359
|
+
independent and can both be on.
|
|
360
|
+
|
|
361
|
+
Example::
|
|
362
|
+
|
|
363
|
+
GithubMicrovmRunners(stack, "Runners",
|
|
364
|
+
github=github,
|
|
365
|
+
scope=scope,
|
|
366
|
+
vm_execution_role=role,
|
|
367
|
+
console_logs=ConsoleLogs.enabled()
|
|
368
|
+
)
|
|
369
|
+
'''
|
|
370
|
+
|
|
371
|
+
@jsii.member(jsii_name="enabled")
|
|
372
|
+
@builtins.classmethod
|
|
373
|
+
def enabled(
|
|
374
|
+
cls,
|
|
375
|
+
log_group: typing.Optional["_aws_cdk_aws_logs_ceddda9d.ILogGroup"] = None,
|
|
376
|
+
) -> "ConsoleLogs":
|
|
377
|
+
'''Capture the runtime console.
|
|
378
|
+
|
|
379
|
+
With no argument the construct creates a log
|
|
380
|
+
group and exposes it as ``runners.vmConsoleLogGroup``. Pass an ``ILogGroup``
|
|
381
|
+
to use one whose retention and KMS key you control. Either way the runner
|
|
382
|
+
set needs ``vmExecutionRole``, and that role needs the two console-write
|
|
383
|
+
actions on the group.
|
|
384
|
+
|
|
385
|
+
:param log_group: destination group. Omitted, the construct creates one with the runner set's ``logRetention`` (two weeks by default).
|
|
386
|
+
|
|
387
|
+
Example::
|
|
388
|
+
|
|
389
|
+
console_capture = ConsoleLogs.enabled(my_console_log_group)
|
|
390
|
+
'''
|
|
391
|
+
if __debug__:
|
|
392
|
+
type_hints = cached_type_hints(_typecheckingstub__0548cfa81769608b199a2a959830e9d47b13bb916b5f4181e977c1f03bfa81c7)
|
|
393
|
+
check_type(argname="argument log_group", value=log_group, expected_type=type_hints["log_group"])
|
|
394
|
+
return typing.cast("ConsoleLogs", jsii.sinvoke(cls, "enabled", [log_group]))
|
|
395
|
+
|
|
396
|
+
@builtins.property
|
|
397
|
+
@jsii.member(jsii_name="logGroup")
|
|
398
|
+
def log_group(self) -> typing.Optional["_aws_cdk_aws_logs_ceddda9d.ILogGroup"]:
|
|
399
|
+
'''The group console output goes to, when one was passed to ``ConsoleLogs.enabled()``. ``undefined`` means the construct creates one.'''
|
|
400
|
+
return typing.cast(typing.Optional["_aws_cdk_aws_logs_ceddda9d.ILogGroup"], jsii.get(self, "logGroup"))
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
@jsii.data_type(
|
|
404
|
+
jsii_type="cdk-github-microvm-runners.GithubAppAuthProps",
|
|
405
|
+
jsii_struct_bases=[],
|
|
406
|
+
name_mapping={
|
|
407
|
+
"app_id": "appId",
|
|
408
|
+
"private_key": "privateKey",
|
|
409
|
+
"webhook_secret": "webhookSecret",
|
|
410
|
+
},
|
|
411
|
+
)
|
|
412
|
+
class GithubAppAuthProps:
|
|
413
|
+
def __init__(
|
|
414
|
+
self,
|
|
415
|
+
*,
|
|
416
|
+
app_id: "GithubAppId",
|
|
417
|
+
private_key: "GithubAppKey",
|
|
418
|
+
webhook_secret: "_aws_cdk_aws_secretsmanager_ceddda9d.ISecret",
|
|
419
|
+
) -> None:
|
|
420
|
+
'''Props for ``GithubAuth.app``.
|
|
421
|
+
|
|
422
|
+
:param app_id: The GitHub App's numeric ID, as a literal or a Secrets Manager reference.
|
|
423
|
+
:param private_key: The App's private key, backed by a secret or a KMS key.
|
|
424
|
+
:param webhook_secret: Secret holding the webhook secret used to validate inbound deliveries.
|
|
425
|
+
'''
|
|
426
|
+
if __debug__:
|
|
427
|
+
type_hints = cached_type_hints(_typecheckingstub__e6e950b235861eb6ceb59c62bebf431836fac157088b1334fedf915b19dec8a0)
|
|
428
|
+
check_type(argname="argument app_id", value=app_id, expected_type=type_hints["app_id"])
|
|
429
|
+
check_type(argname="argument private_key", value=private_key, expected_type=type_hints["private_key"])
|
|
430
|
+
check_type(argname="argument webhook_secret", value=webhook_secret, expected_type=type_hints["webhook_secret"])
|
|
431
|
+
self._values: typing.Dict[builtins.str, typing.Any] = {
|
|
432
|
+
"app_id": app_id,
|
|
433
|
+
"private_key": private_key,
|
|
434
|
+
"webhook_secret": webhook_secret,
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
@builtins.property
|
|
438
|
+
def app_id(self) -> "GithubAppId":
|
|
439
|
+
'''The GitHub App's numeric ID, as a literal or a Secrets Manager reference.'''
|
|
440
|
+
result = self._values.get("app_id")
|
|
441
|
+
assert result is not None, "Required property 'app_id' is missing"
|
|
442
|
+
return typing.cast("GithubAppId", result)
|
|
443
|
+
|
|
444
|
+
@builtins.property
|
|
445
|
+
def private_key(self) -> "GithubAppKey":
|
|
446
|
+
'''The App's private key, backed by a secret or a KMS key.'''
|
|
447
|
+
result = self._values.get("private_key")
|
|
448
|
+
assert result is not None, "Required property 'private_key' is missing"
|
|
449
|
+
return typing.cast("GithubAppKey", result)
|
|
450
|
+
|
|
451
|
+
@builtins.property
|
|
452
|
+
def webhook_secret(self) -> "_aws_cdk_aws_secretsmanager_ceddda9d.ISecret":
|
|
453
|
+
'''Secret holding the webhook secret used to validate inbound deliveries.'''
|
|
454
|
+
result = self._values.get("webhook_secret")
|
|
455
|
+
assert result is not None, "Required property 'webhook_secret' is missing"
|
|
456
|
+
return typing.cast("_aws_cdk_aws_secretsmanager_ceddda9d.ISecret", result)
|
|
457
|
+
|
|
458
|
+
def __eq__(self, rhs: typing.Any) -> builtins.bool:
|
|
459
|
+
return isinstance(rhs, self.__class__) and rhs._values == self._values
|
|
460
|
+
|
|
461
|
+
def __ne__(self, rhs: typing.Any) -> builtins.bool:
|
|
462
|
+
return not (rhs == self)
|
|
463
|
+
|
|
464
|
+
def __repr__(self) -> str:
|
|
465
|
+
return "GithubAppAuthProps(%s)" % ", ".join(
|
|
466
|
+
k + "=" + repr(v) for k, v in self._values.items()
|
|
467
|
+
)
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
class GithubAppId(
|
|
471
|
+
metaclass=jsii.JSIIMeta,
|
|
472
|
+
jsii_type="cdk-github-microvm-runners.GithubAppId",
|
|
473
|
+
):
|
|
474
|
+
'''Where a GitHub App's numeric ID comes from: a literal known at synth time, or a Secrets Manager secret read at runtime.
|
|
475
|
+
|
|
476
|
+
The secret form makes setup single-pass. A GitHub App can only be created
|
|
477
|
+
once the runner set's webhook URL exists, so an App ID that has to be known
|
|
478
|
+
at synth means deploying twice. Referencing the ID by secret, the way the
|
|
479
|
+
private key and webhook secret already are, lets you deploy, then create the
|
|
480
|
+
App and write its ID into the secret, with no redeploy.
|
|
481
|
+
|
|
482
|
+
Build one with the static factories below; the constructor is private.
|
|
483
|
+
|
|
484
|
+
Example::
|
|
485
|
+
|
|
486
|
+
app_id = GithubAppId.from_secret(
|
|
487
|
+
Secret.from_secret_name_v2(stack, "AppId", "microvm-runner/dev/app-id"))
|
|
488
|
+
'''
|
|
489
|
+
|
|
490
|
+
@jsii.member(jsii_name="fromSecret")
|
|
491
|
+
@builtins.classmethod
|
|
492
|
+
def from_secret(
|
|
493
|
+
cls,
|
|
494
|
+
secret: "_aws_cdk_aws_secretsmanager_ceddda9d.ISecret",
|
|
495
|
+
) -> "GithubAppId":
|
|
496
|
+
'''The App ID is read at runtime from a Secrets Manager secret whose value is the numeric ID.
|
|
497
|
+
|
|
498
|
+
The secret need not exist at deploy time.
|
|
499
|
+
|
|
500
|
+
:param secret: -
|
|
501
|
+
|
|
502
|
+
Example::
|
|
503
|
+
|
|
504
|
+
app_id = GithubAppId.from_secret(
|
|
505
|
+
Secret.from_secret_name_v2(stack, "AppId", "microvm-runner/dev/app-id"))
|
|
506
|
+
'''
|
|
507
|
+
if __debug__:
|
|
508
|
+
type_hints = cached_type_hints(_typecheckingstub__aba0941864c428347812aa10a096b18df3ae77616773316bd134e2764ae2657c)
|
|
509
|
+
check_type(argname="argument secret", value=secret, expected_type=type_hints["secret"])
|
|
510
|
+
return typing.cast("GithubAppId", jsii.sinvoke(cls, "fromSecret", [secret]))
|
|
511
|
+
|
|
512
|
+
@jsii.member(jsii_name="fromValue")
|
|
513
|
+
@builtins.classmethod
|
|
514
|
+
def from_value(cls, value: builtins.str) -> "GithubAppId":
|
|
515
|
+
'''The App ID is a literal string known at synth time.
|
|
516
|
+
|
|
517
|
+
:param value: -
|
|
518
|
+
|
|
519
|
+
Example::
|
|
520
|
+
|
|
521
|
+
app_id = GithubAppId.from_value("123456")
|
|
522
|
+
'''
|
|
523
|
+
if __debug__:
|
|
524
|
+
type_hints = cached_type_hints(_typecheckingstub__6b22d9ed14d289886f4ed34dc8cfd25d58e6bbda42419d5097a7a73ea48bd10f)
|
|
525
|
+
check_type(argname="argument value", value=value, expected_type=type_hints["value"])
|
|
526
|
+
return typing.cast("GithubAppId", jsii.sinvoke(cls, "fromValue", [value]))
|
|
527
|
+
|
|
528
|
+
@builtins.property
|
|
529
|
+
@jsii.member(jsii_name="secret")
|
|
530
|
+
def secret(self) -> typing.Optional["_aws_cdk_aws_secretsmanager_ceddda9d.ISecret"]:
|
|
531
|
+
'''The secret holding the ID, for an ID built with ``fromSecret()``.'''
|
|
532
|
+
return typing.cast(typing.Optional["_aws_cdk_aws_secretsmanager_ceddda9d.ISecret"], jsii.get(self, "secret"))
|
|
533
|
+
|
|
534
|
+
@builtins.property
|
|
535
|
+
@jsii.member(jsii_name="value")
|
|
536
|
+
def value(self) -> typing.Optional[builtins.str]:
|
|
537
|
+
'''The literal ID, for an ID built with ``fromValue()``.'''
|
|
538
|
+
return typing.cast(typing.Optional[builtins.str], jsii.get(self, "value"))
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
class GithubAppKey(
|
|
542
|
+
metaclass=jsii.JSIIMeta,
|
|
543
|
+
jsii_type="cdk-github-microvm-runners.GithubAppKey",
|
|
544
|
+
):
|
|
545
|
+
'''Where a GitHub App's private key lives: a Secrets Manager secret holding the PEM, or a KMS key that signs the App's JWTs directly.
|
|
546
|
+
|
|
547
|
+
Build one with the static factories below; the constructor is private.
|
|
548
|
+
|
|
549
|
+
Example::
|
|
550
|
+
|
|
551
|
+
private_key = GithubAppKey.from_secret(
|
|
552
|
+
Secret.from_secret_name_v2(stack, "AppKey", "microvm-runner/dev/app-private-key"))
|
|
553
|
+
'''
|
|
554
|
+
|
|
555
|
+
@jsii.member(jsii_name="fromKmsKey")
|
|
556
|
+
@builtins.classmethod
|
|
557
|
+
def from_kms_key(cls, key: "_aws_cdk_aws_kms_ceddda9d.IKey") -> "GithubAppKey":
|
|
558
|
+
'''The App's private key lives in KMS and is used via ``kms:Sign``.
|
|
559
|
+
|
|
560
|
+
:param key: -
|
|
561
|
+
|
|
562
|
+
Example::
|
|
563
|
+
|
|
564
|
+
from aws_cdk.aws_kms import Key
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
private_key = GithubAppKey.from_kms_key(
|
|
568
|
+
Key.from_key_arn(stack, "AppKey", "arn:aws:kms:us-east-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"))
|
|
569
|
+
'''
|
|
570
|
+
if __debug__:
|
|
571
|
+
type_hints = cached_type_hints(_typecheckingstub__cc9961f681c63592cc8d260fe3e536a71239765b00a83bdec348eff483581f2b)
|
|
572
|
+
check_type(argname="argument key", value=key, expected_type=type_hints["key"])
|
|
573
|
+
return typing.cast("GithubAppKey", jsii.sinvoke(cls, "fromKmsKey", [key]))
|
|
574
|
+
|
|
575
|
+
@jsii.member(jsii_name="fromSecret")
|
|
576
|
+
@builtins.classmethod
|
|
577
|
+
def from_secret(
|
|
578
|
+
cls,
|
|
579
|
+
secret: "_aws_cdk_aws_secretsmanager_ceddda9d.ISecret",
|
|
580
|
+
) -> "GithubAppKey":
|
|
581
|
+
'''The App's private key is stored as a PEM in Secrets Manager.
|
|
582
|
+
|
|
583
|
+
:param secret: -
|
|
584
|
+
|
|
585
|
+
Example::
|
|
586
|
+
|
|
587
|
+
private_key = GithubAppKey.from_secret(
|
|
588
|
+
Secret.from_secret_name_v2(stack, "AppKey", "microvm-runner/dev/app-private-key"))
|
|
589
|
+
'''
|
|
590
|
+
if __debug__:
|
|
591
|
+
type_hints = cached_type_hints(_typecheckingstub__b690547df91198ce68555c0eef4906781d6764b68601422750750169edd60220)
|
|
592
|
+
check_type(argname="argument secret", value=secret, expected_type=type_hints["secret"])
|
|
593
|
+
return typing.cast("GithubAppKey", jsii.sinvoke(cls, "fromSecret", [secret]))
|
|
594
|
+
|
|
595
|
+
@builtins.property
|
|
596
|
+
@jsii.member(jsii_name="kmsKey")
|
|
597
|
+
def kms_key(self) -> typing.Optional["_aws_cdk_aws_kms_ceddda9d.IKey"]:
|
|
598
|
+
'''The signing key, for a key built with ``fromKmsKey()``.'''
|
|
599
|
+
return typing.cast(typing.Optional["_aws_cdk_aws_kms_ceddda9d.IKey"], jsii.get(self, "kmsKey"))
|
|
600
|
+
|
|
601
|
+
@builtins.property
|
|
602
|
+
@jsii.member(jsii_name="secret")
|
|
603
|
+
def secret(self) -> typing.Optional["_aws_cdk_aws_secretsmanager_ceddda9d.ISecret"]:
|
|
604
|
+
'''The secret holding the PEM, for a key built with ``fromSecret()``.'''
|
|
605
|
+
return typing.cast(typing.Optional["_aws_cdk_aws_secretsmanager_ceddda9d.ISecret"], jsii.get(self, "secret"))
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
class GithubAuth(
|
|
609
|
+
metaclass=jsii.JSIIMeta,
|
|
610
|
+
jsii_type="cdk-github-microvm-runners.GithubAuth",
|
|
611
|
+
):
|
|
612
|
+
'''How a runner set authenticates to GitHub: as a GitHub App, whose private key is backed by a secret or a KMS key, or with a personal access token.
|
|
613
|
+
|
|
614
|
+
Either
|
|
615
|
+
form also carries the webhook secret that inbound GitHub deliveries are
|
|
616
|
+
validated against.
|
|
617
|
+
|
|
618
|
+
Build one with the static factories below; the constructor is private.
|
|
619
|
+
|
|
620
|
+
Example::
|
|
621
|
+
|
|
622
|
+
auth = GithubAuth.app(
|
|
623
|
+
app_id=GithubAppId.from_secret(
|
|
624
|
+
Secret.from_secret_name_v2(stack, "AppId", "microvm-runner/dev/app-id")),
|
|
625
|
+
private_key=GithubAppKey.from_secret(
|
|
626
|
+
Secret.from_secret_name_v2(stack, "AppKey", "microvm-runner/dev/app-private-key")),
|
|
627
|
+
webhook_secret=Secret.from_secret_name_v2(stack, "WebhookSecret", "microvm-runner/dev/webhook-secret")
|
|
628
|
+
)
|
|
629
|
+
'''
|
|
630
|
+
|
|
631
|
+
@jsii.member(jsii_name="app")
|
|
632
|
+
@builtins.classmethod
|
|
633
|
+
def app(
|
|
634
|
+
cls,
|
|
635
|
+
*,
|
|
636
|
+
app_id: "GithubAppId",
|
|
637
|
+
private_key: "GithubAppKey",
|
|
638
|
+
webhook_secret: "_aws_cdk_aws_secretsmanager_ceddda9d.ISecret",
|
|
639
|
+
) -> "GithubAuth":
|
|
640
|
+
'''Authenticate as a GitHub App.
|
|
641
|
+
|
|
642
|
+
:param app_id: The GitHub App's numeric ID, as a literal or a Secrets Manager reference.
|
|
643
|
+
:param private_key: The App's private key, backed by a secret or a KMS key.
|
|
644
|
+
:param webhook_secret: Secret holding the webhook secret used to validate inbound deliveries.
|
|
645
|
+
|
|
646
|
+
Example::
|
|
647
|
+
|
|
648
|
+
auth = GithubAuth.app(
|
|
649
|
+
app_id=GithubAppId.from_secret(
|
|
650
|
+
Secret.from_secret_name_v2(stack, "AppId", "microvm-runner/dev/app-id")),
|
|
651
|
+
private_key=GithubAppKey.from_secret(
|
|
652
|
+
Secret.from_secret_name_v2(stack, "AppKey", "microvm-runner/dev/app-private-key")),
|
|
653
|
+
webhook_secret=Secret.from_secret_name_v2(stack, "WebhookSecret", "microvm-runner/dev/webhook-secret")
|
|
654
|
+
)
|
|
655
|
+
'''
|
|
656
|
+
props = GithubAppAuthProps(
|
|
657
|
+
app_id=app_id, private_key=private_key, webhook_secret=webhook_secret
|
|
658
|
+
)
|
|
659
|
+
|
|
660
|
+
return typing.cast("GithubAuth", jsii.sinvoke(cls, "app", [props]))
|
|
661
|
+
|
|
662
|
+
@jsii.member(jsii_name="pat")
|
|
663
|
+
@builtins.classmethod
|
|
664
|
+
def pat(
|
|
665
|
+
cls,
|
|
666
|
+
*,
|
|
667
|
+
token: "_aws_cdk_aws_secretsmanager_ceddda9d.ISecret",
|
|
668
|
+
webhook_secret: "_aws_cdk_aws_secretsmanager_ceddda9d.ISecret",
|
|
669
|
+
) -> "GithubAuth":
|
|
670
|
+
'''Authenticate with a personal access token.
|
|
671
|
+
|
|
672
|
+
:param token: Secret holding a GitHub personal access token.
|
|
673
|
+
:param webhook_secret: Secret holding the webhook secret used to validate inbound deliveries.
|
|
674
|
+
|
|
675
|
+
Example::
|
|
676
|
+
|
|
677
|
+
auth = GithubAuth.pat(
|
|
678
|
+
token=Secret.from_secret_name_v2(stack, "Pat", "microvm-runner/dev/token"),
|
|
679
|
+
webhook_secret=Secret.from_secret_name_v2(stack, "WebhookSecret", "microvm-runner/dev/webhook-secret")
|
|
680
|
+
)
|
|
681
|
+
'''
|
|
682
|
+
props = GithubPatAuthProps(token=token, webhook_secret=webhook_secret)
|
|
683
|
+
|
|
684
|
+
return typing.cast("GithubAuth", jsii.sinvoke(cls, "pat", [props]))
|
|
685
|
+
|
|
686
|
+
@jsii.member(jsii_name="bindEnv")
|
|
687
|
+
def bind_env(self) -> typing.Mapping[builtins.str, builtins.str]:
|
|
688
|
+
'''Serialize to the environment variables the runner set's handlers read: ``GH_AUTH_KIND``, ``GH_APP_ID`` or ``GH_APP_ID_SECRET_ARN``, ``GH_KEY_SECRET_ARN`` or ``GH_KEY_KMS_ARN``, ``GH_PAT_SECRET_ARN``, and ``GH_WEBHOOK_SECRET_ARN``.
|
|
689
|
+
|
|
690
|
+
Entries that do not apply are left out.
|
|
691
|
+
'''
|
|
692
|
+
return typing.cast(typing.Mapping[builtins.str, builtins.str], jsii.invoke(self, "bindEnv", []))
|
|
693
|
+
|
|
694
|
+
@jsii.member(jsii_name="grantRead")
|
|
695
|
+
def grant_read(self, grantee: "_aws_cdk_aws_iam_ceddda9d.IGrantable") -> None:
|
|
696
|
+
'''Grant ``grantee`` read access to whichever credentials this auth carries: the App's secret-backed key and/or ``kms:Sign`` on its KMS key, plus its secret-backed App ID when one is used, or the PAT secret — plus, in every case, read access to the webhook secret.
|
|
697
|
+
|
|
698
|
+
This is the full set, for a handler that has to act as the App. A handler
|
|
699
|
+
that only verifies signatures wants {@link grantReadWebhookSecret}.
|
|
700
|
+
|
|
701
|
+
:param grantee: -
|
|
702
|
+
'''
|
|
703
|
+
if __debug__:
|
|
704
|
+
type_hints = cached_type_hints(_typecheckingstub__970e66a646e2fc86c035066057cff7cd247b431b227ac9f2d5a8c86ed710c988)
|
|
705
|
+
check_type(argname="argument grantee", value=grantee, expected_type=type_hints["grantee"])
|
|
706
|
+
return typing.cast(None, jsii.invoke(self, "grantRead", [grantee]))
|
|
707
|
+
|
|
708
|
+
@jsii.member(jsii_name="grantReadWebhookSecret")
|
|
709
|
+
def grant_read_webhook_secret(
|
|
710
|
+
self,
|
|
711
|
+
grantee: "_aws_cdk_aws_iam_ceddda9d.IGrantable",
|
|
712
|
+
) -> None:
|
|
713
|
+
'''Grant ``grantee`` read access to the webhook secret, and nothing else.
|
|
714
|
+
|
|
715
|
+
This is all a handler needs to verify the HMAC signature GitHub sends with
|
|
716
|
+
every delivery. It is deliberately separate from {@link grantRead}, which
|
|
717
|
+
also hands over the credentials that can act AS the App — minting
|
|
718
|
+
installation tokens, registering runners. A component that only checks
|
|
719
|
+
signatures and enqueues has no use for those, and the webhook handler is
|
|
720
|
+
the one component reachable from the public internet.
|
|
721
|
+
|
|
722
|
+
:param grantee: -
|
|
723
|
+
|
|
724
|
+
Example::
|
|
725
|
+
|
|
726
|
+
github.grant_read_webhook_secret(role)
|
|
727
|
+
'''
|
|
728
|
+
if __debug__:
|
|
729
|
+
type_hints = cached_type_hints(_typecheckingstub__80b1bb7036f50148e74587e4f8bac689760f9f314afddfa588fbc2a86d5062dd)
|
|
730
|
+
check_type(argname="argument grantee", value=grantee, expected_type=type_hints["grantee"])
|
|
731
|
+
return typing.cast(None, jsii.invoke(self, "grantReadWebhookSecret", [grantee]))
|
|
732
|
+
|
|
733
|
+
@builtins.property
|
|
734
|
+
@jsii.member(jsii_name="kind")
|
|
735
|
+
def kind(self) -> "GithubAuthKind":
|
|
736
|
+
'''Whether this is App or personal-access-token authentication.'''
|
|
737
|
+
return typing.cast("GithubAuthKind", jsii.get(self, "kind"))
|
|
738
|
+
|
|
739
|
+
@builtins.property
|
|
740
|
+
@jsii.member(jsii_name="webhookSecret")
|
|
741
|
+
def webhook_secret(self) -> "_aws_cdk_aws_secretsmanager_ceddda9d.ISecret":
|
|
742
|
+
'''Secret holding the webhook secret inbound deliveries are validated against.'''
|
|
743
|
+
return typing.cast("_aws_cdk_aws_secretsmanager_ceddda9d.ISecret", jsii.get(self, "webhookSecret"))
|
|
744
|
+
|
|
745
|
+
@builtins.property
|
|
746
|
+
@jsii.member(jsii_name="appId")
|
|
747
|
+
def app_id(self) -> typing.Optional["GithubAppId"]:
|
|
748
|
+
'''The App's ID, for App authentication.'''
|
|
749
|
+
return typing.cast(typing.Optional["GithubAppId"], jsii.get(self, "appId"))
|
|
750
|
+
|
|
751
|
+
@builtins.property
|
|
752
|
+
@jsii.member(jsii_name="privateKey")
|
|
753
|
+
def private_key(self) -> typing.Optional["GithubAppKey"]:
|
|
754
|
+
'''The App's private key, for App authentication.'''
|
|
755
|
+
return typing.cast(typing.Optional["GithubAppKey"], jsii.get(self, "privateKey"))
|
|
756
|
+
|
|
757
|
+
@builtins.property
|
|
758
|
+
@jsii.member(jsii_name="token")
|
|
759
|
+
def token(self) -> typing.Optional["_aws_cdk_aws_secretsmanager_ceddda9d.ISecret"]:
|
|
760
|
+
'''The personal access token secret, for token authentication.'''
|
|
761
|
+
return typing.cast(typing.Optional["_aws_cdk_aws_secretsmanager_ceddda9d.ISecret"], jsii.get(self, "token"))
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
@jsii.enum(jsii_type="cdk-github-microvm-runners.GithubAuthKind")
|
|
765
|
+
class GithubAuthKind(enum.Enum):
|
|
766
|
+
'''Which credential flow a ``GithubAuth`` represents.'''
|
|
767
|
+
|
|
768
|
+
APP = "APP"
|
|
769
|
+
'''A GitHub App.'''
|
|
770
|
+
PAT = "PAT"
|
|
771
|
+
'''A personal access token.'''
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
class GithubMicrovmRunners(
|
|
775
|
+
_constructs_77d1e7e8.Construct,
|
|
776
|
+
metaclass=jsii.JSIIMeta,
|
|
777
|
+
jsii_type="cdk-github-microvm-runners.GithubMicrovmRunners",
|
|
778
|
+
):
|
|
779
|
+
'''A runner set: one deployment of GitHub Actions runners that run on AWS Lambda MicroVMs, with a fresh VM per job that is thrown away when the job ends.
|
|
780
|
+
|
|
781
|
+
The construct deploys a webhook handler for GitHub's ``workflow_job``
|
|
782
|
+
deliveries, a queue those deliveries become launch and terminate intents on,
|
|
783
|
+
a launcher that starts a VM and registers it with GitHub for each queued
|
|
784
|
+
job, and a janitor that sweeps on a schedule for VMs and runners that
|
|
785
|
+
outlived their job. Every runner class registered through
|
|
786
|
+
``addRunnerClass`` adds an image build of its own, and a runner set needs
|
|
787
|
+
at least one class to synthesize.
|
|
788
|
+
|
|
789
|
+
Deploying it takes two props: how to authenticate to GitHub, and which
|
|
790
|
+
GitHub scope the runners register into. The VMs themselves carry no AWS
|
|
791
|
+
identity unless ``GithubMicrovmRunnersProps.vmExecutionRole`` gives them
|
|
792
|
+
one.
|
|
793
|
+
|
|
794
|
+
Example::
|
|
795
|
+
|
|
796
|
+
runner_set = GithubMicrovmRunners(stack, "Runners",
|
|
797
|
+
github=GithubAuth.app(
|
|
798
|
+
app_id=GithubAppId.from_secret(
|
|
799
|
+
Secret.from_secret_name_v2(stack, "AppId", "microvm-runner/dev/app-id")),
|
|
800
|
+
private_key=GithubAppKey.from_secret(
|
|
801
|
+
Secret.from_secret_name_v2(stack, "AppKey", "microvm-runner/dev/app-private-key")),
|
|
802
|
+
webhook_secret=Secret.from_secret_name_v2(stack, "WebhookSecret", "microvm-runner/dev/webhook-secret")
|
|
803
|
+
),
|
|
804
|
+
scope=RunnerScope.org("my-org")
|
|
805
|
+
)
|
|
806
|
+
|
|
807
|
+
runner_set.add_runner_class("microvm", size=MicrovmSize.GB4)
|
|
808
|
+
'''
|
|
809
|
+
|
|
810
|
+
def __init__(
|
|
811
|
+
self,
|
|
812
|
+
scope_: "_constructs_77d1e7e8.Construct",
|
|
813
|
+
id: builtins.str,
|
|
814
|
+
*,
|
|
815
|
+
github: "GithubAuth",
|
|
816
|
+
scope: "RunnerScope",
|
|
817
|
+
additional_regions: typing.Optional[typing.Sequence[builtins.str]] = None,
|
|
818
|
+
console_logs: typing.Optional["ConsoleLogs"] = None,
|
|
819
|
+
dead_letter_retention: typing.Optional["_aws_cdk_ceddda9d.Duration"] = None,
|
|
820
|
+
emit_metrics: typing.Optional[builtins.bool] = None,
|
|
821
|
+
encryption_key: typing.Optional["_aws_cdk_aws_kms_ceddda9d.IKey"] = None,
|
|
822
|
+
idle_runner_grace_seconds: typing.Optional[jsii.Number] = None,
|
|
823
|
+
image_logs: typing.Optional["ImageLogs"] = None,
|
|
824
|
+
janitor_interval: typing.Optional["_aws_cdk_ceddda9d.Duration"] = None,
|
|
825
|
+
keep_image_versions: typing.Optional[jsii.Number] = None,
|
|
826
|
+
lambda_memory_size: typing.Optional[jsii.Number] = None,
|
|
827
|
+
log_retention: typing.Optional["_aws_cdk_aws_logs_ceddda9d.RetentionDays"] = None,
|
|
828
|
+
max_concurrent_vms: typing.Optional[jsii.Number] = None,
|
|
829
|
+
max_job_duration: typing.Optional["_aws_cdk_ceddda9d.Duration"] = None,
|
|
830
|
+
max_receive_count: typing.Optional[jsii.Number] = None,
|
|
831
|
+
network: typing.Optional["RunnerNetwork"] = None,
|
|
832
|
+
permissions_boundary: typing.Optional["_aws_cdk_aws_iam_ceddda9d.IManagedPolicy"] = None,
|
|
833
|
+
point_in_time_recovery: typing.Optional[builtins.bool] = None,
|
|
834
|
+
recover_stuck_launches: typing.Optional[builtins.bool] = None,
|
|
835
|
+
removal_policy: typing.Optional["_aws_cdk_ceddda9d.RemovalPolicy"] = None,
|
|
836
|
+
vm_execution_role: typing.Optional["_aws_cdk_aws_iam_ceddda9d.IRole"] = None,
|
|
837
|
+
warm_pool_interval: typing.Optional["_aws_cdk_ceddda9d.Duration"] = None,
|
|
838
|
+
webhook: typing.Optional["WebhookEndpoint"] = None,
|
|
839
|
+
webhook_reserved_concurrency: typing.Optional[jsii.Number] = None,
|
|
840
|
+
) -> None:
|
|
841
|
+
'''
|
|
842
|
+
:param scope_: -
|
|
843
|
+
:param id: -
|
|
844
|
+
:param github: How the runner set authenticates to GitHub, as an App or with a personal access token. This also carries the webhook secret.
|
|
845
|
+
:param scope: Which GitHub scope, an organization or a list of repositories, registered runners are visible to.
|
|
846
|
+
:param additional_regions: Additional regions to accept as Lambda MicroVMs regions, beyond the ones this library already knows about. Deploying into a region on neither list fails at synth. Default: [] (only the regions this library knows about)
|
|
847
|
+
:param console_logs: Where a VM's runtime console goes: everything it prints while it boots, runs the runner agent, and runs the job. ``ConsoleLogs.enabled()`` has the construct create the group and expose it as ``vmConsoleLogGroup``, and ``ConsoleLogs.enabled(logGroup)`` uses one you control. The platform writes these logs with the VM's own role, so this requires ``vmExecutionRole``; see ``ConsoleLogs`` for what that role means for job code. Independent of ``imageLogs``. Default: undefined (no runtime console capture)
|
|
848
|
+
:param dead_letter_retention: How long the dead-letter queue retains a failed launch or terminate intent. SQS allows up to 14 days, which is also how long ``recoverStuckLaunches`` has to re-drive a message before SQS drops it. Default: Duration.days(4) (SQS default)
|
|
849
|
+
:param emit_metrics: Report this runner set's CloudWatch custom metrics. Those are the janitor's per-sweep counters, the launcher's per-launch outcomes and spin-up timings, and the warm pool's fill numbers — everything ``GithubMicrovmRunnersMetrics`` names. With this off the handlers report none of them. CloudWatch bills custom metrics per metric per month, and this runner set's bill is not a fixed number: the launcher and warm-pool metrics carry a runner-class dimension, so each one becomes a separate billable metric per registered runner class. The two alarms backed by these metrics, ``sweepErrorsAlarm`` and ``stuckLaunchesRecoveredAlarm``, throw at synth unless this is on, since the metric they watch would never report. ``deadLetterQueueNotEmptyAlarm`` watches an SQS metric and works either way. The metric accessors on ``GithubMicrovmRunnersMetrics`` return a ``Metric`` regardless, so a dashboard can be built ahead of turning metrics on. Default: false (no metrics emitted)
|
|
850
|
+
:param encryption_key: Customer-managed KMS key for this runner set's data at rest: the DynamoDB runner table, the SQS job queue and dead-letter queue, and any log group this construct creates. Log groups you bring yourself, and the GitHub secrets you pass in, keep their own keys. Default: undefined (AWS-managed keys)
|
|
851
|
+
:param idle_runner_grace_seconds: How many seconds a registered runner may sit idle before the janitor's two-strike sweep treats it as stuck. Default: 600
|
|
852
|
+
:param image_logs: Where build-time image logs go: the Docker build layers and the ready-probe banner from each image build. ``ImageLogs.enabled()`` sends them to the platform's own CloudWatch group, and ``ImageLogs.enabled(logGroup)`` to a group whose retention and KMS key you control. These are written by the image build role rather than by a VM, so they need no VM execution role. Independent of ``consoleLogs``. Default: undefined (no image logs)
|
|
853
|
+
:param janitor_interval: How often the janitor sweep runs. Default: Duration.minutes(5)
|
|
854
|
+
:param keep_image_versions: How many MicroVM image versions to keep per runner class. The janitor prunes inactive versions past this count. Default: 5
|
|
855
|
+
:param lambda_memory_size: Memory, in MiB, for the handler Lambdas: the webhook, the launcher, the janitor, and the warm pool. The janitor's sweep scans the runner table and reconciles every running VM, so it is the handler most sensitive to this on a busy runner set. Default: 128
|
|
856
|
+
:param log_retention: Retention for the CloudWatch log groups this construct creates: the handler Lambda log groups and, when console capture is on, the VM console group. Default: logs.RetentionDays.TWO_WEEKS
|
|
857
|
+
:param max_concurrent_vms: Maximum number of MicroVMs this runner set runs at once. Default: 10
|
|
858
|
+
:param max_job_duration: How long a job may run before its MicroVM is terminated. The VM is killed five minutes after this value, not at it. The runner set asks the platform for ``maxJobDuration + 5 minutes``, so that a job which reaches its own limit is stopped by the runner — which reports the timeout to GitHub and lets the VM come down cleanly — rather than by the platform removing the machine underneath it. Treat the five minutes as headroom for that shutdown rather than as extra running time. Default: Duration.hours(6)
|
|
859
|
+
:param max_receive_count: How many times a launch intent is redriven before it dead-letters. A runner set already at ``maxConcurrentVms`` redrives capacity-rejected launches through this same budget, so on a runner set that regularly runs at capacity this count is how long a queued job waits before its launch is dropped. See docs/service-quotas.md. Default: 20
|
|
860
|
+
:param network: How launched MicroVMs and image builds reach the network. Default: RunnerNetwork.internetEgress()
|
|
861
|
+
:param permissions_boundary: Permissions boundary applied to every IAM role this construct creates: the handler execution roles, the per-class image build roles, and the network-connector operator role. It is applied once at construct scope, so roles created later also carry it — the warm-pool handler's role, and the build role of any runner class registered after construction. Default: undefined (no boundary)
|
|
862
|
+
:param point_in_time_recovery: Turn on DynamoDB point-in-time recovery for the runner table. Default: false
|
|
863
|
+
:param recover_stuck_launches: Recover launches that dead-lettered while GitHub Actions was down. Each janitor sweep re-drives dead-lettered launch messages back onto the job queue, but only for jobs GitHub still reports as queued; a launch whose job has since completed or been cancelled is discarded rather than booting a VM for work nobody is waiting on. Recovery happens once an outage ends, since GitHub dispatches no jobs while it is down. The janitor counts each recovered launch under the ``stuckLaunchesRecovered`` metric, which reports when ``emitMetrics`` is on. Default: false
|
|
864
|
+
:param removal_policy: Removal policy for this runner set's stateful resources: the runner table and any log group the construct creates. The table holds correlation data for VMs that are currently running, all of which the janitor can rebuild from the MicroVM and GitHub APIs. Default: RemovalPolicy.DESTROY
|
|
865
|
+
:param vm_execution_role: An AWS identity for this runner set's runner VMs. By default the VMs carry no AWS identity at all: the runner agent talks outbound to GitHub, the just-in-time registration is pushed to the VM over a platform-authenticated channel, and a job that needs AWS assumes its own role through GitHub OIDC. With a role attached, the MicroVM's instance metadata service serves that role's credentials to arbitrary job code, so every job running on this runner set can do whatever the role can do. ``consoleLogs`` requires a role, because the platform writes a VM's console output using it. Default: undefined (the VMs carry no AWS identity)
|
|
866
|
+
:param warm_pool_interval: How often the warm-pool sweep refills pre-booted VMs. It applies only to runner classes that set ``RunnerClassProps.warmPoolSize``, and the warm-pool handler and its schedule are only created once such a class is registered. A runner set with no warm class never runs this sweep, and never reads this value. Default: Duration.minutes(2)
|
|
867
|
+
:param webhook: How the webhook handler is exposed to GitHub. Default: WebhookEndpoint.functionUrl()
|
|
868
|
+
:param webhook_reserved_concurrency: Reserved concurrency for the webhook Lambda, which caps how many webhook deliveries the runner set processes at once. Reserved concurrency is carved out of the account's shared pool of unreserved concurrency, so a runner set that sets it takes that capacity away from every other function in the account. Must be a positive integer when set, since ``0`` would disable the webhook entirely. Default: undefined (no reservation; the webhook draws from the shared pool)
|
|
869
|
+
'''
|
|
870
|
+
if __debug__:
|
|
871
|
+
type_hints = cached_type_hints(_typecheckingstub__f9ccf90cd58a24eaea8e05c002c729a7c0b56c6afdd04d8cd485938eed8facc5)
|
|
872
|
+
check_type(argname="argument scope_", value=scope_, expected_type=type_hints["scope_"])
|
|
873
|
+
check_type(argname="argument id", value=id, expected_type=type_hints["id"])
|
|
874
|
+
props = GithubMicrovmRunnersProps(
|
|
875
|
+
github=github,
|
|
876
|
+
scope=scope,
|
|
877
|
+
additional_regions=additional_regions,
|
|
878
|
+
console_logs=console_logs,
|
|
879
|
+
dead_letter_retention=dead_letter_retention,
|
|
880
|
+
emit_metrics=emit_metrics,
|
|
881
|
+
encryption_key=encryption_key,
|
|
882
|
+
idle_runner_grace_seconds=idle_runner_grace_seconds,
|
|
883
|
+
image_logs=image_logs,
|
|
884
|
+
janitor_interval=janitor_interval,
|
|
885
|
+
keep_image_versions=keep_image_versions,
|
|
886
|
+
lambda_memory_size=lambda_memory_size,
|
|
887
|
+
log_retention=log_retention,
|
|
888
|
+
max_concurrent_vms=max_concurrent_vms,
|
|
889
|
+
max_job_duration=max_job_duration,
|
|
890
|
+
max_receive_count=max_receive_count,
|
|
891
|
+
network=network,
|
|
892
|
+
permissions_boundary=permissions_boundary,
|
|
893
|
+
point_in_time_recovery=point_in_time_recovery,
|
|
894
|
+
recover_stuck_launches=recover_stuck_launches,
|
|
895
|
+
removal_policy=removal_policy,
|
|
896
|
+
vm_execution_role=vm_execution_role,
|
|
897
|
+
warm_pool_interval=warm_pool_interval,
|
|
898
|
+
webhook=webhook,
|
|
899
|
+
webhook_reserved_concurrency=webhook_reserved_concurrency,
|
|
900
|
+
)
|
|
901
|
+
|
|
902
|
+
jsii.create(self.__class__, self, [scope_, id, props])
|
|
903
|
+
|
|
904
|
+
@jsii.member(jsii_name="addRunnerClass")
|
|
905
|
+
def add_runner_class(
|
|
906
|
+
self,
|
|
907
|
+
label: builtins.str,
|
|
908
|
+
*,
|
|
909
|
+
size: "MicrovmSize",
|
|
910
|
+
idle_policy: typing.Optional[typing.Union["MicrovmIdlePolicy", typing.Dict[builtins.str, typing.Any]]] = None,
|
|
911
|
+
image: typing.Optional["RunnerImage"] = None,
|
|
912
|
+
warm_pool_size: typing.Optional[jsii.Number] = None,
|
|
913
|
+
) -> "RunnerClass":
|
|
914
|
+
'''Register a runner class: the ``runs-on`` label a workflow targets, paired with the VM size, and optionally the image, that jobs carrying that label run on.
|
|
915
|
+
|
|
916
|
+
Each class builds its own image. A runner set needs at least one
|
|
917
|
+
class, and one that reaches synth with none fails.
|
|
918
|
+
|
|
919
|
+
Classes can be registered at any point before synth. Everything that
|
|
920
|
+
depends on the full set of them — which labels the webhook accepts, which
|
|
921
|
+
image each label launches, and the janitor's access to each class's image
|
|
922
|
+
— is resolved once, after the last call.
|
|
923
|
+
|
|
924
|
+
Setting ``warmPoolSize`` on a class keeps that many pre-booted VMs ready for
|
|
925
|
+
it. The first class to do so creates the warm-pool handler and its
|
|
926
|
+
schedule, which every later warm class then shares.
|
|
927
|
+
|
|
928
|
+
:param label: the ``runs-on`` label workflows use to target this class.
|
|
929
|
+
:param size: VM memory floor for this class.
|
|
930
|
+
:param idle_policy: Auto-suspend and auto-resume policy for this class's cold-launched VMs. Mutually exclusive with ``warmPoolSize`` on the same class, since both drive the VM's suspended state; setting both throws at ``addRunnerClass`` time. Default: undefined (no idle policy; the platform never auto-suspends)
|
|
931
|
+
:param image: Image this class builds from. Default: RunnerImage.fromOptions()
|
|
932
|
+
:param warm_pool_size: How many pre-booted, suspended VMs to keep ready for this class. A job that matches this class resumes one of them instead of cold-launching a new VM, and falls back to a cold launch when none is available. This is a count, not a flag: ``warmPoolSize: 3`` keeps three VMs ready. The runner set refills the pool on the ``warmPoolInterval`` schedule. Default: undefined (no warm pool; every job cold-launches)
|
|
933
|
+
|
|
934
|
+
:return:
|
|
935
|
+
|
|
936
|
+
the registered ``RunnerClass``, carrying its label, size,
|
|
937
|
+
image pipeline, and image ARN.
|
|
938
|
+
'''
|
|
939
|
+
if __debug__:
|
|
940
|
+
type_hints = cached_type_hints(_typecheckingstub__48e77fc4d43555e4d6ac3d9e5b13de1cbbb1ef807cfc4ce1e0688ac170b863d1)
|
|
941
|
+
check_type(argname="argument label", value=label, expected_type=type_hints["label"])
|
|
942
|
+
props = RunnerClassProps(
|
|
943
|
+
size=size,
|
|
944
|
+
idle_policy=idle_policy,
|
|
945
|
+
image=image,
|
|
946
|
+
warm_pool_size=warm_pool_size,
|
|
947
|
+
)
|
|
948
|
+
|
|
949
|
+
return typing.cast("RunnerClass", jsii.invoke(self, "addRunnerClass", [label, props]))
|
|
950
|
+
|
|
951
|
+
@jsii.member(jsii_name="runnerClass")
|
|
952
|
+
def runner_class(self, label: builtins.str) -> "RunnerClass":
|
|
953
|
+
'''The registered ``RunnerClass`` carrying ``label``.
|
|
954
|
+
|
|
955
|
+
Throws when no class
|
|
956
|
+
with that label has been registered.
|
|
957
|
+
|
|
958
|
+
:param label: the ``runs-on`` label the class was registered under.
|
|
959
|
+
'''
|
|
960
|
+
if __debug__:
|
|
961
|
+
type_hints = cached_type_hints(_typecheckingstub__e74a92121e3eaec69c4009cc027a299a12257a68eccc613318213d92545265f4)
|
|
962
|
+
check_type(argname="argument label", value=label, expected_type=type_hints["label"])
|
|
963
|
+
return typing.cast("RunnerClass", jsii.invoke(self, "runnerClass", [label]))
|
|
964
|
+
|
|
965
|
+
@builtins.property
|
|
966
|
+
@jsii.member(jsii_name="deadLetterQueue")
|
|
967
|
+
def dead_letter_queue(self) -> "_aws_cdk_aws_sqs_ceddda9d.IQueue":
|
|
968
|
+
'''Dead-letter queue holding job-queue messages that ran out of redrives.'''
|
|
969
|
+
return typing.cast("_aws_cdk_aws_sqs_ceddda9d.IQueue", jsii.get(self, "deadLetterQueue"))
|
|
970
|
+
|
|
971
|
+
@builtins.property
|
|
972
|
+
@jsii.member(jsii_name="defaultImageArn")
|
|
973
|
+
def default_image_arn(self) -> builtins.str:
|
|
974
|
+
'''The image a job whose labels match no registered runner class launches on: the class labelled ``microvm`` if one is registered, otherwise the first class registered.
|
|
975
|
+
|
|
976
|
+
Runner classes can be added right up until synth, so this
|
|
977
|
+
is a token that resolves once the set of them is final.
|
|
978
|
+
'''
|
|
979
|
+
return typing.cast(builtins.str, jsii.get(self, "defaultImageArn"))
|
|
980
|
+
|
|
981
|
+
@builtins.property
|
|
982
|
+
@jsii.member(jsii_name="janitorFunction")
|
|
983
|
+
def janitor_function(self) -> "_aws_cdk_aws_lambda_ceddda9d.IFunction":
|
|
984
|
+
'''The janitor Lambda, which runs the scheduled sweep.'''
|
|
985
|
+
return typing.cast("_aws_cdk_aws_lambda_ceddda9d.IFunction", jsii.get(self, "janitorFunction"))
|
|
986
|
+
|
|
987
|
+
@builtins.property
|
|
988
|
+
@jsii.member(jsii_name="jobQueue")
|
|
989
|
+
def job_queue(self) -> "_aws_cdk_aws_sqs_ceddda9d.IQueue":
|
|
990
|
+
'''Queue carrying launch and terminate intents from the webhook handler to the launcher.'''
|
|
991
|
+
return typing.cast("_aws_cdk_aws_sqs_ceddda9d.IQueue", jsii.get(self, "jobQueue"))
|
|
992
|
+
|
|
993
|
+
@builtins.property
|
|
994
|
+
@jsii.member(jsii_name="launcherFunction")
|
|
995
|
+
def launcher_function(self) -> "_aws_cdk_aws_lambda_ceddda9d.IFunction":
|
|
996
|
+
'''The launcher Lambda, which reads the job queue and starts and terminates MicroVMs.'''
|
|
997
|
+
return typing.cast("_aws_cdk_aws_lambda_ceddda9d.IFunction", jsii.get(self, "launcherFunction"))
|
|
998
|
+
|
|
999
|
+
@builtins.property
|
|
1000
|
+
@jsii.member(jsii_name="metrics")
|
|
1001
|
+
def metrics(self) -> "GithubMicrovmRunnersMetrics":
|
|
1002
|
+
'''This runner set's CloudWatch metrics and the ready-made alarms over them.'''
|
|
1003
|
+
return typing.cast("GithubMicrovmRunnersMetrics", jsii.get(self, "metrics"))
|
|
1004
|
+
|
|
1005
|
+
@builtins.property
|
|
1006
|
+
@jsii.member(jsii_name="runnerClasses")
|
|
1007
|
+
def runner_classes(self) -> typing.List["RunnerClass"]:
|
|
1008
|
+
'''Every runner class registered through ``addRunnerClass``, in the order they were registered.
|
|
1009
|
+
|
|
1010
|
+
It is empty until the first class is added, and a
|
|
1011
|
+
runner set that reaches synth with none fails. Each call returns a copy, so
|
|
1012
|
+
changing the returned array does not change the runner set.
|
|
1013
|
+
'''
|
|
1014
|
+
return typing.cast(typing.List["RunnerClass"], jsii.get(self, "runnerClasses"))
|
|
1015
|
+
|
|
1016
|
+
@builtins.property
|
|
1017
|
+
@jsii.member(jsii_name="runnerTable")
|
|
1018
|
+
def runner_table(self) -> "_aws_cdk_aws_dynamodb_ceddda9d.ITable":
|
|
1019
|
+
'''DynamoDB table mapping each runner's name to its MicroVM, and holding the janitor's record of which VMs it already suspects.'''
|
|
1020
|
+
return typing.cast("_aws_cdk_aws_dynamodb_ceddda9d.ITable", jsii.get(self, "runnerTable"))
|
|
1021
|
+
|
|
1022
|
+
@builtins.property
|
|
1023
|
+
@jsii.member(jsii_name="setupCommand")
|
|
1024
|
+
def setup_command(self) -> builtins.str:
|
|
1025
|
+
'''The command that creates this runner set's GitHub App and writes its three secrets.
|
|
1026
|
+
|
|
1027
|
+
It carries the scope, the stack name, and the region this runner
|
|
1028
|
+
set was built with, and is pinned to the version of this library that
|
|
1029
|
+
produced it, so the helper and the construct agree about secret names and
|
|
1030
|
+
stack outputs.
|
|
1031
|
+
|
|
1032
|
+
Surface it as a stack output and the deploy ends by printing the line to
|
|
1033
|
+
paste. On a stack built without an explicit ``env``, the region is a token
|
|
1034
|
+
that reads as ``${Token[AWS.Region.N]}`` here and resolves to the real region
|
|
1035
|
+
in the deployed output.
|
|
1036
|
+
|
|
1037
|
+
Example::
|
|
1038
|
+
|
|
1039
|
+
cdk.CfnOutput(stack, "SetupCommand", value=runners.setup_command)
|
|
1040
|
+
'''
|
|
1041
|
+
return typing.cast(builtins.str, jsii.get(self, "setupCommand"))
|
|
1042
|
+
|
|
1043
|
+
@builtins.property
|
|
1044
|
+
@jsii.member(jsii_name="webhookFunction")
|
|
1045
|
+
def webhook_function(self) -> "_aws_cdk_aws_lambda_ceddda9d.IFunction":
|
|
1046
|
+
'''The webhook Lambda, which GitHub's deliveries reach through ``webhookUrl``.'''
|
|
1047
|
+
return typing.cast("_aws_cdk_aws_lambda_ceddda9d.IFunction", jsii.get(self, "webhookFunction"))
|
|
1048
|
+
|
|
1049
|
+
@builtins.property
|
|
1050
|
+
@jsii.member(jsii_name="webhookUrl")
|
|
1051
|
+
def webhook_url(self) -> builtins.str:
|
|
1052
|
+
'''The webhook handler's public Function URL, which is the payload URL to configure on the GitHub App or webhook.'''
|
|
1053
|
+
return typing.cast(builtins.str, jsii.get(self, "webhookUrl"))
|
|
1054
|
+
|
|
1055
|
+
@builtins.property
|
|
1056
|
+
@jsii.member(jsii_name="vmConsoleLogGroup")
|
|
1057
|
+
def vm_console_log_group(
|
|
1058
|
+
self,
|
|
1059
|
+
) -> typing.Optional["_aws_cdk_aws_logs_ceddda9d.ILogGroup"]:
|
|
1060
|
+
'''Where a VM's runtime console goes when console capture is on: the group the construct created, or the one you supplied.
|
|
1061
|
+
|
|
1062
|
+
``undefined`` when console capture is off.
|
|
1063
|
+
'''
|
|
1064
|
+
return typing.cast(typing.Optional["_aws_cdk_aws_logs_ceddda9d.ILogGroup"], jsii.get(self, "vmConsoleLogGroup"))
|
|
1065
|
+
|
|
1066
|
+
@builtins.property
|
|
1067
|
+
@jsii.member(jsii_name="vmExecutionRole")
|
|
1068
|
+
def vm_execution_role(self) -> typing.Optional["_aws_cdk_aws_iam_ceddda9d.IRole"]:
|
|
1069
|
+
'''The AWS identity launched MicroVMs run with, passed in as ``GithubMicrovmRunnersProps.vmExecutionRole``, or ``undefined`` when the VMs carry no AWS identity. Console capture runs on this role and requires it. A runner set identifies its own VMs by the image they booted from, not by this role.'''
|
|
1070
|
+
return typing.cast(typing.Optional["_aws_cdk_aws_iam_ceddda9d.IRole"], jsii.get(self, "vmExecutionRole"))
|
|
1071
|
+
|
|
1072
|
+
@builtins.property
|
|
1073
|
+
@jsii.member(jsii_name="warmPoolFunction")
|
|
1074
|
+
def warm_pool_function(
|
|
1075
|
+
self,
|
|
1076
|
+
) -> typing.Optional["_aws_cdk_aws_lambda_ceddda9d.IFunction"]:
|
|
1077
|
+
'''The Lambda that refills the warm pool, or ``undefined`` when no registered runner class sets ``RunnerClassProps.warmPoolSize``. It is created by the first class that does, so a runner set with no warm class deploys neither this function nor its schedule.'''
|
|
1078
|
+
return typing.cast(typing.Optional["_aws_cdk_aws_lambda_ceddda9d.IFunction"], jsii.get(self, "warmPoolFunction"))
|
|
1079
|
+
|
|
1080
|
+
|
|
1081
|
+
class GithubMicrovmRunnersMetrics(
|
|
1082
|
+
metaclass=jsii.JSIIMeta,
|
|
1083
|
+
jsii_type="cdk-github-microvm-runners.GithubMicrovmRunnersMetrics",
|
|
1084
|
+
):
|
|
1085
|
+
'''The CloudWatch metrics a runner set reports, and ready-made alarms over them. A ``GithubMicrovmRunners`` exposes its own as ``runners.metrics``.
|
|
1086
|
+
|
|
1087
|
+
The metrics live in the ``MicrovmRunners`` namespace, tagged with the runner
|
|
1088
|
+
set's id. The janitor reports one set of counters per sweep, the launcher
|
|
1089
|
+
one per launch, and the warm pool one per refill sweep. Launcher and
|
|
1090
|
+
warm-pool metrics are also tagged with the runner class the launch belongs
|
|
1091
|
+
to, which is why those accessors take a runner-class label. Every method
|
|
1092
|
+
here names one of those metrics, or the dead-letter queue's own SQS metric;
|
|
1093
|
+
the class carries no data of its own.
|
|
1094
|
+
|
|
1095
|
+
Everything except ``deadLetterQueueDepth`` reports only when
|
|
1096
|
+
``GithubMicrovmRunnersProps.emitMetrics`` is on. The accessors return a
|
|
1097
|
+
``Metric`` either way, so a dashboard can be built ahead of turning metrics
|
|
1098
|
+
on. The two alarms over those metrics throw at synth instead, rather than
|
|
1099
|
+
synthesizing an alarm that could never fire.
|
|
1100
|
+
|
|
1101
|
+
Example::
|
|
1102
|
+
|
|
1103
|
+
cw.Alarm(stack, "SweepErrors",
|
|
1104
|
+
metric=runners.metrics.errors(),
|
|
1105
|
+
threshold=1,
|
|
1106
|
+
evaluation_periods=1
|
|
1107
|
+
)
|
|
1108
|
+
'''
|
|
1109
|
+
|
|
1110
|
+
def __init__(
|
|
1111
|
+
self,
|
|
1112
|
+
runner_set_id: builtins.str,
|
|
1113
|
+
dead_letter_queue: "_aws_cdk_aws_sqs_ceddda9d.IQueue",
|
|
1114
|
+
emit_metrics: typing.Optional[builtins.bool] = None,
|
|
1115
|
+
) -> None:
|
|
1116
|
+
'''
|
|
1117
|
+
:param runner_set_id: -
|
|
1118
|
+
:param dead_letter_queue: -
|
|
1119
|
+
:param emit_metrics: Whether the runner set reports the metrics this class names, which is ``GithubMicrovmRunnersProps.emitMetrics``. Every accessor except ``deadLetterQueueDepth`` depends on it, though they all return a ``Metric`` either way; only the two alarms over those metrics refuse to synthesize.
|
|
1120
|
+
'''
|
|
1121
|
+
if __debug__:
|
|
1122
|
+
type_hints = cached_type_hints(_typecheckingstub__8c3f47f3bf65ddc91d8c105e318179909d2860c56e34cc7b699066e3f7952170)
|
|
1123
|
+
check_type(argname="argument runner_set_id", value=runner_set_id, expected_type=type_hints["runner_set_id"])
|
|
1124
|
+
check_type(argname="argument dead_letter_queue", value=dead_letter_queue, expected_type=type_hints["dead_letter_queue"])
|
|
1125
|
+
check_type(argname="argument emit_metrics", value=emit_metrics, expected_type=type_hints["emit_metrics"])
|
|
1126
|
+
jsii.create(self.__class__, self, [runner_set_id, dead_letter_queue, emit_metrics])
|
|
1127
|
+
|
|
1128
|
+
@jsii.member(jsii_name="cancelledBeforeLaunch")
|
|
1129
|
+
def cancelled_before_launch(
|
|
1130
|
+
self,
|
|
1131
|
+
runner_class_label: builtins.str,
|
|
1132
|
+
) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1133
|
+
'''Launches skipped because the job had already stopped waiting for a runner by the time the launch was processed — cancelled, or its run deleted.
|
|
1134
|
+
|
|
1135
|
+
No VM is booted for these, so a rising count is work avoided rather than
|
|
1136
|
+
work lost. It tracks how often jobs are cancelled while still queued,
|
|
1137
|
+
which is routine on a repository using concurrency groups: every re-push
|
|
1138
|
+
cancels the run it superseded. A count that dwarfs ``ColdBoot`` suggests the
|
|
1139
|
+
workflows feeding this runner set are cancelled more often than they
|
|
1140
|
+
finish, which is usually a question about their triggers rather than
|
|
1141
|
+
about the runner set.
|
|
1142
|
+
|
|
1143
|
+
:param runner_class_label: -
|
|
1144
|
+
|
|
1145
|
+
Example::
|
|
1146
|
+
|
|
1147
|
+
cw.Alarm(stack, "MostlyCancelled",
|
|
1148
|
+
metric=runners.metrics.cancelled_before_launch("microvm"),
|
|
1149
|
+
threshold=50,
|
|
1150
|
+
evaluation_periods=3
|
|
1151
|
+
)
|
|
1152
|
+
'''
|
|
1153
|
+
if __debug__:
|
|
1154
|
+
type_hints = cached_type_hints(_typecheckingstub__5f2f67ec6dfaab44c26a53e7bc3669af5ba74fc2c75f8dcd8afb795779d8ddfa)
|
|
1155
|
+
check_type(argname="argument runner_class_label", value=runner_class_label, expected_type=type_hints["runner_class_label"])
|
|
1156
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "cancelledBeforeLaunch", [runner_class_label]))
|
|
1157
|
+
|
|
1158
|
+
@jsii.member(jsii_name="capacityRejected")
|
|
1159
|
+
def capacity_rejected(
|
|
1160
|
+
self,
|
|
1161
|
+
runner_class_label: builtins.str,
|
|
1162
|
+
) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1163
|
+
'''Launches the MicroVM service rejected for capacity.
|
|
1164
|
+
|
|
1165
|
+
This is the runner
|
|
1166
|
+
set's quota signal: a value that stays above zero means jobs are queueing
|
|
1167
|
+
behind a MicroVM quota, or behind ``maxConcurrentVms``, rather than running,
|
|
1168
|
+
and each rejected launch spends one of its ``maxReceiveCount`` redrives on
|
|
1169
|
+
the way to the dead-letter queue. See docs/service-quotas.md.
|
|
1170
|
+
|
|
1171
|
+
:param runner_class_label: -
|
|
1172
|
+
'''
|
|
1173
|
+
if __debug__:
|
|
1174
|
+
type_hints = cached_type_hints(_typecheckingstub__36d476c29eaf47f8fca7a5205fb5caa5a9749233fb462a093763a6a3200429b4)
|
|
1175
|
+
check_type(argname="argument runner_class_label", value=runner_class_label, expected_type=type_hints["runner_class_label"])
|
|
1176
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "capacityRejected", [runner_class_label]))
|
|
1177
|
+
|
|
1178
|
+
@jsii.member(jsii_name="coldBoot")
|
|
1179
|
+
def cold_boot(
|
|
1180
|
+
self,
|
|
1181
|
+
runner_class_label: builtins.str,
|
|
1182
|
+
) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1183
|
+
'''Launches served by booting a new VM, because no warm VM was available or the class keeps no warm pool.
|
|
1184
|
+
|
|
1185
|
+
:param runner_class_label: -
|
|
1186
|
+
'''
|
|
1187
|
+
if __debug__:
|
|
1188
|
+
type_hints = cached_type_hints(_typecheckingstub__baf385f806ff6b0b2ae70b9d811654097d3297503bd8bdbafe09f5d9ed879629)
|
|
1189
|
+
check_type(argname="argument runner_class_label", value=runner_class_label, expected_type=type_hints["runner_class_label"])
|
|
1190
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "coldBoot", [runner_class_label]))
|
|
1191
|
+
|
|
1192
|
+
@jsii.member(jsii_name="coldSpinUpMs")
|
|
1193
|
+
def cold_spin_up_ms(
|
|
1194
|
+
self,
|
|
1195
|
+
runner_class_label: builtins.str,
|
|
1196
|
+
) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1197
|
+
'''Milliseconds to spin up a cold launch: starting the VM, waiting for it to boot, and pushing the runner's registration.
|
|
1198
|
+
|
|
1199
|
+
Reported as an average rather than a sum.
|
|
1200
|
+
|
|
1201
|
+
:param runner_class_label: -
|
|
1202
|
+
'''
|
|
1203
|
+
if __debug__:
|
|
1204
|
+
type_hints = cached_type_hints(_typecheckingstub__75224a1d56fc14f38e94a3639da5e4ae455f069c6e477bb8fa010333e5c6ae4f)
|
|
1205
|
+
check_type(argname="argument runner_class_label", value=runner_class_label, expected_type=type_hints["runner_class_label"])
|
|
1206
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "coldSpinUpMs", [runner_class_label]))
|
|
1207
|
+
|
|
1208
|
+
@jsii.member(jsii_name="deadLetterQueueDepth")
|
|
1209
|
+
def dead_letter_queue_depth(self) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1210
|
+
'''Messages sitting in the dead-letter queue: a launch or terminate intent SQS gave up redriving.'''
|
|
1211
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "deadLetterQueueDepth", []))
|
|
1212
|
+
|
|
1213
|
+
@jsii.member(jsii_name="deadLetterQueueNotEmptyAlarm")
|
|
1214
|
+
def dead_letter_queue_not_empty_alarm(
|
|
1215
|
+
self,
|
|
1216
|
+
scope: "_constructs_77d1e7e8.Construct",
|
|
1217
|
+
*,
|
|
1218
|
+
evaluation_periods: typing.Optional[jsii.Number] = None,
|
|
1219
|
+
period: typing.Optional["_aws_cdk_ceddda9d.Duration"] = None,
|
|
1220
|
+
threshold: typing.Optional[jsii.Number] = None,
|
|
1221
|
+
) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Alarm":
|
|
1222
|
+
'''Alarm when the dead-letter queue is not empty, meaning SQS gave up redriving a launch or terminate intent.
|
|
1223
|
+
|
|
1224
|
+
A runner set that is keeping up
|
|
1225
|
+
holds this at 0, so any sustained depth means jobs are being dropped,
|
|
1226
|
+
unless ``recoverStuckLaunches`` is draining them. It fires on one message
|
|
1227
|
+
over a single 5-minute period; pass ``RunnerAlarmOptions`` to change
|
|
1228
|
+
that, and ``alarm.addAlarmAction()`` to route it.
|
|
1229
|
+
|
|
1230
|
+
This is the one alarm here that works without
|
|
1231
|
+
``GithubMicrovmRunnersProps.emitMetrics``, because it watches the
|
|
1232
|
+
dead-letter queue's own SQS metric rather than one the handlers report.
|
|
1233
|
+
|
|
1234
|
+
:param scope: -
|
|
1235
|
+
:param evaluation_periods: Consecutive breaching periods before the alarm fires. Default: 1 (3 for the stuck-launch alarm)
|
|
1236
|
+
:param period: Aggregation period for the metric. Default: Duration.minutes(5)
|
|
1237
|
+
:param threshold: Value at or above which the alarm fires. Default: 1
|
|
1238
|
+
|
|
1239
|
+
:default: threshold 1, 1 evaluation period, 5-minute period
|
|
1240
|
+
'''
|
|
1241
|
+
if __debug__:
|
|
1242
|
+
type_hints = cached_type_hints(_typecheckingstub__aca740a7276ae0a556b6b45300b0252ac7d8074b4dd0ab26c6b38fba7adb7eaf)
|
|
1243
|
+
check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"])
|
|
1244
|
+
options = RunnerAlarmOptions(
|
|
1245
|
+
evaluation_periods=evaluation_periods, period=period, threshold=threshold
|
|
1246
|
+
)
|
|
1247
|
+
|
|
1248
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Alarm", jsii.invoke(self, "deadLetterQueueNotEmptyAlarm", [scope, options]))
|
|
1249
|
+
|
|
1250
|
+
@jsii.member(jsii_name="errors")
|
|
1251
|
+
def errors(self) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1252
|
+
'''Janitor sweep count: failures on individual VMs, rows, or image versions during a sweep.
|
|
1253
|
+
|
|
1254
|
+
The sweep isolates each one and still completes.
|
|
1255
|
+
'''
|
|
1256
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "errors", []))
|
|
1257
|
+
|
|
1258
|
+
@jsii.member(jsii_name="imageVersionsPruned")
|
|
1259
|
+
def image_versions_pruned(self) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1260
|
+
'''Janitor sweep count: inactive MicroVM image versions pruned past ``keepImageVersions``.'''
|
|
1261
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "imageVersionsPruned", []))
|
|
1262
|
+
|
|
1263
|
+
@jsii.member(jsii_name="lifetimeKills")
|
|
1264
|
+
def lifetime_kills(self) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1265
|
+
'''Janitor sweep count: VMs terminated for having run longer than ``maxJobDuration`` plus the platform's own grace.'''
|
|
1266
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "lifetimeKills", []))
|
|
1267
|
+
|
|
1268
|
+
@jsii.member(jsii_name="orphansReaped")
|
|
1269
|
+
def orphans_reaped(self) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1270
|
+
'''Janitor sweep count: running VMs that belong to this runner set but have no row in the runner table, reaped once a second sweep has seen the same VM unaccounted for.'''
|
|
1271
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "orphansReaped", []))
|
|
1272
|
+
|
|
1273
|
+
@jsii.member(jsii_name="poolCurrent")
|
|
1274
|
+
def pool_current(
|
|
1275
|
+
self,
|
|
1276
|
+
runner_class_label: builtins.str,
|
|
1277
|
+
) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1278
|
+
'''Warm VMs suspended and available for this class as of the last warm-pool sweep.
|
|
1279
|
+
|
|
1280
|
+
:param runner_class_label: -
|
|
1281
|
+
'''
|
|
1282
|
+
if __debug__:
|
|
1283
|
+
type_hints = cached_type_hints(_typecheckingstub__6153c9a068c30f370bb352b26cc502516866238676a7d8139fc2dd0736dff46a)
|
|
1284
|
+
check_type(argname="argument runner_class_label", value=runner_class_label, expected_type=type_hints["runner_class_label"])
|
|
1285
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "poolCurrent", [runner_class_label]))
|
|
1286
|
+
|
|
1287
|
+
@jsii.member(jsii_name="poolLaunched")
|
|
1288
|
+
def pool_launched(
|
|
1289
|
+
self,
|
|
1290
|
+
runner_class_label: builtins.str,
|
|
1291
|
+
) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1292
|
+
'''Warm VMs the last warm-pool sweep launched to reach ``warmPoolSize``.
|
|
1293
|
+
|
|
1294
|
+
:param runner_class_label: -
|
|
1295
|
+
'''
|
|
1296
|
+
if __debug__:
|
|
1297
|
+
type_hints = cached_type_hints(_typecheckingstub__767e219d8c25f069fd8964ea100816a20869884628a2606dfd2fb3e63b857a8e)
|
|
1298
|
+
check_type(argname="argument runner_class_label", value=runner_class_label, expected_type=type_hints["runner_class_label"])
|
|
1299
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "poolLaunched", [runner_class_label]))
|
|
1300
|
+
|
|
1301
|
+
@jsii.member(jsii_name="poolLaunchFailed")
|
|
1302
|
+
def pool_launch_failed(
|
|
1303
|
+
self,
|
|
1304
|
+
runner_class_label: builtins.str,
|
|
1305
|
+
) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1306
|
+
'''Warm-VM launches a warm-pool sweep attempted and failed.
|
|
1307
|
+
|
|
1308
|
+
A value that stays above zero means the pool is not reaching ``warmPoolSize``, so jobs keep booting new VMs instead of resuming warm ones.
|
|
1309
|
+
|
|
1310
|
+
:param runner_class_label: -
|
|
1311
|
+
'''
|
|
1312
|
+
if __debug__:
|
|
1313
|
+
type_hints = cached_type_hints(_typecheckingstub__6513962ff7d13ce627041f61f3e7a3b13688b30e0cb4c5bfbc63f79b8a32b595)
|
|
1314
|
+
check_type(argname="argument runner_class_label", value=runner_class_label, expected_type=type_hints["runner_class_label"])
|
|
1315
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "poolLaunchFailed", [runner_class_label]))
|
|
1316
|
+
|
|
1317
|
+
@jsii.member(jsii_name="poolTarget")
|
|
1318
|
+
def pool_target(
|
|
1319
|
+
self,
|
|
1320
|
+
runner_class_label: builtins.str,
|
|
1321
|
+
) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1322
|
+
'''This class's ``warmPoolSize``, as the last warm-pool sweep read it.
|
|
1323
|
+
|
|
1324
|
+
:param runner_class_label: -
|
|
1325
|
+
'''
|
|
1326
|
+
if __debug__:
|
|
1327
|
+
type_hints = cached_type_hints(_typecheckingstub__1ba8a40c62efe6c3a58896ea614244a8e6823dd3c7db51567ffbadd71766bd13)
|
|
1328
|
+
check_type(argname="argument runner_class_label", value=runner_class_label, expected_type=type_hints["runner_class_label"])
|
|
1329
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "poolTarget", [runner_class_label]))
|
|
1330
|
+
|
|
1331
|
+
@jsii.member(jsii_name="stuckClaimsRelaunched")
|
|
1332
|
+
def stuck_claims_relaunched(self) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1333
|
+
'''Janitor sweep count: launches that were claimed but never served, re-launched from the orphaned claim.
|
|
1334
|
+
|
|
1335
|
+
This is 0 unless ``recoverStuckLaunches`` is on.
|
|
1336
|
+
'''
|
|
1337
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "stuckClaimsRelaunched", []))
|
|
1338
|
+
|
|
1339
|
+
@jsii.member(jsii_name="stuckLaunchesRecovered")
|
|
1340
|
+
def stuck_launches_recovered(self) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1341
|
+
'''Janitor sweep count: dead-lettered launches re-driven onto the job queue, which is 0 unless ``recoverStuckLaunches`` is on.
|
|
1342
|
+
|
|
1343
|
+
A value that stays high means launches are failing for some reason other than a GitHub outage.
|
|
1344
|
+
'''
|
|
1345
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "stuckLaunchesRecovered", []))
|
|
1346
|
+
|
|
1347
|
+
@jsii.member(jsii_name="stuckLaunchesRecoveredAlarm")
|
|
1348
|
+
def stuck_launches_recovered_alarm(
|
|
1349
|
+
self,
|
|
1350
|
+
scope: "_constructs_77d1e7e8.Construct",
|
|
1351
|
+
*,
|
|
1352
|
+
evaluation_periods: typing.Optional[jsii.Number] = None,
|
|
1353
|
+
period: typing.Optional["_aws_cdk_ceddda9d.Duration"] = None,
|
|
1354
|
+
threshold: typing.Optional[jsii.Number] = None,
|
|
1355
|
+
) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Alarm":
|
|
1356
|
+
'''Alarm on stuck-launch recoveries, the dead-lettered launches the janitor re-drove, which only happens with ``recoverStuckLaunches`` on.
|
|
1357
|
+
|
|
1358
|
+
Recoveries
|
|
1359
|
+
that keep coming mean launches are failing for some reason other than a
|
|
1360
|
+
GitHub outage. It fires on one recovery in each of three consecutive
|
|
1361
|
+
5-minute periods, which rides out a real outage; pass
|
|
1362
|
+
``RunnerAlarmOptions`` to change that.
|
|
1363
|
+
|
|
1364
|
+
Requires ``GithubMicrovmRunnersProps.emitMetrics``, and throws at synth
|
|
1365
|
+
without it.
|
|
1366
|
+
|
|
1367
|
+
:param scope: -
|
|
1368
|
+
:param evaluation_periods: Consecutive breaching periods before the alarm fires. Default: 1 (3 for the stuck-launch alarm)
|
|
1369
|
+
:param period: Aggregation period for the metric. Default: Duration.minutes(5)
|
|
1370
|
+
:param threshold: Value at or above which the alarm fires. Default: 1
|
|
1371
|
+
|
|
1372
|
+
:default: threshold 1, 3 evaluation periods, 5-minute period
|
|
1373
|
+
'''
|
|
1374
|
+
if __debug__:
|
|
1375
|
+
type_hints = cached_type_hints(_typecheckingstub__e1b4b6b8be54f5289f47b9d302cea17d405e67837d60873b6a6536a2a23457e9)
|
|
1376
|
+
check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"])
|
|
1377
|
+
options = RunnerAlarmOptions(
|
|
1378
|
+
evaluation_periods=evaluation_periods, period=period, threshold=threshold
|
|
1379
|
+
)
|
|
1380
|
+
|
|
1381
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Alarm", jsii.invoke(self, "stuckLaunchesRecoveredAlarm", [scope, options]))
|
|
1382
|
+
|
|
1383
|
+
@jsii.member(jsii_name="stuckRunnersReaped")
|
|
1384
|
+
def stuck_runners_reaped(self) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1385
|
+
'''Janitor sweep count: runners that registered with GitHub and then sat idle past ``idleRunnerGraceSeconds``, reaped once a second sweep has seen them the same way.'''
|
|
1386
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "stuckRunnersReaped", []))
|
|
1387
|
+
|
|
1388
|
+
@jsii.member(jsii_name="suspectsCleared")
|
|
1389
|
+
def suspects_cleared(self) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1390
|
+
'''Janitor sweep count: VMs an earlier sweep had marked as suspect, cleared because this sweep found them accounted for or working again.'''
|
|
1391
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "suspectsCleared", []))
|
|
1392
|
+
|
|
1393
|
+
@jsii.member(jsii_name="sweepErrorsAlarm")
|
|
1394
|
+
def sweep_errors_alarm(
|
|
1395
|
+
self,
|
|
1396
|
+
scope: "_constructs_77d1e7e8.Construct",
|
|
1397
|
+
*,
|
|
1398
|
+
evaluation_periods: typing.Optional[jsii.Number] = None,
|
|
1399
|
+
period: typing.Optional["_aws_cdk_ceddda9d.Duration"] = None,
|
|
1400
|
+
threshold: typing.Optional[jsii.Number] = None,
|
|
1401
|
+
) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Alarm":
|
|
1402
|
+
'''Alarm on janitor sweep errors, the per-item failures a sweep isolates and continues past.
|
|
1403
|
+
|
|
1404
|
+
A value that stays above zero means the runner set is
|
|
1405
|
+
failing to reconcile — VMs left running, runners left unreaped — even
|
|
1406
|
+
though each sweep completes. It fires on one error over a single 5-minute
|
|
1407
|
+
period; pass ``RunnerAlarmOptions`` to change that.
|
|
1408
|
+
|
|
1409
|
+
Requires ``GithubMicrovmRunnersProps.emitMetrics``, and throws at synth
|
|
1410
|
+
without it.
|
|
1411
|
+
|
|
1412
|
+
:param scope: -
|
|
1413
|
+
:param evaluation_periods: Consecutive breaching periods before the alarm fires. Default: 1 (3 for the stuck-launch alarm)
|
|
1414
|
+
:param period: Aggregation period for the metric. Default: Duration.minutes(5)
|
|
1415
|
+
:param threshold: Value at or above which the alarm fires. Default: 1
|
|
1416
|
+
|
|
1417
|
+
:default: threshold 1, 1 evaluation period, 5-minute period
|
|
1418
|
+
'''
|
|
1419
|
+
if __debug__:
|
|
1420
|
+
type_hints = cached_type_hints(_typecheckingstub__971f59e7dc4d5b4245765d41b7dcc4075c4dd91870a15df6b9f345ee393cdc61)
|
|
1421
|
+
check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"])
|
|
1422
|
+
options = RunnerAlarmOptions(
|
|
1423
|
+
evaluation_periods=evaluation_periods, period=period, threshold=threshold
|
|
1424
|
+
)
|
|
1425
|
+
|
|
1426
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Alarm", jsii.invoke(self, "sweepErrorsAlarm", [scope, options]))
|
|
1427
|
+
|
|
1428
|
+
@jsii.member(jsii_name="tableRowsCleaned")
|
|
1429
|
+
def table_rows_cleaned(self) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1430
|
+
'''Janitor sweep count: runner table rows deleted, either because the VM they name is confirmed gone or because a real row superseded an orphaned one.'''
|
|
1431
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "tableRowsCleaned", []))
|
|
1432
|
+
|
|
1433
|
+
@jsii.member(jsii_name="warmHit")
|
|
1434
|
+
def warm_hit(
|
|
1435
|
+
self,
|
|
1436
|
+
runner_class_label: builtins.str,
|
|
1437
|
+
) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1438
|
+
'''Launches served from the warm pool: a pre-booted VM claimed and resumed rather than a new one launched.
|
|
1439
|
+
|
|
1440
|
+
:param runner_class_label: -
|
|
1441
|
+
'''
|
|
1442
|
+
if __debug__:
|
|
1443
|
+
type_hints = cached_type_hints(_typecheckingstub__01d47d24112989967339ef8a2bc09fe442210a13ccc3d3fd9583327ebc550f4f)
|
|
1444
|
+
check_type(argname="argument runner_class_label", value=runner_class_label, expected_type=type_hints["runner_class_label"])
|
|
1445
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "warmHit", [runner_class_label]))
|
|
1446
|
+
|
|
1447
|
+
@jsii.member(jsii_name="warmSpinUpMs")
|
|
1448
|
+
def warm_spin_up_ms(
|
|
1449
|
+
self,
|
|
1450
|
+
runner_class_label: builtins.str,
|
|
1451
|
+
) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1452
|
+
'''Milliseconds to spin up a warm launch: claiming the VM, resuming it, and pushing the runner's registration.
|
|
1453
|
+
|
|
1454
|
+
Reported as an average rather than a sum.
|
|
1455
|
+
|
|
1456
|
+
:param runner_class_label: -
|
|
1457
|
+
'''
|
|
1458
|
+
if __debug__:
|
|
1459
|
+
type_hints = cached_type_hints(_typecheckingstub__9b66518a0eb395295f3c9719dcc545a363c50d0d387fe70bdcedc10be787b17a)
|
|
1460
|
+
check_type(argname="argument runner_class_label", value=runner_class_label, expected_type=type_hints["runner_class_label"])
|
|
1461
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "warmSpinUpMs", [runner_class_label]))
|
|
1462
|
+
|
|
1463
|
+
@jsii.member(jsii_name="warmThrottled")
|
|
1464
|
+
def warm_throttled(
|
|
1465
|
+
self,
|
|
1466
|
+
runner_class_label: builtins.str,
|
|
1467
|
+
) -> "_aws_cdk_aws_cloudwatch_ceddda9d.Metric":
|
|
1468
|
+
'''Warm-pool claims that were throttled and fell back to booting a new VM.
|
|
1469
|
+
|
|
1470
|
+
The same launch can also count under ``ColdBoot`` or ``CapacityRejected``.
|
|
1471
|
+
|
|
1472
|
+
:param runner_class_label: -
|
|
1473
|
+
'''
|
|
1474
|
+
if __debug__:
|
|
1475
|
+
type_hints = cached_type_hints(_typecheckingstub__28779afe2a8160e3a792fe0b6661c1c177712ed22d8ddf991f39b625eaa303d6)
|
|
1476
|
+
check_type(argname="argument runner_class_label", value=runner_class_label, expected_type=type_hints["runner_class_label"])
|
|
1477
|
+
return typing.cast("_aws_cdk_aws_cloudwatch_ceddda9d.Metric", jsii.invoke(self, "warmThrottled", [runner_class_label]))
|
|
1478
|
+
|
|
1479
|
+
|
|
1480
|
+
@jsii.data_type(
|
|
1481
|
+
jsii_type="cdk-github-microvm-runners.GithubMicrovmRunnersProps",
|
|
1482
|
+
jsii_struct_bases=[],
|
|
1483
|
+
name_mapping={
|
|
1484
|
+
"github": "github",
|
|
1485
|
+
"scope": "scope",
|
|
1486
|
+
"additional_regions": "additionalRegions",
|
|
1487
|
+
"console_logs": "consoleLogs",
|
|
1488
|
+
"dead_letter_retention": "deadLetterRetention",
|
|
1489
|
+
"emit_metrics": "emitMetrics",
|
|
1490
|
+
"encryption_key": "encryptionKey",
|
|
1491
|
+
"idle_runner_grace_seconds": "idleRunnerGraceSeconds",
|
|
1492
|
+
"image_logs": "imageLogs",
|
|
1493
|
+
"janitor_interval": "janitorInterval",
|
|
1494
|
+
"keep_image_versions": "keepImageVersions",
|
|
1495
|
+
"lambda_memory_size": "lambdaMemorySize",
|
|
1496
|
+
"log_retention": "logRetention",
|
|
1497
|
+
"max_concurrent_vms": "maxConcurrentVms",
|
|
1498
|
+
"max_job_duration": "maxJobDuration",
|
|
1499
|
+
"max_receive_count": "maxReceiveCount",
|
|
1500
|
+
"network": "network",
|
|
1501
|
+
"permissions_boundary": "permissionsBoundary",
|
|
1502
|
+
"point_in_time_recovery": "pointInTimeRecovery",
|
|
1503
|
+
"recover_stuck_launches": "recoverStuckLaunches",
|
|
1504
|
+
"removal_policy": "removalPolicy",
|
|
1505
|
+
"vm_execution_role": "vmExecutionRole",
|
|
1506
|
+
"warm_pool_interval": "warmPoolInterval",
|
|
1507
|
+
"webhook": "webhook",
|
|
1508
|
+
"webhook_reserved_concurrency": "webhookReservedConcurrency",
|
|
1509
|
+
},
|
|
1510
|
+
)
|
|
1511
|
+
class GithubMicrovmRunnersProps:
|
|
1512
|
+
def __init__(
|
|
1513
|
+
self,
|
|
1514
|
+
*,
|
|
1515
|
+
github: "GithubAuth",
|
|
1516
|
+
scope: "RunnerScope",
|
|
1517
|
+
additional_regions: typing.Optional[typing.Sequence[builtins.str]] = None,
|
|
1518
|
+
console_logs: typing.Optional["ConsoleLogs"] = None,
|
|
1519
|
+
dead_letter_retention: typing.Optional["_aws_cdk_ceddda9d.Duration"] = None,
|
|
1520
|
+
emit_metrics: typing.Optional[builtins.bool] = None,
|
|
1521
|
+
encryption_key: typing.Optional["_aws_cdk_aws_kms_ceddda9d.IKey"] = None,
|
|
1522
|
+
idle_runner_grace_seconds: typing.Optional[jsii.Number] = None,
|
|
1523
|
+
image_logs: typing.Optional["ImageLogs"] = None,
|
|
1524
|
+
janitor_interval: typing.Optional["_aws_cdk_ceddda9d.Duration"] = None,
|
|
1525
|
+
keep_image_versions: typing.Optional[jsii.Number] = None,
|
|
1526
|
+
lambda_memory_size: typing.Optional[jsii.Number] = None,
|
|
1527
|
+
log_retention: typing.Optional["_aws_cdk_aws_logs_ceddda9d.RetentionDays"] = None,
|
|
1528
|
+
max_concurrent_vms: typing.Optional[jsii.Number] = None,
|
|
1529
|
+
max_job_duration: typing.Optional["_aws_cdk_ceddda9d.Duration"] = None,
|
|
1530
|
+
max_receive_count: typing.Optional[jsii.Number] = None,
|
|
1531
|
+
network: typing.Optional["RunnerNetwork"] = None,
|
|
1532
|
+
permissions_boundary: typing.Optional["_aws_cdk_aws_iam_ceddda9d.IManagedPolicy"] = None,
|
|
1533
|
+
point_in_time_recovery: typing.Optional[builtins.bool] = None,
|
|
1534
|
+
recover_stuck_launches: typing.Optional[builtins.bool] = None,
|
|
1535
|
+
removal_policy: typing.Optional["_aws_cdk_ceddda9d.RemovalPolicy"] = None,
|
|
1536
|
+
vm_execution_role: typing.Optional["_aws_cdk_aws_iam_ceddda9d.IRole"] = None,
|
|
1537
|
+
warm_pool_interval: typing.Optional["_aws_cdk_ceddda9d.Duration"] = None,
|
|
1538
|
+
webhook: typing.Optional["WebhookEndpoint"] = None,
|
|
1539
|
+
webhook_reserved_concurrency: typing.Optional[jsii.Number] = None,
|
|
1540
|
+
) -> None:
|
|
1541
|
+
'''Props for ``GithubMicrovmRunners``.
|
|
1542
|
+
|
|
1543
|
+
:param github: How the runner set authenticates to GitHub, as an App or with a personal access token. This also carries the webhook secret.
|
|
1544
|
+
:param scope: Which GitHub scope, an organization or a list of repositories, registered runners are visible to.
|
|
1545
|
+
:param additional_regions: Additional regions to accept as Lambda MicroVMs regions, beyond the ones this library already knows about. Deploying into a region on neither list fails at synth. Default: [] (only the regions this library knows about)
|
|
1546
|
+
:param console_logs: Where a VM's runtime console goes: everything it prints while it boots, runs the runner agent, and runs the job. ``ConsoleLogs.enabled()`` has the construct create the group and expose it as ``vmConsoleLogGroup``, and ``ConsoleLogs.enabled(logGroup)`` uses one you control. The platform writes these logs with the VM's own role, so this requires ``vmExecutionRole``; see ``ConsoleLogs`` for what that role means for job code. Independent of ``imageLogs``. Default: undefined (no runtime console capture)
|
|
1547
|
+
:param dead_letter_retention: How long the dead-letter queue retains a failed launch or terminate intent. SQS allows up to 14 days, which is also how long ``recoverStuckLaunches`` has to re-drive a message before SQS drops it. Default: Duration.days(4) (SQS default)
|
|
1548
|
+
:param emit_metrics: Report this runner set's CloudWatch custom metrics. Those are the janitor's per-sweep counters, the launcher's per-launch outcomes and spin-up timings, and the warm pool's fill numbers — everything ``GithubMicrovmRunnersMetrics`` names. With this off the handlers report none of them. CloudWatch bills custom metrics per metric per month, and this runner set's bill is not a fixed number: the launcher and warm-pool metrics carry a runner-class dimension, so each one becomes a separate billable metric per registered runner class. The two alarms backed by these metrics, ``sweepErrorsAlarm`` and ``stuckLaunchesRecoveredAlarm``, throw at synth unless this is on, since the metric they watch would never report. ``deadLetterQueueNotEmptyAlarm`` watches an SQS metric and works either way. The metric accessors on ``GithubMicrovmRunnersMetrics`` return a ``Metric`` regardless, so a dashboard can be built ahead of turning metrics on. Default: false (no metrics emitted)
|
|
1549
|
+
:param encryption_key: Customer-managed KMS key for this runner set's data at rest: the DynamoDB runner table, the SQS job queue and dead-letter queue, and any log group this construct creates. Log groups you bring yourself, and the GitHub secrets you pass in, keep their own keys. Default: undefined (AWS-managed keys)
|
|
1550
|
+
:param idle_runner_grace_seconds: How many seconds a registered runner may sit idle before the janitor's two-strike sweep treats it as stuck. Default: 600
|
|
1551
|
+
:param image_logs: Where build-time image logs go: the Docker build layers and the ready-probe banner from each image build. ``ImageLogs.enabled()`` sends them to the platform's own CloudWatch group, and ``ImageLogs.enabled(logGroup)`` to a group whose retention and KMS key you control. These are written by the image build role rather than by a VM, so they need no VM execution role. Independent of ``consoleLogs``. Default: undefined (no image logs)
|
|
1552
|
+
:param janitor_interval: How often the janitor sweep runs. Default: Duration.minutes(5)
|
|
1553
|
+
:param keep_image_versions: How many MicroVM image versions to keep per runner class. The janitor prunes inactive versions past this count. Default: 5
|
|
1554
|
+
:param lambda_memory_size: Memory, in MiB, for the handler Lambdas: the webhook, the launcher, the janitor, and the warm pool. The janitor's sweep scans the runner table and reconciles every running VM, so it is the handler most sensitive to this on a busy runner set. Default: 128
|
|
1555
|
+
:param log_retention: Retention for the CloudWatch log groups this construct creates: the handler Lambda log groups and, when console capture is on, the VM console group. Default: logs.RetentionDays.TWO_WEEKS
|
|
1556
|
+
:param max_concurrent_vms: Maximum number of MicroVMs this runner set runs at once. Default: 10
|
|
1557
|
+
:param max_job_duration: How long a job may run before its MicroVM is terminated. The VM is killed five minutes after this value, not at it. The runner set asks the platform for ``maxJobDuration + 5 minutes``, so that a job which reaches its own limit is stopped by the runner — which reports the timeout to GitHub and lets the VM come down cleanly — rather than by the platform removing the machine underneath it. Treat the five minutes as headroom for that shutdown rather than as extra running time. Default: Duration.hours(6)
|
|
1558
|
+
:param max_receive_count: How many times a launch intent is redriven before it dead-letters. A runner set already at ``maxConcurrentVms`` redrives capacity-rejected launches through this same budget, so on a runner set that regularly runs at capacity this count is how long a queued job waits before its launch is dropped. See docs/service-quotas.md. Default: 20
|
|
1559
|
+
:param network: How launched MicroVMs and image builds reach the network. Default: RunnerNetwork.internetEgress()
|
|
1560
|
+
:param permissions_boundary: Permissions boundary applied to every IAM role this construct creates: the handler execution roles, the per-class image build roles, and the network-connector operator role. It is applied once at construct scope, so roles created later also carry it — the warm-pool handler's role, and the build role of any runner class registered after construction. Default: undefined (no boundary)
|
|
1561
|
+
:param point_in_time_recovery: Turn on DynamoDB point-in-time recovery for the runner table. Default: false
|
|
1562
|
+
:param recover_stuck_launches: Recover launches that dead-lettered while GitHub Actions was down. Each janitor sweep re-drives dead-lettered launch messages back onto the job queue, but only for jobs GitHub still reports as queued; a launch whose job has since completed or been cancelled is discarded rather than booting a VM for work nobody is waiting on. Recovery happens once an outage ends, since GitHub dispatches no jobs while it is down. The janitor counts each recovered launch under the ``stuckLaunchesRecovered`` metric, which reports when ``emitMetrics`` is on. Default: false
|
|
1563
|
+
:param removal_policy: Removal policy for this runner set's stateful resources: the runner table and any log group the construct creates. The table holds correlation data for VMs that are currently running, all of which the janitor can rebuild from the MicroVM and GitHub APIs. Default: RemovalPolicy.DESTROY
|
|
1564
|
+
:param vm_execution_role: An AWS identity for this runner set's runner VMs. By default the VMs carry no AWS identity at all: the runner agent talks outbound to GitHub, the just-in-time registration is pushed to the VM over a platform-authenticated channel, and a job that needs AWS assumes its own role through GitHub OIDC. With a role attached, the MicroVM's instance metadata service serves that role's credentials to arbitrary job code, so every job running on this runner set can do whatever the role can do. ``consoleLogs`` requires a role, because the platform writes a VM's console output using it. Default: undefined (the VMs carry no AWS identity)
|
|
1565
|
+
:param warm_pool_interval: How often the warm-pool sweep refills pre-booted VMs. It applies only to runner classes that set ``RunnerClassProps.warmPoolSize``, and the warm-pool handler and its schedule are only created once such a class is registered. A runner set with no warm class never runs this sweep, and never reads this value. Default: Duration.minutes(2)
|
|
1566
|
+
:param webhook: How the webhook handler is exposed to GitHub. Default: WebhookEndpoint.functionUrl()
|
|
1567
|
+
:param webhook_reserved_concurrency: Reserved concurrency for the webhook Lambda, which caps how many webhook deliveries the runner set processes at once. Reserved concurrency is carved out of the account's shared pool of unreserved concurrency, so a runner set that sets it takes that capacity away from every other function in the account. Must be a positive integer when set, since ``0`` would disable the webhook entirely. Default: undefined (no reservation; the webhook draws from the shared pool)
|
|
1568
|
+
'''
|
|
1569
|
+
if __debug__:
|
|
1570
|
+
type_hints = cached_type_hints(_typecheckingstub__17269a525bc0ad3b7797a5131db455fcbc4ced673bbd2895bc90ea581a540971)
|
|
1571
|
+
check_type(argname="argument github", value=github, expected_type=type_hints["github"])
|
|
1572
|
+
check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"])
|
|
1573
|
+
check_type(argname="argument additional_regions", value=additional_regions, expected_type=type_hints["additional_regions"])
|
|
1574
|
+
check_type(argname="argument console_logs", value=console_logs, expected_type=type_hints["console_logs"])
|
|
1575
|
+
check_type(argname="argument dead_letter_retention", value=dead_letter_retention, expected_type=type_hints["dead_letter_retention"])
|
|
1576
|
+
check_type(argname="argument emit_metrics", value=emit_metrics, expected_type=type_hints["emit_metrics"])
|
|
1577
|
+
check_type(argname="argument encryption_key", value=encryption_key, expected_type=type_hints["encryption_key"])
|
|
1578
|
+
check_type(argname="argument idle_runner_grace_seconds", value=idle_runner_grace_seconds, expected_type=type_hints["idle_runner_grace_seconds"])
|
|
1579
|
+
check_type(argname="argument image_logs", value=image_logs, expected_type=type_hints["image_logs"])
|
|
1580
|
+
check_type(argname="argument janitor_interval", value=janitor_interval, expected_type=type_hints["janitor_interval"])
|
|
1581
|
+
check_type(argname="argument keep_image_versions", value=keep_image_versions, expected_type=type_hints["keep_image_versions"])
|
|
1582
|
+
check_type(argname="argument lambda_memory_size", value=lambda_memory_size, expected_type=type_hints["lambda_memory_size"])
|
|
1583
|
+
check_type(argname="argument log_retention", value=log_retention, expected_type=type_hints["log_retention"])
|
|
1584
|
+
check_type(argname="argument max_concurrent_vms", value=max_concurrent_vms, expected_type=type_hints["max_concurrent_vms"])
|
|
1585
|
+
check_type(argname="argument max_job_duration", value=max_job_duration, expected_type=type_hints["max_job_duration"])
|
|
1586
|
+
check_type(argname="argument max_receive_count", value=max_receive_count, expected_type=type_hints["max_receive_count"])
|
|
1587
|
+
check_type(argname="argument network", value=network, expected_type=type_hints["network"])
|
|
1588
|
+
check_type(argname="argument permissions_boundary", value=permissions_boundary, expected_type=type_hints["permissions_boundary"])
|
|
1589
|
+
check_type(argname="argument point_in_time_recovery", value=point_in_time_recovery, expected_type=type_hints["point_in_time_recovery"])
|
|
1590
|
+
check_type(argname="argument recover_stuck_launches", value=recover_stuck_launches, expected_type=type_hints["recover_stuck_launches"])
|
|
1591
|
+
check_type(argname="argument removal_policy", value=removal_policy, expected_type=type_hints["removal_policy"])
|
|
1592
|
+
check_type(argname="argument vm_execution_role", value=vm_execution_role, expected_type=type_hints["vm_execution_role"])
|
|
1593
|
+
check_type(argname="argument warm_pool_interval", value=warm_pool_interval, expected_type=type_hints["warm_pool_interval"])
|
|
1594
|
+
check_type(argname="argument webhook", value=webhook, expected_type=type_hints["webhook"])
|
|
1595
|
+
check_type(argname="argument webhook_reserved_concurrency", value=webhook_reserved_concurrency, expected_type=type_hints["webhook_reserved_concurrency"])
|
|
1596
|
+
self._values: typing.Dict[builtins.str, typing.Any] = {
|
|
1597
|
+
"github": github,
|
|
1598
|
+
"scope": scope,
|
|
1599
|
+
}
|
|
1600
|
+
if additional_regions is not None:
|
|
1601
|
+
self._values["additional_regions"] = additional_regions
|
|
1602
|
+
if console_logs is not None:
|
|
1603
|
+
self._values["console_logs"] = console_logs
|
|
1604
|
+
if dead_letter_retention is not None:
|
|
1605
|
+
self._values["dead_letter_retention"] = dead_letter_retention
|
|
1606
|
+
if emit_metrics is not None:
|
|
1607
|
+
self._values["emit_metrics"] = emit_metrics
|
|
1608
|
+
if encryption_key is not None:
|
|
1609
|
+
self._values["encryption_key"] = encryption_key
|
|
1610
|
+
if idle_runner_grace_seconds is not None:
|
|
1611
|
+
self._values["idle_runner_grace_seconds"] = idle_runner_grace_seconds
|
|
1612
|
+
if image_logs is not None:
|
|
1613
|
+
self._values["image_logs"] = image_logs
|
|
1614
|
+
if janitor_interval is not None:
|
|
1615
|
+
self._values["janitor_interval"] = janitor_interval
|
|
1616
|
+
if keep_image_versions is not None:
|
|
1617
|
+
self._values["keep_image_versions"] = keep_image_versions
|
|
1618
|
+
if lambda_memory_size is not None:
|
|
1619
|
+
self._values["lambda_memory_size"] = lambda_memory_size
|
|
1620
|
+
if log_retention is not None:
|
|
1621
|
+
self._values["log_retention"] = log_retention
|
|
1622
|
+
if max_concurrent_vms is not None:
|
|
1623
|
+
self._values["max_concurrent_vms"] = max_concurrent_vms
|
|
1624
|
+
if max_job_duration is not None:
|
|
1625
|
+
self._values["max_job_duration"] = max_job_duration
|
|
1626
|
+
if max_receive_count is not None:
|
|
1627
|
+
self._values["max_receive_count"] = max_receive_count
|
|
1628
|
+
if network is not None:
|
|
1629
|
+
self._values["network"] = network
|
|
1630
|
+
if permissions_boundary is not None:
|
|
1631
|
+
self._values["permissions_boundary"] = permissions_boundary
|
|
1632
|
+
if point_in_time_recovery is not None:
|
|
1633
|
+
self._values["point_in_time_recovery"] = point_in_time_recovery
|
|
1634
|
+
if recover_stuck_launches is not None:
|
|
1635
|
+
self._values["recover_stuck_launches"] = recover_stuck_launches
|
|
1636
|
+
if removal_policy is not None:
|
|
1637
|
+
self._values["removal_policy"] = removal_policy
|
|
1638
|
+
if vm_execution_role is not None:
|
|
1639
|
+
self._values["vm_execution_role"] = vm_execution_role
|
|
1640
|
+
if warm_pool_interval is not None:
|
|
1641
|
+
self._values["warm_pool_interval"] = warm_pool_interval
|
|
1642
|
+
if webhook is not None:
|
|
1643
|
+
self._values["webhook"] = webhook
|
|
1644
|
+
if webhook_reserved_concurrency is not None:
|
|
1645
|
+
self._values["webhook_reserved_concurrency"] = webhook_reserved_concurrency
|
|
1646
|
+
|
|
1647
|
+
@builtins.property
|
|
1648
|
+
def github(self) -> "GithubAuth":
|
|
1649
|
+
'''How the runner set authenticates to GitHub, as an App or with a personal access token.
|
|
1650
|
+
|
|
1651
|
+
This also carries the webhook secret.
|
|
1652
|
+
'''
|
|
1653
|
+
result = self._values.get("github")
|
|
1654
|
+
assert result is not None, "Required property 'github' is missing"
|
|
1655
|
+
return typing.cast("GithubAuth", result)
|
|
1656
|
+
|
|
1657
|
+
@builtins.property
|
|
1658
|
+
def scope(self) -> "RunnerScope":
|
|
1659
|
+
'''Which GitHub scope, an organization or a list of repositories, registered runners are visible to.'''
|
|
1660
|
+
result = self._values.get("scope")
|
|
1661
|
+
assert result is not None, "Required property 'scope' is missing"
|
|
1662
|
+
return typing.cast("RunnerScope", result)
|
|
1663
|
+
|
|
1664
|
+
@builtins.property
|
|
1665
|
+
def additional_regions(self) -> typing.Optional[typing.List[builtins.str]]:
|
|
1666
|
+
'''Additional regions to accept as Lambda MicroVMs regions, beyond the ones this library already knows about.
|
|
1667
|
+
|
|
1668
|
+
Deploying into a region on neither list
|
|
1669
|
+
fails at synth.
|
|
1670
|
+
|
|
1671
|
+
:default: [] (only the regions this library knows about)
|
|
1672
|
+
'''
|
|
1673
|
+
result = self._values.get("additional_regions")
|
|
1674
|
+
return typing.cast(typing.Optional[typing.List[builtins.str]], result)
|
|
1675
|
+
|
|
1676
|
+
@builtins.property
|
|
1677
|
+
def console_logs(self) -> typing.Optional["ConsoleLogs"]:
|
|
1678
|
+
'''Where a VM's runtime console goes: everything it prints while it boots, runs the runner agent, and runs the job.
|
|
1679
|
+
|
|
1680
|
+
``ConsoleLogs.enabled()`` has the
|
|
1681
|
+
construct create the group and expose it as ``vmConsoleLogGroup``, and
|
|
1682
|
+
``ConsoleLogs.enabled(logGroup)`` uses one you control. The platform writes
|
|
1683
|
+
these logs with the VM's own role, so this requires ``vmExecutionRole``; see
|
|
1684
|
+
``ConsoleLogs`` for what that role means for job code. Independent of
|
|
1685
|
+
``imageLogs``.
|
|
1686
|
+
|
|
1687
|
+
:default: undefined (no runtime console capture)
|
|
1688
|
+
'''
|
|
1689
|
+
result = self._values.get("console_logs")
|
|
1690
|
+
return typing.cast(typing.Optional["ConsoleLogs"], result)
|
|
1691
|
+
|
|
1692
|
+
@builtins.property
|
|
1693
|
+
def dead_letter_retention(self) -> typing.Optional["_aws_cdk_ceddda9d.Duration"]:
|
|
1694
|
+
'''How long the dead-letter queue retains a failed launch or terminate intent.
|
|
1695
|
+
|
|
1696
|
+
SQS allows up to 14 days, which is also how long
|
|
1697
|
+
``recoverStuckLaunches`` has to re-drive a message before SQS drops it.
|
|
1698
|
+
|
|
1699
|
+
:default: Duration.days(4) (SQS default)
|
|
1700
|
+
'''
|
|
1701
|
+
result = self._values.get("dead_letter_retention")
|
|
1702
|
+
return typing.cast(typing.Optional["_aws_cdk_ceddda9d.Duration"], result)
|
|
1703
|
+
|
|
1704
|
+
@builtins.property
|
|
1705
|
+
def emit_metrics(self) -> typing.Optional[builtins.bool]:
|
|
1706
|
+
'''Report this runner set's CloudWatch custom metrics.
|
|
1707
|
+
|
|
1708
|
+
Those are the
|
|
1709
|
+
janitor's per-sweep counters, the launcher's per-launch outcomes and
|
|
1710
|
+
spin-up timings, and the warm pool's fill numbers — everything
|
|
1711
|
+
``GithubMicrovmRunnersMetrics`` names. With this off the handlers report
|
|
1712
|
+
none of them.
|
|
1713
|
+
|
|
1714
|
+
CloudWatch bills custom metrics per metric per month, and this runner set's
|
|
1715
|
+
bill is not a fixed number: the launcher and warm-pool metrics carry a
|
|
1716
|
+
runner-class dimension, so each one becomes a separate billable metric per
|
|
1717
|
+
registered runner class.
|
|
1718
|
+
|
|
1719
|
+
The two alarms backed by these metrics, ``sweepErrorsAlarm`` and
|
|
1720
|
+
``stuckLaunchesRecoveredAlarm``, throw at synth unless this is on, since the
|
|
1721
|
+
metric they watch would never report. ``deadLetterQueueNotEmptyAlarm``
|
|
1722
|
+
watches an SQS metric and works either way. The metric accessors on
|
|
1723
|
+
``GithubMicrovmRunnersMetrics`` return a ``Metric`` regardless, so a
|
|
1724
|
+
dashboard can be built ahead of turning metrics on.
|
|
1725
|
+
|
|
1726
|
+
:default: false (no metrics emitted)
|
|
1727
|
+
'''
|
|
1728
|
+
result = self._values.get("emit_metrics")
|
|
1729
|
+
return typing.cast(typing.Optional[builtins.bool], result)
|
|
1730
|
+
|
|
1731
|
+
@builtins.property
|
|
1732
|
+
def encryption_key(self) -> typing.Optional["_aws_cdk_aws_kms_ceddda9d.IKey"]:
|
|
1733
|
+
'''Customer-managed KMS key for this runner set's data at rest: the DynamoDB runner table, the SQS job queue and dead-letter queue, and any log group this construct creates.
|
|
1734
|
+
|
|
1735
|
+
Log groups you bring yourself, and the GitHub
|
|
1736
|
+
secrets you pass in, keep their own keys.
|
|
1737
|
+
|
|
1738
|
+
:default: undefined (AWS-managed keys)
|
|
1739
|
+
'''
|
|
1740
|
+
result = self._values.get("encryption_key")
|
|
1741
|
+
return typing.cast(typing.Optional["_aws_cdk_aws_kms_ceddda9d.IKey"], result)
|
|
1742
|
+
|
|
1743
|
+
@builtins.property
|
|
1744
|
+
def idle_runner_grace_seconds(self) -> typing.Optional[jsii.Number]:
|
|
1745
|
+
'''How many seconds a registered runner may sit idle before the janitor's two-strike sweep treats it as stuck.
|
|
1746
|
+
|
|
1747
|
+
:default: 600
|
|
1748
|
+
'''
|
|
1749
|
+
result = self._values.get("idle_runner_grace_seconds")
|
|
1750
|
+
return typing.cast(typing.Optional[jsii.Number], result)
|
|
1751
|
+
|
|
1752
|
+
@builtins.property
|
|
1753
|
+
def image_logs(self) -> typing.Optional["ImageLogs"]:
|
|
1754
|
+
'''Where build-time image logs go: the Docker build layers and the ready-probe banner from each image build.
|
|
1755
|
+
|
|
1756
|
+
``ImageLogs.enabled()`` sends them
|
|
1757
|
+
to the platform's own CloudWatch group, and ``ImageLogs.enabled(logGroup)``
|
|
1758
|
+
to a group whose retention and KMS key you control. These are written by
|
|
1759
|
+
the image build role rather than by a VM, so they need no VM execution
|
|
1760
|
+
role. Independent of ``consoleLogs``.
|
|
1761
|
+
|
|
1762
|
+
:default: undefined (no image logs)
|
|
1763
|
+
'''
|
|
1764
|
+
result = self._values.get("image_logs")
|
|
1765
|
+
return typing.cast(typing.Optional["ImageLogs"], result)
|
|
1766
|
+
|
|
1767
|
+
@builtins.property
|
|
1768
|
+
def janitor_interval(self) -> typing.Optional["_aws_cdk_ceddda9d.Duration"]:
|
|
1769
|
+
'''How often the janitor sweep runs.
|
|
1770
|
+
|
|
1771
|
+
:default: Duration.minutes(5)
|
|
1772
|
+
'''
|
|
1773
|
+
result = self._values.get("janitor_interval")
|
|
1774
|
+
return typing.cast(typing.Optional["_aws_cdk_ceddda9d.Duration"], result)
|
|
1775
|
+
|
|
1776
|
+
@builtins.property
|
|
1777
|
+
def keep_image_versions(self) -> typing.Optional[jsii.Number]:
|
|
1778
|
+
'''How many MicroVM image versions to keep per runner class.
|
|
1779
|
+
|
|
1780
|
+
The janitor prunes inactive versions past this count.
|
|
1781
|
+
|
|
1782
|
+
:default: 5
|
|
1783
|
+
'''
|
|
1784
|
+
result = self._values.get("keep_image_versions")
|
|
1785
|
+
return typing.cast(typing.Optional[jsii.Number], result)
|
|
1786
|
+
|
|
1787
|
+
@builtins.property
|
|
1788
|
+
def lambda_memory_size(self) -> typing.Optional[jsii.Number]:
|
|
1789
|
+
'''Memory, in MiB, for the handler Lambdas: the webhook, the launcher, the janitor, and the warm pool.
|
|
1790
|
+
|
|
1791
|
+
The janitor's sweep scans the runner table and
|
|
1792
|
+
reconciles every running VM, so it is the handler most sensitive to this
|
|
1793
|
+
on a busy runner set.
|
|
1794
|
+
|
|
1795
|
+
:default: 128
|
|
1796
|
+
'''
|
|
1797
|
+
result = self._values.get("lambda_memory_size")
|
|
1798
|
+
return typing.cast(typing.Optional[jsii.Number], result)
|
|
1799
|
+
|
|
1800
|
+
@builtins.property
|
|
1801
|
+
def log_retention(
|
|
1802
|
+
self,
|
|
1803
|
+
) -> typing.Optional["_aws_cdk_aws_logs_ceddda9d.RetentionDays"]:
|
|
1804
|
+
'''Retention for the CloudWatch log groups this construct creates: the handler Lambda log groups and, when console capture is on, the VM console group.
|
|
1805
|
+
|
|
1806
|
+
:default: logs.RetentionDays.TWO_WEEKS
|
|
1807
|
+
'''
|
|
1808
|
+
result = self._values.get("log_retention")
|
|
1809
|
+
return typing.cast(typing.Optional["_aws_cdk_aws_logs_ceddda9d.RetentionDays"], result)
|
|
1810
|
+
|
|
1811
|
+
@builtins.property
|
|
1812
|
+
def max_concurrent_vms(self) -> typing.Optional[jsii.Number]:
|
|
1813
|
+
'''Maximum number of MicroVMs this runner set runs at once.
|
|
1814
|
+
|
|
1815
|
+
:default: 10
|
|
1816
|
+
'''
|
|
1817
|
+
result = self._values.get("max_concurrent_vms")
|
|
1818
|
+
return typing.cast(typing.Optional[jsii.Number], result)
|
|
1819
|
+
|
|
1820
|
+
@builtins.property
|
|
1821
|
+
def max_job_duration(self) -> typing.Optional["_aws_cdk_ceddda9d.Duration"]:
|
|
1822
|
+
'''How long a job may run before its MicroVM is terminated.
|
|
1823
|
+
|
|
1824
|
+
The VM is killed five minutes after this value, not at it. The runner set
|
|
1825
|
+
asks the platform for ``maxJobDuration + 5 minutes``, so that a job which
|
|
1826
|
+
reaches its own limit is stopped by the runner — which reports the timeout
|
|
1827
|
+
to GitHub and lets the VM come down cleanly — rather than by the platform
|
|
1828
|
+
removing the machine underneath it. Treat the five minutes as headroom for
|
|
1829
|
+
that shutdown rather than as extra running time.
|
|
1830
|
+
|
|
1831
|
+
:default: Duration.hours(6)
|
|
1832
|
+
'''
|
|
1833
|
+
result = self._values.get("max_job_duration")
|
|
1834
|
+
return typing.cast(typing.Optional["_aws_cdk_ceddda9d.Duration"], result)
|
|
1835
|
+
|
|
1836
|
+
@builtins.property
|
|
1837
|
+
def max_receive_count(self) -> typing.Optional[jsii.Number]:
|
|
1838
|
+
'''How many times a launch intent is redriven before it dead-letters.
|
|
1839
|
+
|
|
1840
|
+
A
|
|
1841
|
+
runner set already at ``maxConcurrentVms`` redrives capacity-rejected
|
|
1842
|
+
launches through this same budget, so on a runner set that regularly runs
|
|
1843
|
+
at capacity this count is how long a queued job waits before its launch is
|
|
1844
|
+
dropped. See docs/service-quotas.md.
|
|
1845
|
+
|
|
1846
|
+
:default: 20
|
|
1847
|
+
'''
|
|
1848
|
+
result = self._values.get("max_receive_count")
|
|
1849
|
+
return typing.cast(typing.Optional[jsii.Number], result)
|
|
1850
|
+
|
|
1851
|
+
@builtins.property
|
|
1852
|
+
def network(self) -> typing.Optional["RunnerNetwork"]:
|
|
1853
|
+
'''How launched MicroVMs and image builds reach the network.
|
|
1854
|
+
|
|
1855
|
+
:default: RunnerNetwork.internetEgress()
|
|
1856
|
+
'''
|
|
1857
|
+
result = self._values.get("network")
|
|
1858
|
+
return typing.cast(typing.Optional["RunnerNetwork"], result)
|
|
1859
|
+
|
|
1860
|
+
@builtins.property
|
|
1861
|
+
def permissions_boundary(
|
|
1862
|
+
self,
|
|
1863
|
+
) -> typing.Optional["_aws_cdk_aws_iam_ceddda9d.IManagedPolicy"]:
|
|
1864
|
+
'''Permissions boundary applied to every IAM role this construct creates: the handler execution roles, the per-class image build roles, and the network-connector operator role.
|
|
1865
|
+
|
|
1866
|
+
It is applied once at construct scope, so
|
|
1867
|
+
roles created later also carry it — the warm-pool handler's role, and the
|
|
1868
|
+
build role of any runner class registered after construction.
|
|
1869
|
+
|
|
1870
|
+
:default: undefined (no boundary)
|
|
1871
|
+
'''
|
|
1872
|
+
result = self._values.get("permissions_boundary")
|
|
1873
|
+
return typing.cast(typing.Optional["_aws_cdk_aws_iam_ceddda9d.IManagedPolicy"], result)
|
|
1874
|
+
|
|
1875
|
+
@builtins.property
|
|
1876
|
+
def point_in_time_recovery(self) -> typing.Optional[builtins.bool]:
|
|
1877
|
+
'''Turn on DynamoDB point-in-time recovery for the runner table.
|
|
1878
|
+
|
|
1879
|
+
:default: false
|
|
1880
|
+
'''
|
|
1881
|
+
result = self._values.get("point_in_time_recovery")
|
|
1882
|
+
return typing.cast(typing.Optional[builtins.bool], result)
|
|
1883
|
+
|
|
1884
|
+
@builtins.property
|
|
1885
|
+
def recover_stuck_launches(self) -> typing.Optional[builtins.bool]:
|
|
1886
|
+
'''Recover launches that dead-lettered while GitHub Actions was down.
|
|
1887
|
+
|
|
1888
|
+
Each
|
|
1889
|
+
janitor sweep re-drives dead-lettered launch messages back onto the job
|
|
1890
|
+
queue, but only for jobs GitHub still reports as queued; a launch whose job
|
|
1891
|
+
has since completed or been cancelled is discarded rather than booting a
|
|
1892
|
+
VM for work nobody is waiting on. Recovery happens once an outage ends,
|
|
1893
|
+
since GitHub dispatches no jobs while it is down. The janitor counts each
|
|
1894
|
+
recovered launch under the ``stuckLaunchesRecovered`` metric, which reports
|
|
1895
|
+
when ``emitMetrics`` is on.
|
|
1896
|
+
|
|
1897
|
+
:default: false
|
|
1898
|
+
'''
|
|
1899
|
+
result = self._values.get("recover_stuck_launches")
|
|
1900
|
+
return typing.cast(typing.Optional[builtins.bool], result)
|
|
1901
|
+
|
|
1902
|
+
@builtins.property
|
|
1903
|
+
def removal_policy(self) -> typing.Optional["_aws_cdk_ceddda9d.RemovalPolicy"]:
|
|
1904
|
+
'''Removal policy for this runner set's stateful resources: the runner table and any log group the construct creates.
|
|
1905
|
+
|
|
1906
|
+
The table holds correlation data
|
|
1907
|
+
for VMs that are currently running, all of which the janitor can rebuild
|
|
1908
|
+
from the MicroVM and GitHub APIs.
|
|
1909
|
+
|
|
1910
|
+
:default: RemovalPolicy.DESTROY
|
|
1911
|
+
'''
|
|
1912
|
+
result = self._values.get("removal_policy")
|
|
1913
|
+
return typing.cast(typing.Optional["_aws_cdk_ceddda9d.RemovalPolicy"], result)
|
|
1914
|
+
|
|
1915
|
+
@builtins.property
|
|
1916
|
+
def vm_execution_role(self) -> typing.Optional["_aws_cdk_aws_iam_ceddda9d.IRole"]:
|
|
1917
|
+
'''An AWS identity for this runner set's runner VMs.
|
|
1918
|
+
|
|
1919
|
+
By default the VMs carry
|
|
1920
|
+
no AWS identity at all: the runner agent talks outbound to GitHub, the
|
|
1921
|
+
just-in-time registration is pushed to the VM over a platform-authenticated
|
|
1922
|
+
channel, and a job that needs AWS assumes its own role through GitHub OIDC.
|
|
1923
|
+
|
|
1924
|
+
With a role attached, the MicroVM's instance metadata service serves that
|
|
1925
|
+
role's credentials to arbitrary job code, so every job running on this
|
|
1926
|
+
runner set can do whatever the role can do. ``consoleLogs`` requires a role,
|
|
1927
|
+
because the platform writes a VM's console output using it.
|
|
1928
|
+
|
|
1929
|
+
:default: undefined (the VMs carry no AWS identity)
|
|
1930
|
+
'''
|
|
1931
|
+
result = self._values.get("vm_execution_role")
|
|
1932
|
+
return typing.cast(typing.Optional["_aws_cdk_aws_iam_ceddda9d.IRole"], result)
|
|
1933
|
+
|
|
1934
|
+
@builtins.property
|
|
1935
|
+
def warm_pool_interval(self) -> typing.Optional["_aws_cdk_ceddda9d.Duration"]:
|
|
1936
|
+
'''How often the warm-pool sweep refills pre-booted VMs.
|
|
1937
|
+
|
|
1938
|
+
It applies only to
|
|
1939
|
+
runner classes that set ``RunnerClassProps.warmPoolSize``, and the warm-pool
|
|
1940
|
+
handler and its schedule are only created once such a class is registered.
|
|
1941
|
+
A runner set with no warm class never runs this sweep, and never reads
|
|
1942
|
+
this value.
|
|
1943
|
+
|
|
1944
|
+
:default: Duration.minutes(2)
|
|
1945
|
+
'''
|
|
1946
|
+
result = self._values.get("warm_pool_interval")
|
|
1947
|
+
return typing.cast(typing.Optional["_aws_cdk_ceddda9d.Duration"], result)
|
|
1948
|
+
|
|
1949
|
+
@builtins.property
|
|
1950
|
+
def webhook(self) -> typing.Optional["WebhookEndpoint"]:
|
|
1951
|
+
'''How the webhook handler is exposed to GitHub.
|
|
1952
|
+
|
|
1953
|
+
:default: WebhookEndpoint.functionUrl()
|
|
1954
|
+
'''
|
|
1955
|
+
result = self._values.get("webhook")
|
|
1956
|
+
return typing.cast(typing.Optional["WebhookEndpoint"], result)
|
|
1957
|
+
|
|
1958
|
+
@builtins.property
|
|
1959
|
+
def webhook_reserved_concurrency(self) -> typing.Optional[jsii.Number]:
|
|
1960
|
+
'''Reserved concurrency for the webhook Lambda, which caps how many webhook deliveries the runner set processes at once.
|
|
1961
|
+
|
|
1962
|
+
Reserved concurrency is
|
|
1963
|
+
carved out of the account's shared pool of unreserved concurrency, so a
|
|
1964
|
+
runner set that sets it takes that capacity away from every other function
|
|
1965
|
+
in the account. Must be a positive integer when set, since ``0`` would
|
|
1966
|
+
disable the webhook entirely.
|
|
1967
|
+
|
|
1968
|
+
:default: undefined (no reservation; the webhook draws from the shared pool)
|
|
1969
|
+
'''
|
|
1970
|
+
result = self._values.get("webhook_reserved_concurrency")
|
|
1971
|
+
return typing.cast(typing.Optional[jsii.Number], result)
|
|
1972
|
+
|
|
1973
|
+
def __eq__(self, rhs: typing.Any) -> builtins.bool:
|
|
1974
|
+
return isinstance(rhs, self.__class__) and rhs._values == self._values
|
|
1975
|
+
|
|
1976
|
+
def __ne__(self, rhs: typing.Any) -> builtins.bool:
|
|
1977
|
+
return not (rhs == self)
|
|
1978
|
+
|
|
1979
|
+
def __repr__(self) -> str:
|
|
1980
|
+
return "GithubMicrovmRunnersProps(%s)" % ", ".join(
|
|
1981
|
+
k + "=" + repr(v) for k, v in self._values.items()
|
|
1982
|
+
)
|
|
1983
|
+
|
|
1984
|
+
|
|
1985
|
+
@jsii.data_type(
|
|
1986
|
+
jsii_type="cdk-github-microvm-runners.GithubPatAuthProps",
|
|
1987
|
+
jsii_struct_bases=[],
|
|
1988
|
+
name_mapping={"token": "token", "webhook_secret": "webhookSecret"},
|
|
1989
|
+
)
|
|
1990
|
+
class GithubPatAuthProps:
|
|
1991
|
+
def __init__(
|
|
1992
|
+
self,
|
|
1993
|
+
*,
|
|
1994
|
+
token: "_aws_cdk_aws_secretsmanager_ceddda9d.ISecret",
|
|
1995
|
+
webhook_secret: "_aws_cdk_aws_secretsmanager_ceddda9d.ISecret",
|
|
1996
|
+
) -> None:
|
|
1997
|
+
'''Props for ``GithubAuth.pat``.
|
|
1998
|
+
|
|
1999
|
+
:param token: Secret holding a GitHub personal access token.
|
|
2000
|
+
:param webhook_secret: Secret holding the webhook secret used to validate inbound deliveries.
|
|
2001
|
+
'''
|
|
2002
|
+
if __debug__:
|
|
2003
|
+
type_hints = cached_type_hints(_typecheckingstub__af35288b9c48eea9cffeb6e1080b684e480ae2227583407499a01041a243a072)
|
|
2004
|
+
check_type(argname="argument token", value=token, expected_type=type_hints["token"])
|
|
2005
|
+
check_type(argname="argument webhook_secret", value=webhook_secret, expected_type=type_hints["webhook_secret"])
|
|
2006
|
+
self._values: typing.Dict[builtins.str, typing.Any] = {
|
|
2007
|
+
"token": token,
|
|
2008
|
+
"webhook_secret": webhook_secret,
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
@builtins.property
|
|
2012
|
+
def token(self) -> "_aws_cdk_aws_secretsmanager_ceddda9d.ISecret":
|
|
2013
|
+
'''Secret holding a GitHub personal access token.'''
|
|
2014
|
+
result = self._values.get("token")
|
|
2015
|
+
assert result is not None, "Required property 'token' is missing"
|
|
2016
|
+
return typing.cast("_aws_cdk_aws_secretsmanager_ceddda9d.ISecret", result)
|
|
2017
|
+
|
|
2018
|
+
@builtins.property
|
|
2019
|
+
def webhook_secret(self) -> "_aws_cdk_aws_secretsmanager_ceddda9d.ISecret":
|
|
2020
|
+
'''Secret holding the webhook secret used to validate inbound deliveries.'''
|
|
2021
|
+
result = self._values.get("webhook_secret")
|
|
2022
|
+
assert result is not None, "Required property 'webhook_secret' is missing"
|
|
2023
|
+
return typing.cast("_aws_cdk_aws_secretsmanager_ceddda9d.ISecret", result)
|
|
2024
|
+
|
|
2025
|
+
def __eq__(self, rhs: typing.Any) -> builtins.bool:
|
|
2026
|
+
return isinstance(rhs, self.__class__) and rhs._values == self._values
|
|
2027
|
+
|
|
2028
|
+
def __ne__(self, rhs: typing.Any) -> builtins.bool:
|
|
2029
|
+
return not (rhs == self)
|
|
2030
|
+
|
|
2031
|
+
def __repr__(self) -> str:
|
|
2032
|
+
return "GithubPatAuthProps(%s)" % ", ".join(
|
|
2033
|
+
k + "=" + repr(v) for k, v in self._values.items()
|
|
2034
|
+
)
|
|
2035
|
+
|
|
2036
|
+
|
|
2037
|
+
@jsii.data_type(
|
|
2038
|
+
jsii_type="cdk-github-microvm-runners.ImageAsset",
|
|
2039
|
+
jsii_struct_bases=[],
|
|
2040
|
+
name_mapping={"source": "source", "target": "target"},
|
|
2041
|
+
)
|
|
2042
|
+
class ImageAsset:
|
|
2043
|
+
def __init__(self, *, source: builtins.str, target: builtins.str) -> None:
|
|
2044
|
+
'''One extra file or directory baked into the image.
|
|
2045
|
+
|
|
2046
|
+
``source`` is a path on the machine running ``cdk synth``. The image pipeline
|
|
2047
|
+
reads it off disk when it stages the Docker build context, and the rendered
|
|
2048
|
+
Dockerfile copies it to ``target`` inside the image.
|
|
2049
|
+
|
|
2050
|
+
:param source: Path (file or directory) on the build machine to copy into the image.
|
|
2051
|
+
:param target: Absolute path inside the image to copy ``source`` to.
|
|
2052
|
+
'''
|
|
2053
|
+
if __debug__:
|
|
2054
|
+
type_hints = cached_type_hints(_typecheckingstub__d7d3da112d28b428bdfaadffe313adf1b4f0e1018b1cbf217c7687e156912c49)
|
|
2055
|
+
check_type(argname="argument source", value=source, expected_type=type_hints["source"])
|
|
2056
|
+
check_type(argname="argument target", value=target, expected_type=type_hints["target"])
|
|
2057
|
+
self._values: typing.Dict[builtins.str, typing.Any] = {
|
|
2058
|
+
"source": source,
|
|
2059
|
+
"target": target,
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
@builtins.property
|
|
2063
|
+
def source(self) -> builtins.str:
|
|
2064
|
+
'''Path (file or directory) on the build machine to copy into the image.'''
|
|
2065
|
+
result = self._values.get("source")
|
|
2066
|
+
assert result is not None, "Required property 'source' is missing"
|
|
2067
|
+
return typing.cast(builtins.str, result)
|
|
2068
|
+
|
|
2069
|
+
@builtins.property
|
|
2070
|
+
def target(self) -> builtins.str:
|
|
2071
|
+
'''Absolute path inside the image to copy ``source`` to.'''
|
|
2072
|
+
result = self._values.get("target")
|
|
2073
|
+
assert result is not None, "Required property 'target' is missing"
|
|
2074
|
+
return typing.cast(builtins.str, result)
|
|
2075
|
+
|
|
2076
|
+
def __eq__(self, rhs: typing.Any) -> builtins.bool:
|
|
2077
|
+
return isinstance(rhs, self.__class__) and rhs._values == self._values
|
|
2078
|
+
|
|
2079
|
+
def __ne__(self, rhs: typing.Any) -> builtins.bool:
|
|
2080
|
+
return not (rhs == self)
|
|
2081
|
+
|
|
2082
|
+
def __repr__(self) -> str:
|
|
2083
|
+
return "ImageAsset(%s)" % ", ".join(
|
|
2084
|
+
k + "=" + repr(v) for k, v in self._values.items()
|
|
2085
|
+
)
|
|
2086
|
+
|
|
2087
|
+
|
|
2088
|
+
class ImageLogs(
|
|
2089
|
+
metaclass=jsii.JSIIMeta,
|
|
2090
|
+
jsii_type="cdk-github-microvm-runners.ImageLogs",
|
|
2091
|
+
):
|
|
2092
|
+
'''Build-time image logs for a runner set: the Docker build layers and the ready-probe banner an image emits while it is built.
|
|
2093
|
+
|
|
2094
|
+
Off unless you add it.
|
|
2095
|
+
|
|
2096
|
+
These logs are written while the image builds, by the image build role
|
|
2097
|
+
rather than by a VM, so image logging needs no VM execution role and puts no
|
|
2098
|
+
credentials on a runner. ``ConsoleLogs`` covers the runtime counterpart, which
|
|
2099
|
+
does need a role. The two are independent and can both be on.
|
|
2100
|
+
|
|
2101
|
+
Example::
|
|
2102
|
+
|
|
2103
|
+
GithubMicrovmRunners(stack, "Runners",
|
|
2104
|
+
github=github,
|
|
2105
|
+
scope=scope,
|
|
2106
|
+
image_logs=ImageLogs.enabled()
|
|
2107
|
+
)
|
|
2108
|
+
'''
|
|
2109
|
+
|
|
2110
|
+
@jsii.member(jsii_name="enabled")
|
|
2111
|
+
@builtins.classmethod
|
|
2112
|
+
def enabled(
|
|
2113
|
+
cls,
|
|
2114
|
+
log_group: typing.Optional["_aws_cdk_aws_logs_ceddda9d.ILogGroup"] = None,
|
|
2115
|
+
) -> "ImageLogs":
|
|
2116
|
+
'''Send image-build logs to CloudWatch.
|
|
2117
|
+
|
|
2118
|
+
With no argument they go to the
|
|
2119
|
+
platform's own group (``/aws/lambda-microvms/…``). Pass an ``ILogGroup`` to
|
|
2120
|
+
send them to a group whose retention and KMS key you control.
|
|
2121
|
+
|
|
2122
|
+
:param log_group: destination group. Omitted, the platform's own group.
|
|
2123
|
+
|
|
2124
|
+
Example::
|
|
2125
|
+
|
|
2126
|
+
build_logs = ImageLogs.enabled(my_build_log_group)
|
|
2127
|
+
'''
|
|
2128
|
+
if __debug__:
|
|
2129
|
+
type_hints = cached_type_hints(_typecheckingstub__5c18afa4a05ee3b3cf8019fa8e3bf98a9dc803b4ff31600008a4916dce15cd6a)
|
|
2130
|
+
check_type(argname="argument log_group", value=log_group, expected_type=type_hints["log_group"])
|
|
2131
|
+
return typing.cast("ImageLogs", jsii.sinvoke(cls, "enabled", [log_group]))
|
|
2132
|
+
|
|
2133
|
+
@builtins.property
|
|
2134
|
+
@jsii.member(jsii_name="logGroup")
|
|
2135
|
+
def log_group(self) -> typing.Optional["_aws_cdk_aws_logs_ceddda9d.ILogGroup"]:
|
|
2136
|
+
'''The group build logs go to, when one was passed to ``ImageLogs.enabled()``. ``undefined`` means the platform's own group.'''
|
|
2137
|
+
return typing.cast(typing.Optional["_aws_cdk_aws_logs_ceddda9d.ILogGroup"], jsii.get(self, "logGroup"))
|
|
2138
|
+
|
|
2139
|
+
|
|
2140
|
+
class ImagePipeline(
|
|
2141
|
+
_constructs_77d1e7e8.Construct,
|
|
2142
|
+
metaclass=jsii.JSIIMeta,
|
|
2143
|
+
jsii_type="cdk-github-microvm-runners.ImagePipeline",
|
|
2144
|
+
):
|
|
2145
|
+
'''The build behind one runner class's MicroVM image.
|
|
2146
|
+
|
|
2147
|
+
``addRunnerClass`` creates
|
|
2148
|
+
one for each class it registers and returns it as
|
|
2149
|
+
``RunnerClass.imagePipeline``, so this is a handle you read rather than a
|
|
2150
|
+
construct you instantiate.
|
|
2151
|
+
|
|
2152
|
+
It stages the class's Dockerfile and build context as a CDK asset, declares
|
|
2153
|
+
the ``AWS::Lambda::MicrovmImage`` resource that CloudFormation builds from it,
|
|
2154
|
+
and creates the IAM role that build runs as. Reading it is how you reach the
|
|
2155
|
+
built image's name and ARN, and the role the build runs as.
|
|
2156
|
+
|
|
2157
|
+
Example::
|
|
2158
|
+
|
|
2159
|
+
build_class = runners.add_runner_class("build",
|
|
2160
|
+
size=MicrovmSize.GB4,
|
|
2161
|
+
image=RunnerImage.from_options(system_packages=["jq"])
|
|
2162
|
+
)
|
|
2163
|
+
|
|
2164
|
+
cdk.CfnOutput(stack, "BuildImageName",
|
|
2165
|
+
value=build_class.image_pipeline.image_name
|
|
2166
|
+
)
|
|
2167
|
+
'''
|
|
2168
|
+
|
|
2169
|
+
def __init__(
|
|
2170
|
+
self,
|
|
2171
|
+
scope: "_constructs_77d1e7e8.Construct",
|
|
2172
|
+
id: builtins.str,
|
|
2173
|
+
*,
|
|
2174
|
+
image: "RunnerImage",
|
|
2175
|
+
network: "RunnerNetwork",
|
|
2176
|
+
runner_set_id: builtins.str,
|
|
2177
|
+
size: "MicrovmSize",
|
|
2178
|
+
base_image_version: typing.Optional[builtins.str] = None,
|
|
2179
|
+
image_logs: typing.Optional["ImageLogs"] = None,
|
|
2180
|
+
ready_timeout_seconds: typing.Optional[jsii.Number] = None,
|
|
2181
|
+
run_timeout_seconds: typing.Optional[jsii.Number] = None,
|
|
2182
|
+
) -> None:
|
|
2183
|
+
'''
|
|
2184
|
+
:param scope: -
|
|
2185
|
+
:param id: -
|
|
2186
|
+
:param image: The runner image to build: ``RunnerImage.fromOptions()`` for a synthesized Dockerfile, ``RunnerImage.fromInline(text)`` for Dockerfile text, or ``RunnerImage.fromDockerfile(dir)`` for a Dockerfile and build context on disk.
|
|
2187
|
+
:param network: How the build and the VMs reach the network.
|
|
2188
|
+
:param runner_set_id: Identifier for the runner set this image belongs to. It is combined with the first 8 hex characters of the image's ``contentHash`` to form the image's name, so a content change publishes a new image and an unchanged one is a no-op. Must match ``^[a-zA-Z0-9-_]+$``, and must be 55 characters or fewer so that ``<runnerSetId>-<8-hex-chars>`` stays within the service's 64-character name limit.
|
|
2189
|
+
:param size: The size the built image runs at, which becomes its memory floor.
|
|
2190
|
+
:param base_image_version: Version of the managed ``al2023-1`` base image to build from. Default: '0'
|
|
2191
|
+
:param image_logs: Where the build's logs go. Left unset, the build emits no logs; ``ImageLogs.enabled()`` sends them to the platform's group, and ``ImageLogs.enabled(logGroup)`` to a group you supply.
|
|
2192
|
+
:param ready_timeout_seconds: Seconds the service waits for the in-VM agent's ``/ready`` hook before failing the image build. Default: 300
|
|
2193
|
+
:param run_timeout_seconds: Seconds the service waits for the in-VM agent's ``/run`` hook to accept a launch. Service maximum: 60. Default: 60
|
|
2194
|
+
'''
|
|
2195
|
+
if __debug__:
|
|
2196
|
+
type_hints = cached_type_hints(_typecheckingstub__38e8b0a65e40c9bfd130b4244eef3af238aac180d3c10606a513fef86e7aa169)
|
|
2197
|
+
check_type(argname="argument scope", value=scope, expected_type=type_hints["scope"])
|
|
2198
|
+
check_type(argname="argument id", value=id, expected_type=type_hints["id"])
|
|
2199
|
+
props = ImagePipelineProps(
|
|
2200
|
+
image=image,
|
|
2201
|
+
network=network,
|
|
2202
|
+
runner_set_id=runner_set_id,
|
|
2203
|
+
size=size,
|
|
2204
|
+
base_image_version=base_image_version,
|
|
2205
|
+
image_logs=image_logs,
|
|
2206
|
+
ready_timeout_seconds=ready_timeout_seconds,
|
|
2207
|
+
run_timeout_seconds=run_timeout_seconds,
|
|
2208
|
+
)
|
|
2209
|
+
|
|
2210
|
+
jsii.create(self.__class__, self, [scope, id, props])
|
|
2211
|
+
|
|
2212
|
+
@builtins.property
|
|
2213
|
+
@jsii.member(jsii_name="buildRole")
|
|
2214
|
+
def build_role(self) -> "_aws_cdk_aws_iam_ceddda9d.IRole":
|
|
2215
|
+
'''IAM role the image build runs as, able to read the staged build context and pull any private container base image.'''
|
|
2216
|
+
return typing.cast("_aws_cdk_aws_iam_ceddda9d.IRole", jsii.get(self, "buildRole"))
|
|
2217
|
+
|
|
2218
|
+
@builtins.property
|
|
2219
|
+
@jsii.member(jsii_name="imageArn")
|
|
2220
|
+
def image_arn(self) -> builtins.str:
|
|
2221
|
+
'''ARN of the built MicroVM image.'''
|
|
2222
|
+
return typing.cast(builtins.str, jsii.get(self, "imageArn"))
|
|
2223
|
+
|
|
2224
|
+
@builtins.property
|
|
2225
|
+
@jsii.member(jsii_name="imageName")
|
|
2226
|
+
def image_name(self) -> builtins.str:
|
|
2227
|
+
'''Name of the built MicroVM image, ``<runnerSetId>-<8 hex characters of the content hash>``.'''
|
|
2228
|
+
return typing.cast(builtins.str, jsii.get(self, "imageName"))
|
|
2229
|
+
|
|
2230
|
+
@builtins.property
|
|
2231
|
+
@jsii.member(jsii_name="imageResource")
|
|
2232
|
+
def image_resource(self) -> "_aws_cdk_aws_lambda_ceddda9d.CfnMicrovmImage":
|
|
2233
|
+
'''The underlying ``AWS::Lambda::MicrovmImage`` resource.'''
|
|
2234
|
+
return typing.cast("_aws_cdk_aws_lambda_ceddda9d.CfnMicrovmImage", jsii.get(self, "imageResource"))
|
|
2235
|
+
|
|
2236
|
+
|
|
2237
|
+
@jsii.data_type(
|
|
2238
|
+
jsii_type="cdk-github-microvm-runners.ImagePipelineProps",
|
|
2239
|
+
jsii_struct_bases=[],
|
|
2240
|
+
name_mapping={
|
|
2241
|
+
"image": "image",
|
|
2242
|
+
"network": "network",
|
|
2243
|
+
"runner_set_id": "runnerSetId",
|
|
2244
|
+
"size": "size",
|
|
2245
|
+
"base_image_version": "baseImageVersion",
|
|
2246
|
+
"image_logs": "imageLogs",
|
|
2247
|
+
"ready_timeout_seconds": "readyTimeoutSeconds",
|
|
2248
|
+
"run_timeout_seconds": "runTimeoutSeconds",
|
|
2249
|
+
},
|
|
2250
|
+
)
|
|
2251
|
+
class ImagePipelineProps:
|
|
2252
|
+
def __init__(
|
|
2253
|
+
self,
|
|
2254
|
+
*,
|
|
2255
|
+
image: "RunnerImage",
|
|
2256
|
+
network: "RunnerNetwork",
|
|
2257
|
+
runner_set_id: builtins.str,
|
|
2258
|
+
size: "MicrovmSize",
|
|
2259
|
+
base_image_version: typing.Optional[builtins.str] = None,
|
|
2260
|
+
image_logs: typing.Optional["ImageLogs"] = None,
|
|
2261
|
+
ready_timeout_seconds: typing.Optional[jsii.Number] = None,
|
|
2262
|
+
run_timeout_seconds: typing.Optional[jsii.Number] = None,
|
|
2263
|
+
) -> None:
|
|
2264
|
+
'''Props for ``ImagePipeline``.
|
|
2265
|
+
|
|
2266
|
+
:param image: The runner image to build: ``RunnerImage.fromOptions()`` for a synthesized Dockerfile, ``RunnerImage.fromInline(text)`` for Dockerfile text, or ``RunnerImage.fromDockerfile(dir)`` for a Dockerfile and build context on disk.
|
|
2267
|
+
:param network: How the build and the VMs reach the network.
|
|
2268
|
+
:param runner_set_id: Identifier for the runner set this image belongs to. It is combined with the first 8 hex characters of the image's ``contentHash`` to form the image's name, so a content change publishes a new image and an unchanged one is a no-op. Must match ``^[a-zA-Z0-9-_]+$``, and must be 55 characters or fewer so that ``<runnerSetId>-<8-hex-chars>`` stays within the service's 64-character name limit.
|
|
2269
|
+
:param size: The size the built image runs at, which becomes its memory floor.
|
|
2270
|
+
:param base_image_version: Version of the managed ``al2023-1`` base image to build from. Default: '0'
|
|
2271
|
+
:param image_logs: Where the build's logs go. Left unset, the build emits no logs; ``ImageLogs.enabled()`` sends them to the platform's group, and ``ImageLogs.enabled(logGroup)`` to a group you supply.
|
|
2272
|
+
:param ready_timeout_seconds: Seconds the service waits for the in-VM agent's ``/ready`` hook before failing the image build. Default: 300
|
|
2273
|
+
:param run_timeout_seconds: Seconds the service waits for the in-VM agent's ``/run`` hook to accept a launch. Service maximum: 60. Default: 60
|
|
2274
|
+
'''
|
|
2275
|
+
if __debug__:
|
|
2276
|
+
type_hints = cached_type_hints(_typecheckingstub__c8c6d3e3f7a844305d6a7d687bb74edba13926e6cdb04020bf45116bbb7f2407)
|
|
2277
|
+
check_type(argname="argument image", value=image, expected_type=type_hints["image"])
|
|
2278
|
+
check_type(argname="argument network", value=network, expected_type=type_hints["network"])
|
|
2279
|
+
check_type(argname="argument runner_set_id", value=runner_set_id, expected_type=type_hints["runner_set_id"])
|
|
2280
|
+
check_type(argname="argument size", value=size, expected_type=type_hints["size"])
|
|
2281
|
+
check_type(argname="argument base_image_version", value=base_image_version, expected_type=type_hints["base_image_version"])
|
|
2282
|
+
check_type(argname="argument image_logs", value=image_logs, expected_type=type_hints["image_logs"])
|
|
2283
|
+
check_type(argname="argument ready_timeout_seconds", value=ready_timeout_seconds, expected_type=type_hints["ready_timeout_seconds"])
|
|
2284
|
+
check_type(argname="argument run_timeout_seconds", value=run_timeout_seconds, expected_type=type_hints["run_timeout_seconds"])
|
|
2285
|
+
self._values: typing.Dict[builtins.str, typing.Any] = {
|
|
2286
|
+
"image": image,
|
|
2287
|
+
"network": network,
|
|
2288
|
+
"runner_set_id": runner_set_id,
|
|
2289
|
+
"size": size,
|
|
2290
|
+
}
|
|
2291
|
+
if base_image_version is not None:
|
|
2292
|
+
self._values["base_image_version"] = base_image_version
|
|
2293
|
+
if image_logs is not None:
|
|
2294
|
+
self._values["image_logs"] = image_logs
|
|
2295
|
+
if ready_timeout_seconds is not None:
|
|
2296
|
+
self._values["ready_timeout_seconds"] = ready_timeout_seconds
|
|
2297
|
+
if run_timeout_seconds is not None:
|
|
2298
|
+
self._values["run_timeout_seconds"] = run_timeout_seconds
|
|
2299
|
+
|
|
2300
|
+
@builtins.property
|
|
2301
|
+
def image(self) -> "RunnerImage":
|
|
2302
|
+
'''The runner image to build: ``RunnerImage.fromOptions()`` for a synthesized Dockerfile, ``RunnerImage.fromInline(text)`` for Dockerfile text, or ``RunnerImage.fromDockerfile(dir)`` for a Dockerfile and build context on disk.'''
|
|
2303
|
+
result = self._values.get("image")
|
|
2304
|
+
assert result is not None, "Required property 'image' is missing"
|
|
2305
|
+
return typing.cast("RunnerImage", result)
|
|
2306
|
+
|
|
2307
|
+
@builtins.property
|
|
2308
|
+
def network(self) -> "RunnerNetwork":
|
|
2309
|
+
'''How the build and the VMs reach the network.'''
|
|
2310
|
+
result = self._values.get("network")
|
|
2311
|
+
assert result is not None, "Required property 'network' is missing"
|
|
2312
|
+
return typing.cast("RunnerNetwork", result)
|
|
2313
|
+
|
|
2314
|
+
@builtins.property
|
|
2315
|
+
def runner_set_id(self) -> builtins.str:
|
|
2316
|
+
'''Identifier for the runner set this image belongs to.
|
|
2317
|
+
|
|
2318
|
+
It is combined with
|
|
2319
|
+
the first 8 hex characters of the image's ``contentHash`` to form the
|
|
2320
|
+
image's name, so a content change publishes a new image and an unchanged
|
|
2321
|
+
one is a no-op. Must match ``^[a-zA-Z0-9-_]+$``, and must be 55 characters
|
|
2322
|
+
or fewer so that ``<runnerSetId>-<8-hex-chars>`` stays within the service's
|
|
2323
|
+
64-character name limit.
|
|
2324
|
+
'''
|
|
2325
|
+
result = self._values.get("runner_set_id")
|
|
2326
|
+
assert result is not None, "Required property 'runner_set_id' is missing"
|
|
2327
|
+
return typing.cast(builtins.str, result)
|
|
2328
|
+
|
|
2329
|
+
@builtins.property
|
|
2330
|
+
def size(self) -> "MicrovmSize":
|
|
2331
|
+
'''The size the built image runs at, which becomes its memory floor.'''
|
|
2332
|
+
result = self._values.get("size")
|
|
2333
|
+
assert result is not None, "Required property 'size' is missing"
|
|
2334
|
+
return typing.cast("MicrovmSize", result)
|
|
2335
|
+
|
|
2336
|
+
@builtins.property
|
|
2337
|
+
def base_image_version(self) -> typing.Optional[builtins.str]:
|
|
2338
|
+
'''Version of the managed ``al2023-1`` base image to build from.
|
|
2339
|
+
|
|
2340
|
+
:default: '0'
|
|
2341
|
+
'''
|
|
2342
|
+
result = self._values.get("base_image_version")
|
|
2343
|
+
return typing.cast(typing.Optional[builtins.str], result)
|
|
2344
|
+
|
|
2345
|
+
@builtins.property
|
|
2346
|
+
def image_logs(self) -> typing.Optional["ImageLogs"]:
|
|
2347
|
+
'''Where the build's logs go.
|
|
2348
|
+
|
|
2349
|
+
Left unset, the build emits no logs; ``ImageLogs.enabled()`` sends them to the platform's group, and ``ImageLogs.enabled(logGroup)`` to a group you supply.
|
|
2350
|
+
'''
|
|
2351
|
+
result = self._values.get("image_logs")
|
|
2352
|
+
return typing.cast(typing.Optional["ImageLogs"], result)
|
|
2353
|
+
|
|
2354
|
+
@builtins.property
|
|
2355
|
+
def ready_timeout_seconds(self) -> typing.Optional[jsii.Number]:
|
|
2356
|
+
'''Seconds the service waits for the in-VM agent's ``/ready`` hook before failing the image build.
|
|
2357
|
+
|
|
2358
|
+
:default: 300
|
|
2359
|
+
'''
|
|
2360
|
+
result = self._values.get("ready_timeout_seconds")
|
|
2361
|
+
return typing.cast(typing.Optional[jsii.Number], result)
|
|
2362
|
+
|
|
2363
|
+
@builtins.property
|
|
2364
|
+
def run_timeout_seconds(self) -> typing.Optional[jsii.Number]:
|
|
2365
|
+
'''Seconds the service waits for the in-VM agent's ``/run`` hook to accept a launch.
|
|
2366
|
+
|
|
2367
|
+
Service maximum: 60.
|
|
2368
|
+
|
|
2369
|
+
:default: 60
|
|
2370
|
+
'''
|
|
2371
|
+
result = self._values.get("run_timeout_seconds")
|
|
2372
|
+
return typing.cast(typing.Optional[jsii.Number], result)
|
|
2373
|
+
|
|
2374
|
+
def __eq__(self, rhs: typing.Any) -> builtins.bool:
|
|
2375
|
+
return isinstance(rhs, self.__class__) and rhs._values == self._values
|
|
2376
|
+
|
|
2377
|
+
def __ne__(self, rhs: typing.Any) -> builtins.bool:
|
|
2378
|
+
return not (rhs == self)
|
|
2379
|
+
|
|
2380
|
+
def __repr__(self) -> str:
|
|
2381
|
+
return "ImagePipelineProps(%s)" % ", ".join(
|
|
2382
|
+
k + "=" + repr(v) for k, v in self._values.items()
|
|
2383
|
+
)
|
|
2384
|
+
|
|
2385
|
+
|
|
2386
|
+
@jsii.data_type(
|
|
2387
|
+
jsii_type="cdk-github-microvm-runners.MicrovmIdlePolicy",
|
|
2388
|
+
jsii_struct_bases=[],
|
|
2389
|
+
name_mapping={
|
|
2390
|
+
"max_idle_duration": "maxIdleDuration",
|
|
2391
|
+
"suspended_duration": "suspendedDuration",
|
|
2392
|
+
"auto_resume": "autoResume",
|
|
2393
|
+
},
|
|
2394
|
+
)
|
|
2395
|
+
class MicrovmIdlePolicy:
|
|
2396
|
+
def __init__(
|
|
2397
|
+
self,
|
|
2398
|
+
*,
|
|
2399
|
+
max_idle_duration: "_aws_cdk_ceddda9d.Duration",
|
|
2400
|
+
suspended_duration: "_aws_cdk_ceddda9d.Duration",
|
|
2401
|
+
auto_resume: typing.Optional[builtins.bool] = None,
|
|
2402
|
+
) -> None:
|
|
2403
|
+
'''When the platform suspends and resumes a runner class's cold-launched VMs.
|
|
2404
|
+
|
|
2405
|
+
This mirrors the MicroVM service's own ``idlePolicy`` shape, expressed as
|
|
2406
|
+
``Duration``s rather than raw seconds. Set it on a runner class through
|
|
2407
|
+
``RunnerClassProps.idlePolicy``.
|
|
2408
|
+
|
|
2409
|
+
:param max_idle_duration: Idle time before the platform auto-suspends the VM.
|
|
2410
|
+
:param suspended_duration: How long a suspended VM is kept before the platform terminates it. Required. The MicroVM service rejects a launch whose idle policy omits this value, and it offers no value meaning "keep the suspended VM indefinitely", so every idle policy names a duration.
|
|
2411
|
+
:param auto_resume: Auto-resume the VM on activity. Default: false
|
|
2412
|
+
'''
|
|
2413
|
+
if __debug__:
|
|
2414
|
+
type_hints = cached_type_hints(_typecheckingstub__299a6933558be6e9144d105ecb8f71fdfa2731d8f7934fa33118eb063140eb10)
|
|
2415
|
+
check_type(argname="argument max_idle_duration", value=max_idle_duration, expected_type=type_hints["max_idle_duration"])
|
|
2416
|
+
check_type(argname="argument suspended_duration", value=suspended_duration, expected_type=type_hints["suspended_duration"])
|
|
2417
|
+
check_type(argname="argument auto_resume", value=auto_resume, expected_type=type_hints["auto_resume"])
|
|
2418
|
+
self._values: typing.Dict[builtins.str, typing.Any] = {
|
|
2419
|
+
"max_idle_duration": max_idle_duration,
|
|
2420
|
+
"suspended_duration": suspended_duration,
|
|
2421
|
+
}
|
|
2422
|
+
if auto_resume is not None:
|
|
2423
|
+
self._values["auto_resume"] = auto_resume
|
|
2424
|
+
|
|
2425
|
+
@builtins.property
|
|
2426
|
+
def max_idle_duration(self) -> "_aws_cdk_ceddda9d.Duration":
|
|
2427
|
+
'''Idle time before the platform auto-suspends the VM.'''
|
|
2428
|
+
result = self._values.get("max_idle_duration")
|
|
2429
|
+
assert result is not None, "Required property 'max_idle_duration' is missing"
|
|
2430
|
+
return typing.cast("_aws_cdk_ceddda9d.Duration", result)
|
|
2431
|
+
|
|
2432
|
+
@builtins.property
|
|
2433
|
+
def suspended_duration(self) -> "_aws_cdk_ceddda9d.Duration":
|
|
2434
|
+
'''How long a suspended VM is kept before the platform terminates it.
|
|
2435
|
+
|
|
2436
|
+
Required. The MicroVM service rejects a launch whose idle policy omits
|
|
2437
|
+
this value, and it offers no value meaning "keep the suspended VM
|
|
2438
|
+
indefinitely", so every idle policy names a duration.
|
|
2439
|
+
'''
|
|
2440
|
+
result = self._values.get("suspended_duration")
|
|
2441
|
+
assert result is not None, "Required property 'suspended_duration' is missing"
|
|
2442
|
+
return typing.cast("_aws_cdk_ceddda9d.Duration", result)
|
|
2443
|
+
|
|
2444
|
+
@builtins.property
|
|
2445
|
+
def auto_resume(self) -> typing.Optional[builtins.bool]:
|
|
2446
|
+
'''Auto-resume the VM on activity.
|
|
2447
|
+
|
|
2448
|
+
:default: false
|
|
2449
|
+
'''
|
|
2450
|
+
result = self._values.get("auto_resume")
|
|
2451
|
+
return typing.cast(typing.Optional[builtins.bool], result)
|
|
2452
|
+
|
|
2453
|
+
def __eq__(self, rhs: typing.Any) -> builtins.bool:
|
|
2454
|
+
return isinstance(rhs, self.__class__) and rhs._values == self._values
|
|
2455
|
+
|
|
2456
|
+
def __ne__(self, rhs: typing.Any) -> builtins.bool:
|
|
2457
|
+
return not (rhs == self)
|
|
2458
|
+
|
|
2459
|
+
def __repr__(self) -> str:
|
|
2460
|
+
return "MicrovmIdlePolicy(%s)" % ", ".join(
|
|
2461
|
+
k + "=" + repr(v) for k, v in self._values.items()
|
|
2462
|
+
)
|
|
2463
|
+
|
|
2464
|
+
|
|
2465
|
+
class MicrovmSize(
|
|
2466
|
+
metaclass=jsii.JSIIMeta,
|
|
2467
|
+
jsii_type="cdk-github-microvm-runners.MicrovmSize",
|
|
2468
|
+
):
|
|
2469
|
+
'''The memory a MicroVM runs with.
|
|
2470
|
+
|
|
2471
|
+
Each runner class picks one preset, and that preset becomes the memory floor
|
|
2472
|
+
of the image the class builds. Pick from the static presets below; the
|
|
2473
|
+
constructor is private.
|
|
2474
|
+
|
|
2475
|
+
A preset is a **floor, not an allocation**. It is the minimum the image is
|
|
2476
|
+
built with, and the platform provisions above it — measured at roughly four
|
|
2477
|
+
times the request, so a class on ``GB1`` has been observed booting with about
|
|
2478
|
+
4 GB and 2 vCPU, and one on ``GB4`` with about 16 GB and 8 vCPU. Two things
|
|
2479
|
+
follow: a workload usually fits a smaller preset than its memory figure
|
|
2480
|
+
suggests, and the account's memory quota is charged the measured allocation
|
|
2481
|
+
rather than the floor. The service quotas guide carries the arithmetic.
|
|
2482
|
+
|
|
2483
|
+
vCPU and disk follow from the preset and are not separately settable — the
|
|
2484
|
+
image resource takes a memory floor and nothing else.
|
|
2485
|
+
|
|
2486
|
+
Example::
|
|
2487
|
+
|
|
2488
|
+
runners.add_runner_class("microvm-8gb", size=MicrovmSize.GB8)
|
|
2489
|
+
'''
|
|
2490
|
+
|
|
2491
|
+
@jsii.python.classproperty
|
|
2492
|
+
@jsii.member(jsii_name="GB0_5")
|
|
2493
|
+
def GB0_5(cls) -> "MicrovmSize":
|
|
2494
|
+
'''Memory floor of 0.5 GB.'''
|
|
2495
|
+
return typing.cast("MicrovmSize", jsii.sget(cls, "GB0_5"))
|
|
2496
|
+
|
|
2497
|
+
@jsii.python.classproperty
|
|
2498
|
+
@jsii.member(jsii_name="GB1")
|
|
2499
|
+
def GB1(cls) -> "MicrovmSize":
|
|
2500
|
+
'''Memory floor of 1 GB.'''
|
|
2501
|
+
return typing.cast("MicrovmSize", jsii.sget(cls, "GB1"))
|
|
2502
|
+
|
|
2503
|
+
@jsii.python.classproperty
|
|
2504
|
+
@jsii.member(jsii_name="GB2")
|
|
2505
|
+
def GB2(cls) -> "MicrovmSize":
|
|
2506
|
+
'''Memory floor of 2 GB.'''
|
|
2507
|
+
return typing.cast("MicrovmSize", jsii.sget(cls, "GB2"))
|
|
2508
|
+
|
|
2509
|
+
@jsii.python.classproperty
|
|
2510
|
+
@jsii.member(jsii_name="GB4")
|
|
2511
|
+
def GB4(cls) -> "MicrovmSize":
|
|
2512
|
+
'''Memory floor of 4 GB.'''
|
|
2513
|
+
return typing.cast("MicrovmSize", jsii.sget(cls, "GB4"))
|
|
2514
|
+
|
|
2515
|
+
@jsii.python.classproperty
|
|
2516
|
+
@jsii.member(jsii_name="GB8")
|
|
2517
|
+
def GB8(cls) -> "MicrovmSize":
|
|
2518
|
+
'''Memory floor of 8 GB.'''
|
|
2519
|
+
return typing.cast("MicrovmSize", jsii.sget(cls, "GB8"))
|
|
2520
|
+
|
|
2521
|
+
@builtins.property
|
|
2522
|
+
@jsii.member(jsii_name="memoryGb")
|
|
2523
|
+
def memory_gb(self) -> jsii.Number:
|
|
2524
|
+
'''Memory floor in GB.'''
|
|
2525
|
+
return typing.cast(jsii.Number, jsii.get(self, "memoryGb"))
|
|
2526
|
+
|
|
2527
|
+
@builtins.property
|
|
2528
|
+
@jsii.member(jsii_name="memoryMib")
|
|
2529
|
+
def memory_mib(self) -> jsii.Number:
|
|
2530
|
+
'''Memory in MiB, the unit the MicroVM image's ``minimumMemoryInMiB`` takes.'''
|
|
2531
|
+
return typing.cast(jsii.Number, jsii.get(self, "memoryMib"))
|
|
2532
|
+
|
|
2533
|
+
|
|
2534
|
+
@jsii.data_type(
|
|
2535
|
+
jsii_type="cdk-github-microvm-runners.RunnerAlarmOptions",
|
|
2536
|
+
jsii_struct_bases=[],
|
|
2537
|
+
name_mapping={
|
|
2538
|
+
"evaluation_periods": "evaluationPeriods",
|
|
2539
|
+
"period": "period",
|
|
2540
|
+
"threshold": "threshold",
|
|
2541
|
+
},
|
|
2542
|
+
)
|
|
2543
|
+
class RunnerAlarmOptions:
|
|
2544
|
+
def __init__(
|
|
2545
|
+
self,
|
|
2546
|
+
*,
|
|
2547
|
+
evaluation_periods: typing.Optional[jsii.Number] = None,
|
|
2548
|
+
period: typing.Optional["_aws_cdk_ceddda9d.Duration"] = None,
|
|
2549
|
+
threshold: typing.Optional[jsii.Number] = None,
|
|
2550
|
+
) -> None:
|
|
2551
|
+
'''Tuning for the ready-made alarms on ``GithubMicrovmRunnersMetrics``.
|
|
2552
|
+
|
|
2553
|
+
:param evaluation_periods: Consecutive breaching periods before the alarm fires. Default: 1 (3 for the stuck-launch alarm)
|
|
2554
|
+
:param period: Aggregation period for the metric. Default: Duration.minutes(5)
|
|
2555
|
+
:param threshold: Value at or above which the alarm fires. Default: 1
|
|
2556
|
+
'''
|
|
2557
|
+
if __debug__:
|
|
2558
|
+
type_hints = cached_type_hints(_typecheckingstub__117c59b0a49dcc58de82f614adb71603b95518cace779312d23dbc393e930d0f)
|
|
2559
|
+
check_type(argname="argument evaluation_periods", value=evaluation_periods, expected_type=type_hints["evaluation_periods"])
|
|
2560
|
+
check_type(argname="argument period", value=period, expected_type=type_hints["period"])
|
|
2561
|
+
check_type(argname="argument threshold", value=threshold, expected_type=type_hints["threshold"])
|
|
2562
|
+
self._values: typing.Dict[builtins.str, typing.Any] = {}
|
|
2563
|
+
if evaluation_periods is not None:
|
|
2564
|
+
self._values["evaluation_periods"] = evaluation_periods
|
|
2565
|
+
if period is not None:
|
|
2566
|
+
self._values["period"] = period
|
|
2567
|
+
if threshold is not None:
|
|
2568
|
+
self._values["threshold"] = threshold
|
|
2569
|
+
|
|
2570
|
+
@builtins.property
|
|
2571
|
+
def evaluation_periods(self) -> typing.Optional[jsii.Number]:
|
|
2572
|
+
'''Consecutive breaching periods before the alarm fires.
|
|
2573
|
+
|
|
2574
|
+
:default: 1 (3 for the stuck-launch alarm)
|
|
2575
|
+
'''
|
|
2576
|
+
result = self._values.get("evaluation_periods")
|
|
2577
|
+
return typing.cast(typing.Optional[jsii.Number], result)
|
|
2578
|
+
|
|
2579
|
+
@builtins.property
|
|
2580
|
+
def period(self) -> typing.Optional["_aws_cdk_ceddda9d.Duration"]:
|
|
2581
|
+
'''Aggregation period for the metric.
|
|
2582
|
+
|
|
2583
|
+
:default: Duration.minutes(5)
|
|
2584
|
+
'''
|
|
2585
|
+
result = self._values.get("period")
|
|
2586
|
+
return typing.cast(typing.Optional["_aws_cdk_ceddda9d.Duration"], result)
|
|
2587
|
+
|
|
2588
|
+
@builtins.property
|
|
2589
|
+
def threshold(self) -> typing.Optional[jsii.Number]:
|
|
2590
|
+
'''Value at or above which the alarm fires.
|
|
2591
|
+
|
|
2592
|
+
:default: 1
|
|
2593
|
+
'''
|
|
2594
|
+
result = self._values.get("threshold")
|
|
2595
|
+
return typing.cast(typing.Optional[jsii.Number], result)
|
|
2596
|
+
|
|
2597
|
+
def __eq__(self, rhs: typing.Any) -> builtins.bool:
|
|
2598
|
+
return isinstance(rhs, self.__class__) and rhs._values == self._values
|
|
2599
|
+
|
|
2600
|
+
def __ne__(self, rhs: typing.Any) -> builtins.bool:
|
|
2601
|
+
return not (rhs == self)
|
|
2602
|
+
|
|
2603
|
+
def __repr__(self) -> str:
|
|
2604
|
+
return "RunnerAlarmOptions(%s)" % ", ".join(
|
|
2605
|
+
k + "=" + repr(v) for k, v in self._values.items()
|
|
2606
|
+
)
|
|
2607
|
+
|
|
2608
|
+
|
|
2609
|
+
@jsii.data_type(
|
|
2610
|
+
jsii_type="cdk-github-microvm-runners.RunnerClass",
|
|
2611
|
+
jsii_struct_bases=[],
|
|
2612
|
+
name_mapping={
|
|
2613
|
+
"image_arn": "imageArn",
|
|
2614
|
+
"image_pipeline": "imagePipeline",
|
|
2615
|
+
"label": "label",
|
|
2616
|
+
"size": "size",
|
|
2617
|
+
},
|
|
2618
|
+
)
|
|
2619
|
+
class RunnerClass:
|
|
2620
|
+
def __init__(
|
|
2621
|
+
self,
|
|
2622
|
+
*,
|
|
2623
|
+
image_arn: builtins.str,
|
|
2624
|
+
image_pipeline: "ImagePipeline",
|
|
2625
|
+
label: builtins.str,
|
|
2626
|
+
size: "MicrovmSize",
|
|
2627
|
+
) -> None:
|
|
2628
|
+
'''Handle returned by ``GithubMicrovmRunners.addRunnerClass``.
|
|
2629
|
+
|
|
2630
|
+
:param image_arn: ARN of this class's built MicroVM image (a CloudFormation token at synth).
|
|
2631
|
+
:param image_pipeline: The image pipeline that builds and publishes this class's MicroVM image.
|
|
2632
|
+
:param label: The ``runs-on`` label workflows target to run on this class.
|
|
2633
|
+
:param size: The VM memory floor this class launches at.
|
|
2634
|
+
'''
|
|
2635
|
+
if __debug__:
|
|
2636
|
+
type_hints = cached_type_hints(_typecheckingstub__23472a12727bc341ce55563246f68a52c49776a6814a52ab825cec01db0cdc89)
|
|
2637
|
+
check_type(argname="argument image_arn", value=image_arn, expected_type=type_hints["image_arn"])
|
|
2638
|
+
check_type(argname="argument image_pipeline", value=image_pipeline, expected_type=type_hints["image_pipeline"])
|
|
2639
|
+
check_type(argname="argument label", value=label, expected_type=type_hints["label"])
|
|
2640
|
+
check_type(argname="argument size", value=size, expected_type=type_hints["size"])
|
|
2641
|
+
self._values: typing.Dict[builtins.str, typing.Any] = {
|
|
2642
|
+
"image_arn": image_arn,
|
|
2643
|
+
"image_pipeline": image_pipeline,
|
|
2644
|
+
"label": label,
|
|
2645
|
+
"size": size,
|
|
2646
|
+
}
|
|
2647
|
+
|
|
2648
|
+
@builtins.property
|
|
2649
|
+
def image_arn(self) -> builtins.str:
|
|
2650
|
+
'''ARN of this class's built MicroVM image (a CloudFormation token at synth).'''
|
|
2651
|
+
result = self._values.get("image_arn")
|
|
2652
|
+
assert result is not None, "Required property 'image_arn' is missing"
|
|
2653
|
+
return typing.cast(builtins.str, result)
|
|
2654
|
+
|
|
2655
|
+
@builtins.property
|
|
2656
|
+
def image_pipeline(self) -> "ImagePipeline":
|
|
2657
|
+
'''The image pipeline that builds and publishes this class's MicroVM image.'''
|
|
2658
|
+
result = self._values.get("image_pipeline")
|
|
2659
|
+
assert result is not None, "Required property 'image_pipeline' is missing"
|
|
2660
|
+
return typing.cast("ImagePipeline", result)
|
|
2661
|
+
|
|
2662
|
+
@builtins.property
|
|
2663
|
+
def label(self) -> builtins.str:
|
|
2664
|
+
'''The ``runs-on`` label workflows target to run on this class.'''
|
|
2665
|
+
result = self._values.get("label")
|
|
2666
|
+
assert result is not None, "Required property 'label' is missing"
|
|
2667
|
+
return typing.cast(builtins.str, result)
|
|
2668
|
+
|
|
2669
|
+
@builtins.property
|
|
2670
|
+
def size(self) -> "MicrovmSize":
|
|
2671
|
+
'''The VM memory floor this class launches at.'''
|
|
2672
|
+
result = self._values.get("size")
|
|
2673
|
+
assert result is not None, "Required property 'size' is missing"
|
|
2674
|
+
return typing.cast("MicrovmSize", result)
|
|
2675
|
+
|
|
2676
|
+
def __eq__(self, rhs: typing.Any) -> builtins.bool:
|
|
2677
|
+
return isinstance(rhs, self.__class__) and rhs._values == self._values
|
|
2678
|
+
|
|
2679
|
+
def __ne__(self, rhs: typing.Any) -> builtins.bool:
|
|
2680
|
+
return not (rhs == self)
|
|
2681
|
+
|
|
2682
|
+
def __repr__(self) -> str:
|
|
2683
|
+
return "RunnerClass(%s)" % ", ".join(
|
|
2684
|
+
k + "=" + repr(v) for k, v in self._values.items()
|
|
2685
|
+
)
|
|
2686
|
+
|
|
2687
|
+
|
|
2688
|
+
@jsii.data_type(
|
|
2689
|
+
jsii_type="cdk-github-microvm-runners.RunnerClassProps",
|
|
2690
|
+
jsii_struct_bases=[],
|
|
2691
|
+
name_mapping={
|
|
2692
|
+
"size": "size",
|
|
2693
|
+
"idle_policy": "idlePolicy",
|
|
2694
|
+
"image": "image",
|
|
2695
|
+
"warm_pool_size": "warmPoolSize",
|
|
2696
|
+
},
|
|
2697
|
+
)
|
|
2698
|
+
class RunnerClassProps:
|
|
2699
|
+
def __init__(
|
|
2700
|
+
self,
|
|
2701
|
+
*,
|
|
2702
|
+
size: "MicrovmSize",
|
|
2703
|
+
idle_policy: typing.Optional[typing.Union["MicrovmIdlePolicy", typing.Dict[builtins.str, typing.Any]]] = None,
|
|
2704
|
+
image: typing.Optional["RunnerImage"] = None,
|
|
2705
|
+
warm_pool_size: typing.Optional[jsii.Number] = None,
|
|
2706
|
+
) -> None:
|
|
2707
|
+
'''Props for ``GithubMicrovmRunners.addRunnerClass``.
|
|
2708
|
+
|
|
2709
|
+
:param size: VM memory floor for this class.
|
|
2710
|
+
:param idle_policy: Auto-suspend and auto-resume policy for this class's cold-launched VMs. Mutually exclusive with ``warmPoolSize`` on the same class, since both drive the VM's suspended state; setting both throws at ``addRunnerClass`` time. Default: undefined (no idle policy; the platform never auto-suspends)
|
|
2711
|
+
:param image: Image this class builds from. Default: RunnerImage.fromOptions()
|
|
2712
|
+
:param warm_pool_size: How many pre-booted, suspended VMs to keep ready for this class. A job that matches this class resumes one of them instead of cold-launching a new VM, and falls back to a cold launch when none is available. This is a count, not a flag: ``warmPoolSize: 3`` keeps three VMs ready. The runner set refills the pool on the ``warmPoolInterval`` schedule. Default: undefined (no warm pool; every job cold-launches)
|
|
2713
|
+
'''
|
|
2714
|
+
if isinstance(idle_policy, dict):
|
|
2715
|
+
idle_policy = MicrovmIdlePolicy(**idle_policy)
|
|
2716
|
+
if __debug__:
|
|
2717
|
+
type_hints = cached_type_hints(_typecheckingstub__6e46f2bbd7884caef4f137e6dac784cd99ef109d84b58f3f7acf963f03c723a7)
|
|
2718
|
+
check_type(argname="argument size", value=size, expected_type=type_hints["size"])
|
|
2719
|
+
check_type(argname="argument idle_policy", value=idle_policy, expected_type=type_hints["idle_policy"])
|
|
2720
|
+
check_type(argname="argument image", value=image, expected_type=type_hints["image"])
|
|
2721
|
+
check_type(argname="argument warm_pool_size", value=warm_pool_size, expected_type=type_hints["warm_pool_size"])
|
|
2722
|
+
self._values: typing.Dict[builtins.str, typing.Any] = {
|
|
2723
|
+
"size": size,
|
|
2724
|
+
}
|
|
2725
|
+
if idle_policy is not None:
|
|
2726
|
+
self._values["idle_policy"] = idle_policy
|
|
2727
|
+
if image is not None:
|
|
2728
|
+
self._values["image"] = image
|
|
2729
|
+
if warm_pool_size is not None:
|
|
2730
|
+
self._values["warm_pool_size"] = warm_pool_size
|
|
2731
|
+
|
|
2732
|
+
@builtins.property
|
|
2733
|
+
def size(self) -> "MicrovmSize":
|
|
2734
|
+
'''VM memory floor for this class.'''
|
|
2735
|
+
result = self._values.get("size")
|
|
2736
|
+
assert result is not None, "Required property 'size' is missing"
|
|
2737
|
+
return typing.cast("MicrovmSize", result)
|
|
2738
|
+
|
|
2739
|
+
@builtins.property
|
|
2740
|
+
def idle_policy(self) -> typing.Optional["MicrovmIdlePolicy"]:
|
|
2741
|
+
'''Auto-suspend and auto-resume policy for this class's cold-launched VMs.
|
|
2742
|
+
|
|
2743
|
+
Mutually exclusive with ``warmPoolSize`` on the same class, since both drive
|
|
2744
|
+
the VM's suspended state; setting both throws at ``addRunnerClass`` time.
|
|
2745
|
+
|
|
2746
|
+
:default: undefined (no idle policy; the platform never auto-suspends)
|
|
2747
|
+
'''
|
|
2748
|
+
result = self._values.get("idle_policy")
|
|
2749
|
+
return typing.cast(typing.Optional["MicrovmIdlePolicy"], result)
|
|
2750
|
+
|
|
2751
|
+
@builtins.property
|
|
2752
|
+
def image(self) -> typing.Optional["RunnerImage"]:
|
|
2753
|
+
'''Image this class builds from.
|
|
2754
|
+
|
|
2755
|
+
:default: RunnerImage.fromOptions()
|
|
2756
|
+
'''
|
|
2757
|
+
result = self._values.get("image")
|
|
2758
|
+
return typing.cast(typing.Optional["RunnerImage"], result)
|
|
2759
|
+
|
|
2760
|
+
@builtins.property
|
|
2761
|
+
def warm_pool_size(self) -> typing.Optional[jsii.Number]:
|
|
2762
|
+
'''How many pre-booted, suspended VMs to keep ready for this class.
|
|
2763
|
+
|
|
2764
|
+
A job
|
|
2765
|
+
that matches this class resumes one of them instead of cold-launching a
|
|
2766
|
+
new VM, and falls back to a cold launch when none is available. This is a
|
|
2767
|
+
count, not a flag: ``warmPoolSize: 3`` keeps three VMs ready. The runner set
|
|
2768
|
+
refills the pool on the ``warmPoolInterval`` schedule.
|
|
2769
|
+
|
|
2770
|
+
:default: undefined (no warm pool; every job cold-launches)
|
|
2771
|
+
'''
|
|
2772
|
+
result = self._values.get("warm_pool_size")
|
|
2773
|
+
return typing.cast(typing.Optional[jsii.Number], result)
|
|
2774
|
+
|
|
2775
|
+
def __eq__(self, rhs: typing.Any) -> builtins.bool:
|
|
2776
|
+
return isinstance(rhs, self.__class__) and rhs._values == self._values
|
|
2777
|
+
|
|
2778
|
+
def __ne__(self, rhs: typing.Any) -> builtins.bool:
|
|
2779
|
+
return not (rhs == self)
|
|
2780
|
+
|
|
2781
|
+
def __repr__(self) -> str:
|
|
2782
|
+
return "RunnerClassProps(%s)" % ", ".join(
|
|
2783
|
+
k + "=" + repr(v) for k, v in self._values.items()
|
|
2784
|
+
)
|
|
2785
|
+
|
|
2786
|
+
|
|
2787
|
+
class RunnerImage(
|
|
2788
|
+
metaclass=jsii.JSIIMeta,
|
|
2789
|
+
jsii_type="cdk-github-microvm-runners.RunnerImage",
|
|
2790
|
+
):
|
|
2791
|
+
'''The image a runner class's VMs boot from: one this library synthesizes, or one you author yourself.
|
|
2792
|
+
|
|
2793
|
+
Build one with the static factories below; the constructor is private.
|
|
2794
|
+
|
|
2795
|
+
Example::
|
|
2796
|
+
|
|
2797
|
+
runners.add_runner_class("build",
|
|
2798
|
+
size=MicrovmSize.GB4,
|
|
2799
|
+
image=RunnerImage.from_options(
|
|
2800
|
+
system_packages=["jq", "ripgrep"]
|
|
2801
|
+
)
|
|
2802
|
+
)
|
|
2803
|
+
'''
|
|
2804
|
+
|
|
2805
|
+
@jsii.member(jsii_name="fromDockerfile")
|
|
2806
|
+
@builtins.classmethod
|
|
2807
|
+
def from_dockerfile(cls, dir: builtins.str) -> "RunnerImage":
|
|
2808
|
+
'''Use your own Dockerfile, and the build context around it, from the directory ``dir``.
|
|
2809
|
+
|
|
2810
|
+
The whole directory is staged as the Docker build
|
|
2811
|
+
context, so a Dockerfile that needs to ``COPY`` files of its own belongs
|
|
2812
|
+
here rather than in ``RunnerImage.fromInline``.
|
|
2813
|
+
|
|
2814
|
+
The ``contentHash`` recorded on the returned instance is derived from the
|
|
2815
|
+
path string. The directory's actual contents are read and hashed later,
|
|
2816
|
+
when the image pipeline stages them as a CDK asset.
|
|
2817
|
+
|
|
2818
|
+
A relative ``dir`` is resolved against the process working directory, which
|
|
2819
|
+
is wherever ``cdk`` was invoked. Anchor it to the file that declares the
|
|
2820
|
+
runner class instead by passing ``path.join(__dirname, 'runner-image')``.
|
|
2821
|
+
|
|
2822
|
+
:param dir: -
|
|
2823
|
+
|
|
2824
|
+
Example::
|
|
2825
|
+
|
|
2826
|
+
custom_image = RunnerImage.from_dockerfile("runner-image")
|
|
2827
|
+
'''
|
|
2828
|
+
if __debug__:
|
|
2829
|
+
type_hints = cached_type_hints(_typecheckingstub__979f58111abc04b49545772d5ca529893452a46b62def883e284f0c2b1f0f73d)
|
|
2830
|
+
check_type(argname="argument dir", value=dir, expected_type=type_hints["dir"])
|
|
2831
|
+
return typing.cast("RunnerImage", jsii.sinvoke(cls, "fromDockerfile", [dir]))
|
|
2832
|
+
|
|
2833
|
+
@jsii.member(jsii_name="fromInline")
|
|
2834
|
+
@builtins.classmethod
|
|
2835
|
+
def from_inline(cls, dockerfile: builtins.str) -> "RunnerImage":
|
|
2836
|
+
'''Use your own Dockerfile, supplied as text.
|
|
2837
|
+
|
|
2838
|
+
The text is staged verbatim as
|
|
2839
|
+
the build context's ``Dockerfile``, alongside the ``microvm-runner/``
|
|
2840
|
+
directory the image pipeline injects and nothing else. A Dockerfile that
|
|
2841
|
+
needs to ``COPY`` files of its own belongs with
|
|
2842
|
+
``RunnerImage.fromDockerfile``, which stages a whole directory.
|
|
2843
|
+
|
|
2844
|
+
The text must ``COPY microvm-runner/agent.mjs`` and start the staged
|
|
2845
|
+
entrypoint, because that agent is what serves the MicroVM lifecycle hooks
|
|
2846
|
+
the platform calls. This is checked here, and a Dockerfile that does not
|
|
2847
|
+
copy the agent throws.
|
|
2848
|
+
|
|
2849
|
+
The ``contentHash`` recorded on the returned instance is a sha256 over the
|
|
2850
|
+
supplied text.
|
|
2851
|
+
|
|
2852
|
+
:param dockerfile: -
|
|
2853
|
+
|
|
2854
|
+
Example::
|
|
2855
|
+
|
|
2856
|
+
inline_image = RunnerImage.from_inline("""
|
|
2857
|
+
FROM public.ecr.aws/lambda/microvms:al2023-minimal
|
|
2858
|
+
|
|
2859
|
+
RUN dnf install -y git jq
|
|
2860
|
+
|
|
2861
|
+
COPY microvm-runner/agent.mjs /opt/microvm-runner/agent.mjs
|
|
2862
|
+
COPY microvm-runner/entrypoint.sh /opt/microvm-runner/entrypoint.sh
|
|
2863
|
+
ENTRYPOINT ["/opt/microvm-runner/entrypoint.sh"]
|
|
2864
|
+
""")
|
|
2865
|
+
'''
|
|
2866
|
+
if __debug__:
|
|
2867
|
+
type_hints = cached_type_hints(_typecheckingstub__2d9215b22cc740b2c93f48e4e0744fe50e43a7a33f85974d48dbebd1e184d9d4)
|
|
2868
|
+
check_type(argname="argument dockerfile", value=dockerfile, expected_type=type_hints["dockerfile"])
|
|
2869
|
+
return typing.cast("RunnerImage", jsii.sinvoke(cls, "fromInline", [dockerfile]))
|
|
2870
|
+
|
|
2871
|
+
@jsii.member(jsii_name="fromOptions")
|
|
2872
|
+
@builtins.classmethod
|
|
2873
|
+
def from_options(
|
|
2874
|
+
cls,
|
|
2875
|
+
*,
|
|
2876
|
+
additional_os_capabilities: typing.Optional[typing.Sequence[builtins.str]] = None,
|
|
2877
|
+
assets: typing.Optional[typing.Sequence[typing.Union["ImageAsset", typing.Dict[builtins.str, typing.Any]]]] = None,
|
|
2878
|
+
environment: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None,
|
|
2879
|
+
runner_version: typing.Optional["RunnerVersion"] = None,
|
|
2880
|
+
setup_commands: typing.Optional[typing.Sequence[builtins.str]] = None,
|
|
2881
|
+
system_packages: typing.Optional[typing.Sequence[builtins.str]] = None,
|
|
2882
|
+
toolchains: typing.Optional[typing.Sequence["RunnerToolchain"]] = None,
|
|
2883
|
+
) -> "RunnerImage":
|
|
2884
|
+
'''Synthesize a Dockerfile from ``opts`` — extra packages, setup commands, assets, environment variables, toolchains, and the ``actions/runner`` release to install.
|
|
2885
|
+
|
|
2886
|
+
The image's ``contentHash`` is computed here, over the
|
|
2887
|
+
rendered Dockerfile text and the list of assets it copies.
|
|
2888
|
+
|
|
2889
|
+
:param additional_os_capabilities: Extra Linux capabilities granted to the MicroVM's operating system. Default: ['ALL']
|
|
2890
|
+
:param assets: Extra files and directories to copy into the image.
|
|
2891
|
+
:param environment: Extra environment variables baked into the image.
|
|
2892
|
+
:param runner_version: ``actions/runner`` release to install. Default: RunnerVersion.latest()
|
|
2893
|
+
:param setup_commands: Extra ``RUN`` commands, executed in order after packages, assets, and environment variables are laid down.
|
|
2894
|
+
:param system_packages: Extra ``dnf`` packages to install alongside the fixed base set.
|
|
2895
|
+
:param toolchains: Language runtimes to bake into the hosted tool cache, so ``actions/setup-*`` finds them without downloading anything. An image with none of these is smaller; one toolchain entry is needed per version your workflows ask for. Default: []
|
|
2896
|
+
|
|
2897
|
+
Example::
|
|
2898
|
+
|
|
2899
|
+
build_image = RunnerImage.from_options(
|
|
2900
|
+
system_packages=["jq", "ripgrep"],
|
|
2901
|
+
setup_commands=["npm install -g pnpm@10"],
|
|
2902
|
+
environment={"LANG": "C.UTF-8"},
|
|
2903
|
+
toolchains=[RunnerToolchain.python("3.12.7")]
|
|
2904
|
+
)
|
|
2905
|
+
'''
|
|
2906
|
+
opts = RunnerImageOptions(
|
|
2907
|
+
additional_os_capabilities=additional_os_capabilities,
|
|
2908
|
+
assets=assets,
|
|
2909
|
+
environment=environment,
|
|
2910
|
+
runner_version=runner_version,
|
|
2911
|
+
setup_commands=setup_commands,
|
|
2912
|
+
system_packages=system_packages,
|
|
2913
|
+
toolchains=toolchains,
|
|
2914
|
+
)
|
|
2915
|
+
|
|
2916
|
+
return typing.cast("RunnerImage", jsii.sinvoke(cls, "fromOptions", [opts]))
|
|
2917
|
+
|
|
2918
|
+
@builtins.property
|
|
2919
|
+
@jsii.member(jsii_name="additionalOsCapabilities")
|
|
2920
|
+
def additional_os_capabilities(self) -> typing.List[builtins.str]:
|
|
2921
|
+
'''Extra Linux capabilities granted to the MicroVM's operating system.
|
|
2922
|
+
|
|
2923
|
+
``fromOptions()`` takes this from ``RunnerImageOptions``; ``fromDockerfile()``
|
|
2924
|
+
and ``fromInline()`` always carry ``['ALL']``.
|
|
2925
|
+
'''
|
|
2926
|
+
return typing.cast(typing.List[builtins.str], jsii.get(self, "additionalOsCapabilities"))
|
|
2927
|
+
|
|
2928
|
+
@builtins.property
|
|
2929
|
+
@jsii.member(jsii_name="contentHash")
|
|
2930
|
+
def content_hash(self) -> builtins.str:
|
|
2931
|
+
'''sha256 content hash, part of the built image's name.
|
|
2932
|
+
|
|
2933
|
+
For
|
|
2934
|
+
``fromOptions()`` it covers the rendered Dockerfile and the options that
|
|
2935
|
+
produced it; for ``fromInline()``, the supplied Dockerfile text; for
|
|
2936
|
+
``fromDockerfile()``, the directory path.
|
|
2937
|
+
'''
|
|
2938
|
+
return typing.cast(builtins.str, jsii.get(self, "contentHash"))
|
|
2939
|
+
|
|
2940
|
+
@builtins.property
|
|
2941
|
+
@jsii.member(jsii_name="assets")
|
|
2942
|
+
def assets(self) -> typing.Optional[typing.List["ImageAsset"]]:
|
|
2943
|
+
'''The ``{source, target}`` pairs from ``RunnerImageOptions.assets``. Set for ``fromOptions()``, whose rendered Dockerfile copies each one into the image. ``undefined`` for ``fromDockerfile()``, which stages your whole directory instead, and for ``fromInline()``, whose build context holds the Dockerfile and the injected agent and nothing else.'''
|
|
2944
|
+
return typing.cast(typing.Optional[typing.List["ImageAsset"]], jsii.get(self, "assets"))
|
|
2945
|
+
|
|
2946
|
+
@builtins.property
|
|
2947
|
+
@jsii.member(jsii_name="dockerfile")
|
|
2948
|
+
def dockerfile(self) -> typing.Optional[builtins.str]:
|
|
2949
|
+
'''Dockerfile text: rendered for ``fromOptions()``, supplied by you for ``fromInline()``.
|
|
2950
|
+
|
|
2951
|
+
``undefined`` for ``fromDockerfile()``, whose Dockerfile
|
|
2952
|
+
lives on disk under ``dockerfileDir``.
|
|
2953
|
+
'''
|
|
2954
|
+
return typing.cast(typing.Optional[builtins.str], jsii.get(self, "dockerfile"))
|
|
2955
|
+
|
|
2956
|
+
@builtins.property
|
|
2957
|
+
@jsii.member(jsii_name="dockerfileDir")
|
|
2958
|
+
def dockerfile_dir(self) -> typing.Optional[builtins.str]:
|
|
2959
|
+
'''The directory holding your own Dockerfile and build context.
|
|
2960
|
+
|
|
2961
|
+
Set for
|
|
2962
|
+
``fromDockerfile()``, ``undefined`` for ``fromOptions()`` and ``fromInline()``,
|
|
2963
|
+
which both carry their Dockerfile as ``dockerfile`` text.
|
|
2964
|
+
'''
|
|
2965
|
+
return typing.cast(typing.Optional[builtins.str], jsii.get(self, "dockerfileDir"))
|
|
2966
|
+
|
|
2967
|
+
|
|
2968
|
+
@jsii.data_type(
|
|
2969
|
+
jsii_type="cdk-github-microvm-runners.RunnerImageOptions",
|
|
2970
|
+
jsii_struct_bases=[],
|
|
2971
|
+
name_mapping={
|
|
2972
|
+
"additional_os_capabilities": "additionalOsCapabilities",
|
|
2973
|
+
"assets": "assets",
|
|
2974
|
+
"environment": "environment",
|
|
2975
|
+
"runner_version": "runnerVersion",
|
|
2976
|
+
"setup_commands": "setupCommands",
|
|
2977
|
+
"system_packages": "systemPackages",
|
|
2978
|
+
"toolchains": "toolchains",
|
|
2979
|
+
},
|
|
2980
|
+
)
|
|
2981
|
+
class RunnerImageOptions:
|
|
2982
|
+
def __init__(
|
|
2983
|
+
self,
|
|
2984
|
+
*,
|
|
2985
|
+
additional_os_capabilities: typing.Optional[typing.Sequence[builtins.str]] = None,
|
|
2986
|
+
assets: typing.Optional[typing.Sequence[typing.Union["ImageAsset", typing.Dict[builtins.str, typing.Any]]]] = None,
|
|
2987
|
+
environment: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None,
|
|
2988
|
+
runner_version: typing.Optional["RunnerVersion"] = None,
|
|
2989
|
+
setup_commands: typing.Optional[typing.Sequence[builtins.str]] = None,
|
|
2990
|
+
system_packages: typing.Optional[typing.Sequence[builtins.str]] = None,
|
|
2991
|
+
toolchains: typing.Optional[typing.Sequence["RunnerToolchain"]] = None,
|
|
2992
|
+
) -> None:
|
|
2993
|
+
'''Options for ``RunnerImage.fromOptions``.
|
|
2994
|
+
|
|
2995
|
+
:param additional_os_capabilities: Extra Linux capabilities granted to the MicroVM's operating system. Default: ['ALL']
|
|
2996
|
+
:param assets: Extra files and directories to copy into the image.
|
|
2997
|
+
:param environment: Extra environment variables baked into the image.
|
|
2998
|
+
:param runner_version: ``actions/runner`` release to install. Default: RunnerVersion.latest()
|
|
2999
|
+
:param setup_commands: Extra ``RUN`` commands, executed in order after packages, assets, and environment variables are laid down.
|
|
3000
|
+
:param system_packages: Extra ``dnf`` packages to install alongside the fixed base set.
|
|
3001
|
+
:param toolchains: Language runtimes to bake into the hosted tool cache, so ``actions/setup-*`` finds them without downloading anything. An image with none of these is smaller; one toolchain entry is needed per version your workflows ask for. Default: []
|
|
3002
|
+
'''
|
|
3003
|
+
if __debug__:
|
|
3004
|
+
type_hints = cached_type_hints(_typecheckingstub__6fd3c247efc1bf4be6517722f43505c0df1d4ecea290c5f473194c94910a6cb8)
|
|
3005
|
+
check_type(argname="argument additional_os_capabilities", value=additional_os_capabilities, expected_type=type_hints["additional_os_capabilities"])
|
|
3006
|
+
check_type(argname="argument assets", value=assets, expected_type=type_hints["assets"])
|
|
3007
|
+
check_type(argname="argument environment", value=environment, expected_type=type_hints["environment"])
|
|
3008
|
+
check_type(argname="argument runner_version", value=runner_version, expected_type=type_hints["runner_version"])
|
|
3009
|
+
check_type(argname="argument setup_commands", value=setup_commands, expected_type=type_hints["setup_commands"])
|
|
3010
|
+
check_type(argname="argument system_packages", value=system_packages, expected_type=type_hints["system_packages"])
|
|
3011
|
+
check_type(argname="argument toolchains", value=toolchains, expected_type=type_hints["toolchains"])
|
|
3012
|
+
self._values: typing.Dict[builtins.str, typing.Any] = {}
|
|
3013
|
+
if additional_os_capabilities is not None:
|
|
3014
|
+
self._values["additional_os_capabilities"] = additional_os_capabilities
|
|
3015
|
+
if assets is not None:
|
|
3016
|
+
self._values["assets"] = assets
|
|
3017
|
+
if environment is not None:
|
|
3018
|
+
self._values["environment"] = environment
|
|
3019
|
+
if runner_version is not None:
|
|
3020
|
+
self._values["runner_version"] = runner_version
|
|
3021
|
+
if setup_commands is not None:
|
|
3022
|
+
self._values["setup_commands"] = setup_commands
|
|
3023
|
+
if system_packages is not None:
|
|
3024
|
+
self._values["system_packages"] = system_packages
|
|
3025
|
+
if toolchains is not None:
|
|
3026
|
+
self._values["toolchains"] = toolchains
|
|
3027
|
+
|
|
3028
|
+
@builtins.property
|
|
3029
|
+
def additional_os_capabilities(self) -> typing.Optional[typing.List[builtins.str]]:
|
|
3030
|
+
'''Extra Linux capabilities granted to the MicroVM's operating system.
|
|
3031
|
+
|
|
3032
|
+
:default: ['ALL']
|
|
3033
|
+
'''
|
|
3034
|
+
result = self._values.get("additional_os_capabilities")
|
|
3035
|
+
return typing.cast(typing.Optional[typing.List[builtins.str]], result)
|
|
3036
|
+
|
|
3037
|
+
@builtins.property
|
|
3038
|
+
def assets(self) -> typing.Optional[typing.List["ImageAsset"]]:
|
|
3039
|
+
'''Extra files and directories to copy into the image.'''
|
|
3040
|
+
result = self._values.get("assets")
|
|
3041
|
+
return typing.cast(typing.Optional[typing.List["ImageAsset"]], result)
|
|
3042
|
+
|
|
3043
|
+
@builtins.property
|
|
3044
|
+
def environment(
|
|
3045
|
+
self,
|
|
3046
|
+
) -> typing.Optional[typing.Mapping[builtins.str, builtins.str]]:
|
|
3047
|
+
'''Extra environment variables baked into the image.'''
|
|
3048
|
+
result = self._values.get("environment")
|
|
3049
|
+
return typing.cast(typing.Optional[typing.Mapping[builtins.str, builtins.str]], result)
|
|
3050
|
+
|
|
3051
|
+
@builtins.property
|
|
3052
|
+
def runner_version(self) -> typing.Optional["RunnerVersion"]:
|
|
3053
|
+
'''``actions/runner`` release to install.
|
|
3054
|
+
|
|
3055
|
+
:default: RunnerVersion.latest()
|
|
3056
|
+
'''
|
|
3057
|
+
result = self._values.get("runner_version")
|
|
3058
|
+
return typing.cast(typing.Optional["RunnerVersion"], result)
|
|
3059
|
+
|
|
3060
|
+
@builtins.property
|
|
3061
|
+
def setup_commands(self) -> typing.Optional[typing.List[builtins.str]]:
|
|
3062
|
+
'''Extra ``RUN`` commands, executed in order after packages, assets, and environment variables are laid down.'''
|
|
3063
|
+
result = self._values.get("setup_commands")
|
|
3064
|
+
return typing.cast(typing.Optional[typing.List[builtins.str]], result)
|
|
3065
|
+
|
|
3066
|
+
@builtins.property
|
|
3067
|
+
def system_packages(self) -> typing.Optional[typing.List[builtins.str]]:
|
|
3068
|
+
'''Extra ``dnf`` packages to install alongside the fixed base set.'''
|
|
3069
|
+
result = self._values.get("system_packages")
|
|
3070
|
+
return typing.cast(typing.Optional[typing.List[builtins.str]], result)
|
|
3071
|
+
|
|
3072
|
+
@builtins.property
|
|
3073
|
+
def toolchains(self) -> typing.Optional[typing.List["RunnerToolchain"]]:
|
|
3074
|
+
'''Language runtimes to bake into the hosted tool cache, so ``actions/setup-*`` finds them without downloading anything.
|
|
3075
|
+
|
|
3076
|
+
An image with none of these is smaller; one toolchain entry is needed per version your workflows ask for.
|
|
3077
|
+
|
|
3078
|
+
:default: []
|
|
3079
|
+
'''
|
|
3080
|
+
result = self._values.get("toolchains")
|
|
3081
|
+
return typing.cast(typing.Optional[typing.List["RunnerToolchain"]], result)
|
|
3082
|
+
|
|
3083
|
+
def __eq__(self, rhs: typing.Any) -> builtins.bool:
|
|
3084
|
+
return isinstance(rhs, self.__class__) and rhs._values == self._values
|
|
3085
|
+
|
|
3086
|
+
def __ne__(self, rhs: typing.Any) -> builtins.bool:
|
|
3087
|
+
return not (rhs == self)
|
|
3088
|
+
|
|
3089
|
+
def __repr__(self) -> str:
|
|
3090
|
+
return "RunnerImageOptions(%s)" % ", ".join(
|
|
3091
|
+
k + "=" + repr(v) for k, v in self._values.items()
|
|
3092
|
+
)
|
|
3093
|
+
|
|
3094
|
+
|
|
3095
|
+
class RunnerNetwork(
|
|
3096
|
+
metaclass=jsii.JSIIMeta,
|
|
3097
|
+
jsii_type="cdk-github-microvm-runners.RunnerNetwork",
|
|
3098
|
+
):
|
|
3099
|
+
'''How a runner set's MicroVMs reach the network: direct internet egress, Lambda VPC runtime connectors you already have, or a connector the construct builds from a CDK VPC.
|
|
3100
|
+
|
|
3101
|
+
Build one with the static factories below; the constructor is private.
|
|
3102
|
+
|
|
3103
|
+
Example::
|
|
3104
|
+
|
|
3105
|
+
GithubMicrovmRunners(stack, "Runners",
|
|
3106
|
+
github=github,
|
|
3107
|
+
scope=scope,
|
|
3108
|
+
network=RunnerNetwork.vpc(vpc)
|
|
3109
|
+
)
|
|
3110
|
+
'''
|
|
3111
|
+
|
|
3112
|
+
@jsii.member(jsii_name="internetEgress")
|
|
3113
|
+
@builtins.classmethod
|
|
3114
|
+
def internet_egress(cls) -> "RunnerNetwork":
|
|
3115
|
+
'''Runners egress directly to the internet (no VPC connector).
|
|
3116
|
+
|
|
3117
|
+
Example::
|
|
3118
|
+
|
|
3119
|
+
network = RunnerNetwork.internet_egress()
|
|
3120
|
+
'''
|
|
3121
|
+
return typing.cast("RunnerNetwork", jsii.sinvoke(cls, "internetEgress", []))
|
|
3122
|
+
|
|
3123
|
+
@jsii.member(jsii_name="vpc")
|
|
3124
|
+
@builtins.classmethod
|
|
3125
|
+
def vpc(
|
|
3126
|
+
cls,
|
|
3127
|
+
vpc: "_aws_cdk_aws_ec2_ceddda9d.IVpc",
|
|
3128
|
+
*,
|
|
3129
|
+
security_groups: typing.Optional[typing.Sequence["_aws_cdk_aws_ec2_ceddda9d.ISecurityGroup"]] = None,
|
|
3130
|
+
subnets: typing.Optional[typing.Union["_aws_cdk_aws_ec2_ceddda9d.SubnetSelection", typing.Dict[builtins.str, typing.Any]]] = None,
|
|
3131
|
+
) -> "RunnerNetwork":
|
|
3132
|
+
'''Runners egress through a network connector the construct builds from the given CDK VPC, along with the security group and the ENI-management operator role that connector needs.
|
|
3133
|
+
|
|
3134
|
+
You supply the VPC; no connector ARN
|
|
3135
|
+
is required. ``connectorArns`` is empty on the returned instance, and the
|
|
3136
|
+
construct fills in the connector's real ARN at synth.
|
|
3137
|
+
|
|
3138
|
+
:param vpc: -
|
|
3139
|
+
:param security_groups: Security groups attached to the connector's ENIs. Default: - a new security group is created on the VPC
|
|
3140
|
+
:param subnets: Which of the VPC's subnets the connector's ENIs land in. Default: - the VPC's private-with-egress subnets (CDK's ``selectSubnets()`` default; falls back to isolated, then public, subnets if the VPC has none of the preceding kind)
|
|
3141
|
+
|
|
3142
|
+
Example::
|
|
3143
|
+
|
|
3144
|
+
network = RunnerNetwork.vpc(vpc,
|
|
3145
|
+
subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE_ISOLATED),
|
|
3146
|
+
security_groups=[my_security_group]
|
|
3147
|
+
)
|
|
3148
|
+
'''
|
|
3149
|
+
if __debug__:
|
|
3150
|
+
type_hints = cached_type_hints(_typecheckingstub__d2491e4912faff169fbaad1c4fb389eb29f77ce187a242a0af01526ea53ad4d7)
|
|
3151
|
+
check_type(argname="argument vpc", value=vpc, expected_type=type_hints["vpc"])
|
|
3152
|
+
opts = RunnerNetworkVpcOptions(
|
|
3153
|
+
security_groups=security_groups, subnets=subnets
|
|
3154
|
+
)
|
|
3155
|
+
|
|
3156
|
+
return typing.cast("RunnerNetwork", jsii.sinvoke(cls, "vpc", [vpc, opts]))
|
|
3157
|
+
|
|
3158
|
+
@jsii.member(jsii_name="vpcConnector")
|
|
3159
|
+
@builtins.classmethod
|
|
3160
|
+
def vpc_connector(
|
|
3161
|
+
cls,
|
|
3162
|
+
connector_arns: typing.Sequence[builtins.str],
|
|
3163
|
+
) -> "RunnerNetwork":
|
|
3164
|
+
'''Runners are attached to the given Lambda runtime connector ARNs.
|
|
3165
|
+
|
|
3166
|
+
:param connector_arns: -
|
|
3167
|
+
|
|
3168
|
+
Example::
|
|
3169
|
+
|
|
3170
|
+
network = RunnerNetwork.vpc_connector(["arn:aws:lambda:us-east-1:111122223333:network-connector:my-connector"
|
|
3171
|
+
])
|
|
3172
|
+
'''
|
|
3173
|
+
if __debug__:
|
|
3174
|
+
type_hints = cached_type_hints(_typecheckingstub__6db194aaaafe63c89cd0b5bfe1846487e92f6c50fdaa2c8c2e3d8689ff54dfd1)
|
|
3175
|
+
check_type(argname="argument connector_arns", value=connector_arns, expected_type=type_hints["connector_arns"])
|
|
3176
|
+
return typing.cast("RunnerNetwork", jsii.sinvoke(cls, "vpcConnector", [connector_arns]))
|
|
3177
|
+
|
|
3178
|
+
@builtins.property
|
|
3179
|
+
@jsii.member(jsii_name="connectorArns")
|
|
3180
|
+
def connector_arns(self) -> typing.List[builtins.str]:
|
|
3181
|
+
'''Runtime connector ARNs.
|
|
3182
|
+
|
|
3183
|
+
Empty for direct internet egress, and empty for
|
|
3184
|
+
a ``vpc()`` network until the construct builds its connector at synth.
|
|
3185
|
+
'''
|
|
3186
|
+
return typing.cast(typing.List[builtins.str], jsii.get(self, "connectorArns"))
|
|
3187
|
+
|
|
3188
|
+
@builtins.property
|
|
3189
|
+
@jsii.member(jsii_name="kind")
|
|
3190
|
+
def kind(self) -> "RunnerNetworkKind":
|
|
3191
|
+
'''Which networking mode this instance carries.'''
|
|
3192
|
+
return typing.cast("RunnerNetworkKind", jsii.get(self, "kind"))
|
|
3193
|
+
|
|
3194
|
+
@builtins.property
|
|
3195
|
+
@jsii.member(jsii_name="securityGroups")
|
|
3196
|
+
def security_groups(
|
|
3197
|
+
self,
|
|
3198
|
+
) -> typing.Optional[typing.List["_aws_cdk_aws_ec2_ceddda9d.ISecurityGroup"]]:
|
|
3199
|
+
'''Security groups for the built connector, set only for a ``vpc()`` network.'''
|
|
3200
|
+
return typing.cast(typing.Optional[typing.List["_aws_cdk_aws_ec2_ceddda9d.ISecurityGroup"]], jsii.get(self, "securityGroups"))
|
|
3201
|
+
|
|
3202
|
+
@builtins.property
|
|
3203
|
+
@jsii.member(jsii_name="sourceVpc")
|
|
3204
|
+
def source_vpc(self) -> typing.Optional["_aws_cdk_aws_ec2_ceddda9d.IVpc"]:
|
|
3205
|
+
'''The VPC to build a connector from, set only for a ``vpc()`` network.'''
|
|
3206
|
+
return typing.cast(typing.Optional["_aws_cdk_aws_ec2_ceddda9d.IVpc"], jsii.get(self, "sourceVpc"))
|
|
3207
|
+
|
|
3208
|
+
@builtins.property
|
|
3209
|
+
@jsii.member(jsii_name="subnets")
|
|
3210
|
+
def subnets(self) -> typing.Optional["_aws_cdk_aws_ec2_ceddda9d.SubnetSelection"]:
|
|
3211
|
+
'''Subnet selection for the built connector, set only for a ``vpc()`` network.'''
|
|
3212
|
+
return typing.cast(typing.Optional["_aws_cdk_aws_ec2_ceddda9d.SubnetSelection"], jsii.get(self, "subnets"))
|
|
3213
|
+
|
|
3214
|
+
|
|
3215
|
+
@jsii.enum(jsii_type="cdk-github-microvm-runners.RunnerNetworkKind")
|
|
3216
|
+
class RunnerNetworkKind(enum.Enum):
|
|
3217
|
+
'''Which networking mode a ``RunnerNetwork`` carries.'''
|
|
3218
|
+
|
|
3219
|
+
INTERNET = "INTERNET"
|
|
3220
|
+
'''Direct internet egress, with no Lambda VPC runtime connector.'''
|
|
3221
|
+
CONNECTORS = "CONNECTORS"
|
|
3222
|
+
'''Runners attached to caller-supplied Lambda runtime connector ARNs.'''
|
|
3223
|
+
VPC = "VPC"
|
|
3224
|
+
'''Runners attached to a connector the construct builds from a CDK VPC.'''
|
|
3225
|
+
|
|
3226
|
+
|
|
3227
|
+
@jsii.data_type(
|
|
3228
|
+
jsii_type="cdk-github-microvm-runners.RunnerNetworkVpcOptions",
|
|
3229
|
+
jsii_struct_bases=[],
|
|
3230
|
+
name_mapping={"security_groups": "securityGroups", "subnets": "subnets"},
|
|
3231
|
+
)
|
|
3232
|
+
class RunnerNetworkVpcOptions:
|
|
3233
|
+
def __init__(
|
|
3234
|
+
self,
|
|
3235
|
+
*,
|
|
3236
|
+
security_groups: typing.Optional[typing.Sequence["_aws_cdk_aws_ec2_ceddda9d.ISecurityGroup"]] = None,
|
|
3237
|
+
subnets: typing.Optional[typing.Union["_aws_cdk_aws_ec2_ceddda9d.SubnetSelection", typing.Dict[builtins.str, typing.Any]]] = None,
|
|
3238
|
+
) -> None:
|
|
3239
|
+
'''Options for ``RunnerNetwork.vpc``.
|
|
3240
|
+
|
|
3241
|
+
:param security_groups: Security groups attached to the connector's ENIs. Default: - a new security group is created on the VPC
|
|
3242
|
+
:param subnets: Which of the VPC's subnets the connector's ENIs land in. Default: - the VPC's private-with-egress subnets (CDK's ``selectSubnets()`` default; falls back to isolated, then public, subnets if the VPC has none of the preceding kind)
|
|
3243
|
+
'''
|
|
3244
|
+
if isinstance(subnets, dict):
|
|
3245
|
+
subnets = _aws_cdk_aws_ec2_ceddda9d.SubnetSelection(**subnets)
|
|
3246
|
+
if __debug__:
|
|
3247
|
+
type_hints = cached_type_hints(_typecheckingstub__940d8682a239c73072340b0492130025e2f1d8c0d2614466732fa878426abf8c)
|
|
3248
|
+
check_type(argname="argument security_groups", value=security_groups, expected_type=type_hints["security_groups"])
|
|
3249
|
+
check_type(argname="argument subnets", value=subnets, expected_type=type_hints["subnets"])
|
|
3250
|
+
self._values: typing.Dict[builtins.str, typing.Any] = {}
|
|
3251
|
+
if security_groups is not None:
|
|
3252
|
+
self._values["security_groups"] = security_groups
|
|
3253
|
+
if subnets is not None:
|
|
3254
|
+
self._values["subnets"] = subnets
|
|
3255
|
+
|
|
3256
|
+
@builtins.property
|
|
3257
|
+
def security_groups(
|
|
3258
|
+
self,
|
|
3259
|
+
) -> typing.Optional[typing.List["_aws_cdk_aws_ec2_ceddda9d.ISecurityGroup"]]:
|
|
3260
|
+
'''Security groups attached to the connector's ENIs.
|
|
3261
|
+
|
|
3262
|
+
:default: - a new security group is created on the VPC
|
|
3263
|
+
'''
|
|
3264
|
+
result = self._values.get("security_groups")
|
|
3265
|
+
return typing.cast(typing.Optional[typing.List["_aws_cdk_aws_ec2_ceddda9d.ISecurityGroup"]], result)
|
|
3266
|
+
|
|
3267
|
+
@builtins.property
|
|
3268
|
+
def subnets(self) -> typing.Optional["_aws_cdk_aws_ec2_ceddda9d.SubnetSelection"]:
|
|
3269
|
+
'''Which of the VPC's subnets the connector's ENIs land in.
|
|
3270
|
+
|
|
3271
|
+
:default:
|
|
3272
|
+
|
|
3273
|
+
- the VPC's private-with-egress subnets (CDK's
|
|
3274
|
+
``selectSubnets()`` default; falls back to isolated, then public, subnets
|
|
3275
|
+
if the VPC has none of the preceding kind)
|
|
3276
|
+
'''
|
|
3277
|
+
result = self._values.get("subnets")
|
|
3278
|
+
return typing.cast(typing.Optional["_aws_cdk_aws_ec2_ceddda9d.SubnetSelection"], result)
|
|
3279
|
+
|
|
3280
|
+
def __eq__(self, rhs: typing.Any) -> builtins.bool:
|
|
3281
|
+
return isinstance(rhs, self.__class__) and rhs._values == self._values
|
|
3282
|
+
|
|
3283
|
+
def __ne__(self, rhs: typing.Any) -> builtins.bool:
|
|
3284
|
+
return not (rhs == self)
|
|
3285
|
+
|
|
3286
|
+
def __repr__(self) -> str:
|
|
3287
|
+
return "RunnerNetworkVpcOptions(%s)" % ", ".join(
|
|
3288
|
+
k + "=" + repr(v) for k, v in self._values.items()
|
|
3289
|
+
)
|
|
3290
|
+
|
|
3291
|
+
|
|
3292
|
+
class RunnerScope(
|
|
3293
|
+
metaclass=jsii.JSIIMeta,
|
|
3294
|
+
jsii_type="cdk-github-microvm-runners.RunnerScope",
|
|
3295
|
+
):
|
|
3296
|
+
'''Which GitHub scope registered runners are visible to: an entire organization, or an explicit list of ``owner/repo`` repositories.
|
|
3297
|
+
|
|
3298
|
+
Build one with the static factories below; the constructor is private.
|
|
3299
|
+
|
|
3300
|
+
Example::
|
|
3301
|
+
|
|
3302
|
+
org_scope = RunnerScope.org("my-org")
|
|
3303
|
+
'''
|
|
3304
|
+
|
|
3305
|
+
@jsii.member(jsii_name="org")
|
|
3306
|
+
@builtins.classmethod
|
|
3307
|
+
def org(cls, org: builtins.str) -> "RunnerScope":
|
|
3308
|
+
'''Runners are registered at the organization level.
|
|
3309
|
+
|
|
3310
|
+
:param org: -
|
|
3311
|
+
|
|
3312
|
+
Example::
|
|
3313
|
+
|
|
3314
|
+
org_scope = RunnerScope.org("my-org")
|
|
3315
|
+
'''
|
|
3316
|
+
if __debug__:
|
|
3317
|
+
type_hints = cached_type_hints(_typecheckingstub__a306ec12ac8b86304298f1b4650c1ad69974d0773eef2b6f6245b92666d89c8f)
|
|
3318
|
+
check_type(argname="argument org", value=org, expected_type=type_hints["org"])
|
|
3319
|
+
return typing.cast("RunnerScope", jsii.sinvoke(cls, "org", [org]))
|
|
3320
|
+
|
|
3321
|
+
@jsii.member(jsii_name="repos")
|
|
3322
|
+
@builtins.classmethod
|
|
3323
|
+
def repos(cls, repos: typing.Sequence[builtins.str]) -> "RunnerScope":
|
|
3324
|
+
'''Runners are registered against an explicit list of ``owner/repo`` repos.
|
|
3325
|
+
|
|
3326
|
+
:param repos: -
|
|
3327
|
+
|
|
3328
|
+
Example::
|
|
3329
|
+
|
|
3330
|
+
repo_scope = RunnerScope.repos(["my-org/api", "my-org/web"])
|
|
3331
|
+
'''
|
|
3332
|
+
if __debug__:
|
|
3333
|
+
type_hints = cached_type_hints(_typecheckingstub__a81b46da719563a103d6a4dc08b1337ad955b8bb3e417594cba8689ec1b3990e)
|
|
3334
|
+
check_type(argname="argument repos", value=repos, expected_type=type_hints["repos"])
|
|
3335
|
+
return typing.cast("RunnerScope", jsii.sinvoke(cls, "repos", [repos]))
|
|
3336
|
+
|
|
3337
|
+
@jsii.member(jsii_name="toJson")
|
|
3338
|
+
def to_json(self) -> builtins.str:
|
|
3339
|
+
'''Serialize this scope to the JSON form the runner set's handlers read at runtime.'''
|
|
3340
|
+
return typing.cast(builtins.str, jsii.invoke(self, "toJson", []))
|
|
3341
|
+
|
|
3342
|
+
@builtins.property
|
|
3343
|
+
@jsii.member(jsii_name="kind")
|
|
3344
|
+
def kind(self) -> "RunnerScopeKind":
|
|
3345
|
+
'''Whether this scope is an organization or a list of repositories.'''
|
|
3346
|
+
return typing.cast("RunnerScopeKind", jsii.get(self, "kind"))
|
|
3347
|
+
|
|
3348
|
+
@builtins.property
|
|
3349
|
+
@jsii.member(jsii_name="organization")
|
|
3350
|
+
def organization(self) -> typing.Optional[builtins.str]:
|
|
3351
|
+
'''The organization, for a scope built with ``RunnerScope.org()``.'''
|
|
3352
|
+
return typing.cast(typing.Optional[builtins.str], jsii.get(self, "organization"))
|
|
3353
|
+
|
|
3354
|
+
@builtins.property
|
|
3355
|
+
@jsii.member(jsii_name="repositories")
|
|
3356
|
+
def repositories(self) -> typing.Optional[typing.List[builtins.str]]:
|
|
3357
|
+
'''The ``owner/repo`` list, for a scope built with ``RunnerScope.repos()``.'''
|
|
3358
|
+
return typing.cast(typing.Optional[typing.List[builtins.str]], jsii.get(self, "repositories"))
|
|
3359
|
+
|
|
3360
|
+
|
|
3361
|
+
@jsii.enum(jsii_type="cdk-github-microvm-runners.RunnerScopeKind")
|
|
3362
|
+
class RunnerScopeKind(enum.Enum):
|
|
3363
|
+
'''Which GitHub scope a ``RunnerScope`` represents.'''
|
|
3364
|
+
|
|
3365
|
+
ORG = "ORG"
|
|
3366
|
+
'''Runners are registered at the organization level.'''
|
|
3367
|
+
REPOS = "REPOS"
|
|
3368
|
+
'''Runners are registered against an explicit list of repositories.'''
|
|
3369
|
+
|
|
3370
|
+
|
|
3371
|
+
class RunnerToolchain(
|
|
3372
|
+
metaclass=jsii.JSIIMeta,
|
|
3373
|
+
jsii_type="cdk-github-microvm-runners.RunnerToolchain",
|
|
3374
|
+
):
|
|
3375
|
+
'''A language runtime baked into the runner image's hosted tool cache at ``/opt/hostedtoolcache``, where ``actions/setup-python`` and ``actions/setup-node`` find it without downloading anything.
|
|
3376
|
+
|
|
3377
|
+
Those actions otherwise fetch
|
|
3378
|
+
OS-specific prebuilt runtimes, which are not published for the AL2023 image
|
|
3379
|
+
these runners use.
|
|
3380
|
+
|
|
3381
|
+
Several versions can be baked in at once, and a workflow asking for
|
|
3382
|
+
``python-version: "3.12"`` matches a baked ``3.12.7``.
|
|
3383
|
+
|
|
3384
|
+
Build one with the static factories below; the constructor is private.
|
|
3385
|
+
|
|
3386
|
+
Example::
|
|
3387
|
+
|
|
3388
|
+
test_image = RunnerImage.from_options(
|
|
3389
|
+
toolchains=[
|
|
3390
|
+
RunnerToolchain.python("3.12.7"),
|
|
3391
|
+
RunnerToolchain.node("22.11.0")
|
|
3392
|
+
]
|
|
3393
|
+
)
|
|
3394
|
+
'''
|
|
3395
|
+
|
|
3396
|
+
@jsii.member(jsii_name="node")
|
|
3397
|
+
@builtins.classmethod
|
|
3398
|
+
def node(cls, version: builtins.str) -> "RunnerToolchain":
|
|
3399
|
+
'''Node.js, from the official arm64 tarball. Full semver, e.g. ``'22.11.0'``.
|
|
3400
|
+
|
|
3401
|
+
:param version: -
|
|
3402
|
+
|
|
3403
|
+
Example::
|
|
3404
|
+
|
|
3405
|
+
node = RunnerToolchain.node("22.11.0")
|
|
3406
|
+
'''
|
|
3407
|
+
if __debug__:
|
|
3408
|
+
type_hints = cached_type_hints(_typecheckingstub__8065d4439361f9bbc84bece8879c41a0993b4a423dfaaebe72c927aabc755b9f)
|
|
3409
|
+
check_type(argname="argument version", value=version, expected_type=type_hints["version"])
|
|
3410
|
+
return typing.cast("RunnerToolchain", jsii.sinvoke(cls, "node", [version]))
|
|
3411
|
+
|
|
3412
|
+
@jsii.member(jsii_name="python")
|
|
3413
|
+
@builtins.classmethod
|
|
3414
|
+
def python(cls, version: builtins.str) -> "RunnerToolchain":
|
|
3415
|
+
'''CPython, built from source.
|
|
3416
|
+
|
|
3417
|
+
``version`` is a full semver, e.g. ``'3.12.7'``.
|
|
3418
|
+
|
|
3419
|
+
:param version: -
|
|
3420
|
+
|
|
3421
|
+
Example::
|
|
3422
|
+
|
|
3423
|
+
python = RunnerToolchain.python("3.12.7")
|
|
3424
|
+
'''
|
|
3425
|
+
if __debug__:
|
|
3426
|
+
type_hints = cached_type_hints(_typecheckingstub__4f0bd7c1b2e6ac73b706efb23ff6a848ee29451cef59db547c475ce88a7b1cd8)
|
|
3427
|
+
check_type(argname="argument version", value=version, expected_type=type_hints["version"])
|
|
3428
|
+
return typing.cast("RunnerToolchain", jsii.sinvoke(cls, "python", [version]))
|
|
3429
|
+
|
|
3430
|
+
@builtins.property
|
|
3431
|
+
@jsii.member(jsii_name="kind")
|
|
3432
|
+
def kind(self) -> "ToolchainKind":
|
|
3433
|
+
'''Which runtime this is.'''
|
|
3434
|
+
return typing.cast("ToolchainKind", jsii.get(self, "kind"))
|
|
3435
|
+
|
|
3436
|
+
@builtins.property
|
|
3437
|
+
@jsii.member(jsii_name="version")
|
|
3438
|
+
def version(self) -> builtins.str:
|
|
3439
|
+
'''The full semver release baked in, e.g. ``'3.12.7'``.'''
|
|
3440
|
+
return typing.cast(builtins.str, jsii.get(self, "version"))
|
|
3441
|
+
|
|
3442
|
+
|
|
3443
|
+
class RunnerVersion(
|
|
3444
|
+
metaclass=jsii.JSIIMeta,
|
|
3445
|
+
jsii_type="cdk-github-microvm-runners.RunnerVersion",
|
|
3446
|
+
):
|
|
3447
|
+
'''Which ``actions/runner`` release to install on the MicroVM image.
|
|
3448
|
+
|
|
3449
|
+
Build one with the static factories below; the constructor is private.
|
|
3450
|
+
|
|
3451
|
+
Example::
|
|
3452
|
+
|
|
3453
|
+
pinned_image = RunnerImage.from_options(
|
|
3454
|
+
runner_version=RunnerVersion.of("2.328.0")
|
|
3455
|
+
)
|
|
3456
|
+
'''
|
|
3457
|
+
|
|
3458
|
+
@jsii.member(jsii_name="latest")
|
|
3459
|
+
@builtins.classmethod
|
|
3460
|
+
def latest(cls) -> "RunnerVersion":
|
|
3461
|
+
'''Use the ``actions/runner`` release this library currently pins (``DEFAULT_RUNNER_VERSION``).
|
|
3462
|
+
|
|
3463
|
+
No version is carried on the instance; the
|
|
3464
|
+
image build fills the pinned value in at synth.
|
|
3465
|
+
|
|
3466
|
+
Example::
|
|
3467
|
+
|
|
3468
|
+
runner_version = RunnerVersion.latest()
|
|
3469
|
+
'''
|
|
3470
|
+
return typing.cast("RunnerVersion", jsii.sinvoke(cls, "latest", []))
|
|
3471
|
+
|
|
3472
|
+
@jsii.member(jsii_name="of")
|
|
3473
|
+
@builtins.classmethod
|
|
3474
|
+
def of(cls, version: builtins.str) -> "RunnerVersion":
|
|
3475
|
+
'''Pin an explicit ``actions/runner`` release, e.g. ``"2.319.1"``.
|
|
3476
|
+
|
|
3477
|
+
:param version: -
|
|
3478
|
+
|
|
3479
|
+
Example::
|
|
3480
|
+
|
|
3481
|
+
pinned_runner = RunnerVersion.of("2.328.0")
|
|
3482
|
+
'''
|
|
3483
|
+
if __debug__:
|
|
3484
|
+
type_hints = cached_type_hints(_typecheckingstub__3a8918cc0c6992425d68b709ebd9491ff2eb553b34ff18a312fc59f3604f2a65)
|
|
3485
|
+
check_type(argname="argument version", value=version, expected_type=type_hints["version"])
|
|
3486
|
+
return typing.cast("RunnerVersion", jsii.sinvoke(cls, "of", [version]))
|
|
3487
|
+
|
|
3488
|
+
@builtins.property
|
|
3489
|
+
@jsii.member(jsii_name="version")
|
|
3490
|
+
def version(self) -> typing.Optional[builtins.str]:
|
|
3491
|
+
'''The pinned release, for a version built with ``RunnerVersion.of()``. ``undefined`` for ``RunnerVersion.latest()``.'''
|
|
3492
|
+
return typing.cast(typing.Optional[builtins.str], jsii.get(self, "version"))
|
|
3493
|
+
|
|
3494
|
+
|
|
3495
|
+
@jsii.enum(jsii_type="cdk-github-microvm-runners.ToolchainKind")
|
|
3496
|
+
class ToolchainKind(enum.Enum):
|
|
3497
|
+
'''How a toolchain is installed into the image's hosted tool cache.'''
|
|
3498
|
+
|
|
3499
|
+
PYTHON = "PYTHON"
|
|
3500
|
+
'''CPython, built from source (``configure --prefix … --enable-shared``) on AL2023.'''
|
|
3501
|
+
NODE = "NODE"
|
|
3502
|
+
'''Node.js, unpacked from the official nodejs.org linux-arm64 tarball.'''
|
|
3503
|
+
|
|
3504
|
+
|
|
3505
|
+
class WebhookEndpoint(
|
|
3506
|
+
metaclass=jsii.JSIIMeta,
|
|
3507
|
+
jsii_type="cdk-github-microvm-runners.WebhookEndpoint",
|
|
3508
|
+
):
|
|
3509
|
+
'''How the webhook handler is exposed to GitHub's ``workflow_job`` deliveries.
|
|
3510
|
+
|
|
3511
|
+
The one form today is a Lambda Function URL. It is created with
|
|
3512
|
+
``authType: NONE``; the auth boundary is the HMAC-SHA256 signature GitHub
|
|
3513
|
+
sends with every delivery, which the handler verifies against the webhook
|
|
3514
|
+
secret before it does anything else.
|
|
3515
|
+
|
|
3516
|
+
Example::
|
|
3517
|
+
|
|
3518
|
+
GithubMicrovmRunners(stack, "Runners",
|
|
3519
|
+
github=github,
|
|
3520
|
+
scope=scope,
|
|
3521
|
+
webhook=WebhookEndpoint.function_url()
|
|
3522
|
+
)
|
|
3523
|
+
'''
|
|
3524
|
+
|
|
3525
|
+
@jsii.member(jsii_name="functionUrl")
|
|
3526
|
+
@builtins.classmethod
|
|
3527
|
+
def function_url(cls) -> "WebhookEndpoint":
|
|
3528
|
+
'''Expose the webhook handler on a Lambda Function URL.
|
|
3529
|
+
|
|
3530
|
+
Example::
|
|
3531
|
+
|
|
3532
|
+
webhook = WebhookEndpoint.function_url()
|
|
3533
|
+
'''
|
|
3534
|
+
return typing.cast("WebhookEndpoint", jsii.sinvoke(cls, "functionUrl", []))
|
|
3535
|
+
|
|
3536
|
+
@builtins.property
|
|
3537
|
+
@jsii.member(jsii_name="kind")
|
|
3538
|
+
def kind(self) -> "WebhookEndpointKind":
|
|
3539
|
+
'''Which form of endpoint this instance represents.'''
|
|
3540
|
+
return typing.cast("WebhookEndpointKind", jsii.get(self, "kind"))
|
|
3541
|
+
|
|
3542
|
+
|
|
3543
|
+
@jsii.enum(jsii_type="cdk-github-microvm-runners.WebhookEndpointKind")
|
|
3544
|
+
class WebhookEndpointKind(enum.Enum):
|
|
3545
|
+
'''Which form of endpoint a ``WebhookEndpoint`` represents.'''
|
|
3546
|
+
|
|
3547
|
+
FUNCTION_URL = "FUNCTION_URL"
|
|
3548
|
+
'''A Lambda Function URL.'''
|
|
3549
|
+
|
|
3550
|
+
|
|
3551
|
+
__all__ = [
|
|
3552
|
+
"ConsoleLogs",
|
|
3553
|
+
"GithubAppAuthProps",
|
|
3554
|
+
"GithubAppId",
|
|
3555
|
+
"GithubAppKey",
|
|
3556
|
+
"GithubAuth",
|
|
3557
|
+
"GithubAuthKind",
|
|
3558
|
+
"GithubMicrovmRunners",
|
|
3559
|
+
"GithubMicrovmRunnersMetrics",
|
|
3560
|
+
"GithubMicrovmRunnersProps",
|
|
3561
|
+
"GithubPatAuthProps",
|
|
3562
|
+
"ImageAsset",
|
|
3563
|
+
"ImageLogs",
|
|
3564
|
+
"ImagePipeline",
|
|
3565
|
+
"ImagePipelineProps",
|
|
3566
|
+
"MicrovmIdlePolicy",
|
|
3567
|
+
"MicrovmSize",
|
|
3568
|
+
"RunnerAlarmOptions",
|
|
3569
|
+
"RunnerClass",
|
|
3570
|
+
"RunnerClassProps",
|
|
3571
|
+
"RunnerImage",
|
|
3572
|
+
"RunnerImageOptions",
|
|
3573
|
+
"RunnerNetwork",
|
|
3574
|
+
"RunnerNetworkKind",
|
|
3575
|
+
"RunnerNetworkVpcOptions",
|
|
3576
|
+
"RunnerScope",
|
|
3577
|
+
"RunnerScopeKind",
|
|
3578
|
+
"RunnerToolchain",
|
|
3579
|
+
"RunnerVersion",
|
|
3580
|
+
"ToolchainKind",
|
|
3581
|
+
"WebhookEndpoint",
|
|
3582
|
+
"WebhookEndpointKind",
|
|
3583
|
+
]
|
|
3584
|
+
|
|
3585
|
+
publication.publish()
|
|
3586
|
+
|
|
3587
|
+
def _typecheckingstub__0548cfa81769608b199a2a959830e9d47b13bb916b5f4181e977c1f03bfa81c7(
|
|
3588
|
+
log_group: typing.Optional[_aws_cdk_aws_logs_ceddda9d.ILogGroup] = None,
|
|
3589
|
+
) -> None:
|
|
3590
|
+
"""Type checking stubs"""
|
|
3591
|
+
pass
|
|
3592
|
+
|
|
3593
|
+
def _typecheckingstub__e6e950b235861eb6ceb59c62bebf431836fac157088b1334fedf915b19dec8a0(
|
|
3594
|
+
*,
|
|
3595
|
+
app_id: GithubAppId,
|
|
3596
|
+
private_key: GithubAppKey,
|
|
3597
|
+
webhook_secret: _aws_cdk_aws_secretsmanager_ceddda9d.ISecret,
|
|
3598
|
+
) -> None:
|
|
3599
|
+
"""Type checking stubs"""
|
|
3600
|
+
pass
|
|
3601
|
+
|
|
3602
|
+
def _typecheckingstub__aba0941864c428347812aa10a096b18df3ae77616773316bd134e2764ae2657c(
|
|
3603
|
+
secret: _aws_cdk_aws_secretsmanager_ceddda9d.ISecret,
|
|
3604
|
+
) -> None:
|
|
3605
|
+
"""Type checking stubs"""
|
|
3606
|
+
pass
|
|
3607
|
+
|
|
3608
|
+
def _typecheckingstub__6b22d9ed14d289886f4ed34dc8cfd25d58e6bbda42419d5097a7a73ea48bd10f(
|
|
3609
|
+
value: builtins.str,
|
|
3610
|
+
) -> None:
|
|
3611
|
+
"""Type checking stubs"""
|
|
3612
|
+
pass
|
|
3613
|
+
|
|
3614
|
+
def _typecheckingstub__cc9961f681c63592cc8d260fe3e536a71239765b00a83bdec348eff483581f2b(
|
|
3615
|
+
key: _aws_cdk_aws_kms_ceddda9d.IKey,
|
|
3616
|
+
) -> None:
|
|
3617
|
+
"""Type checking stubs"""
|
|
3618
|
+
pass
|
|
3619
|
+
|
|
3620
|
+
def _typecheckingstub__b690547df91198ce68555c0eef4906781d6764b68601422750750169edd60220(
|
|
3621
|
+
secret: _aws_cdk_aws_secretsmanager_ceddda9d.ISecret,
|
|
3622
|
+
) -> None:
|
|
3623
|
+
"""Type checking stubs"""
|
|
3624
|
+
pass
|
|
3625
|
+
|
|
3626
|
+
def _typecheckingstub__970e66a646e2fc86c035066057cff7cd247b431b227ac9f2d5a8c86ed710c988(
|
|
3627
|
+
grantee: _aws_cdk_aws_iam_ceddda9d.IGrantable,
|
|
3628
|
+
) -> None:
|
|
3629
|
+
"""Type checking stubs"""
|
|
3630
|
+
pass
|
|
3631
|
+
|
|
3632
|
+
def _typecheckingstub__80b1bb7036f50148e74587e4f8bac689760f9f314afddfa588fbc2a86d5062dd(
|
|
3633
|
+
grantee: _aws_cdk_aws_iam_ceddda9d.IGrantable,
|
|
3634
|
+
) -> None:
|
|
3635
|
+
"""Type checking stubs"""
|
|
3636
|
+
pass
|
|
3637
|
+
|
|
3638
|
+
def _typecheckingstub__f9ccf90cd58a24eaea8e05c002c729a7c0b56c6afdd04d8cd485938eed8facc5(
|
|
3639
|
+
scope_: _constructs_77d1e7e8.Construct,
|
|
3640
|
+
id: builtins.str,
|
|
3641
|
+
*,
|
|
3642
|
+
github: GithubAuth,
|
|
3643
|
+
scope: RunnerScope,
|
|
3644
|
+
additional_regions: typing.Optional[typing.Sequence[builtins.str]] = None,
|
|
3645
|
+
console_logs: typing.Optional[ConsoleLogs] = None,
|
|
3646
|
+
dead_letter_retention: typing.Optional[_aws_cdk_ceddda9d.Duration] = None,
|
|
3647
|
+
emit_metrics: typing.Optional[builtins.bool] = None,
|
|
3648
|
+
encryption_key: typing.Optional[_aws_cdk_aws_kms_ceddda9d.IKey] = None,
|
|
3649
|
+
idle_runner_grace_seconds: typing.Optional[jsii.Number] = None,
|
|
3650
|
+
image_logs: typing.Optional[ImageLogs] = None,
|
|
3651
|
+
janitor_interval: typing.Optional[_aws_cdk_ceddda9d.Duration] = None,
|
|
3652
|
+
keep_image_versions: typing.Optional[jsii.Number] = None,
|
|
3653
|
+
lambda_memory_size: typing.Optional[jsii.Number] = None,
|
|
3654
|
+
log_retention: typing.Optional[_aws_cdk_aws_logs_ceddda9d.RetentionDays] = None,
|
|
3655
|
+
max_concurrent_vms: typing.Optional[jsii.Number] = None,
|
|
3656
|
+
max_job_duration: typing.Optional[_aws_cdk_ceddda9d.Duration] = None,
|
|
3657
|
+
max_receive_count: typing.Optional[jsii.Number] = None,
|
|
3658
|
+
network: typing.Optional[RunnerNetwork] = None,
|
|
3659
|
+
permissions_boundary: typing.Optional[_aws_cdk_aws_iam_ceddda9d.IManagedPolicy] = None,
|
|
3660
|
+
point_in_time_recovery: typing.Optional[builtins.bool] = None,
|
|
3661
|
+
recover_stuck_launches: typing.Optional[builtins.bool] = None,
|
|
3662
|
+
removal_policy: typing.Optional[_aws_cdk_ceddda9d.RemovalPolicy] = None,
|
|
3663
|
+
vm_execution_role: typing.Optional[_aws_cdk_aws_iam_ceddda9d.IRole] = None,
|
|
3664
|
+
warm_pool_interval: typing.Optional[_aws_cdk_ceddda9d.Duration] = None,
|
|
3665
|
+
webhook: typing.Optional[WebhookEndpoint] = None,
|
|
3666
|
+
webhook_reserved_concurrency: typing.Optional[jsii.Number] = None,
|
|
3667
|
+
) -> None:
|
|
3668
|
+
"""Type checking stubs"""
|
|
3669
|
+
pass
|
|
3670
|
+
|
|
3671
|
+
def _typecheckingstub__48e77fc4d43555e4d6ac3d9e5b13de1cbbb1ef807cfc4ce1e0688ac170b863d1(
|
|
3672
|
+
label: builtins.str,
|
|
3673
|
+
*,
|
|
3674
|
+
size: MicrovmSize,
|
|
3675
|
+
idle_policy: typing.Optional[typing.Union[MicrovmIdlePolicy, typing.Dict[builtins.str, typing.Any]]] = None,
|
|
3676
|
+
image: typing.Optional[RunnerImage] = None,
|
|
3677
|
+
warm_pool_size: typing.Optional[jsii.Number] = None,
|
|
3678
|
+
) -> None:
|
|
3679
|
+
"""Type checking stubs"""
|
|
3680
|
+
pass
|
|
3681
|
+
|
|
3682
|
+
def _typecheckingstub__e74a92121e3eaec69c4009cc027a299a12257a68eccc613318213d92545265f4(
|
|
3683
|
+
label: builtins.str,
|
|
3684
|
+
) -> None:
|
|
3685
|
+
"""Type checking stubs"""
|
|
3686
|
+
pass
|
|
3687
|
+
|
|
3688
|
+
def _typecheckingstub__8c3f47f3bf65ddc91d8c105e318179909d2860c56e34cc7b699066e3f7952170(
|
|
3689
|
+
runner_set_id: builtins.str,
|
|
3690
|
+
dead_letter_queue: _aws_cdk_aws_sqs_ceddda9d.IQueue,
|
|
3691
|
+
emit_metrics: typing.Optional[builtins.bool] = None,
|
|
3692
|
+
) -> None:
|
|
3693
|
+
"""Type checking stubs"""
|
|
3694
|
+
pass
|
|
3695
|
+
|
|
3696
|
+
def _typecheckingstub__5f2f67ec6dfaab44c26a53e7bc3669af5ba74fc2c75f8dcd8afb795779d8ddfa(
|
|
3697
|
+
runner_class_label: builtins.str,
|
|
3698
|
+
) -> None:
|
|
3699
|
+
"""Type checking stubs"""
|
|
3700
|
+
pass
|
|
3701
|
+
|
|
3702
|
+
def _typecheckingstub__36d476c29eaf47f8fca7a5205fb5caa5a9749233fb462a093763a6a3200429b4(
|
|
3703
|
+
runner_class_label: builtins.str,
|
|
3704
|
+
) -> None:
|
|
3705
|
+
"""Type checking stubs"""
|
|
3706
|
+
pass
|
|
3707
|
+
|
|
3708
|
+
def _typecheckingstub__baf385f806ff6b0b2ae70b9d811654097d3297503bd8bdbafe09f5d9ed879629(
|
|
3709
|
+
runner_class_label: builtins.str,
|
|
3710
|
+
) -> None:
|
|
3711
|
+
"""Type checking stubs"""
|
|
3712
|
+
pass
|
|
3713
|
+
|
|
3714
|
+
def _typecheckingstub__75224a1d56fc14f38e94a3639da5e4ae455f069c6e477bb8fa010333e5c6ae4f(
|
|
3715
|
+
runner_class_label: builtins.str,
|
|
3716
|
+
) -> None:
|
|
3717
|
+
"""Type checking stubs"""
|
|
3718
|
+
pass
|
|
3719
|
+
|
|
3720
|
+
def _typecheckingstub__aca740a7276ae0a556b6b45300b0252ac7d8074b4dd0ab26c6b38fba7adb7eaf(
|
|
3721
|
+
scope: _constructs_77d1e7e8.Construct,
|
|
3722
|
+
*,
|
|
3723
|
+
evaluation_periods: typing.Optional[jsii.Number] = None,
|
|
3724
|
+
period: typing.Optional[_aws_cdk_ceddda9d.Duration] = None,
|
|
3725
|
+
threshold: typing.Optional[jsii.Number] = None,
|
|
3726
|
+
) -> None:
|
|
3727
|
+
"""Type checking stubs"""
|
|
3728
|
+
pass
|
|
3729
|
+
|
|
3730
|
+
def _typecheckingstub__6153c9a068c30f370bb352b26cc502516866238676a7d8139fc2dd0736dff46a(
|
|
3731
|
+
runner_class_label: builtins.str,
|
|
3732
|
+
) -> None:
|
|
3733
|
+
"""Type checking stubs"""
|
|
3734
|
+
pass
|
|
3735
|
+
|
|
3736
|
+
def _typecheckingstub__767e219d8c25f069fd8964ea100816a20869884628a2606dfd2fb3e63b857a8e(
|
|
3737
|
+
runner_class_label: builtins.str,
|
|
3738
|
+
) -> None:
|
|
3739
|
+
"""Type checking stubs"""
|
|
3740
|
+
pass
|
|
3741
|
+
|
|
3742
|
+
def _typecheckingstub__6513962ff7d13ce627041f61f3e7a3b13688b30e0cb4c5bfbc63f79b8a32b595(
|
|
3743
|
+
runner_class_label: builtins.str,
|
|
3744
|
+
) -> None:
|
|
3745
|
+
"""Type checking stubs"""
|
|
3746
|
+
pass
|
|
3747
|
+
|
|
3748
|
+
def _typecheckingstub__1ba8a40c62efe6c3a58896ea614244a8e6823dd3c7db51567ffbadd71766bd13(
|
|
3749
|
+
runner_class_label: builtins.str,
|
|
3750
|
+
) -> None:
|
|
3751
|
+
"""Type checking stubs"""
|
|
3752
|
+
pass
|
|
3753
|
+
|
|
3754
|
+
def _typecheckingstub__e1b4b6b8be54f5289f47b9d302cea17d405e67837d60873b6a6536a2a23457e9(
|
|
3755
|
+
scope: _constructs_77d1e7e8.Construct,
|
|
3756
|
+
*,
|
|
3757
|
+
evaluation_periods: typing.Optional[jsii.Number] = None,
|
|
3758
|
+
period: typing.Optional[_aws_cdk_ceddda9d.Duration] = None,
|
|
3759
|
+
threshold: typing.Optional[jsii.Number] = None,
|
|
3760
|
+
) -> None:
|
|
3761
|
+
"""Type checking stubs"""
|
|
3762
|
+
pass
|
|
3763
|
+
|
|
3764
|
+
def _typecheckingstub__971f59e7dc4d5b4245765d41b7dcc4075c4dd91870a15df6b9f345ee393cdc61(
|
|
3765
|
+
scope: _constructs_77d1e7e8.Construct,
|
|
3766
|
+
*,
|
|
3767
|
+
evaluation_periods: typing.Optional[jsii.Number] = None,
|
|
3768
|
+
period: typing.Optional[_aws_cdk_ceddda9d.Duration] = None,
|
|
3769
|
+
threshold: typing.Optional[jsii.Number] = None,
|
|
3770
|
+
) -> None:
|
|
3771
|
+
"""Type checking stubs"""
|
|
3772
|
+
pass
|
|
3773
|
+
|
|
3774
|
+
def _typecheckingstub__01d47d24112989967339ef8a2bc09fe442210a13ccc3d3fd9583327ebc550f4f(
|
|
3775
|
+
runner_class_label: builtins.str,
|
|
3776
|
+
) -> None:
|
|
3777
|
+
"""Type checking stubs"""
|
|
3778
|
+
pass
|
|
3779
|
+
|
|
3780
|
+
def _typecheckingstub__9b66518a0eb395295f3c9719dcc545a363c50d0d387fe70bdcedc10be787b17a(
|
|
3781
|
+
runner_class_label: builtins.str,
|
|
3782
|
+
) -> None:
|
|
3783
|
+
"""Type checking stubs"""
|
|
3784
|
+
pass
|
|
3785
|
+
|
|
3786
|
+
def _typecheckingstub__28779afe2a8160e3a792fe0b6661c1c177712ed22d8ddf991f39b625eaa303d6(
|
|
3787
|
+
runner_class_label: builtins.str,
|
|
3788
|
+
) -> None:
|
|
3789
|
+
"""Type checking stubs"""
|
|
3790
|
+
pass
|
|
3791
|
+
|
|
3792
|
+
def _typecheckingstub__17269a525bc0ad3b7797a5131db455fcbc4ced673bbd2895bc90ea581a540971(
|
|
3793
|
+
*,
|
|
3794
|
+
github: GithubAuth,
|
|
3795
|
+
scope: RunnerScope,
|
|
3796
|
+
additional_regions: typing.Optional[typing.Sequence[builtins.str]] = None,
|
|
3797
|
+
console_logs: typing.Optional[ConsoleLogs] = None,
|
|
3798
|
+
dead_letter_retention: typing.Optional[_aws_cdk_ceddda9d.Duration] = None,
|
|
3799
|
+
emit_metrics: typing.Optional[builtins.bool] = None,
|
|
3800
|
+
encryption_key: typing.Optional[_aws_cdk_aws_kms_ceddda9d.IKey] = None,
|
|
3801
|
+
idle_runner_grace_seconds: typing.Optional[jsii.Number] = None,
|
|
3802
|
+
image_logs: typing.Optional[ImageLogs] = None,
|
|
3803
|
+
janitor_interval: typing.Optional[_aws_cdk_ceddda9d.Duration] = None,
|
|
3804
|
+
keep_image_versions: typing.Optional[jsii.Number] = None,
|
|
3805
|
+
lambda_memory_size: typing.Optional[jsii.Number] = None,
|
|
3806
|
+
log_retention: typing.Optional[_aws_cdk_aws_logs_ceddda9d.RetentionDays] = None,
|
|
3807
|
+
max_concurrent_vms: typing.Optional[jsii.Number] = None,
|
|
3808
|
+
max_job_duration: typing.Optional[_aws_cdk_ceddda9d.Duration] = None,
|
|
3809
|
+
max_receive_count: typing.Optional[jsii.Number] = None,
|
|
3810
|
+
network: typing.Optional[RunnerNetwork] = None,
|
|
3811
|
+
permissions_boundary: typing.Optional[_aws_cdk_aws_iam_ceddda9d.IManagedPolicy] = None,
|
|
3812
|
+
point_in_time_recovery: typing.Optional[builtins.bool] = None,
|
|
3813
|
+
recover_stuck_launches: typing.Optional[builtins.bool] = None,
|
|
3814
|
+
removal_policy: typing.Optional[_aws_cdk_ceddda9d.RemovalPolicy] = None,
|
|
3815
|
+
vm_execution_role: typing.Optional[_aws_cdk_aws_iam_ceddda9d.IRole] = None,
|
|
3816
|
+
warm_pool_interval: typing.Optional[_aws_cdk_ceddda9d.Duration] = None,
|
|
3817
|
+
webhook: typing.Optional[WebhookEndpoint] = None,
|
|
3818
|
+
webhook_reserved_concurrency: typing.Optional[jsii.Number] = None,
|
|
3819
|
+
) -> None:
|
|
3820
|
+
"""Type checking stubs"""
|
|
3821
|
+
pass
|
|
3822
|
+
|
|
3823
|
+
def _typecheckingstub__af35288b9c48eea9cffeb6e1080b684e480ae2227583407499a01041a243a072(
|
|
3824
|
+
*,
|
|
3825
|
+
token: _aws_cdk_aws_secretsmanager_ceddda9d.ISecret,
|
|
3826
|
+
webhook_secret: _aws_cdk_aws_secretsmanager_ceddda9d.ISecret,
|
|
3827
|
+
) -> None:
|
|
3828
|
+
"""Type checking stubs"""
|
|
3829
|
+
pass
|
|
3830
|
+
|
|
3831
|
+
def _typecheckingstub__d7d3da112d28b428bdfaadffe313adf1b4f0e1018b1cbf217c7687e156912c49(
|
|
3832
|
+
*,
|
|
3833
|
+
source: builtins.str,
|
|
3834
|
+
target: builtins.str,
|
|
3835
|
+
) -> None:
|
|
3836
|
+
"""Type checking stubs"""
|
|
3837
|
+
pass
|
|
3838
|
+
|
|
3839
|
+
def _typecheckingstub__5c18afa4a05ee3b3cf8019fa8e3bf98a9dc803b4ff31600008a4916dce15cd6a(
|
|
3840
|
+
log_group: typing.Optional[_aws_cdk_aws_logs_ceddda9d.ILogGroup] = None,
|
|
3841
|
+
) -> None:
|
|
3842
|
+
"""Type checking stubs"""
|
|
3843
|
+
pass
|
|
3844
|
+
|
|
3845
|
+
def _typecheckingstub__38e8b0a65e40c9bfd130b4244eef3af238aac180d3c10606a513fef86e7aa169(
|
|
3846
|
+
scope: _constructs_77d1e7e8.Construct,
|
|
3847
|
+
id: builtins.str,
|
|
3848
|
+
*,
|
|
3849
|
+
image: RunnerImage,
|
|
3850
|
+
network: RunnerNetwork,
|
|
3851
|
+
runner_set_id: builtins.str,
|
|
3852
|
+
size: MicrovmSize,
|
|
3853
|
+
base_image_version: typing.Optional[builtins.str] = None,
|
|
3854
|
+
image_logs: typing.Optional[ImageLogs] = None,
|
|
3855
|
+
ready_timeout_seconds: typing.Optional[jsii.Number] = None,
|
|
3856
|
+
run_timeout_seconds: typing.Optional[jsii.Number] = None,
|
|
3857
|
+
) -> None:
|
|
3858
|
+
"""Type checking stubs"""
|
|
3859
|
+
pass
|
|
3860
|
+
|
|
3861
|
+
def _typecheckingstub__c8c6d3e3f7a844305d6a7d687bb74edba13926e6cdb04020bf45116bbb7f2407(
|
|
3862
|
+
*,
|
|
3863
|
+
image: RunnerImage,
|
|
3864
|
+
network: RunnerNetwork,
|
|
3865
|
+
runner_set_id: builtins.str,
|
|
3866
|
+
size: MicrovmSize,
|
|
3867
|
+
base_image_version: typing.Optional[builtins.str] = None,
|
|
3868
|
+
image_logs: typing.Optional[ImageLogs] = None,
|
|
3869
|
+
ready_timeout_seconds: typing.Optional[jsii.Number] = None,
|
|
3870
|
+
run_timeout_seconds: typing.Optional[jsii.Number] = None,
|
|
3871
|
+
) -> None:
|
|
3872
|
+
"""Type checking stubs"""
|
|
3873
|
+
pass
|
|
3874
|
+
|
|
3875
|
+
def _typecheckingstub__299a6933558be6e9144d105ecb8f71fdfa2731d8f7934fa33118eb063140eb10(
|
|
3876
|
+
*,
|
|
3877
|
+
max_idle_duration: _aws_cdk_ceddda9d.Duration,
|
|
3878
|
+
suspended_duration: _aws_cdk_ceddda9d.Duration,
|
|
3879
|
+
auto_resume: typing.Optional[builtins.bool] = None,
|
|
3880
|
+
) -> None:
|
|
3881
|
+
"""Type checking stubs"""
|
|
3882
|
+
pass
|
|
3883
|
+
|
|
3884
|
+
def _typecheckingstub__117c59b0a49dcc58de82f614adb71603b95518cace779312d23dbc393e930d0f(
|
|
3885
|
+
*,
|
|
3886
|
+
evaluation_periods: typing.Optional[jsii.Number] = None,
|
|
3887
|
+
period: typing.Optional[_aws_cdk_ceddda9d.Duration] = None,
|
|
3888
|
+
threshold: typing.Optional[jsii.Number] = None,
|
|
3889
|
+
) -> None:
|
|
3890
|
+
"""Type checking stubs"""
|
|
3891
|
+
pass
|
|
3892
|
+
|
|
3893
|
+
def _typecheckingstub__23472a12727bc341ce55563246f68a52c49776a6814a52ab825cec01db0cdc89(
|
|
3894
|
+
*,
|
|
3895
|
+
image_arn: builtins.str,
|
|
3896
|
+
image_pipeline: ImagePipeline,
|
|
3897
|
+
label: builtins.str,
|
|
3898
|
+
size: MicrovmSize,
|
|
3899
|
+
) -> None:
|
|
3900
|
+
"""Type checking stubs"""
|
|
3901
|
+
pass
|
|
3902
|
+
|
|
3903
|
+
def _typecheckingstub__6e46f2bbd7884caef4f137e6dac784cd99ef109d84b58f3f7acf963f03c723a7(
|
|
3904
|
+
*,
|
|
3905
|
+
size: MicrovmSize,
|
|
3906
|
+
idle_policy: typing.Optional[typing.Union[MicrovmIdlePolicy, typing.Dict[builtins.str, typing.Any]]] = None,
|
|
3907
|
+
image: typing.Optional[RunnerImage] = None,
|
|
3908
|
+
warm_pool_size: typing.Optional[jsii.Number] = None,
|
|
3909
|
+
) -> None:
|
|
3910
|
+
"""Type checking stubs"""
|
|
3911
|
+
pass
|
|
3912
|
+
|
|
3913
|
+
def _typecheckingstub__979f58111abc04b49545772d5ca529893452a46b62def883e284f0c2b1f0f73d(
|
|
3914
|
+
dir: builtins.str,
|
|
3915
|
+
) -> None:
|
|
3916
|
+
"""Type checking stubs"""
|
|
3917
|
+
pass
|
|
3918
|
+
|
|
3919
|
+
def _typecheckingstub__2d9215b22cc740b2c93f48e4e0744fe50e43a7a33f85974d48dbebd1e184d9d4(
|
|
3920
|
+
dockerfile: builtins.str,
|
|
3921
|
+
) -> None:
|
|
3922
|
+
"""Type checking stubs"""
|
|
3923
|
+
pass
|
|
3924
|
+
|
|
3925
|
+
def _typecheckingstub__6fd3c247efc1bf4be6517722f43505c0df1d4ecea290c5f473194c94910a6cb8(
|
|
3926
|
+
*,
|
|
3927
|
+
additional_os_capabilities: typing.Optional[typing.Sequence[builtins.str]] = None,
|
|
3928
|
+
assets: typing.Optional[typing.Sequence[typing.Union[ImageAsset, typing.Dict[builtins.str, typing.Any]]]] = None,
|
|
3929
|
+
environment: typing.Optional[typing.Mapping[builtins.str, builtins.str]] = None,
|
|
3930
|
+
runner_version: typing.Optional[RunnerVersion] = None,
|
|
3931
|
+
setup_commands: typing.Optional[typing.Sequence[builtins.str]] = None,
|
|
3932
|
+
system_packages: typing.Optional[typing.Sequence[builtins.str]] = None,
|
|
3933
|
+
toolchains: typing.Optional[typing.Sequence[RunnerToolchain]] = None,
|
|
3934
|
+
) -> None:
|
|
3935
|
+
"""Type checking stubs"""
|
|
3936
|
+
pass
|
|
3937
|
+
|
|
3938
|
+
def _typecheckingstub__d2491e4912faff169fbaad1c4fb389eb29f77ce187a242a0af01526ea53ad4d7(
|
|
3939
|
+
vpc: _aws_cdk_aws_ec2_ceddda9d.IVpc,
|
|
3940
|
+
*,
|
|
3941
|
+
security_groups: typing.Optional[typing.Sequence[_aws_cdk_aws_ec2_ceddda9d.ISecurityGroup]] = None,
|
|
3942
|
+
subnets: typing.Optional[typing.Union[_aws_cdk_aws_ec2_ceddda9d.SubnetSelection, typing.Dict[builtins.str, typing.Any]]] = None,
|
|
3943
|
+
) -> None:
|
|
3944
|
+
"""Type checking stubs"""
|
|
3945
|
+
pass
|
|
3946
|
+
|
|
3947
|
+
def _typecheckingstub__6db194aaaafe63c89cd0b5bfe1846487e92f6c50fdaa2c8c2e3d8689ff54dfd1(
|
|
3948
|
+
connector_arns: typing.Sequence[builtins.str],
|
|
3949
|
+
) -> None:
|
|
3950
|
+
"""Type checking stubs"""
|
|
3951
|
+
pass
|
|
3952
|
+
|
|
3953
|
+
def _typecheckingstub__940d8682a239c73072340b0492130025e2f1d8c0d2614466732fa878426abf8c(
|
|
3954
|
+
*,
|
|
3955
|
+
security_groups: typing.Optional[typing.Sequence[_aws_cdk_aws_ec2_ceddda9d.ISecurityGroup]] = None,
|
|
3956
|
+
subnets: typing.Optional[typing.Union[_aws_cdk_aws_ec2_ceddda9d.SubnetSelection, typing.Dict[builtins.str, typing.Any]]] = None,
|
|
3957
|
+
) -> None:
|
|
3958
|
+
"""Type checking stubs"""
|
|
3959
|
+
pass
|
|
3960
|
+
|
|
3961
|
+
def _typecheckingstub__a306ec12ac8b86304298f1b4650c1ad69974d0773eef2b6f6245b92666d89c8f(
|
|
3962
|
+
org: builtins.str,
|
|
3963
|
+
) -> None:
|
|
3964
|
+
"""Type checking stubs"""
|
|
3965
|
+
pass
|
|
3966
|
+
|
|
3967
|
+
def _typecheckingstub__a81b46da719563a103d6a4dc08b1337ad955b8bb3e417594cba8689ec1b3990e(
|
|
3968
|
+
repos: typing.Sequence[builtins.str],
|
|
3969
|
+
) -> None:
|
|
3970
|
+
"""Type checking stubs"""
|
|
3971
|
+
pass
|
|
3972
|
+
|
|
3973
|
+
def _typecheckingstub__8065d4439361f9bbc84bece8879c41a0993b4a423dfaaebe72c927aabc755b9f(
|
|
3974
|
+
version: builtins.str,
|
|
3975
|
+
) -> None:
|
|
3976
|
+
"""Type checking stubs"""
|
|
3977
|
+
pass
|
|
3978
|
+
|
|
3979
|
+
def _typecheckingstub__4f0bd7c1b2e6ac73b706efb23ff6a848ee29451cef59db547c475ce88a7b1cd8(
|
|
3980
|
+
version: builtins.str,
|
|
3981
|
+
) -> None:
|
|
3982
|
+
"""Type checking stubs"""
|
|
3983
|
+
pass
|
|
3984
|
+
|
|
3985
|
+
def _typecheckingstub__3a8918cc0c6992425d68b709ebd9491ff2eb553b34ff18a312fc59f3604f2a65(
|
|
3986
|
+
version: builtins.str,
|
|
3987
|
+
) -> None:
|
|
3988
|
+
"""Type checking stubs"""
|
|
3989
|
+
pass
|