terraform {
  required_providers {
    coder = {
      source  = "coder/coder"
      version = "~> 0.7.0"
    }
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~>3.47.0"
    }
  }
}

data "coder_parameter" "location" {
  name         = "location"
  display_name = "Location"
  description  = "What location should your workspace live in?"
  default      = "eastus"
  icon         = "/emojis/1f310.png"
  mutable      = false
  option {
    name  = "US (Virginia)"
    value = "eastus"
    icon  = "/emojis/1f1fa-1f1f8.png"
  }
  option {
    name  = "US (Virginia) 2"
    value = "eastus2"
    icon  = "/emojis/1f1fa-1f1f8.png"
  }
  option {
    name  = "US (Texas)"
    value = "southcentralus"
    icon  = "/emojis/1f1fa-1f1f8.png"
  }
  option {
    name  = "US (Washington)"
    value = "westus2"
    icon  = "/emojis/1f1fa-1f1f8.png"
  }
  option {
    name  = "US (Arizona)"
    value = "westus3"
    icon  = "/emojis/1f1fa-1f1f8.png"
  }
  option {
    name  = "US (Iowa)"
    value = "centralus"
    icon  = "/emojis/1f1fa-1f1f8.png"
  }
  option {
    name  = "Canada (Toronto)"
    value = "canadacentral"
    icon  = "/emojis/1f1e8-1f1e6.png"
  }
  option {
    name  = "Brazil (Sao Paulo)"
    value = "brazilsouth"
    icon  = "/emojis/1f1e7-1f1f7.png"
  }
  option {
    name  = "East Asia (Hong Kong)"
    value = "eastasia"
    icon  = "/emojis/1f1f0-1f1f7.png"
  }
  option {
    name  = "Southeast Asia (Singapore)"
    value = "southeastasia"
    icon  = "/emojis/1f1f0-1f1f7.png"
  }
  option {
    name  = "Australia (New South Wales)"
    value = "australiaeast"
    icon  = "/emojis/1f1e6-1f1fa.png"
  }
  option {
    name  = "China (Hebei)"
    value = "chinanorth3"
    icon  = "/emojis/1f1e8-1f1f3.png"
  }
  option {
    name  = "India (Pune)"
    value = "centralindia"
    icon  = "/emojis/1f1ee-1f1f3.png"
  }
  option {
    name  = "Japan (Tokyo)"
    value = "japaneast"
    icon  = "/emojis/1f1ef-1f1f5.png"
  }
  option {
    name  = "Korea (Seoul)"
    value = "koreacentral"
    icon  = "/emojis/1f1f0-1f1f7.png"
  }
  option {
    name  = "Europe (Ireland)"
    value = "northeurope"
    icon  = "/emojis/1f1ea-1f1fa.png"
  }
  option {
    name  = "Europe (Netherlands)"
    value = "westeurope"
    icon  = "/emojis/1f1ea-1f1fa.png"
  }
  option {
    name  = "France (Paris)"
    value = "francecentral"
    icon  = "/emojis/1f1eb-1f1f7.png"
  }
  option {
    name  = "Germany (Frankfurt)"
    value = "germanywestcentral"
    icon  = "/emojis/1f1e9-1f1ea.png"
  }
  option {
    name  = "Norway (Oslo)"
    value = "norwayeast"
    icon  = "/emojis/1f1f3-1f1f4.png"
  }
  option {
    name  = "Sweden (Gävle)"
    value = "swedencentral"
    icon  = "/emojis/1f1f8-1f1ea.png"
  }
  option {
    name  = "Switzerland (Zurich)"
    value = "switzerlandnorth"
    icon  = "/emojis/1f1e8-1f1ed.png"
  }
  option {
    name  = "Qatar (Doha)"
    value = "qatarcentral"
    icon  = "/emojis/1f1f6-1f1e6.png"
  }
  option {
    name  = "UAE (Dubai)"
    value = "uaenorth"
    icon  = "/emojis/1f1e6-1f1ea.png"
  }
  option {
    name  = "South Africa (Johannesburg)"
    value = "southafricanorth"
    icon  = "/emojis/1f1ff-1f1e6.png"
  }
  option {
    name  = "UK (London)"
    value = "uksouth"
    icon  = "/emojis/1f1ec-1f1e7.png"
  }
}

data "coder_parameter" "instance_type" {
  name         = "instance_type"
  display_name = "Instance type"
  description  = "What instance type should your workspace use?"
  default      = "Standard_B4ms"
  icon         = "/icon/azure.png"
  mutable      = false
  option {
    name  = "Standard_B1ms (1 vCPU, 2 GiB RAM)"
    value = "Standard_B1ms"
  }
  option {
    name  = "Standard_B2ms (2 vCPU, 8 GiB RAM)"
    value = "Standard_B2ms"
  }
  option {
    name  = "Standard_B4ms (4 vCPU, 16 GiB RAM)"
    value = "Standard_B4ms"
  }
  option {
    name  = "Standard_B8ms (8 vCPU, 32 GiB RAM)"
    value = "Standard_B8ms"
  }
  option {
    name  = "Standard_B12ms (12 vCPU, 48 GiB RAM)"
    value = "Standard_B12ms"
  }
  option {
    name  = "Standard_B16ms (16 vCPU, 64 GiB RAM)"
    value = "Standard_B16ms"
  }
  option {
    name  = "Standard_D2as_v5 (2 vCPU, 8 GiB RAM)"
    value = "Standard_D2as_v5"
  }
  option {
    name  = "Standard_D4as_v5 (4 vCPU, 16 GiB RAM)"
    value = "Standard_D4as_v5"
  }
  option {
    name  = "Standard_D8as_v5 (8 vCPU, 32 GiB RAM)"
    value = "Standard_D8as_v5"
  }
  option {
    name  = "Standard_D16as_v5 (16 vCPU, 64 GiB RAM)"
    value = "Standard_D16as_v5"
  }
  option {
    name  = "Standard_D32as_v5 (32 vCPU, 128 GiB RAM)"
    value = "Standard_D32as_v5"
  }
}

