Skip to content

Commit 9bf444e

Browse files
fix(compute-providers): remove MicroVM duration label
1 parent a000a3f commit 9bf444e

8 files changed

Lines changed: 57 additions & 56 deletions

File tree

lambdas/libs/compute-providers/aws/microvm/README.md

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,11 @@ separate roles, prefixes, and provider deployments.
6060
When a runner matcher enables dynamic labels, workflow jobs can override the
6161
following `RunMicrovm` inputs:
6262

63-
| Label | Override |
64-
| --------------------------------------------------- | ---------------------------------------------- |
65-
| `ghr-microvm-egress-network-connectors:<arn>` | One egress network connector ARN |
66-
| `ghr-microvm-image-arn:<arn>` | MicroVM image ARN |
67-
| `ghr-microvm-image-version:<version>` | MicroVM image version |
68-
| `ghr-microvm-maximum-duration-in-seconds:<seconds>` | Maximum lifetime from 1 through 28,800 seconds |
63+
| Label | Override |
64+
| --------------------------------------------- | -------------------------------- |
65+
| `ghr-microvm-egress-network-connectors:<arn>` | One egress network connector ARN |
66+
| `ghr-microvm-image-arn:<arn>` | MicroVM image ARN |
67+
| `ghr-microvm-image-version:<version>` | MicroVM image version |
6968

7069
Repeat `ghr-microvm-egress-network-connectors:<arn>` to attach multiple
7170
connectors. Specify one ARN per label; `RunMicrovm` accepts at most 10. These
@@ -84,7 +83,7 @@ explicit `allowed` list for the corresponding key.
8483

8584
Use the matcher's `awsDynamicLabelsPolicy` to restrict values accepted from
8685
workflow jobs. The MicroVM policy keys are `egress-network-connectors`,
87-
`image-arn`, `image-version`, and `maximum-duration-in-seconds`. For example:
86+
`image-arn`, and `image-version`. For example:
8887

