diff --git a/.images/flyio-basic.png b/.images/flyio-basic.png new file mode 100644 index 0000000..4cd21a2 Binary files /dev/null and b/.images/flyio-basic.png differ diff --git a/.images/flyio-custom.png b/.images/flyio-custom.png new file mode 100644 index 0000000..4ca25a4 Binary files /dev/null and b/.images/flyio-custom.png differ diff --git a/.images/flyio-filtered.png b/.images/flyio-filtered.png new file mode 100644 index 0000000..f7b0711 Binary files /dev/null and b/.images/flyio-filtered.png differ diff --git a/fly-region/README.md b/fly-region/README.md index 7c14f53..f6ec1e5 100644 --- a/fly-region/README.md +++ b/fly-region/README.md @@ -9,8 +9,56 @@ tags: [helper, parameter, fly] # Fly.io Region -A parameter with all fly.io regions. This allows developers to select the region closest to them. +This module adds Fly.io regions to your Coder template. Regions can be whitelisted using the `regions` argument and given custom names and custom icons with their respective map arguments (`custom_names`, `custom_icons`). ## Examples -TODO +### Using default settings + +We can use the simplest format here, only adding a default selection as the `atl` region. + +```hcl +module "fly-region" { + source = "https://registry.coder.com/modules/fly-region" + default = "atl" +} +``` + +![Fly.io Default](../.images/flyio-basic.png) + +### Using region whitelist + +The regions argument can be used to display only the desired regions in the Coder parameter. + +```hcl +module "fly-region" { + source = "https://registry.coder.com/modules/fly-region" + default = "ams" + regions = ["ams", "arn", "atl"] +} +``` + +![Fly.io Filtered Regions](../.images/flyio-filtered.png) + +### Using custom icons and names + +Set custom icons and names with their respective maps. + +```hcl +module "fly-region" { + source = "https://registry.coder.com/modules/fly-region" + default = "ams" + custom_icons = { + "ams" = "/emojis/1f90e.png" + } + custom_names = { + "ams" = "We love the Netherlands!" + } +} +``` + +![Fly.io custom icon and name](../.images/flyio-custom.png) + +## Associated template + +Also see the Coder template registry for a [Fly.io template](https://registry.coder.com/templates/fly-docker-image) that provisions workspaces as Fly.io machines. diff --git a/fly-region/main.test.ts b/fly-region/main.test.ts new file mode 100644 index 0000000..86f6bfc --- /dev/null +++ b/fly-region/main.test.ts @@ -0,0 +1,25 @@ +import { describe, expect, it } from "bun:test"; +import { + executeScriptInContainer, + runTerraformApply, + runTerraformInit, + testRequiredVariables, +} from "../test"; + +describe("fly-region", async () => { + await runTerraformInit(import.meta.dir); + + testRequiredVariables(import.meta.dir, {}); + + it("default output", async () => { + const state = await runTerraformApply(import.meta.dir, {}); + expect(state.outputs.value.value).toBe(""); + }); + + it("customized default", async () => { + const state = await runTerraformApply(import.meta.dir, { + default: "atl", + }); + expect(state.outputs.value.value).toBe("atl"); + }); +}); diff --git a/fly-region/main.tf b/fly-region/main.tf new file mode 100644 index 0000000..ff6a9e3 --- /dev/null +++ b/fly-region/main.tf @@ -0,0 +1,287 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + coder = { + source = "coder/coder" + version = ">= 0.12" + } + } +} + +variable "display_name" { + default = "Fly.io Region" + description = "The display name of the parameter." + type = string +} + +variable "description" { + default = "The region to deploy workspace infrastructure." + description = "The description of the parameter." + type = string +} + +variable "default" { + default = null + description = "The default region to use if no region is specified." + type = string +} + +variable "mutable" { + default = false + description = "Whether the parameter can be changed after creation." + type = bool +} + +variable "custom_names" { + default = {} + description = "A map of custom display names for region IDs." + type = map(string) +} + +variable "custom_icons" { + default = {} + description = "A map of custom icons for region IDs." + type = map(string) +} + +variable "regions" { + default = [] + description = "List of regions to include for region selection." + type = list(string) +} + +locals { + regions = { + "ams" = { + name = "Amsterdam, Netherlands" + gateway = true + paid_only = false + icon = "/emojis/1f1f3-1f1f1.png" + } + "arn" = { + name = "Stockholm, Sweden" + gateway = false + paid_only = false + icon = "/emojis/1f1f8-1f1ea.png" + } + "atl" = { + name = "Atlanta, Georgia (US)" + gateway = false + paid_only = false + icon = "/emojis/1f1fa-1f1f8.png" + } + "bog" = { + name = "Bogotá, Colombia" + gateway = false + paid_only = false + icon = "/emojis/1f1e8-1f1f4.png" + } + "bom" = { + name = "Mumbai, India" + gateway = true + paid_only = true + icon = "/emojis/1f1ee-1f1f3.png" + } + "bos" = { + name = "Boston, Massachusetts (US)" + gateway = false + paid_only = false + icon = "/emojis/1f1fa-1f1f8.png" + } + "cdg" = { + name = "Paris, France" + gateway = true + paid_only = false + icon = "/emojis/1f1eb-1f1f7.png" + } + "den" = { + name = "Denver, Colorado (US)" + gateway = false + paid_only = false + icon = "/emojis/1f1fa-1f1f8.png" + } + "dfw" = { + name = "Dallas, Texas (US)" + gateway = true + paid_only = false + icon = "/emojis/1f1fa-1f1f8.png" + } + "ewr" = { + name = "Secaucus, NJ (US)" + gateway = false + paid_only = false + icon = "/emojis/1f1fa-1f1f8.png" + } + "eze" = { + name = "Ezeiza, Argentina" + gateway = false + paid_only = false + icon = "/emojis/1f1e6-1f1f7.png" + } + "fra" = { + name = "Frankfurt, Germany" + gateway = true + paid_only = true + icon = "/emojis/1f1e9-1f1ea.png" + } + "gdl" = { + name = "Guadalajara, Mexico" + gateway = false + paid_only = false + icon = "/emojis/1f1f2-1f1fd.png" + } + "gig" = { + name = "Rio de Janeiro, Brazil" + gateway = false + paid_only = false + icon = "/emojis/1f1e7-1f1f7.png" + } + "gru" = { + name = "Sao Paulo, Brazil" + gateway = false + paid_only = false + icon = "/emojis/1f1e7-1f1f7.png" + } + "hkg" = { + name = "Hong Kong, Hong Kong" + gateway = true + paid_only = false + icon = "/emojis/1f1ed-1f1f0.png" + } + "iad" = { + name = "Ashburn, Virginia (US)" + gateway = true + paid_only = false + icon = "/emojis/1f1fa-1f1f8.png" + } + "jnb" = { + name = "Johannesburg, South Africa" + gateway = false + paid_only = false + icon = "/emojis/1f1ff-1f1e6.png" + } + "lax" = { + name = "Los Angeles, California (US)" + gateway = true + paid_only = false + icon = "/emojis/1f1fa-1f1f8.png" + } + "lhr" = { + name = "London, United Kingdom" + gateway = true + paid_only = false + icon = "/emojis/1f1ec-1f1e7.png" + } + "mad" = { + name = "Madrid, Spain" + gateway = false + paid_only = false + icon = "/emojis/1f1ea-1f1f8.png" + } + "mia" = { + name = "Miami, Florida (US)" + gateway = false + paid_only = false + icon = "/emojis/1f1fa-1f1f8.png" + } + "nrt" = { + name = "Tokyo, Japan" + gateway = true + paid_only = false + icon = "/emojis/1f1ef-1f1f5.png" + } + "ord" = { + name = "Chicago, Illinois (US)" + gateway = true + paid_only = false + icon = "/emojis/1f1fa-1f1f8.png" + } + "otp" = { + name = "Bucharest, Romania" + gateway = false + paid_only = false + icon = "/emojis/1f1f7-1f1f4.png" + } + "phx" = { + name = "Phoenix, Arizona (US)" + gateway = false + paid_only = false + icon = "/emojis/1f1fa-1f1f8.png" + } + "qro" = { + name = "Querétaro, Mexico" + gateway = false + paid_only = false + icon = "/emojis/1f1f2-1f1fd.png" + } + "scl" = { + name = "Santiago, Chile" + gateway = true + paid_only = false + icon = "/emojis/1f1e8-1f1f1.png" + } + "sea" = { + name = "Seattle, Washington (US)" + gateway = true + paid_only = false + icon = "/emojis/1f1fa-1f1f8.png" + } + "sin" = { + name = "Singapore, Singapore" + gateway = true + paid_only = false + icon = "/emojis/1f1f8-1f1ec.png" + } + "sjc" = { + name = "San Jose, California (US)" + gateway = true + paid_only = false + icon = "/emojis/1f1fa-1f1f8.png" + } + "syd" = { + name = "Sydney, Australia" + gateway = true + paid_only = false + icon = "/emojis/1f1e6-1f1fa.png" + } + "waw" = { + name = "Warsaw, Poland" + gateway = false + paid_only = false + icon = "/emojis/1f1f5-1f1f1.png" + } + "yul" = { + name = "Montreal, Canada" + gateway = false + paid_only = false + icon = "/emojis/1f1e8-1f1e6.png" + } + "yyz" = { + name = "Toronto, Canada" + gateway = true + paid_only = false + icon = "/emojis/1f1e8-1f1e6.png" + } + } +} + +data "coder_parameter" "fly_region" { + name = "flyio_region" + display_name = var.display_name + description = var.description + default = (var.default != null && var.default != "") && ((var.default != null ? contains(var.regions, var.default) : false) || length(var.regions) == 0) ? var.default : null + mutable = var.mutable + dynamic "option" { + for_each = { for k, v in local.regions : k => v if anytrue([for d in var.regions : k == d]) || length(var.regions) == 0 } + content { + name = try(var.custom_names[option.key], option.value.name) + icon = try(var.custom_icons[option.key], option.value.icon) + value = option.key + } + } +} + +output "value" { + value = data.coder_parameter.fly_region.value +} \ No newline at end of file