Skip to content

Commit 341e27d

Browse files
authored
chore(deployments): lazily update ECR repo cache settings (#2734)
To avoid doing a migration for the ECR repo cache settings, we lazily do it on the next deployment for that project. Failures to update the repo settings are just logged and will not cause the deployment to fail.
1 parent 9821d02 commit 341e27d

File tree

1 file changed

+83
-15
lines changed

1 file changed

+83
-15
lines changed

apps/webapp/app/v3/getDeploymentImageRef.server.ts

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
RepositoryNotFoundException,
88
GetAuthorizationTokenCommand,
99
PutLifecyclePolicyCommand,
10+
PutImageTagMutabilityCommand,
1011
} from "@aws-sdk/client-ecr";
1112
import { STSClient, AssumeRoleCommand } from "@aws-sdk/client-sts";
1213
import { tryCatch } from "@trigger.dev/core";
@@ -196,6 +197,22 @@ export function parseRegistryTags(tags: string): Tag[] {
196197
.filter((tag): tag is Tag => tag !== null);
197198
}
198199

200+
const untaggedImageExpirationPolicy = JSON.stringify({
201+
rules: [
202+
{
203+
rulePriority: 1,
204+
description: "Expire untagged images older than 3 days",
205+
selection: {
206+
tagStatus: "untagged",
207+
countType: "sinceImagePushed",
208+
countUnit: "days",
209+
countNumber: 3,
210+
},
211+
action: { type: "expire" },
212+
},
213+
],
214+
});
215+
199216
async function createEcrRepository({
200217
repositoryName,
201218
region,
@@ -241,27 +258,62 @@ async function createEcrRepository({
241258
new PutLifecyclePolicyCommand({
242259
repositoryName: result.repository.repositoryName,
243260
registryId: result.repository.registryId,
244-
lifecyclePolicyText: JSON.stringify({
245-
rules: [
246-
{
247-
rulePriority: 1,
248-
description: "Expire untagged images older than 3 days",
249-
selection: {
250-
tagStatus: "untagged",
251-
countType: "sinceImagePushed",
252-
countUnit: "days",
253-
countNumber: 3,
254-
},
255-
action: { type: "expire" },
256-
},
257-
],
258-
}),
261+
lifecyclePolicyText: untaggedImageExpirationPolicy,
259262
})
260263
);
261264

262265
return result.repository;
263266
}
264267

268+
async function updateEcrRepositoryCacheSettings({
269+
repositoryName,
270+
region,
271+
accountId,
272+
assumeRole,
273+
}: {
274+
repositoryName: string;
275+
region: string;
276+
accountId?: string;
277+
assumeRole?: AssumeRoleConfig;
278+
}): Promise<void> {
279+
logger.debug("Updating ECR repository tag mutability to IMMUTABLE_WITH_EXCLUSION", {
280+
repositoryName,
281+
region,
282+
});
283+
284+
const ecr = await createEcrClient({ region, assumeRole });
285+
286+
await ecr.send(
287+
new PutImageTagMutabilityCommand({
288+
repositoryName,
289+
registryId: accountId,
290+
imageTagMutability: "IMMUTABLE_WITH_EXCLUSION",
291+
imageTagMutabilityExclusionFilters: [
292+
{
293+
// only the `cache` tag will be mutable, all other tags will be immutable
294+
filter: "cache",
295+
filterType: "WILDCARD",
296+
},
297+
],
298+
})
299+
);
300+
301+
// When the `cache` tag is mutated, the old cache images are untagged.
302+
// This policy matches those images and expires them to avoid bloating the repository.
303+
await ecr.send(
304+
new PutLifecyclePolicyCommand({
305+
repositoryName,
306+
registryId: accountId,
307+
lifecyclePolicyText: untaggedImageExpirationPolicy,
308+
})
309+
);
310+
311+
logger.debug("Successfully updated ECR repository to IMMUTABLE_WITH_EXCLUSION", {
312+
repositoryName,
313+
region,
314+
});
315+
}
316+
265317
async function getEcrRepository({
266318
repositoryName,
267319
region,
@@ -350,6 +402,22 @@ async function ensureEcrRepositoryExists({
350402

351403
if (existingRepo) {
352404
logger.debug("ECR repository already exists", { repositoryName, region, existingRepo });
405+
406+
// check if the repository is missing the cache settings
407+
if (existingRepo.imageTagMutability === "IMMUTABLE") {
408+
const [updateError] = await tryCatch(
409+
updateEcrRepositoryCacheSettings({ repositoryName, region, accountId, assumeRole })
410+
);
411+
412+
if (updateError) {
413+
logger.error("Failed to update ECR repository cache settings", {
414+
repositoryName,
415+
region,
416+
updateError,
417+
});
418+
}
419+
}
420+
353421
return {
354422
repo: existingRepo,
355423
repoCreated: false,

0 commit comments

Comments
 (0)