diff --git a/.icons/vsphere.svg b/.icons/vsphere.svg new file mode 100644 index 000000000..e50dd3ca8 --- /dev/null +++ b/.icons/vsphere.svg @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/registry/anis/templates/vmware-linux/README.md b/registry/anis/templates/vmware-linux/README.md new file mode 100644 index 000000000..e56957fc8 --- /dev/null +++ b/registry/anis/templates/vmware-linux/README.md @@ -0,0 +1,81 @@ +--- +display_name: VMware vSphere VM (Linux) +description: Provision VMware vSphere virtual machines as Coder workspaces +icon: ../../../../.icons/vsphere.svg +verified: false +tags: [vm, linux, vmware, vsphere] +--- + +# Summary + +Provision VMware vSphere virtual machines as [Coder workspaces](https://coder.com/docs/workspaces) using this Terraform template. + +## Prerequisites + +To deploy Coder workspaces on VMware vSphere, you'll need the following: + +### vSphere Resources + +Before deploying, ensure your vSphere environment has: + +- A **vSphere Datacenter** already created +- A **Compute Cluster** within that datacenter +- A **Datastore** with sufficient storage capacity +- A **Network** (port group) accessible by VMs +- A **VM Template** with Ubuntu and cloud-init configured + +### VM Template Requirements + +Your VM template must have + +- **cloud-init** installed and configured for VMware datasource + +### vSphere Authentication + +You'll need the following credentials: + +- **vSphere Server** (hostname or IP) +- **Username** +- **Password** +- **Datacenter Name** +- **Cluster Name** +- **Datastore Name** +- **Network Name** +- **VM Template Name** + +[VMware Provider Documentation](https://registry.terraform.io/providers/hashicorp/vsphere/latest/docs) + +--- + +## Example `.tfvars` File + +```hcl +vsphere_server = "vcenter.example.com" +vsphere_username = "administrator@vsphere.local" +vsphere_password = "YourSecurePassword123!" +vsphere_datacenter = "DC01" +cluster_name = "Cluster01" +vsphere_datastore = "datastore1" +vsphere_network = "VM Network" +vm_template = "ubuntu-22.04-cloud-init-template" +``` + +--- + +## Architecture + +This template creates: + +- A **vSphere Virtual Machine** per workspace +- **Dynamic resource allocation** (CPU, memory configurable by users) +- **Two disks**: root disk (from template) and separate home volume +- **Coder agent** installed via cloud-init +- **code-server** for browser-based VS Code access + +## Workspace Parameters + +Users can customize their workspace with: + +- **VCPUs**: 1, 2, 4, or 8 virtual CPUs +- **Memory**: 1, 2, 4, 8, 16, or 32 GB RAM +- **Home Volume Size**: 10-1024 GB (default: 20 GB) diff --git a/registry/anis/templates/vmware-linux/cloud-init/cloud-config.yaml.tftpl b/registry/anis/templates/vmware-linux/cloud-init/cloud-config.yaml.tftpl new file mode 100644 index 000000000..5faeab3d5 --- /dev/null +++ b/registry/anis/templates/vmware-linux/cloud-init/cloud-config.yaml.tftpl @@ -0,0 +1,56 @@ +#cloud-config +hostname: ${hostname} +users: + - name: ${username} + sudo: ["ALL=(ALL) NOPASSWD:ALL"] + groups: sudo + shell: /bin/bash +packages: + - git + - curl + - wget + - unzip +disk_setup: + /dev/sdb: + table_type: "gpt" + layout: true + overwrite: false +fs_setup: + - label: ${home_volume_label} + filesystem: ext4 + device: /dev/sdb + partition: auto +mounts: + - ["/dev/sdb", "/home/${username}", "ext4", "defaults", "0", "2"] +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=${username} + ExecStart=/opt/coder/init + Environment=CODER_AGENT_TOKEN=${coder_agent_token} + Restart=always + RestartSec=10 + TimeoutStopSec=90 + KillMode=process + + OOMScoreAdjust=-1000 + SyslogIdentifier=coder-agent + + [Install] + WantedBy=multi-user.target +runcmd: + - mkdir -p /home/${username} + - chown ${username}:${username} /home/${username} + - systemctl enable coder-agent + - systemctl start coder-agent diff --git a/registry/anis/templates/vmware-linux/main.tf b/registry/anis/templates/vmware-linux/main.tf new file mode 100644 index 000000000..64a604f93 --- /dev/null +++ b/registry/anis/templates/vmware-linux/main.tf @@ -0,0 +1,241 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + } + vsphere = { + source = "vmware/vsphere" + } + } +} + + +provider "vsphere" { + user = var.vsphere_username + password = var.vsphere_password + vsphere_server = var.vsphere_server + + allow_unverified_ssl = true +} + +variable "vsphere_username" { + type = string + default = "" +} +variable "vsphere_password" { + type = string + default = "" + sensitive = true +} +variable "vsphere_server" { + type = string + default = "" +} +variable "datacenter_name" { + type = string + default = "" +} +variable "cluster_name" { + type = string + default = "" +} +variable "datastore_name" { + type = string + default = "" + sensitive = true +} +variable "network_name" { + type = string + default = "" +} +variable "vm_template" { + type = string + default = "" +} + +locals { + vm_name = "coder-${lower(data.coder_workspace_owner.me.name)}-${lower(data.coder_workspace.me.name)}" + root_disk_label = substr("${local.vm_name}-root", 0, 32) + home_volume_label = substr("${local.vm_name}-home", 0, 32) +} + +data "coder_parameter" "instance_vcpus" { + name = "instance_vcpus" + display_name = "VCPUs" + description = "Number of VCPUs " + type = "number" + default = 1 + mutable = true + option { + name = "1 VCPUS" + value = 1 + } + option { + name = "2 VCPUS" + value = 2 + } + option { + name = "4 VCPUS" + value = 4 + } + option { + name = "8 VCPUS" + value = 8 + } +} + +data "coder_parameter" "instance_memory" { + name = "instance_memory" + display_name = "Memory (GB)" + description = "Amount of RAM" + type = "number" + default = 2048 + mutable = true + option { + name = "1 GB" + value = 1024 + } + option { + name = "2 GB" + value = 2048 + } + option { + name = "4 GB" + value = 4096 + } + option { + name = "8 GB" + value = 8192 + } + option { + name = "16 GB" + value = 16384 + } + option { + name = "32 GB" + value = 32768 + } +} + +data "coder_parameter" "home_volume_size" { + name = "home_volume_size" + display_name = "Home Volume Size (GB)" + description = "How large would you like your home volume to be (in GB)?" + type = "number" + default = 20 + mutable = true + + validation { + min = 10 + max = 1024 + monotonic = "increasing" + } +} + +data "coder_workspace" "me" {} +data "coder_workspace_owner" "me" {} + +resource "coder_agent" "main" { + os = "linux" + arch = "amd64" + + metadata { + key = "cpu" + display_name = "CPU Usage" + interval = 5 + timeout = 5 + script = "coder stat cpu" + } + metadata { + key = "memory" + display_name = "Memory Usage" + interval = 5 + timeout = 5 + script = "coder stat mem" + } + metadata { + key = "home" + display_name = "Home Usage" + interval = 600 # every 10 minutes + timeout = 30 # df can take a while on large filesystems + script = "coder stat disk --path /home/${lower(data.coder_workspace_owner.me.name)}" + } +} + +data "vsphere_datacenter" "dc" { + name = var.datacenter_name +} + +data "vsphere_datastore" "datastore" { + name = var.datastore_name + datacenter_id = "${data.vsphere_datacenter.dc.id}" +} + +data "vsphere_compute_cluster" "cluster" { + name = var.cluster_name + datacenter_id = "${data.vsphere_datacenter.dc.id}" +} + +data "vsphere_network" "network" { + name = var.network_name + datacenter_id = "${data.vsphere_datacenter.dc.id}" +} + +data "vsphere_virtual_machine" "template" { + name = var.vm_template + datacenter_id = "${data.vsphere_datacenter.dc.id}" +} + +locals { + cloud_init_config = templatefile("cloud-init/cloud-config.yaml.tftpl", { + hostname = local.vm_name + username = lower(data.coder_workspace_owner.me.name) + home_volume_label = local.home_volume_label + init_script = base64encode(coder_agent.main.init_script) + coder_agent_token = coder_agent.main.token + }) +} + +resource "vsphere_virtual_machine" "workspace" { + name = local.vm_name + firmware = data.vsphere_virtual_machine.template.firmware + resource_pool_id = "${data.vsphere_compute_cluster.cluster.resource_pool_id}" + datastore_id = "${data.vsphere_datastore.datastore.id}" + + num_cpus = data.coder_parameter.instance_vcpus.value + memory = data.coder_parameter.instance_memory.value + guest_id = "${data.vsphere_virtual_machine.template.guest_id}" + + scsi_type = "${data.vsphere_virtual_machine.template.scsi_type}" + + network_interface { + network_id = "${data.vsphere_network.network.id}" + adapter_type = "${data.vsphere_virtual_machine.template.network_interface_types[0]}" + } + + disk { + label = "disk0" + size = "${data.vsphere_virtual_machine.template.disks.0.size}" + } + disk { + label = local.home_volume_label + size = data.coder_parameter.home_volume_size.value + unit_number = 1 + } + extra_config = { + "guestinfo.userdata" = base64encode(local.cloud_init_config) + "guestinfo.userdata.encoding" = "base64" + } + clone { + template_uuid = "${data.vsphere_virtual_machine.template.id}" + } +} + +module "code-server" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/code-server/coder" + version = "~> 1.0" + + agent_id = coder_agent.main.id + order = 1 +} \ No newline at end of file