Verda Instance Builder

Type: verda-instance

Artifact BuilderId: verda.instance

The verda-instance builder creates a Verda instance, waits for it to become reachable, and runs standard Packer provisioners over SSH.

By default the artifact is the created instance. With artifact_type = "os_volume", the builder shuts down the instance, clones its OS volume, and returns the cloned volume artifact. The returned OS volume ID can be used later as the Verda instance image value in Terraform or another API client.

A successful instance artifact remains live until Packer destroys it. Set keep_instance = true to prevent artifact destruction and failed-build cleanup from deleting the build instance. OS volume builds delete their temporary instance after capture unless keep_instance is enabled.

Configuration Reference

Required

Optional

Additional Volume Blocks

Use volume blocks to create additional non-OS data volumes with the instance.

Required volume fields:

Optional volume fields:

Communicator Config

This builder supports the ssh and none communicators. SSH is the default and uses root as the default username.

Most SSH options below are inherited from Packer’s standard SSH communicator. The Verda-specific SSH settings are ssh_key_ids, temporary_ssh_key_name, and skip_temporary_ssh_key. By default the builder generates a temporary Packer key pair, creates a temporary Verda SSH key from its public key, passes that key ID when creating the build instance, and deletes the Verda key during cleanup.

Basic Example

packer {
  required_plugins {
    verda = {
      version = ">= 0.1.0"
      source  = "github.com/thevilledev/verda"
    }
  }
}

source "verda-instance" "ubuntu" {
  instance_type = "1L40S.20V"
  location_code = "FIN-03"
  image         = "ubuntu-24.04"
  hostname      = "packer-verda-example"

  ssh_username = "root"
}

build {
  sources = ["source.verda-instance.ubuntu"]

  provisioner "shell" {
    inline = [
      "cloud-init status --wait || true",
      "uname -a",
    ]
  }
}

Spot Builds

Set is_spot = true to create the Packer build instance as Verda spot capacity. This defaults contract to SPOT. Setting contract = "SPOT" is also accepted and sends the same spot request to Verda. Configurations that set is_spot = true with a non-SPOT contract are rejected during packer validate.

source "verda-instance" "ubuntu_spot" {
  instance_type = "1L40S.20V"
  location_code = "FIN-03"
  image         = "ubuntu-24.04"
  hostname      = "packer-verda-spot-example"

  is_spot = true

  ssh_username = "root"
}

Spot builds can also set discontinuation behavior for volumes created with the instance. Use os_volume_spot_behavior for the OS volume and on_spot_discontinue inside each volume block. Valid values are keep_detached, move_to_trash, and delete_permanently.

OS Volume Artifacts

Set artifact_type = "os_volume" to return a cloned OS volume instead of the instance. The effective artifact locations are the configured artifact_volume_location_codes followed by the source instance location when it was not already listed, compared case-insensitively. The first configured location is the primary artifact ID, while console output and generated data expose every location and volume ID.

Verda does not support cloning an attached OS volume directly across datacenters. The builder first creates the source-location artifact, waits for it to become detached, and uses that artifact as the source for the remaining locations. The source-location artifact is included once in the effective artifact set.

Instances booted later from an existing OS volume cannot rely on Verda ssh_key_ids injection. Bake durable login keys into the guest during the Packer build, and enable ssh_clear_authorized_keys so Packer’s temporary build key is removed before the volume is captured.

variable "authorized_keys_file" {
  type        = string
  description = "Path to an authorized_keys-format file to bake into the OS volume."
}

source "verda-instance" "ubuntu_volume" {
  instance_type = "1A6000.10V"
  location_code = "FIN-01"
  image         = "ubuntu-24.04"
  hostname      = "packer-verda-volume"

  ssh_username              = "root"
  ssh_clear_authorized_keys = true

  artifact_type                  = "os_volume"
  artifact_volume_name           = "packer-verda-volume-root"
  artifact_volume_location_codes = ["FIN-01", "FIN-03"]
}

build {
  sources = ["source.verda-instance.ubuntu_volume"]

  provisioner "file" {
    source      = var.authorized_keys_file
    destination = "/tmp/verda_authorized_keys"
  }

  provisioner "shell" {
    inline = [
      "cloud-init status --wait || true",
      "install -d -m 0700 /root/.ssh",
      "touch /root/.ssh/authorized_keys",
      "chmod 0600 /root/.ssh/authorized_keys",
      "while IFS= read -r key; do [ -n \"$key\" ] || continue; grep -qxF \"$key\" /root/.ssh/authorized_keys || printf '%s\\n' \"$key\" >> /root/.ssh/authorized_keys; done < /tmp/verda_authorized_keys",
      "chown root:root /root/.ssh /root/.ssh/authorized_keys",
      "rm -f /tmp/verda_authorized_keys",
    ]
  }
}

Persisting volume IDs

The Packer artifact ID is singular, so use a manifest post-processor to persist the complete multi-location mapping. Manifest custom data values are strings; encode the list and map as JSON.

post-processor "manifest" {
  output = "packer-manifest.json"

  custom_data = {
    VolumeID            = build.VolumeID
    SourceOSVolumeID    = build.SourceOSVolumeID
    VolumeIDs           = jsonencode(build.VolumeIDs)
    VolumeIDsByLocation = jsonencode(build.VolumeIDsByLocation)
  }
}

Packer appends repeated runs to the manifest. For a single-build workflow, inspect the latest entry:

jq '.builds[-1].custom_data.VolumeIDsByLocation | fromjson' packer-manifest.json

Terraform Handoff

Use the Packer OS volume artifact ID, or a clone of it, as the Terraform verda_instance.image value. Do not pass it through existing_volumes; that field attaches additional non-OS volumes. Do not rely on ssh_key_ids here when booting from an existing OS volume; the keys must already be present in the guest image, or installed by a boot script that runs inside the guest.

For multiple locations, select the volume ID matching each instance location. The manifest stores the map as a JSON string inside its JSON document, so decode both layers. For multiple instances in the same location, clone that location’s Packer artifact once per instance before passing each clone ID as image.

locals {
  packer_manifest = jsondecode(file("${path.module}/packer-manifest.json"))
  packer_build    = local.packer_manifest.builds[length(local.packer_manifest.builds) - 1]

  os_volume_ids_by_location = jsondecode(
    local.packer_build.custom_data.VolumeIDsByLocation
  )
}

resource "verda_instance" "app" {
  instance_type = "1B200.30V"
  image         = local.os_volume_ids_by_location["FIN-03"]
  hostname      = "app-01"
  description   = "App server from Packer OS volume"
  location      = "FIN-03"
  ssh_key_ids   = []
}

Verda volumes do not expose tags, labels, or arbitrary metadata through the public API, Terraform provider, or Go SDK. Put release identifiers in the volume name or track them in external inventory.