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 digitalocean = {
7 source = "digitalocean/digitalocean"
8 }
9 }
10}
11
12provider "coder" {
13}
14
15variable "step1_do_project_id" {
16 type = string
17 description = <<-EOF
18 Enter project ID
19
20 $ doctl projects list
21 EOF
22 sensitive = true
23
24 validation {
25 # make sure length of alphanumeric string is 36
26 condition = length(var.step1_do_project_id) == 36
27 error_message = "Invalid Digital Ocean Project ID."
28 }
29
30}
31
32variable "step2_do_admin_ssh_key" {
33 type = number
34 description = <<-EOF
35 Enter admin SSH key ID (some Droplet images require an SSH key to be set):
36
37 Can be set to "0" for no key.
38
39 Note: Setting this to zero will break Fedora images and notify root passwords via email.
40
41 $ doctl compute ssh-key list
42 EOF
43 sensitive = true
44
45 validation {
46 condition = var.step2_do_admin_ssh_key >= 0
47 error_message = "Invalid Digital Ocean SSH key ID, a number is required."
48 }
49}
50
51data "coder_parameter" "droplet_image" {
52 name = "droplet_image"
53 display_name = "Droplet image"
54 description = "Which Droplet image would you like to use?"
55 default = "ubuntu-22-04-x64"
56 type = "string"
57 mutable = false
58 option {
59 name = "AlmaLinux 9"
60 value = "almalinux-9-x64"
61 icon = "/icon/almalinux.svg"
62 }
63 option {
64 name = "AlmaLinux 8"
65 value = "almalinux-8-x64"
66 icon = "/icon/almalinux.svg"
67 }
68 option {
69 name = "Fedora 39"
70 value = "fedora-39-x64"
71 icon = "/icon/fedora.svg"
72 }
73 option {
74 name = "Fedora 38"
75 value = "fedora-38-x64"
76 icon = "/icon/fedora.svg"
77 }
78 option {
79 name = "CentOS Stream 9"
80 value = "centos-stream-9-x64"
81 icon = "/icon/centos.svg"
82 }
83 option {
84 name = "CentOS Stream 8"
85 value = "centos-stream-8-x64"
86 icon = "/icon/centos.svg"
87 }
88 option {
89 name = "Debian 12"
90 value = "debian-12-x64"
91 icon = "/icon/debian.svg"
92 }
93 option {
94 name = "Debian 11"
95 value = "debian-11-x64"
96 icon = "/icon/debian.svg"
97 }
98 option {
99 name = "Debian 10"
100 value = "debian-10-x64"
101 icon = "/icon/debian.svg"
102 }
103 option {
104 name = "Rocky Linux 9"
105 value = "rockylinux-9-x64"
106 icon = "/icon/rockylinux.svg"
107 }
108 option {
109 name = "Rocky Linux 8"
110 value = "rockylinux-8-x64"
111 icon = "/icon/rockylinux.svg"
112 }
113 option {
114 name = "Ubuntu 22.04 (LTS)"
115 value = "ubuntu-22-04-x64"
116 icon = "/icon/ubuntu.svg"
117 }
118 option {
119 name = "Ubuntu 20.04 (LTS)"
120 value = "ubuntu-20-04-x64"
121 icon = "/icon/ubuntu.svg"
122 }
123}
124
125data "coder_parameter" "droplet_size" {
126 name = "droplet_size"
127 display_name = "Droplet size"
128 description = "Which Droplet configuration would you like to use?"
129 default = "s-1vcpu-1gb"
130 type = "string"
131 icon = "/icon/memory.svg"
132 mutable = false
133 # s-1vcpu-512mb-10gb is unsupported in tor1, blr1, lon1, sfo2, and nyc3 regions
134 # s-8vcpu-16gb access requires a support ticket with Digital Ocean
135 option {
136 name = "1 vCPU, 1 GB RAM"
137 value = "s-1vcpu-1gb"
138 }
139 option {
140 name = "1 vCPU, 2 GB RAM"
141 value = "s-1vcpu-2gb"
142 }
143 option {
144 name = "2 vCPU, 2 GB RAM"
145 value = "s-2vcpu-2gb"
146 }
147 option {
148 name = "2 vCPU, 4 GB RAM"
149 value = "s-2vcpu-4gb"
150 }
151 option {
152 name = "4 vCPU, 8 GB RAM"
153 value = "s-4vcpu-8gb"
154 }
155}
156
157data "coder_parameter" "home_volume_size" {
158 name = "home_volume_size"
159 display_name = "Home volume size"
160 description = "How large would you like your home volume to be (in GB)?"
161 type = "number"
162 default = "20"
163 mutable = false
164 validation {
165 min = 1
166 max = 100 # Sizes larger than 100 GB require a support ticket with Digital Ocean
167 }
168}
169
170data "coder_parameter" "region" {
171 name = "region"
172 display_name = "Region"
173 description = "This is the region where your workspace will be created."
174 icon = "/emojis/1f30e.png"
175 type = "string"
176 default = "ams3"
177 mutable = false
178 # nyc1, sfo1, and ams2 regions were excluded because they do not support volumes, which are used to persist data while decreasing cost
179 option {
180 name = "Canada (Toronto)"
181 value = "tor1"
182 icon = "/emojis/1f1e8-1f1e6.png"
183 }
184 option {
185 name = "Germany (Frankfurt)"
186 value = "fra1"
187 icon = "/emojis/1f1e9-1f1ea.png"
188 }
189 option {
190 name = "India (Bangalore)"
191 value = "blr1"
192 icon = "/emojis/1f1ee-1f1f3.png"
193 }
194 option {
195 name = "Netherlands (Amsterdam)"
196 value = "ams3"
197 icon = "/emojis/1f1f3-1f1f1.png"
198 }
199 option {
200 name = "Singapore"
201 value = "sgp1"
202 icon = "/emojis/1f1f8-1f1ec.png"
203 }
204 option {
205 name = "United Kingdom (London)"
206 value = "lon1"
207 icon = "/emojis/1f1ec-1f1e7.png"
208 }
209 option {
210 name = "United States (California - 2)"
211 value = "sfo2"
212 icon = "/emojis/1f1fa-1f1f8.png"
213 }
214 option {
215 name = "United States (California - 3)"
216 value = "sfo3"
217 icon = "/emojis/1f1fa-1f1f8.png"
218 }
219 option {
220 name = "United States (New York - 1)"
221 value = "nyc1"
222 icon = "/emojis/1f1fa-1f1f8.png"
223 }
224 option {
225 name = "United States (New York - 3)"
226 value = "nyc3"
227 icon = "/emojis/1f1fa-1f1f8.png"
228 }
229}
230
231# Configure the DigitalOcean Provider
232provider "digitalocean" {
233 # Recommended: use environment variable DIGITALOCEAN_TOKEN with your personal access token when starting coderd
234 # alternatively, you can pass the token via a variable.
235}
236
237data "coder_workspace" "me" {}
238data "coder_workspace_owner" "me" {}
239
240resource "coder_agent" "main" {
241 os = "linux"
242 arch = "amd64"
243
244 metadata {
245 key = "cpu"
246 display_name = "CPU Usage"
247 interval = 5
248 timeout = 5
249 script = "coder stat cpu"
250 }
251 metadata {
252 key = "memory"
253 display_name = "Memory Usage"
254 interval = 5
255 timeout = 5
256 script = "coder stat mem"
257 }
258 metadata {
259 key = "home"
260 display_name = "Home Usage"
261 interval = 600 # every 10 minutes
262 timeout = 30 # df can take a while on large filesystems
263 script = "coder stat disk --path /home/${lower(data.coder_workspace_owner.me.name)}"
264 }
265}
266
267resource "digitalocean_volume" "home_volume" {
268 region = data.coder_parameter.region.value
269 name = "coder-${data.coder_workspace.me.id}-home"
270 size = data.coder_parameter.home_volume_size.value
271 initial_filesystem_type = "ext4"
272 initial_filesystem_label = "coder-home"
273 # Protect the volume from being deleted due to changes in attributes.
274 lifecycle {
275 ignore_changes = all
276 }
277}
278
279resource "digitalocean_droplet" "workspace" {
280 region = data.coder_parameter.region.value
281 count = data.coder_workspace.me.start_count
282 name = "coder-${lower(data.coder_workspace_owner.me.name)}-${lower(data.coder_workspace.me.name)}"
283 image = data.coder_parameter.droplet_image.value
284 size = data.coder_parameter.droplet_size.value
285
286 volume_ids = [digitalocean_volume.home_volume.id]
287 user_data = templatefile("cloud-config.yaml.tftpl", {
288 username = lower(data.coder_workspace_owner.me.name)
289 home_volume_label = digitalocean_volume.home_volume.initial_filesystem_label
290 init_script = base64encode(coder_agent.main.init_script)
291 coder_agent_token = coder_agent.main.token
292 })
293 # Required to provision Fedora.
294 ssh_keys = var.step2_do_admin_ssh_key > 0 ? [var.step2_do_admin_ssh_key] : []
295}
296
297resource "digitalocean_project_resources" "project" {
298 project = var.step1_do_project_id
299 # Workaround for terraform plan when using count.
300 resources = length(digitalocean_droplet.workspace) > 0 ? [
301 digitalocean_volume.home_volume.urn,
302 digitalocean_droplet.workspace[0].urn
303 ] : [
304 digitalocean_volume.home_volume.urn
305 ]
306}
307
308resource "coder_metadata" "workspace-info" {
309 count = data.coder_workspace.me.start_count
310 resource_id = digitalocean_droplet.workspace[0].id
311
312 item {
313 key = "region"
314 value = digitalocean_droplet.workspace[0].region
315 }
316 item {
317 key = "image"
318 value = digitalocean_droplet.workspace[0].image
319 }
320}
321
322resource "coder_metadata" "volume-info" {
323 resource_id = digitalocean_volume.home_volume.id
324
325 item {
326 key = "size"
327 value = "${digitalocean_volume.home_volume.size} GiB"
328 }
329}
330