From 8d73582e4fb2f12f55c0d7b1296300717e939d3d Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Wed, 25 May 2022 19:53:54 +0300 Subject: [PATCH 01/12] feat: Add examples/do-droplet-linux for Digital Ocean Droplets --- examples/do-droplet-linux/README.md | 15 +++ .../do-droplet-linux/cloud-config.yaml.tftpl | 46 ++++++++ examples/do-droplet-linux/main.tf | 104 ++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 examples/do-droplet-linux/README.md create mode 100644 examples/do-droplet-linux/cloud-config.yaml.tftpl create mode 100644 examples/do-droplet-linux/main.tf diff --git a/examples/do-droplet-linux/README.md b/examples/do-droplet-linux/README.md new file mode 100644 index 0000000000000..15c291e4da807 --- /dev/null +++ b/examples/do-droplet-linux/README.md @@ -0,0 +1,15 @@ +--- +name: Develop in Linux on a Digital Ocean Droplet +description: Get started with Linux development on a Digital Ocean Droplet. +tags: [cloud, digitalocean] +--- + +# do-droplet-linux + +This is an example for deploying workspaces on Digital Ocean Droplets. + +## Requirements + +- Digital Ocean Personal Access Token (PAT) +- Digital Ocean Project ID (e.g. `doctl projects list`) + - Remove `variable "step2_do_project_id"` and `resource "digitalocean_project_resources" "project"` if you don't want project association. diff --git a/examples/do-droplet-linux/cloud-config.yaml.tftpl b/examples/do-droplet-linux/cloud-config.yaml.tftpl new file mode 100644 index 0000000000000..fcd19659c20fe --- /dev/null +++ b/examples/do-droplet-linux/cloud-config.yaml.tftpl @@ -0,0 +1,46 @@ +#cloud-config +users: + - name: coder + sudo: ["ALL=(ALL) NOPASSWD:ALL"] + groups: sudo + shell: /bin/bash +packages: + - git +mounts: + - [ + "LABEL=${home_volume_label}", + /home/coder, + auto, + "defaults,uid=1000,gid=1000", + ] +write_files: + - path: /opt/coder/init + permissions: "0755" + encoding: b64 + content: ${init_script} + - path: /etc/systemd/system/coder-agent.service + permissions: "0644" + content: | + [Unit] + Description=Coder Agent + After=network-online.target + Wants=network-online.target + + [Service] + User=coder + ExecStart=/opt/coder/init + Environment=CODER_AGENT_TOKEN=${coder_agent_token} + Restart=always + RestartSec=10 + TimeoutStopSec=90 + KillMode=process + + OOMScoreAdjust=-900 + SyslogIdentifier=coder-agent + + [Install] + WantedBy=multi-user.target +runcmd: + - chown coder:coder /home/coder + - systemctl enable coder-agent + - systemctl start coder-agent diff --git a/examples/do-droplet-linux/main.tf b/examples/do-droplet-linux/main.tf new file mode 100644 index 0000000000000..b9c360bfbe9bf --- /dev/null +++ b/examples/do-droplet-linux/main.tf @@ -0,0 +1,104 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + version = "0.4.1" + } + digitalocean = { + source = "digitalocean/digitalocean" + version = "~> 2.0" + } + } +} + +variable "step1_do_token" { + type = string + description = "Enter token (refer to docs at ...)" + sensitive = true + + validation { + condition = length(var.step1_do_token) == 71 && substr(var.step1_do_token, 0, 4) == "dop_" + error_message = "Invalid Digital Ocean Personal Access Token." + } +} + +variable "step2_do_project_id" { + type = string + description = "Enter project ID (see e.g. doctl projects list)" + sensitive = true + + validation { + condition = length(var.step2_do_project_id) == 36 + error_message = "Invalid Digital Ocean Project ID." + } +} + +variable "droplet_image" { + description = "Which Droplet image would you like to use for your workspace?" + default = "ubuntu-22-04-x64" + validation { + condition = contains(["debian-11-x64", "fedora-36-x64", "ubuntu-22-04-x64"], var.droplet_image) + error_message = "Value must be debian-11-x64, fedora-36-x64 or ubuntu-22-04-x64." + } +} + +variable "droplet_size" { + description = "Which Droplet configuration would you like to use?" + validation { + condition = contains(["s-1vcpu-1gb", "s-1vcpu-2gb", "s-2vcpu-2gb"], var.droplet_size) + error_message = "Value must be s-1vcpu-1gb, s-1vcpu-2gb or s-2vcpu-2gb." + } +} + +variable "region" { + description = "Which region would you like to use?" + validation { + condition = contains(["nyc1", "nyc3", "ams3"], var.region) + error_message = "Value must be nyc1, nyc3, or ams3." + } +} + +# Configure the DigitalOcean Provider +provider "digitalocean" { + token = var.step1_do_token +} + +data "coder_workspace" "me" {} + +resource "coder_agent" "dev" { + os = "linux" + arch = "amd64" +} + +resource "digitalocean_volume" "home_volume" { + region = var.region + name = "coder-${data.coder_workspace.me.owner}-${data.coder_workspace.me.name}-home" + size = 20 + initial_filesystem_type = "ext4" + initial_filesystem_label = "coder-home" +} + +resource "digitalocean_droplet" "workspace" { + region = var.region + count = data.coder_workspace.me.start_count + name = "coder-${data.coder_workspace.me.owner}-${data.coder_workspace.me.name}" + image = var.droplet_image + size = var.droplet_size + volume_ids = [digitalocean_volume.home_volume.id] + user_data = templatefile("cloud-config.yaml.tftpl", { + home_volume_label = digitalocean_volume.home_volume.initial_filesystem_label + init_script = base64encode(coder_agent.dev.init_script) + coder_agent_token = coder_agent.dev.token + }) +} + +# resource "digitalocean_project_resources" "project" { +# project = var.step2_do_project_id +# # Workaround for terraform plan when using count. +# resources = length(digitalocean_droplet.workspace) > 0 ? [ +# digitalocean_volume.home_volume.urn, +# digitalocean_droplet.workspace[0].urn +# ] : [ +# digitalocean_volume.home_volume.urn +# ] +# } From 0b2c8d466a4edf240b1587dca0fa853eaaf82d15 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Wed, 25 May 2022 20:51:18 +0300 Subject: [PATCH 02/12] feat: Add support for coder user username --- examples/do-droplet-linux/cloud-config.yaml.tftpl | 8 ++++---- examples/do-droplet-linux/main.tf | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/do-droplet-linux/cloud-config.yaml.tftpl b/examples/do-droplet-linux/cloud-config.yaml.tftpl index fcd19659c20fe..a2400b5461f33 100644 --- a/examples/do-droplet-linux/cloud-config.yaml.tftpl +++ b/examples/do-droplet-linux/cloud-config.yaml.tftpl @@ -1,6 +1,6 @@ #cloud-config users: - - name: coder + - name: ${username} sudo: ["ALL=(ALL) NOPASSWD:ALL"] groups: sudo shell: /bin/bash @@ -9,7 +9,7 @@ packages: mounts: - [ "LABEL=${home_volume_label}", - /home/coder, + "/home/${username}", auto, "defaults,uid=1000,gid=1000", ] @@ -27,7 +27,7 @@ write_files: Wants=network-online.target [Service] - User=coder + User=${username} ExecStart=/opt/coder/init Environment=CODER_AGENT_TOKEN=${coder_agent_token} Restart=always @@ -41,6 +41,6 @@ write_files: [Install] WantedBy=multi-user.target runcmd: - - chown coder:coder /home/coder + - chown ${username}:${username} /home/${username} - systemctl enable coder-agent - systemctl start coder-agent diff --git a/examples/do-droplet-linux/main.tf b/examples/do-droplet-linux/main.tf index b9c360bfbe9bf..64ace92bee0b3 100644 --- a/examples/do-droplet-linux/main.tf +++ b/examples/do-droplet-linux/main.tf @@ -86,6 +86,7 @@ resource "digitalocean_droplet" "workspace" { size = var.droplet_size volume_ids = [digitalocean_volume.home_volume.id] user_data = templatefile("cloud-config.yaml.tftpl", { + username = data.coder_workspace.me.owner home_volume_label = digitalocean_volume.home_volume.initial_filesystem_label init_script = base64encode(coder_agent.dev.init_script) coder_agent_token = coder_agent.dev.token From 2e98e1d5f813ea562114b2898c35a26f036baf8a Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Fri, 27 May 2022 11:58:21 +0300 Subject: [PATCH 03/12] chore: Rename do-droplet-linux => do-linux --- examples/{do-droplet-linux => do-linux}/README.md | 0 examples/{do-droplet-linux => do-linux}/cloud-config.yaml.tftpl | 0 examples/{do-droplet-linux => do-linux}/main.tf | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename examples/{do-droplet-linux => do-linux}/README.md (100%) rename examples/{do-droplet-linux => do-linux}/cloud-config.yaml.tftpl (100%) rename examples/{do-droplet-linux => do-linux}/main.tf (100%) diff --git a/examples/do-droplet-linux/README.md b/examples/do-linux/README.md similarity index 100% rename from examples/do-droplet-linux/README.md rename to examples/do-linux/README.md diff --git a/examples/do-droplet-linux/cloud-config.yaml.tftpl b/examples/do-linux/cloud-config.yaml.tftpl similarity index 100% rename from examples/do-droplet-linux/cloud-config.yaml.tftpl rename to examples/do-linux/cloud-config.yaml.tftpl diff --git a/examples/do-droplet-linux/main.tf b/examples/do-linux/main.tf similarity index 100% rename from examples/do-droplet-linux/main.tf rename to examples/do-linux/main.tf From b599799f0e1edaf26d43fd1d0465faa282b22fc8 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Fri, 27 May 2022 13:39:30 +0300 Subject: [PATCH 04/12] feat: Add regions, images, sizes and variable for home volume size --- examples/do-linux/main.tf | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/examples/do-linux/main.tf b/examples/do-linux/main.tf index 64ace92bee0b3..5fa81d0bb2e68 100644 --- a/examples/do-linux/main.tf +++ b/examples/do-linux/main.tf @@ -37,24 +37,34 @@ variable "droplet_image" { description = "Which Droplet image would you like to use for your workspace?" default = "ubuntu-22-04-x64" validation { - condition = contains(["debian-11-x64", "fedora-36-x64", "ubuntu-22-04-x64"], var.droplet_image) - error_message = "Value must be debian-11-x64, fedora-36-x64 or ubuntu-22-04-x64." + condition = contains(["ubuntu-22-04-x64", "ubuntu-20-04-x64", "fedora-36-x64", "fedora-35-x64", "debian-11-x64", "debian-10-x64", "centos-stream-9-x64", "centos-stream-8-x64", "rockylinux-8-x64", "rockylinux-8-4-x64"], var.droplet_image) + error_message = "Value must be ubuntu-22-04-x64, ubuntu-20-04-x64, fedora-36-x64, fedora-35-x64, debian-11-x64, debian-10-x64, centos-stream-9-x64, centos-stream-8-x64, rockylinux-8-x64 or rockylinux-8-4-x64." } } variable "droplet_size" { description = "Which Droplet configuration would you like to use?" validation { - condition = contains(["s-1vcpu-1gb", "s-1vcpu-2gb", "s-2vcpu-2gb"], var.droplet_size) - error_message = "Value must be s-1vcpu-1gb, s-1vcpu-2gb or s-2vcpu-2gb." + condition = contains(["s-1vcpu-1gb", "s-1vcpu-2gb", "s-2vcpu-2gb", "s-2vcpu-4gb", "s-4vcpu-8gb", "s-8vcpu-16gb"], var.droplet_size) + error_message = "Value must be s-1vcpu-1gb, s-1vcpu-2gb, s-2vcpu-2gb, s-2vcpu-4gb, s-4vcpu-8gb or s-8vcpu-16gb." + } +} + +variable "home_volume_size" { + type = number + description = "How large would you like your home volume to be (in GB)?" + default = 20 + validation { + condition = var.home_volume_size >= 1 + error_message = "Value must be greather than or equal to 1." } } variable "region" { description = "Which region would you like to use?" validation { - condition = contains(["nyc1", "nyc3", "ams3"], var.region) - error_message = "Value must be nyc1, nyc3, or ams3." + condition = contains(["nyc1", "nyc2", "nyc3", "sfo1", "sfo2", "sfo3", "ams2", "ams3", "sgp1", "lon1", "fra1", "tor1", "blr1"], var.region) + error_message = "Value must be nyc1, nyc2, nyc3, sfo1, sfo2, sfo3, ams2, ams3, sgp1, lon1, fra1, tor1 or blr1." } } @@ -73,7 +83,7 @@ resource "coder_agent" "dev" { resource "digitalocean_volume" "home_volume" { region = var.region name = "coder-${data.coder_workspace.me.owner}-${data.coder_workspace.me.name}-home" - size = 20 + size = var.home_volume_size initial_filesystem_type = "ext4" initial_filesystem_label = "coder-home" } From 08483d8dcd4b4887bd93afb9d493d8a5a6bae387 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Fri, 27 May 2022 13:40:38 +0300 Subject: [PATCH 05/12] feat: Set default values to skip in admin, docs, Fedora fix --- examples/do-linux/main.tf | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/examples/do-linux/main.tf b/examples/do-linux/main.tf index 5fa81d0bb2e68..cde99437d14a4 100644 --- a/examples/do-linux/main.tf +++ b/examples/do-linux/main.tf @@ -13,7 +13,7 @@ terraform { variable "step1_do_token" { type = string - description = "Enter token (refer to docs at ...)" + description = "Enter token (see documentation at https://docs.digitalocean.com/reference/api/create-personal-access-token/)" sensitive = true validation { @@ -24,7 +24,11 @@ variable "step1_do_token" { variable "step2_do_project_id" { type = string - description = "Enter project ID (see e.g. doctl projects list)" + description = <<-EOF + Enter project ID + + $ doctl projects list + EOF sensitive = true validation { @@ -33,7 +37,20 @@ variable "step2_do_project_id" { } } +variable "step3_do_admin_ssh_key" { + type = number + description = <<-EOF + Enter admin SSH key ID (some Droplet images require an SSH key to be set): + + Note: Leaving this as zero will break Fedora images and notify root passwords via email. + + $ doctl compute ssh-key list + EOF + sensitive = true +} + variable "droplet_image" { + type = string description = "Which Droplet image would you like to use for your workspace?" default = "ubuntu-22-04-x64" validation { @@ -43,7 +60,9 @@ variable "droplet_image" { } variable "droplet_size" { + type = string description = "Which Droplet configuration would you like to use?" + default = "s-1vcpu-1gb" validation { condition = contains(["s-1vcpu-1gb", "s-1vcpu-2gb", "s-2vcpu-2gb", "s-2vcpu-4gb", "s-4vcpu-8gb", "s-8vcpu-16gb"], var.droplet_size) error_message = "Value must be s-1vcpu-1gb, s-1vcpu-2gb, s-2vcpu-2gb, s-2vcpu-4gb, s-4vcpu-8gb or s-8vcpu-16gb." @@ -61,7 +80,9 @@ variable "home_volume_size" { } variable "region" { + type = string description = "Which region would you like to use?" + default = "ams3" validation { condition = contains(["nyc1", "nyc2", "nyc3", "sfo1", "sfo2", "sfo3", "ams2", "ams3", "sgp1", "lon1", "fra1", "tor1", "blr1"], var.region) error_message = "Value must be nyc1, nyc2, nyc3, sfo1, sfo2, sfo3, ams2, ams3, sgp1, lon1, fra1, tor1 or blr1." @@ -101,6 +122,8 @@ resource "digitalocean_droplet" "workspace" { init_script = base64encode(coder_agent.dev.init_script) coder_agent_token = coder_agent.dev.token }) + # Required to provision Fedora. + ssh_keys = concat([], var.step3_do_admin_ssh_key > 0 ? [var.step3_do_admin_ssh_key] : []) } # resource "digitalocean_project_resources" "project" { From a075df303161865658302b6cc2aee86d0a57389a Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Fri, 27 May 2022 13:54:24 +0300 Subject: [PATCH 06/12] chore: Improve SSH key message --- examples/do-linux/main.tf | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/do-linux/main.tf b/examples/do-linux/main.tf index cde99437d14a4..e24fd81c5483f 100644 --- a/examples/do-linux/main.tf +++ b/examples/do-linux/main.tf @@ -42,11 +42,18 @@ variable "step3_do_admin_ssh_key" { description = <<-EOF Enter admin SSH key ID (some Droplet images require an SSH key to be set): - Note: Leaving this as zero will break Fedora images and notify root passwords via email. + Can be set to zero. + + Note: Setting this to zero will break Fedora images and notify root passwords via email. $ doctl compute ssh-key list EOF sensitive = true + + validation { + condition = var.step3_do_admin_ssh_key >= 0 + error_message = "Invalid Digital Ocean SSH key ID, a number is required." + } } variable "droplet_image" { From 0e8e3380724a15bd7933c4729b01f5cb5d5ac97a Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Fri, 27 May 2022 13:55:28 +0300 Subject: [PATCH 07/12] chore: Remove unneeded concat --- examples/do-linux/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/do-linux/main.tf b/examples/do-linux/main.tf index e24fd81c5483f..e2d911ede9e4d 100644 --- a/examples/do-linux/main.tf +++ b/examples/do-linux/main.tf @@ -130,7 +130,7 @@ resource "digitalocean_droplet" "workspace" { coder_agent_token = coder_agent.dev.token }) # Required to provision Fedora. - ssh_keys = concat([], var.step3_do_admin_ssh_key > 0 ? [var.step3_do_admin_ssh_key] : []) + ssh_keys = var.step3_do_admin_ssh_key > 0 ? [var.step3_do_admin_ssh_key] : [] } # resource "digitalocean_project_resources" "project" { From 4fd4f7a7afc16ef1f02ce193ce536e1dcb803f24 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Fri, 27 May 2022 14:54:19 +0300 Subject: [PATCH 08/12] Update examples/do-linux/main.tf Co-authored-by: Cian Johnston --- examples/do-linux/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/do-linux/main.tf b/examples/do-linux/main.tf index e2d911ede9e4d..240afde0f6f95 100644 --- a/examples/do-linux/main.tf +++ b/examples/do-linux/main.tf @@ -82,7 +82,7 @@ variable "home_volume_size" { default = 20 validation { condition = var.home_volume_size >= 1 - error_message = "Value must be greather than or equal to 1." + error_message = "Value must be greater than or equal to 1." } } From 9bddba8874d425e76f33737011db409c721a54a3 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Fri, 27 May 2022 15:03:40 +0300 Subject: [PATCH 09/12] chore: Update readme --- examples/do-linux/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/do-linux/README.md b/examples/do-linux/README.md index 15c291e4da807..b99cc77465950 100644 --- a/examples/do-linux/README.md +++ b/examples/do-linux/README.md @@ -6,10 +6,12 @@ tags: [cloud, digitalocean] # do-droplet-linux -This is an example for deploying workspaces on Digital Ocean Droplets. +This is an example for deploying workspaces as Digital Ocean Droplets. ## Requirements - Digital Ocean Personal Access Token (PAT) - Digital Ocean Project ID (e.g. `doctl projects list`) - Remove `variable "step2_do_project_id"` and `resource "digitalocean_project_resources" "project"` if you don't want project association. +- (Optional) Digital Ocean SSH key ID (e.g. `doctl compute ssh-key list`) + - Only required for Fedora images to work. From bc96c590502b2e04e59468e36593ca73116e4a33 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Fri, 27 May 2022 15:06:43 +0300 Subject: [PATCH 10/12] chore: Add note about bug --- examples/do-linux/main.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/do-linux/main.tf b/examples/do-linux/main.tf index 240afde0f6f95..e9d611dddcde8 100644 --- a/examples/do-linux/main.tf +++ b/examples/do-linux/main.tf @@ -133,6 +133,7 @@ resource "digitalocean_droplet" "workspace" { ssh_keys = var.step3_do_admin_ssh_key > 0 ? [var.step3_do_admin_ssh_key] : [] } +# Temporarily disabled because it breaks SSH. (https://github.com/coder/coder/issues/1750) # resource "digitalocean_project_resources" "project" { # project = var.step2_do_project_id # # Workaround for terraform plan when using count. From 9489f87e20e454162cb68b61387cb153b051e3ed Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Fri, 27 May 2022 15:22:27 +0300 Subject: [PATCH 11/12] chore: Move example to examples/tempaltes/ --- examples/{ => templates}/do-linux/README.md | 0 examples/{ => templates}/do-linux/cloud-config.yaml.tftpl | 0 examples/{ => templates}/do-linux/main.tf | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename examples/{ => templates}/do-linux/README.md (100%) rename examples/{ => templates}/do-linux/cloud-config.yaml.tftpl (100%) rename examples/{ => templates}/do-linux/main.tf (100%) diff --git a/examples/do-linux/README.md b/examples/templates/do-linux/README.md similarity index 100% rename from examples/do-linux/README.md rename to examples/templates/do-linux/README.md diff --git a/examples/do-linux/cloud-config.yaml.tftpl b/examples/templates/do-linux/cloud-config.yaml.tftpl similarity index 100% rename from examples/do-linux/cloud-config.yaml.tftpl rename to examples/templates/do-linux/cloud-config.yaml.tftpl diff --git a/examples/do-linux/main.tf b/examples/templates/do-linux/main.tf similarity index 100% rename from examples/do-linux/main.tf rename to examples/templates/do-linux/main.tf From e0bef8163bc5fee8baff6c014cdd1db03db50ecf Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Fri, 27 May 2022 17:07:53 +0300 Subject: [PATCH 12/12] Update README.md --- examples/templates/do-linux/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/templates/do-linux/README.md b/examples/templates/do-linux/README.md index b99cc77465950..398b18501ba63 100644 --- a/examples/templates/do-linux/README.md +++ b/examples/templates/do-linux/README.md @@ -4,7 +4,7 @@ description: Get started with Linux development on a Digital Ocean Droplet. tags: [cloud, digitalocean] --- -# do-droplet-linux +# do-linux This is an example for deploying workspaces as Digital Ocean Droplets.