Files
coder-templates/iaas-instance/main.tf
2026-03-22 02:35:30 +01:00

196 lines
5.0 KiB
HCL

terraform {
required_providers {
coder = {
source = "coder/coder"
}
incus = {
source = "lxc/incus"
version = "1.0.2"
}
}
}
provider "coder" {}
provider "incus" {
accept_remote_certificate = true
generate_client_certificates = true
default_remote = var.remote_name
remote {
name = var.remote_name
address = var.remote_address
token = var.remote_token
}
}
variable "remote_name" {
description = "Incus remote host/cluster name"
type = string
default = "remote"
}
variable "remote_address" {
description = "Incus remote address (e.g. https://lxc.example.com:8443)"
type = string
}
variable "remote_token" {
description = "Incus remote API token with permissions to manage instances"
type = string
sensitive = true
}
variable "remote_coder_project" {
description = "Incus remote project to use for instances"
type = string
default = "default"
}
variable "remote_coder_network" {
description = "Incus remote network to attach instances to"
type = string
}
variable "remote_coder_profiles" {
description = "Incus remote profiles to use for instances"
type = list(string)
default = []
}
variable "remote_coder_images" {
description = "Incus remote images to use for instances"
type = list(string)
default = []
}
variable "remote_coder_instance_type" {
description = "Incus remote instance type (e.g. virtual-machine or container)"
type = string
default = "virtual-machine"
}
variable "remote_coder_storage_pool" {
description = "Incus remote storage pool to use for instances"
type = string
}
data "coder_workspace" "me" {}
data "coder_workspace_owner" "me" {}
# data "coder_parameter" "isolated" { # TO BE IMPLEMENTED - requires network configuration in the module
# name = "isolated"
# display_name = "Isolated Environment(dedicated network)"
# type = "bool"
# mutable = true
# default = false
# }
data "coder_parameter" "profile" {
name = "profile"
display_name = "Instance Profile"
type = "string"
mutable = true
dynamic "option" {
for_each = [for p in var.remote_coder_profiles : { name = title(p), value = p }]
content {
name = option.value.name
value = option.value.value
}
}
}
data "coder_parameter" "image" {
name = "image"
display_name = "Instance Image"
type = "string"
mutable = true
dynamic "option" {
for_each = [for img in var.remote_coder_images : { name = title(img), value = img }]
content {
name = option.value.name
value = option.value.value
}
}
}
resource "coder_agent" "dev" {
arch = "amd64"
os = "linux"
env = {
GIT_AUTHOR_NAME = data.coder_workspace_owner.me.name
GIT_AUTHOR_EMAIL = data.coder_workspace_owner.me.email
}
startup_script_behavior = "non-blocking"
startup_script = <<-EOT
set -e
# Add any startup scripts here
EOT
metadata {
display_name = "CPU Usage"
key = "cpu_usage"
script = "coder stat cpu"
interval = 10
timeout = 1
order = 1
}
metadata {
display_name = "RAM Usage"
key = "ram_usage"
script = "coder stat mem"
interval = 10
timeout = 1
order = 2
}
metadata {
display_name = "Disk Usage"
key = "disk_usage"
script = "coder stat disk"
interval = 600
timeout = 30
order = 3
}
}
locals {
hostname = lower(data.coder_workspace.me.name)
vm_name = "coder-${lower(data.coder_workspace_owner.me.name)}-${local.hostname}"
snippet_filename = "${local.vm_name}.yml"
base_user = replace(replace(replace(lower(data.coder_workspace_owner.me.name), " ", "-"), "/", "-"), "@", "-") # to avoid special characters in the username
linux_user = contains(["root", "admin", "daemon", "bin", "sys"], local.base_user) ? "${local.base_user}1" : local.base_user # to avoid conflict with system users
rendered_user_data = templatefile("${path.module}/cloud-init/user-data.tftpl", {
coder_token = coder_agent.dev.token
coder_init_script_b64 = base64encode(coder_agent.dev.init_script)
hostname = local.vm_name
linux_user = local.linux_user
})
}
resource "incus_instance" "workspace" {
count = data.coder_workspace.me.start_count
remote = var.remote_name
name = local.vm_name
image = data.coder_parameter.image.value
type = var.remote_coder_instance_type
profiles = data.coder_parameter.profile.value != "" ? [data.coder_parameter.profile.value] : [] # if profile is not selected, use no profile instead of default
project = var.remote_coder_project
running = true
config = {
"cloud-init.user-data" = local.rendered_user_data
}
}
module "code-server" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/code-server/coder"
version = "1.3.1"
agent_id = coder_agent.dev.id
}