From f49229f2ef65b3d35a04a289945ab4e1c040d2cc Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Sat, 17 Jan 2026 09:14:24 +0000 Subject: [PATCH] fix(ci): ensure no gap during AMI replacement When an AMI name collision occurs during image creation, use a safe replacement strategy: 1. Create temp image with unique name 2. Wait for temp image to be available 3. Copy temp image to final name 4. Wait for final image to be available 5. Only then deregister old and temp images This ensures CI jobs always have a working AMI available during the daily image rebuild - the old image is kept until the new one is fully ready. Co-Authored-By: Claude Opus 4.5 --- scripts/machine.mjs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/scripts/machine.mjs b/scripts/machine.mjs index 0d20b6e36f..9fdc100a34 100755 --- a/scripts/machine.mjs +++ b/scripts/machine.mjs @@ -224,6 +224,7 @@ const aws = { */ async createImage(options) { const flags = aws.getFlags(options); + const finalName = options?.name; /** @type {string | undefined} */ let existingImageId; @@ -246,9 +247,29 @@ const aws = { return ImageId; } + // Name collision: create with temp name, wait for availability, copy with final name, + // then deregister old and temp images. This ensures no gap where the image is unavailable. + const tempName = `${finalName}-temp-${Date.now()}`; + const tempFlags = aws.getFlags({ ...options, name: tempName }); + const { ImageId: tempImageId } = await aws.spawn($`ec2 create-image ${tempFlags}`); + + // Wait for temp image to be available + await aws.waitImage("image-available", tempImageId); + + // Copy temp image to final name + const region = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || "us-east-1"; + const { ImageId: finalImageId } = await aws.spawn( + $`ec2 copy-image --source-image-id ${tempImageId} --source-region ${region} --name ${finalName}`, + ); + + // Wait for final image to be available + await aws.waitImage("image-available", finalImageId); + + // Now safe to deregister old and temp images await aws.spawn($`ec2 deregister-image --image-id ${existingImageId}`); - const { ImageId } = await aws.spawn($`ec2 create-image ${flags}`); - return ImageId; + await aws.spawn($`ec2 deregister-image --image-id ${tempImageId}`); + + return finalImageId; }, /**