data "coder_parameter" "home_size" {
  name         = "home_size"
  display_name = "Home volume size"
  description  = "How large would you like your home volume to be (in GB)?"
  default      = 20
  type         = "number"
  icon         = "/icon/azure.png"
  mutable      = false
  validation {
    min = 1
    max = 1024
  }
}

provider "azurerm" {
  features {}
}

data "coder_workspace" "me" {
}

resource "coder_agent" "main" {
  arch = "amd64"
  os   = "linux"
  auth = "azure-instance-identity"

  metadata {
    key          = "cpu"
    display_name = "CPU Usage"
    interval     = 5
    timeout      = 5
    script       = <<-EOT
      #!/bin/bash
      set -e
      top -bn1 | grep "Cpu(s)" | awk '{print $2 + $4 "%"}'
    EOT
  }
  metadata {
    key          = "memory"
    display_name = "Memory Usage"
    interval     = 5
    timeout      = 5
    script       = <<-EOT
      #!/bin/bash
      set -e
      free -m | awk 'NR==2{printf "%.2f%%\t", $3*100/$2 }'
    EOT
  }
  metadata {
    key          = "disk"
    display_name = "Disk Usage"
    interval     = 600 # every 10 minutes
    timeout      = 30  # df can take a while on large filesystems
    script       = <<-EOT
      #!/bin/bash
      set -e
      df /home/coder | awk '$NF=="/"{printf "%s", $5}'
    EOT
  }
}

locals {
  prefix = "coder-${data.coder_workspace.me.owner}-${data.coder_workspace.me.name}"

  userdata = templatefile("cloud-config.yaml.tftpl", {
    username    = "coder" # Ensure this user/group does not exist in your VM image
    init_script = base64encode(coder_agent.main.init_script)
    hostname    = lower(data.coder_workspace.me.name)
  })
}

resource "azurerm_resource_group" "main" {
  name     = "${local.prefix}-resources"
  location = data.coder_parameter.location.value

  tags = {
    Coder_Provisioned = "true"
  }
}

// Uncomment here and in the azurerm_network_interface resource to obtain a public IP
#resource "azurerm_public_ip" "main" {
#  name                = "publicip"
#  resource_group_name = azurerm_resource_group.main.name
#  location            = azurerm_resource_group.main.location
#  allocation_method   = "Static"
#
#  tags = {
#    Coder_Provisioned = "true"
#  }
#}

resource "azurerm_virtual_network" "main" {
  name                = "network"
  address_space       = ["10.0.0.0/24"]
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name

  tags = {
    Coder_Provisioned = "true"
  }
}

resource "azurerm_subnet" "internal" {
  name                 = "internal"
  resource_group_name  = azurerm_resource_group.main.name
  virtual_network_name = azurerm_virtual_network.main.name
  address_prefixes     = ["10.0.0.0/29"]
}

resource "azurerm_network_interface" "main" {
  name                = "nic"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location

  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.internal.id
    private_ip_address_allocation = "Dynamic"
    // Uncomment for public IP address as well as azurerm_public_ip resource above
    //public_ip_address_id = azurerm_public_ip.main.id
  }

  tags = {
    Coder_Provisioned = "true"
  }
}

resource "azurerm_managed_disk" "home" {
  create_option        = "Empty"
  location             = azurerm_resource_group.main.location
  name                 = "home"
  resource_group_name  = azurerm_resource_group.main.name
  storage_account_type = "StandardSSD_LRS"
  disk_size_gb         = data.coder_parameter.home_size.value
}

// azurerm requires an SSH key (or password) for an admin user or it won't start a VM.  However,
// cloud-init overwrites this anyway, so we'll just use a dummy SSH key.
resource "tls_private_key" "dummy" {
  algorithm = "RSA"
  rsa_bits  = 4096
}

resource "azurerm_linux_virtual_machine" "main" {
  count               = data.coder_workspace.me.transition == "start" ? 1 : 0
  name                = "vm"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location
  size                = data.coder_parameter.instance_type.value
  // cloud-init overwrites this, so the value here doesn't matter
  admin_username = "adminuser"
  admin_ssh_key {
    public_key = tls_private_key.dummy.public_key_openssh
    username   = "adminuser"
  }

  network_interface_ids = [
    azurerm_network_interface.main.id,
  ]
  computer_name = lower(data.coder_workspace.me.name)
  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }
  source_image_reference {
    publisher = "Canonical"
    offer     = "0001-com-ubuntu-server-focal"
    sku       = "20_04-lts-gen2"
    version   = "latest"
  }
  user_data = base64encode(local.userdata)

  tags = {
    Coder_Provisioned = "true"
  }
}

resource "azurerm_virtual_machine_data_disk_attachment" "home" {
  count              = data.coder_workspace.me.transition == "start" ? 1 : 0
  managed_disk_id    = azurerm_managed_disk.home.id
  virtual_machine_id = azurerm_linux_virtual_machine.main[0].id
  lun                = "10"
  caching            = "ReadWrite"
}

resource "coder_metadata" "workspace_info" {
  count       = data.coder_workspace.me.start_count
  resource_id = azurerm_linux_virtual_machine.main[0].id

  item {
    key   = "type"
    value = azurerm_linux_virtual_machine.main[0].size
  }
}

resource "coder_metadata" "home_info" {
  resource_id = azurerm_managed_disk.home.id

  item {
    key   = "size"
    value = "${data.coder_parameter.home_size.value} GiB"
  }
}
