feat: add digitalocean region module (#355)
Co-authored-by: Atif Ali <atif@coder.com>
This commit is contained in:
parent
7e53098bea
commit
c4c484089f
87
registry/umair/modules/digitalocean-region/README.md
Normal file
87
registry/umair/modules/digitalocean-region/README.md
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
---
|
||||||
|
display_name: DigitalOcean Region
|
||||||
|
description: A parameter with human region names and icons
|
||||||
|
icon: ../../../../.icons/digital-ocean.svg
|
||||||
|
verified: true
|
||||||
|
tags: [helper, parameter, digitalocean, regions]
|
||||||
|
---
|
||||||
|
|
||||||
|
# DigitalOcean Region
|
||||||
|
|
||||||
|
This module adds DigitalOcean regions to your Coder template with automatic GPU filtering. You can customize display names and icons using the `custom_names` and `custom_icons` arguments.
|
||||||
|
|
||||||
|
The simplest usage is:
|
||||||
|
|
||||||
|
```tf
|
||||||
|
module "digitalocean-region" {
|
||||||
|
count = data.coder_workspace.me.start_count
|
||||||
|
source = "registry.coder.com/coder/digitalocean-region/coder"
|
||||||
|
version = "1.0.0"
|
||||||
|
default = "ams3"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Basic usage
|
||||||
|
|
||||||
|
```tf
|
||||||
|
module "digitalocean-region" {
|
||||||
|
count = data.coder_workspace.me.start_count
|
||||||
|
source = "registry.coder.com/coder/digitalocean-region/coder"
|
||||||
|
version = "1.0.0"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### With custom configuration
|
||||||
|
|
||||||
|
```tf
|
||||||
|
module "digitalocean-region" {
|
||||||
|
count = data.coder_workspace.me.start_count
|
||||||
|
source = "registry.coder.com/coder/digitalocean-region/coder"
|
||||||
|
version = "1.0.0"
|
||||||
|
default = "ams3"
|
||||||
|
mutable = true
|
||||||
|
|
||||||
|
custom_icons = {
|
||||||
|
"ams3" = "/emojis/1f1f3-1f1f1.png"
|
||||||
|
}
|
||||||
|
|
||||||
|
custom_names = {
|
||||||
|
"ams3" = "Europe - Amsterdam (Primary)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### GPU-only toggle (internal parameter)
|
||||||
|
|
||||||
|
This module automatically exposes a "GPU-only regions" checkbox in the template UI. When checked, it shows only GPU-capable regions and auto-selects the first one. When unchecked, it shows all available regions.
|
||||||
|
|
||||||
|
## Available Regions
|
||||||
|
|
||||||
|
Refer to DigitalOcean’s official availability matrix for the most up-to-date information.
|
||||||
|
|
||||||
|
- GPU availability: currently only in `nyc2` and `tor1` (per DO docs). Others are non-GPU.
|
||||||
|
- See: https://docs.digitalocean.com/platform/regional-availability/
|
||||||
|
|
||||||
|
### All datacenters (GPU status)
|
||||||
|
|
||||||
|
- `nyc2` - New York, United States (Legacy) - **GPU available**
|
||||||
|
- `tor1` - Toronto, Canada - **GPU available**
|
||||||
|
- `nyc3` - New York, United States
|
||||||
|
- `ams3` - Amsterdam, Netherlands
|
||||||
|
- `sfo3` - San Francisco, United States
|
||||||
|
- `sgp1` - Singapore
|
||||||
|
- `lon1` - London, United Kingdom
|
||||||
|
- `fra1` - Frankfurt, Germany
|
||||||
|
- `blr1` - Bangalore, India
|
||||||
|
- `syd1` - Sydney, Australia
|
||||||
|
- `atl1` - Atlanta, United States
|
||||||
|
- `nyc1` - New York, United States (Legacy)
|
||||||
|
- `sfo2` - San Francisco, United States (Legacy)
|
||||||
|
- `sfo1` - San Francisco, United States (Legacy)
|
||||||
|
- `ams2` - Amsterdam, Netherlands (Legacy)
|
||||||
|
|
||||||
|
## Associated template
|
||||||
|
|
||||||
|
Also see the Coder template registry for a [DigitalOcean Droplet template](https://registry.coder.com/templates/digitalocean-droplet) that provisions workspaces as DigitalOcean Droplets.
|
||||||
45
registry/umair/modules/digitalocean-region/main.test.ts
Normal file
45
registry/umair/modules/digitalocean-region/main.test.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { describe, expect, it } from "bun:test";
|
||||||
|
import {
|
||||||
|
runTerraformApply,
|
||||||
|
runTerraformInit,
|
||||||
|
testRequiredVariables,
|
||||||
|
} from "~test";
|
||||||
|
|
||||||
|
describe("digitalocean-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("ams2");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("customized default", async () => {
|
||||||
|
const state = await runTerraformApply(import.meta.dir, {
|
||||||
|
regions: '["nyc1","ams3"]',
|
||||||
|
default: "ams3",
|
||||||
|
});
|
||||||
|
expect(state.outputs.value.value).toBe("ams3");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("gpu only invalid default", async () => {
|
||||||
|
const state = await runTerraformApply(import.meta.dir, {
|
||||||
|
regions: '["nyc1"]',
|
||||||
|
default: "nyc1",
|
||||||
|
gpu_only: "true",
|
||||||
|
});
|
||||||
|
expect(state.outputs.value.value).toBe("nyc1");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("gpu only valid default", async () => {
|
||||||
|
const state = await runTerraformApply(import.meta.dir, {
|
||||||
|
regions: '["tor1"]',
|
||||||
|
default: "tor1",
|
||||||
|
gpu_only: "true",
|
||||||
|
});
|
||||||
|
expect(state.outputs.value.value).toBe("tor1");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add more tests as needed for coder_parameter_order or other features
|
||||||
|
});
|
||||||
187
registry/umair/modules/digitalocean-region/main.tf
Normal file
187
registry/umair/modules/digitalocean-region/main.tf
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
terraform {
|
||||||
|
required_version = ">= 1.0"
|
||||||
|
|
||||||
|
required_providers {
|
||||||
|
coder = {
|
||||||
|
source = "coder/coder"
|
||||||
|
version = ">= 0.11"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "display_name" {
|
||||||
|
default = "DigitalOcean 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 = "Default region"
|
||||||
|
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 "single_zone_per_region" {
|
||||||
|
default = true
|
||||||
|
description = "Whether to only include a single zone per region."
|
||||||
|
type = bool
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "coder_parameter_order" {
|
||||||
|
type = number
|
||||||
|
description = "The order determines the position of a template parameter in the UI/CLI presentation. The lowest order is shown first and parameters with equal order are sorted by name (ascending order)."
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
data "coder_parameter" "gpu_only" {
|
||||||
|
name = "digitalocean_gpu_only"
|
||||||
|
display_name = "GPU-only regions"
|
||||||
|
description = "Show only regions with GPUs"
|
||||||
|
type = "bool"
|
||||||
|
form_type = "checkbox"
|
||||||
|
default = false
|
||||||
|
mutable = var.mutable
|
||||||
|
order = var.coder_parameter_order
|
||||||
|
}
|
||||||
|
|
||||||
|
locals {
|
||||||
|
zones = {
|
||||||
|
# Active datacenters (recommended for new workloads)
|
||||||
|
"nyc1" = {
|
||||||
|
gpu = false
|
||||||
|
name = "New York City, USA (NYC1)"
|
||||||
|
icon = "/emojis/1f1fa-1f1f8.png"
|
||||||
|
}
|
||||||
|
"nyc3" = {
|
||||||
|
gpu = false
|
||||||
|
name = "New York City, USA (NYC3)"
|
||||||
|
icon = "/emojis/1f1fa-1f1f8.png"
|
||||||
|
}
|
||||||
|
"ams3" = {
|
||||||
|
gpu = false
|
||||||
|
name = "Amsterdam, Netherlands"
|
||||||
|
icon = "/emojis/1f1f3-1f1f1.png"
|
||||||
|
}
|
||||||
|
"sfo3" = {
|
||||||
|
gpu = false
|
||||||
|
name = "San Francisco, USA"
|
||||||
|
icon = "/emojis/1f1fa-1f1f8.png"
|
||||||
|
}
|
||||||
|
"sgp1" = {
|
||||||
|
gpu = false
|
||||||
|
name = "Singapore"
|
||||||
|
icon = "/emojis/1f1f8-1f1ec.png"
|
||||||
|
}
|
||||||
|
"lon1" = {
|
||||||
|
gpu = false
|
||||||
|
name = "London, United Kingdom"
|
||||||
|
icon = "/emojis/1f1ec-1f1e7.png"
|
||||||
|
}
|
||||||
|
"fra1" = {
|
||||||
|
gpu = false
|
||||||
|
name = "Frankfurt, Germany"
|
||||||
|
icon = "/emojis/1f1e9-1f1ea.png"
|
||||||
|
}
|
||||||
|
"tor1" = {
|
||||||
|
gpu = true
|
||||||
|
name = "Toronto, Canada"
|
||||||
|
icon = "/emojis/1f1e8-1f1e6.png"
|
||||||
|
}
|
||||||
|
"blr1" = {
|
||||||
|
gpu = false
|
||||||
|
name = "Bangalore, India"
|
||||||
|
icon = "/emojis/1f1ee-1f1f3.png"
|
||||||
|
}
|
||||||
|
"syd1" = {
|
||||||
|
gpu = false
|
||||||
|
name = "Sydney, Australia"
|
||||||
|
icon = "/emojis/1f1e6-1f1fa.png"
|
||||||
|
}
|
||||||
|
"atl1" = {
|
||||||
|
gpu = false
|
||||||
|
name = "Atlanta, USA"
|
||||||
|
icon = "/emojis/1f1fa-1f1f8.png"
|
||||||
|
}
|
||||||
|
# Legacy/Restricted datacenters (not recommended for new workloads)
|
||||||
|
"nyc2" = {
|
||||||
|
gpu = true # GPU available but restricted to existing users
|
||||||
|
name = "New York City, USA (Legacy)"
|
||||||
|
icon = "/emojis/1f1fa-1f1f8.png"
|
||||||
|
}
|
||||||
|
"sfo2" = {
|
||||||
|
gpu = false # No GPU available per current regional availability
|
||||||
|
name = "San Francisco, USA (Legacy SFO2)"
|
||||||
|
icon = "/emojis/1f1fa-1f1f8.png"
|
||||||
|
}
|
||||||
|
"sfo1" = {
|
||||||
|
gpu = false # No GPU in legacy datacenter
|
||||||
|
name = "San Francisco, USA (Legacy SFO1)"
|
||||||
|
icon = "/emojis/1f1fa-1f1f8.png"
|
||||||
|
}
|
||||||
|
"ams2" = {
|
||||||
|
gpu = false # No GPU in legacy datacenter
|
||||||
|
name = "Amsterdam, Netherlands (Legacy)"
|
||||||
|
icon = "/emojis/1f1f3-1f1f1.png"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
locals {
|
||||||
|
allowed_regions = data.coder_parameter.gpu_only.value ? [for k, v in local.zones : k if v.gpu] : keys(local.zones)
|
||||||
|
default_region = data.coder_parameter.gpu_only.value ? (length([for k, v in local.zones : k if v.gpu]) > 0 ? [for k, v in local.zones : k if v.gpu][0] : null) : (var.default != null && var.default != "" ? var.default : keys(local.zones)[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
data "coder_parameter" "region" {
|
||||||
|
name = "digitalocean_region"
|
||||||
|
display_name = var.display_name
|
||||||
|
description = var.description
|
||||||
|
icon = "/icon/digital-ocean.svg"
|
||||||
|
mutable = var.mutable
|
||||||
|
form_type = "radio"
|
||||||
|
default = local.default_region
|
||||||
|
order = var.coder_parameter_order
|
||||||
|
dynamic "option" {
|
||||||
|
for_each = {
|
||||||
|
for k, v in local.zones : k => v
|
||||||
|
if contains(local.allowed_regions, k)
|
||||||
|
}
|
||||||
|
content {
|
||||||
|
icon = try(var.custom_icons[option.key], option.value.icon)
|
||||||
|
name = try(var.custom_names[option.key], option.value.name)
|
||||||
|
description = option.key
|
||||||
|
value = option.key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
output "value" {
|
||||||
|
description = "DigitalOcean region identifier."
|
||||||
|
value = data.coder_parameter.region.value
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user