Skip to content

azure-linux example template #3348

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions examples/templates/azure-linux/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
name: Develop in Linux on Azure
description: Get started with Linux development on Microsoft Azure.
tags: [cloud, azure, linux]
---

# azure-linux

To get started, run `coder templates init`. When prompted, select this template.
Follow the on-screen instructions to proceed.

## Authentication

This template assumes that coderd is run in an environment that is authenticated
with Azure. For example, run `az login` then `az account set --subscription=<id>`
to import credentials on the system and user running coderd. For other ways to
authenticate [consult the Terraform docs](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs#authenticating-to-azure).
56 changes: 56 additions & 0 deletions examples/templates/azure-linux/cloud-config.yaml.tftpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#cloud-config
cloud_final_modules:
- [scripts-user, always]
bootcmd:
# work around https://github.com/hashicorp/terraform-provider-azurerm/issues/6117
- until [ -e /dev/disk/azure/scsi1/lun10 ]; do sleep 1; done
device_aliases:
homedir: /dev/disk/azure/scsi1/lun10
disk_setup:
homedir:
table_type: gpt
layout: true
fs_setup:
- label: coder_home
filesystem: ext4
device: homedir.1
mounts:
- ["LABEL=coder_home", "/home/${username}"]
hostname: ${hostname}
users:
- name: ${username}
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
groups: sudo
shell: /bin/bash
packages:
- git
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
Restart=always
RestartSec=10
TimeoutStopSec=90
KillMode=process

OOMScoreAdjust=-900
SyslogIdentifier=coder-agent

[Install]
WantedBy=multi-user.target
runcmd:
- chown ${username}:${username} /home/${username}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- chown ${username}:${username} /home/${username}
- chown -R ${username}:${username} /home/${username}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I worry this could rewrite ownership in unintended ways, especially around groups

- systemctl enable coder-agent
- systemctl start coder-agent
211 changes: 211 additions & 0 deletions examples/templates/azure-linux/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
terraform {
required_providers {
coder = {
source = "coder/coder"
version = "0.4.3"
}
azurerm = {
source = "hashicorp/azurerm"
version = "=3.0.0"
}
}
}

variable "location" {
description = "What location should your workspace live in?"
default = "eastus"
validation {
condition = contains([
"eastus",
"southcentralus",
"westus2",
"australiaeast",
"southeastasia",
"northeurope",
"westeurope",
"centralindia",
"eastasia",
"japaneast",
"brazilsouth",
"asia",
"asiapacific",
"australia",
"brazil",
"india",
"japan",
"southafrica",
"switzerland",
"uae",
], var.location)
error_message = "Invalid location!"
}
}

variable "instance_type" {
description = "What instance type should your workspace use?"
default = "Standard_B4ms"
validation {
condition = contains([
"Standard_B1ms",
"Standard_B2ms",
"Standard_B4ms",
"Standard_B8ms",
"Standard_B12ms",
"Standard_B16ms",
"Standard_D2as_v5",
"Standard_D4as_v5",
"Standard_D8as_v5",
"Standard_D16as_v5",
"Standard_D32as_v5",
], var.instance_type)
error_message = "Invalid instance type!"
}
}

variable "home_size" {
type = number
description = "How large would you like your home volume to be (in GB)?"
default = 20
validation {
condition = var.home_size >= 1
error_message = "Value must be greater than or equal to 1."
}
}

provider "azurerm" {
features {}
}

data "coder_workspace" "me" {
}

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

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

userdata = templatefile("cloud-config.yaml.tftpl", {
username = lower(substr(data.coder_workspace.me.owner, 0, 32))
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 = var.location

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 = var.home_size
}

// 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 = var.instance_type
// 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"
}