Copy and paste the following into main.tf
and run coder template push
:
1terraform {
2 required_providers {
3 coder = {
4 source = "coder/coder"
5 }
6 azurerm = {
7 source = "hashicorp/azurerm"
8 }
9 }
10}
11
12# See https://registry.coder.com/modules/azure-region
13module "azure_region" {
14 source = "registry.coder.com/modules/azure-region/coder"
15
16 # This ensures that the latest version of the module gets downloaded, you can also pin the module version to prevent breaking changes in production.
17 version = ">= 1.0.0"
18
19 default = "eastus"
20}
21
22data "coder_parameter" "instance_type" {
23 name = "instance_type"
24 display_name = "Instance type"
25 description = "What instance type should your workspace use?"
26 default = "Standard_B4ms"
27 icon = "/icon/azure.png"
28 mutable = false
29 option {
30 name = "Standard_B1ms (1 vCPU, 2 GiB RAM)"
31 value = "Standard_B1ms"
32 }
33 option {
34 name = "Standard_B2ms (2 vCPU, 8 GiB RAM)"
35 value = "Standard_B2ms"
36 }
37 option {
38 name = "Standard_B4ms (4 vCPU, 16 GiB RAM)"
39 value = "Standard_B4ms"
40 }
41 option {
42 name = "Standard_B8ms (8 vCPU, 32 GiB RAM)"
43 value = "Standard_B8ms"
44 }
45 option {
46 name = "Standard_B12ms (12 vCPU, 48 GiB RAM)"
47 value = "Standard_B12ms"
48 }
49 option {
50 name = "Standard_B16ms (16 vCPU, 64 GiB RAM)"
51 value = "Standard_B16ms"
52 }
53 option {
54 name = "Standard_D2as_v5 (2 vCPU, 8 GiB RAM)"
55 value = "Standard_D2as_v5"
56 }
57 option {
58 name = "Standard_D4as_v5 (4 vCPU, 16 GiB RAM)"
59 value = "Standard_D4as_v5"
60 }
61 option {
62 name = "Standard_D8as_v5 (8 vCPU, 32 GiB RAM)"
63 value = "Standard_D8as_v5"
64 }
65 option {
66 name = "Standard_D16as_v5 (16 vCPU, 64 GiB RAM)"
67 value = "Standard_D16as_v5"
68 }
69 option {
70 name = "Standard_D32as_v5 (32 vCPU, 128 GiB RAM)"
71 value = "Standard_D32as_v5"
72 }
73}
74
75data "coder_parameter" "home_size" {
76 name = "home_size"
77 display_name = "Home volume size"
78 description = "How large would you like your home volume to be (in GB)?"
79 default = 20
80 type = "number"
81 icon = "/icon/azure.png"
82 mutable = false
83 validation {
84 min = 1
85 max = 1024
86 }
87}
88
89provider "azurerm" {
90 features {}
91}
92
93data "coder_workspace" "me" {}
94data "coder_workspace_owner" "me" {}
95
96resource "coder_agent" "main" {
97 arch = "amd64"
98 os = "linux"
99 auth = "azure-instance-identity"
100
101 metadata {
102 key = "cpu"
103 display_name = "CPU Usage"
104 interval = 5
105 timeout = 5
106 script = <<-EOT
107 #!/bin/bash
108 set -e
109 top -bn1 | grep "Cpu(s)" | awk '{print $2 + $4 "%"}'
110 EOT
111 }
112 metadata {
113 key = "memory"
114 display_name = "Memory Usage"
115 interval = 5
116 timeout = 5
117 script = <<-EOT
118 #!/bin/bash
119 set -e
120 free -m | awk 'NR==2{printf "%.2f%%\t", $3*100/$2 }'
121 EOT
122 }
123 metadata {
124 key = "disk"
125 display_name = "Disk Usage"
126 interval = 600 # every 10 minutes
127 timeout = 30 # df can take a while on large filesystems
128 script = <<-EOT
129 #!/bin/bash
130 set -e
131 df /home/coder | awk '$NF=="/"{printf "%s", $5}'
132 EOT
133 }
134}
135
136# See https://registry.coder.com/modules/code-server
137module "code-server" {
138 count = data.coder_workspace.me.start_count
139 source = "registry.coder.com/modules/code-server/coder"
140
141 # This ensures that the latest version of the module gets downloaded, you can also pin the module version to prevent breaking changes in production.
142 version = ">= 1.0.0"
143
144 agent_id = coder_agent.main.id
145 order = 1
146}
147
148# See https://registry.coder.com/modules/jetbrains-gateway
149module "jetbrains_gateway" {
150 count = data.coder_workspace.me.start_count
151 source = "registry.coder.com/modules/jetbrains-gateway/coder"
152
153 # JetBrains IDEs to make available for the user to select
154 jetbrains_ides = ["IU", "PY", "WS", "PS", "RD", "CL", "GO", "RM"]
155 default = "IU"
156
157 # Default folder to open when starting a JetBrains IDE
158 folder = "/home/coder"
159
160 # This ensures that the latest version of the module gets downloaded, you can also pin the module version to prevent breaking changes in production.
161 version = ">= 1.0.0"
162
163 agent_id = coder_agent.main.id
164 agent_name = "main"
165 order = 2
166}
167
168locals {
169 prefix = "coder-${data.coder_workspace_owner.me.name}-${data.coder_workspace.me.name}"
170
171 userdata = templatefile("cloud-config.yaml.tftpl", {
172 username = "coder" # Ensure this user/group does not exist in your VM image
173 init_script = base64encode(coder_agent.main.init_script)
174 hostname = lower(data.coder_workspace.me.name)
175 })
176}
177
178resource "azurerm_resource_group" "main" {
179 name = "${local.prefix}-resources"
180 location = module.azure_region.value
181
182 tags = {
183 Coder_Provisioned = "true"
184 }
185}
186
187// Uncomment here and in the azurerm_network_interface resource to obtain a public IP
188#resource "azurerm_public_ip" "main" {
189# name = "publicip"
190# resource_group_name = azurerm_resource_group.main.name
191# location = azurerm_resource_group.main.location
192# allocation_method = "Static"
193#
194# tags = {
195# Coder_Provisioned = "true"
196# }
197#}
198
199resource "azurerm_virtual_network" "main" {
200 name = "network"
201 address_space = ["10.0.0.0/24"]
202 location = azurerm_resource_group.main.location
203 resource_group_name = azurerm_resource_group.main.name
204
205 tags = {
206 Coder_Provisioned = "true"
207 }
208}
209
210resource "azurerm_subnet" "internal" {
211 name = "internal"
212 resource_group_name = azurerm_resource_group.main.name
213 virtual_network_name = azurerm_virtual_network.main.name
214 address_prefixes = ["10.0.0.0/29"]
215}
216
217resource "azurerm_network_interface" "main" {
218 name = "nic"
219 resource_group_name = azurerm_resource_group.main.name
220 location = azurerm_resource_group.main.location
221
222 ip_configuration {
223 name = "internal"
224 subnet_id = azurerm_subnet.internal.id
225 private_ip_address_allocation = "Dynamic"
226 // Uncomment for public IP address as well as azurerm_public_ip resource above
227 //public_ip_address_id = azurerm_public_ip.main.id
228 }
229
230 tags = {
231 Coder_Provisioned = "true"
232 }
233}
234
235resource "azurerm_managed_disk" "home" {
236 create_option = "Empty"
237 location = azurerm_resource_group.main.location
238 name = "home"
239 resource_group_name = azurerm_resource_group.main.name
240 storage_account_type = "StandardSSD_LRS"
241 disk_size_gb = data.coder_parameter.home_size.value
242}
243
244// azurerm requires an SSH key (or password) for an admin user or it won't start a VM. However,
245// cloud-init overwrites this anyway, so we'll just use a dummy SSH key.
246resource "tls_private_key" "dummy" {
247 algorithm = "RSA"
248 rsa_bits = 4096
249}
250
251resource "azurerm_linux_virtual_machine" "main" {
252 count = data.coder_workspace.me.transition == "start" ? 1 : 0
253 name = "vm"
254 resource_group_name = azurerm_resource_group.main.name
255 location = azurerm_resource_group.main.location
256 size = data.coder_parameter.instance_type.value
257 // cloud-init overwrites this, so the value here doesn't matter
258 admin_username = "adminuser"
259 admin_ssh_key {
260 public_key = tls_private_key.dummy.public_key_openssh
261 username = "adminuser"
262 }
263
264 network_interface_ids = [
265 azurerm_network_interface.main.id,
266 ]
267 computer_name = lower(data.coder_workspace.me.name)
268 os_disk {
269 caching = "ReadWrite"
270 storage_account_type = "Standard_LRS"
271 }
272 source_image_reference {
273 publisher = "Canonical"
274 offer = "0001-com-ubuntu-server-focal"
275 sku = "20_04-lts-gen2"
276 version = "latest"
277 }
278 user_data = base64encode(local.userdata)
279
280 tags = {
281 Coder_Provisioned = "true"
282 }
283}
284
285resource "azurerm_virtual_machine_data_disk_attachment" "home" {
286 count = data.coder_workspace.me.transition == "start" ? 1 : 0
287 managed_disk_id = azurerm_managed_disk.home.id
288 virtual_machine_id = azurerm_linux_virtual_machine.main[0].id
289 lun = "10"
290 caching = "ReadWrite"
291}
292
293resource "coder_metadata" "workspace_info" {
294 count = data.coder_workspace.me.start_count
295 resource_id = azurerm_linux_virtual_machine.main[0].id
296
297 item {
298 key = "type"
299 value = azurerm_linux_virtual_machine.main[0].size
300 }
301}
302
303resource "coder_metadata" "home_info" {
304 resource_id = azurerm_managed_disk.home.id
305
306 item {
307 key = "size"
308 value = "${data.coder_parameter.home_size.value} GiB"
309 }
310}
311