8988
```json
9089
{
@@ -97,9 +96,6 @@ workflow jobs. The MicroVM policy keys are `egress-network-connectors`,
9796
},
9897
"image-version": {
9998
"allowed": ["3.*"]
100-
},
101-
"maximum-duration-in-seconds": {
102-
"max": 3600
10399
}
104100
}
105101
}

lambdas/libs/compute-providers/aws/microvm/src/control-plane/runner-config.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ describe('createMicrovmRunners', () => {
138138
expect(setMicrovmGithubRunnerId).toHaveBeenNthCalledWith(1, metadataSsmPath, 'mvm-1', 'github-mvm-1');
139139
});
140140

141-
it('applies dynamic labels to the RunMicrovm configuration and metadata tags', async () => {
141+
it('applies dynamic labels without overriding the deployment-controlled duration', async () => {
142142
const overrideImageArn = 'arn:aws:lambda:eu-west-1:123456789012:microvm-image:runner-large';
143143
const overrideEgressConnectorArn =
144144
'arn:aws:lambda:eu-west-1:123456789012:network-connector:github-runner-private-egress';
@@ -151,7 +151,6 @@ describe('createMicrovmRunners', () => {
151151
egressNetworkConnectors: [overrideEgressConnectorArn],
152152
imageIdentifier: overrideImageArn,
153153
imageVersion: '3.0',
154-
maximumDurationInSeconds: 7200,
155154
});
156155

157156
expect(runMicrovmRunner).toHaveBeenCalledWith({
@@ -160,7 +159,7 @@ describe('createMicrovmRunners', () => {
160159
imageIdentifier: overrideImageArn,
161160
imageVersion: '3.0',
162161
executionRoleArn: 'arn:aws:iam::123456789012:role/microvm-runner',
163-
maximumDurationInSeconds: 7200,
162+
maximumDurationInSeconds: 1200,
164163
metadataSsmPath,
165164
},
166165
environment: 'unit-test',

lambdas/libs/compute-providers/aws/microvm/src/control-plane/scale-up.test.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,32 +50,33 @@ describe('createMicrovmScaleUpProvider', () => {
5050
`ghr-microvm-egress-network-connectors:${overrideEgressConnectorArn}`,
5151
`ghr-microvm-image-arn:${overrideImageArn}`,
5252
'ghr-microvm-image-version:3.0',
53-
'ghr-microvm-maximum-duration-in-seconds:7200',
5453
]),
5554
).resolves.toEqual({
5655
runnerLabels: [
5756
`ghr-microvm-egress-network-connectors:${overrideEgressConnectorArn}`,
5857
`ghr-microvm-image-arn:${overrideImageArn}`,
5958
'ghr-microvm-image-version:3.0',
60-
'ghr-microvm-maximum-duration-in-seconds:7200',
6159
],
6260
state: {
6361
overrides: {
6462
egressNetworkConnectors: [overrideEgressConnectorArn],
6563
imageIdentifier: overrideImageArn,
6664
imageVersion: '3.0',
67-
maximumDurationInSeconds: 7200,
6865
},
6966
},
7067
});
7168
});
7269

73-
it('rejects unsupported MicroVM override labels at the control-plane boundary', async () => {
70+
it.each([
71+
['ghr-microvm-memory:8192', "key 'memory' is not a supported MicroVM override"],
72+
[
73+
'ghr-microvm-maximum-duration-in-seconds:7200',
74+
"key 'maximum-duration-in-seconds' is not a supported MicroVM override",
75+
],
76+
])('rejects unsupported MicroVM override label %s at the control-plane boundary', async (label, reason) => {
7477
const provider = createMicrovmScaleUpProvider(createStartRunnerConfig);
7578

76-
await expect(provider.resolveLabelsForRunners(['ghr-microvm-memory:8192'])).rejects.toThrow(
77-
"key 'memory' is not a supported MicroVM override",
78-
);
79+
await expect(provider.resolveLabelsForRunners([label])).rejects.toThrow(reason);
7980
});
8081

8182
it('counts managed MicroVMs for the runner owner', async () => {

lambdas/libs/compute-providers/aws/microvm/src/dynamic-labels.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,12 @@ describe('parseMicrovmDynamicLabels', () => {
1515
`ghr-microvm-egress-network-connectors:${internetEgressConnectorArn}`,
1616
`ghr-microvm-image-arn:${imageArn}`,
1717
'ghr-microvm-image-version:3.0',
18-
'ghr-microvm-maximum-duration-in-seconds:7200',
1918
]),
2019
).toEqual({
2120
overrides: {
2221
egressNetworkConnectors: [egressConnectorArn, internetEgressConnectorArn],
2322
imageIdentifier: imageArn,
2423
imageVersion: '3.0',
25-
maximumDurationInSeconds: 7200,
2624
},
2725
violations: [],
2826
});
@@ -40,8 +38,10 @@ describe('parseMicrovmDynamicLabels', () => {
4038
],
4139
['ghr-microvm-image-arn:not-an-arn', 'is not a valid customer MicroVM image ARN'],
4240
['ghr-microvm-image-version:', "key 'image-version' requires a value"],
43-
['ghr-microvm-maximum-duration-in-seconds:0', 'maximum duration must be an integer between 1 and 28800'],
44-
['ghr-microvm-maximum-duration-in-seconds:28801', 'maximum duration must be an integer between 1 and 28800'],
41+
[
42+
'ghr-microvm-maximum-duration-in-seconds:7200',
43+
"key 'maximum-duration-in-seconds' is not a supported MicroVM override",
44+
],
4545
])('rejects invalid override %s', (label, reason) => {
4646
const result = parseMicrovmDynamicLabels([label]);
4747

lambdas/libs/compute-providers/aws/microvm/src/dynamic-labels.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
export const MICROVM_DYNAMIC_LABEL_PREFIX = 'ghr-microvm-';
22

3-
const MAXIMUM_DURATION_IN_SECONDS = 28_800;
43
const MAXIMUM_EGRESS_NETWORK_CONNECTORS = 10;
54
const MICROVM_IMAGE_ARN_PATTERN = /^arn:[^:]+:lambda:[^:]+:[0-9]{12}:microvm-image:.+$/;
65
const MICROVM_NETWORK_CONNECTOR_ARN_PATTERN =
@@ -10,7 +9,6 @@ export interface MicrovmDynamicLabelOverrides {
109
egressNetworkConnectors?: string[];
1110
imageIdentifier?: string;
1211
imageVersion?: string;
13-
maximumDurationInSeconds?: number;
1412
}
1513

1614
export interface MicrovmDynamicLabelViolation {
@@ -69,18 +67,6 @@ export function parseMicrovmDynamicLabels(labels: string[]): {
6967
case 'image-version':
7068
overrides.imageVersion = value;
7169
break;
72-
case 'maximum-duration-in-seconds': {
73-
const duration = Number(value);
74-
if (!Number.isInteger(duration) || duration < 1 || duration > MAXIMUM_DURATION_IN_SECONDS) {
75-
violations.push({
76-
label,
77-
reason: `maximum duration must be an integer between 1 and ${MAXIMUM_DURATION_IN_SECONDS}`,
78-
});
79-
} else {
80-
overrides.maximumDurationInSeconds = duration;
81-
}
82-
break;
83-
}
8470
default:
8571
violations.push({ label, reason: `key '${key}' is not a supported MicroVM override` });
8672
}

lambdas/libs/compute-providers/aws/microvm/src/webhook/dynamic-labels.test.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ describe('microvmDynamicLabelProvider', () => {
2020
`ghr-microvm-egress-network-connectors:${egressConnectorArn}`,
2121
`ghr-microvm-image-arn:${imageArn}`,
2222
'ghr-microvm-image-version:3.0',
23-
'ghr-microvm-maximum-duration-in-seconds:7200',
2423
];
2524

2625
expect(getViolations(queue, dynamicLabels)).toEqual([]);
@@ -32,7 +31,6 @@ describe('microvmDynamicLabelProvider', () => {
3231
`ghr-microvm-egress-network-connectors:${egressConnectorArn}`,
3332
`ghr-microvm-image-arn:${imageArn}`,
3433
'ghr-microvm-image-version:3.0',
35-
'ghr-microvm-maximum-duration-in-seconds:3600',
3634
]),
3735
).toEqual([
3836
{
@@ -50,25 +48,31 @@ describe('microvmDynamicLabelProvider', () => {
5048
]);
5149
});
5250

53-
it('preserves violations from the MicroVM label parser', () => {
54-
expect(getViolations(microvmQueue(), ['ghr-microvm-memory:8192'])).toEqual([
51+
it.each([
52+
['ghr-microvm-memory:8192', "key 'memory' is not a supported MicroVM override"],
53+
[
54+
'ghr-microvm-maximum-duration-in-seconds:7200',
55+
"key 'maximum-duration-in-seconds' is not a supported MicroVM override",
56+
],
57+
])('preserves the parser violation for %s', (label, reason) => {
58+
expect(getViolations(microvmQueue(), [label])).toEqual([
5559
{
56-
label: 'ghr-microvm-memory:8192',
57-
reason: "key 'memory' is not a supported MicroVM override",
60+
label,
61+
reason,
5862
},
5963
]);
6064
});
6165

6266
it('enforces the AWS dynamic-label policy', () => {
6367
const queue = microvmQueue();
6468
queue.matcherConfig.awsDynamicLabelsPolicy = {
65-
restricted_keys: { 'maximum-duration-in-seconds': { max: 3600 } },
69+
restricted_keys: { 'image-version': { allowed: ['2.*'] } },
6670
};
6771

68-
expect(getViolations(queue, ['ghr-microvm-maximum-duration-in-seconds:7200'])).toEqual([
72+
expect(getViolations(queue, ['ghr-microvm-image-version:3.0'])).toEqual([
6973
{
70-
label: 'ghr-microvm-maximum-duration-in-seconds:7200',
71-
reason: "value '7200' exceeds max '3600'",
74+
label: 'ghr-microvm-image-version:3.0',
75+
reason: "value '3.0' not in allowed list",
7276
},
7377
]);
7478
});

lambdas/libs/compute-providers/aws/microvm/webhook.test.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,20 @@ import { provider } from './webhook';
33

44
defineWebhookProviderContractTests({
55
provider,
6-
acceptedDynamicLabels: ['ghr-microvm-maximum-duration-in-seconds:3600'],
6+
acceptedDynamicLabels: ['ghr-microvm-image-version:3.0'],
7+
configureQueue: (queue) => {
8+
queue.matcherConfig.awsDynamicLabelsPolicy = {
9+
restricted_keys: {
10+
'image-version': { allowed: ['3.0'] },
11+
},
12+
};
13+
},
714
rejectingPolicies: [
815
{
916
name: 'blocked keys',
1017
apply: (queue) => {
1118
queue.matcherConfig.awsDynamicLabelsPolicy = {
12-
blocked_keys: ['maximum-duration-in-seconds'],
19+
blocked_keys: ['image-version'],
1320
};
1421
},
1522
},
@@ -18,7 +25,7 @@ defineWebhookProviderContractTests({
1825
apply: (queue) => {
1926
queue.matcherConfig.awsDynamicLabelsPolicy = {
2027
restricted_keys: {
21-
'maximum-duration-in-seconds': { max: 1800 },
28+
'image-version': { allowed: ['2.*'] },
2229
},
2330
};
2431
},

lambdas/libs/compute-providers/test/webhook-provider-contract.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,25 @@ interface RejectingPolicyCase {
1313
interface WebhookProviderContractOptions<TProvider extends ComputeProviderType> {
1414
provider: WebhookProviderModule<TProvider>;
1515
acceptedDynamicLabels: readonly [string, ...string[]];
16+
configureQueue?(queue: RunnerMatcherConfig): void;
1617
rejectingPolicies: readonly [RejectingPolicyCase, ...RejectingPolicyCase[]];
1718
}
1819

1920
export function defineWebhookProviderContractTests<TProvider extends ComputeProviderType>({
2021
provider,
2122
acceptedDynamicLabels,
23+
configureQueue,
2224
rejectingPolicies,
2325
}: WebhookProviderContractOptions<TProvider>): void {
2426
const nonGhrLabels = ['self-hosted', 'linux'];
2527
const dynamicLabels = [...acceptedDynamicLabels];
2628

29+
function configuredRunnerQueue(id: string, computeProvider?: ComputeProviderType): RunnerMatcherConfig {
30+
const queue = runnerQueue(id, computeProvider);
31+
configureQueue?.(queue);
32+
return queue;
33+
}
34+
2735
function expectProviderSelected(queue: RunnerMatcherConfig) {
2836
expect(selectDynamicLabelQueue([queue], nonGhrLabels, dynamicLabels)).toEqual({
2937
queue,
@@ -33,35 +41,35 @@ export function defineWebhookProviderContractTests<TProvider extends ComputeProv
3341

3442
describe(`${provider.type} webhook provider contract`, () => {
3543
it('selects an explicitly configured provider through the production registry', () => {
36-
expectProviderSelected(runnerQueue(`${provider.type}-configured`, provider.type));
44+
expectProviderSelected(configuredRunnerQueue(`${provider.type}-configured`, provider.type));
3745
});
3846

3947
it('skips the provider when dynamic labels are disabled', () => {
40-
const queue = runnerQueue(`${provider.type}-disabled`, provider.type);
48+
const queue = configuredRunnerQueue(`${provider.type}-disabled`, provider.type);
4149
queue.matcherConfig.enableDynamicLabels = false;
4250

4351
expect(selectDynamicLabelQueue([queue], nonGhrLabels, dynamicLabels)).toBeUndefined();
4452
});
4553

4654
for (const policy of rejectingPolicies) {
4755
it(`skips the provider when its ${policy.name} policy rejects the labels`, () => {
48-
const queue = runnerQueue(`${provider.type}-policy-rejected`, provider.type);
56+
const queue = configuredRunnerQueue(`${provider.type}-policy-rejected`, provider.type);
4957
policy.apply(queue);
5058

5159
expect(selectDynamicLabelQueue([queue], nonGhrLabels, dynamicLabels)).toBeUndefined();
5260
});
5361
}
5462

5563
it('normalizes provider configuration before registry selection', () => {
56-
const queue = runnerQueue(`${provider.type}-normalized`);
64+
const queue = configuredRunnerQueue(`${provider.type}-normalized`);
5765
(queue as unknown as { computeProvider: string }).computeProvider = ` ${provider.type.toUpperCase()} `;
5866

5967
expectProviderSelected(queue);
6068
});
6169

6270
if (provider.type === defaultComputeProvider) {
6371
it('selects the default provider when the queue omits provider configuration', () => {
64-
expectProviderSelected(runnerQueue(`${provider.type}-default`));
72+
expectProviderSelected(configuredRunnerQueue(`${provider.type}-default`));
6573
});
6674
}
6775
});

0 commit comments

Comments
 (0)