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 }