Skip to content

Commit

Permalink
rewrite nixpkgs's create-amis script using Terraform
Browse files Browse the repository at this point in the history
  • Loading branch information
AmineChikhaoui committed Jun 4, 2023
1 parent acc635f commit 6c8ebb8
Show file tree
Hide file tree
Showing 11 changed files with 305 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,10 @@

# Terraform
.terraform*
!.terraform.lock.hcl
*tfstate
*tfstate.backup
*.aarch64.*.tfvars
*.x86_64.*.tfvars
.current-workspace
copy.tf.json
24 changes: 24 additions & 0 deletions amis/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions amis/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.PHONY: plan apply

arch=x86_64
version=23.05

tfvarsFile=$(version).$(arch).current.tfvars

$(tfvarsFile) .current-workspace:
./pull-latest $(version) $(arch)

copy.tf.json: regions.jq regions.json
@jq -f regions.jq regions.json > copy.tf.json

plan: copy.tf.json $(tfvarsFile) .current-workspace
@terraform workspace select -or-create $(shell cat .current-workspace)
@terraform plan -var-file=$(tfvarsFile)

apply: copy.tf.json $(tfvarsFile)
@terraform workspace select -or-create $(shell cat .current-workspace)
@terraform apply -var-file=$(tfvarsFile)
12 changes: 12 additions & 0 deletions amis/generate-nixpkgs-update
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#! /usr/bin/env bash

version="$1"

echo "append the following to nixpkgs: nixos/modules/virtualisation/amazon-ec2-amis.nix"
echo "make sure to update latest attribute to point to $version !"
echo

terraform output -json \
| jq \
--arg version "$version" \
'.[]|.value|"\"\($version)\".\(.region).\(.arch).hvm-ebs = \(.id);"' -r
108 changes: 108 additions & 0 deletions amis/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
locals {
image_info_file = file("${var.image_store_path}/nix-support/image-info.json")

image_info = jsondecode(local.image_info_file)
image_system = local.image_info.system
root_disk = local.image_info.disks.root

is_zfs = lookup(local.image_info.disks, "boot", null) != null ? true : false
zfs_boot = local.is_zfs ? local.image_info.disks.boot : null

label_suffix = local.is_zfs ? "-ZFS" : ""
image_label = "${local.image_info.label}${local.label_suffix}"
image_name = "NixOS-${local.image_label}-${local.image_system}"
image_description = "NixOS ${local.image_label} ${local.image_system}"

arch_mapping = {
"aarch64-linux" = "arm64"
"x86_64-linux" = "x86_64"
}

image_logical_bytes = (
local.is_zfs ? local.zfs_boot.logical_bytes : local.root_disk.logical_bytes
)
image_logical_gigabytes = floor(
(local.image_logical_bytes - 1) / 1024 / 1024 / 1024 + 1
)
zfs_boot_file = local.is_zfs ? { boot = local.zfs_boot.file } : {}
image_files = merge(
{ root = local.root_disk.file }
, local.zfs_boot_file
)
}

resource "aws_s3_object" "image_file" {
for_each = local.image_files
bucket = var.bucket
key = trimprefix(each.value, "/")
source = each.value
}

resource "aws_ebs_snapshot_import" "image_import" {
for_each = aws_s3_object.image_file
disk_container {
description = "nixos-image-${local.image_label}-${local.image_system}"
format = "VHD"
user_bucket {
s3_bucket = each.value.bucket
s3_key = each.value.key
}
}

role_name = var.service_role_name
}

locals {
# When ZFS is used the boot device is "boot"
boot_snapshot = (local.is_zfs ?
aws_ebs_snapshot_import.image_import["boot"] :
aws_ebs_snapshot_import.image_import["root"]
)
}

