Skip to content

How to add a block volume to a template

How-to · Updated Jul 2026

Coming from another cloud?

▸AWS·EBS Attach Volume

This Quake AI feature maps to AWS’s EBS Attach Volume.

▸Google Cloud·Persistent Disk Attach

This Quake AI feature maps to Google Cloud’s Persistent Disk Attach.

How to add a block volume to a template

Attach a block volume to an instance that a template provisions, format it on first boot, and record the mount in /etc/fstab so the filesystem mounts after a reboot. This guide extends templates without persistent data disks, such as simple-vm.

These templates provide reference implementations:

Prerequisites

Windows: CLI examples use bash. Set up a Linux CLI environment on Windows before proceeding.

  • You deployed a template from iac/templates/ and ran tofu init in that directory
  • OpenTofu or Terraform installed with Quake AI credentials configured
  • Enough block-storage quota for the new volume (openstack limits show --absolute -c name -c value | grep volumes)

Reference pattern from existing templates#

The wordpress-mysql template declares a block volume, an attachment to the MySQL instance, and a cloud-init script that formats and mounts the disk:

HCL
resource "openstack_blockstorage_volume_v3" "mysql_data" {
  name = "${local.name_prefix}-mysql-data"
  size = var.db_volume_size
}

resource "openstack_compute_volume_attach_v2" "mysql_data" {
  instance_id = openstack_compute_instance_v2.mysql.id
  volume_id   = openstack_blockstorage_volume_v3.mysql_data.id
}

The mount logic lives in cloud-init/mysql.yaml:

YAML
#cloud-config
runcmd:
  - |
    set -e
    DEV=/dev/sdb
    for i in $(seq 1 30); do [ -b "$DEV" ] && break; sleep 5; done
    if ! blkid "$DEV" >/dev/null 2>&1; then mkfs.ext4 -F "$DEV"; fi
    mkdir -p /var/lib/mysql
    mount "$DEV" /var/lib/mysql
    grep -q "$DEV" /etc/fstab || echo "$DEV /var/lib/mysql ext4 defaults,nofail 0 2" >> /etc/fstab

On Quake AI, the boot volume occupies the first SCSI device. The first attached data volume appears as /dev/sdb, which is the path used by the templates in this repository.

Add volume resources to your template#

The following example extends simple-vm. Adjust resource names and the mount path for your workload.

1. Declare variables#

Add to variables.tf:

HCL
variable "data_volume_size" {
  description = "Size in GB for the attached data volume"
  type        = number
  default     = 20
}

variable "data_mount_path" {
  description = "Filesystem path where the data volume is mounted"
  type        = string
  default     = "/mnt/data"
}

2. Create the volume and attachment#

Add to main.tf (or a new storage.tf):

HCL
resource "openstack_blockstorage_volume_v3" "data" {
  name = "${var.instance_name}-data"
  size = var.data_volume_size
}

resource "openstack_compute_volume_attach_v2" "data" {
  instance_id = openstack_compute_instance_v2.vm.id
  volume_id   = openstack_blockstorage_volume_v3.data.id
}

Place the attachment after the instance resource so OpenTofu can resolve openstack_compute_instance_v2.vm.id.

3. Mount the volume on first boot#

Create cloud-init/data-volume.yaml:

YAML
#cloud-config
runcmd:
  - |
    set -e
    DEV=/dev/sdb
    MOUNT=${mount_path}
    for i in $(seq 1 30); do [ -b "$DEV" ] && break; sleep 5; done
    if ! blkid "$DEV" >/dev/null 2>&1; then mkfs.ext4 -F "$DEV"; fi
    mkdir -p "$MOUNT"
    mount "$DEV" "$MOUNT"
    grep -q "$DEV" /etc/fstab || echo "$DEV $MOUNT ext4 defaults,nofail 0 2" >> /etc/fstab

Wire it into the instance. If the instance has no existing user_data, add:

HCL
resource "openstack_compute_instance_v2" "vm" {
  # ... existing arguments ...

  user_data = templatefile("${path.module}/cloud-init/data-volume.yaml", {
    mount_path = var.data_mount_path
  })
}

Plan and apply#

From the template directory:

bash
tofu plan
tofu apply

The plan shows one new openstack_blockstorage_volume_v3 and one openstack_compute_volume_attach_v2. It also shows an instance replacement when you add user_data for the first time.

Verify the attachment and mount#

See also#

Usage Guidelines

The sample code, software libraries, command line tools, proofs of concept, templates, and other related technology on this page (including any of the foregoing that is provided by Quake AI personnel) is provided to you as Quake AI Content under the Quake AI Customer Agreement, or the relevant written agreement between you and Quake AI (whichever applies). Do not use this Quake AI Content in your production accounts, or on production or other critical data. You are responsible for testing, securing, and optimizing the Quake AI Content (such as sample code) as appropriate for production grade use based on your specific quality control practices and standards. Deploying Quake AI Content may incur Quake AI charges for creating or using Quake AI chargeable resources, such as running Compute instances or storing data in Object Storage. Your use is also subject to the Acceptable Use Policy.

For the full policy, see Usage Guidelines.

Last validated: 10.07.2026

Was this page helpful?