Publish AMI artifact IDs to SSM

This commit is contained in:
Timothy J. Aveni
2026-06-28 17:41:21 -07:00
parent 70797543e4
commit 30d6ba2332
3 changed files with 109 additions and 6 deletions
+76 -5
View File
@@ -10,14 +10,15 @@ const repoRoot = process.env.QUIXOS_REPO_ROOT ?? path.resolve(sourceScriptDir, "
const amiBuilderDir = process.env.QUIXOS_AMI_BUILDER_DIR ?? path.resolve(repoRoot, "tofu/ami-builder");
const centralDir = path.resolve(amiBuilderDir, "../central");
const usage = `Usage: nix run ./tofu/ami-builder#ami-artifacts -- <list|delete> [options]
const usage = `Usage: nix run ./tofu/ami-builder#ami-artifacts -- <list|delete|publish-ssm> [options]
Commands:
list List published AMI artifacts and deployment references
delete --ami-id <ami> Deregister an AMI and delete its root and /nix snapshots
list List published AMI artifacts and deployment references
delete --ami-id <ami> Deregister an AMI and delete its root and /nix snapshots
publish-ssm --ami-id <ami> Publish an existing AMI into the SSM artifact registry
Options:
--ami-id <ami> AMI to delete
--ami-id <ami> AMI to operate on
--aws-region <region> AWS region (default: AWS_REGION or us-west-2)
--name <name> AMI project tag (default: nixos-zfs-ec2)
--architecture <arm64|x86_64> Filter by architecture
@@ -62,7 +63,7 @@ const parseArgs = (argv) => {
console.error(usage.trimEnd());
process.exit(command ? 0 : 1);
}
if (command !== "list" && command !== "delete") {
if (command !== "list" && command !== "delete" && command !== "publish-ssm") {
throw new Error(`Unknown command: ${command}\n\n${usage}`);
}
@@ -287,6 +288,72 @@ const deleteArtifact = (state) => {
}
};
const getImage = (state) => {
const result = awsJson([
"ec2",
"describe-images",
"--region",
state.awsRegion,
"--owners",
"self",
"--image-ids",
state.amiId,
]);
const image = result?.Images?.[0];
if (!image) {
throw new Error(`AMI not found: ${state.amiId}`);
}
return image;
};
const putSsmParameter = (state, name, value) => {
run("aws", [
"ssm",
"put-parameter",
"--region",
state.awsRegion,
"--name",
name,
"--type",
"String",
"--value",
value,
"--overwrite",
]);
};
const publishSsmArtifact = (state) => {
if (!state.amiId) {
throw new Error("Missing --ami-id");
}
const image = getImage(state);
const tags = amiTags(image);
const architecture = tags.Architecture ?? image.Architecture ?? "";
const builderGitRev = tags.BuilderGitRev ?? "";
const inputHash = tags.InputHash ?? "";
if (!architecture) {
throw new Error(`AMI ${state.amiId} is missing Architecture metadata`);
}
if (!builderGitRev) {
throw new Error(`AMI ${state.amiId} is missing BuilderGitRev tag`);
}
if (!inputHash) {
throw new Error(`AMI ${state.amiId} is missing InputHash tag`);
}
const prefix = `/quixos/amis/${state.name}/${architecture}`;
const parameters = [
`${prefix}/recommended`,
`${prefix}/by-builder-rev/${builderGitRev}`,
`${prefix}/by-input-hash/${inputHash}`,
];
for (const parameter of parameters) {
console.error(`Writing ${parameter} = ${state.amiId}`);
putSsmParameter(state, parameter, state.amiId);
}
};
const main = () => {
const state = parseArgs(process.argv.slice(2));
requireCommand("aws");
@@ -296,6 +363,10 @@ const main = () => {
listArtifacts(state);
return;
}
if (state.command === "publish-ssm") {
publishSsmArtifact(state);
return;
}
deleteArtifact(state);
};