resource "aws_ami" "nixos_ami" {
name = local.image_name
virtualization_type = "hvm"
root_device_name = "/dev/xvda"
architecture = local.arch_mapping[local.image_system]
boot_mode = local.image_info.boot_mode
ena_support = true
sriov_net_support = "simple"

ebs_block_device {
device_name = "/dev/xvda"
snapshot_id = local.boot_snapshot.id
volume_size = local.boot_snapshot.volume_size
delete_on_termination = true
volume_type = "gp3"
}

dynamic "ebs_block_device" {
for_each = local.is_zfs ? { zfs = true } : {}

content {
device_name = "/dev/xvdb"
snapshot_id = aws_ebs_snapshot_import.image_import["root"].id
volume_size = aws_ebs_snapshot_import.image_import["root"].id
delete_on_termination = true
volume_type = "gp3"
}
}

lifecycle {
ignore_changes = [deprecation_time]
}
}

resource "aws_ami_launch_permission" "public_access" {
image_id = aws_ami.nixos_ami.id
group = "all"
}

output "ami" {
value = {
region = var.aws_region
arch = local.image_system
id = aws_ami.nixos_ami.id
}
}
17 changes: 17 additions & 0 deletions amis/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
locals {
image_tags = {
# TODO remove the testing prefix
Name = "${local.image_name} - terraform testing"
Description = local.image_description
System = local.image_system
Release = terraform.workspace
Official = false
}
}

provider "aws" {
region = "eu-west-1"
default_tags {
tags = local.image_tags
}
}
23 changes: 23 additions & 0 deletions amis/pull-latest
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#! /usr/bin/env bash
#

version="$1"
arch="$2"
hydraJob="nixos.amazonImage"
baseUrl="https://hydra.nixos.org/job/nixos"

build=$(curl -sL \
-H 'Content-type: application/json' \
"${baseUrl}/release-${version}-small/${hydraJob}.${arch}-linux/latest")

storePath=$(echo "$build" | jq '.buildoutputs|.out|.path' -r)
buildId=$(echo "$build" | jq .id -r)

nix-store -r "${storePath}"

tfvarsFile="${version}.${arch}.${buildId}.tfvars"

echo "image_store_path = \"${storePath}\"" > "$tfvarsFile"
ln -s "$tfvarsFile" "${version}.${arch}.current.tfvars"

echo "${version}.${arch}.${buildId}" > .current-workspace
38 changes: 38 additions & 0 deletions amis/regions.jq
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[
.[]|
{ "provider": {
"aws": {
"region": . ,
"alias": .
}
},
"resource": {
"aws_ami_copy": {
"copy_\(.)": {
"name": "${local.image_name}",
"description": "${local.image_description}",
"source_ami_id": "${aws_ami.nixos_ami.id}",
"source_ami_region": "${var.aws_region}",
"provider": "aws.\(.)",
"lifecycle": { "ignore_changes": [ "deprecation_time" ] }
}
},
"aws_ami_launch_permission": {
"public_access_\(.)": {
"image_id": "${aws_ami_copy.copy_\(.).id}",
"group": "all",
"provider": "aws.\(.)"
}
}
},
"output": {
"ami_\(.)": {
"value": {
"id": "${aws_ami_copy.copy_\(.).id}",
"arch": "${local.image_system}",
"region": .
}
}
}
}
]
23 changes: 23 additions & 0 deletions amis/regions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[
"af-south-1",
"ap-east-1",
"ap-northeast-1",
"ap-northeast-2",
"ap-northeast-3",
"ap-south-1",
"ap-southeast-1",
"ap-southeast-2",
"ap-southeast-3",
"ca-central-1",
"eu-central-1",
"eu-north-1",
"eu-south-1",
"eu-west-2",
"eu-west-3",
"me-south-1",
"sa-east-1",
"us-east-1",
"us-east-2",
"us-west-1",
"us-west-2"
]
15 changes: 15 additions & 0 deletions amis/state.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
terraform {
backend "s3" {
bucket = "nixos-terraform-state"
encrypt = true
key = "nixos-amis.tfstate"
workspace_key_prefix = "targets/amis/releases"
region = "eu-west-1"
}

required_providers {
aws = {
source = "hashicorp/aws"
}
}
}
18 changes: 18 additions & 0 deletions amis/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
variable "aws_region" {
type = string
default = "eu-west-1"
}

variable "bucket" {
type = string
default = "nixos-amis"
}

variable "service_role_name" {
type = string
default = "vmimport"
}

variable "image_store_path" {
type = string
}

0 comments on commit 6c8ebb8

Please sign in to comment.