dtcloud_vm (Resource)
Manages a virtual machine.
This resource builds the machine, renames it, resizes it, changes its power state and destroys it.
Interfaces and volumes added after boot belong to dtcloud_vm_network_interface and
dtcloud_vm_volume_attachment.
Example Usage
resource "dtcloud_vm" "web" {
name = "web-01"
flavor_id = data.dtcloud_flavors.small.flavors[0].id
state = "running"
key_name = dtcloud_ssh_key.deploy.name
# Written as it should reach the guest; the provider base64-encodes it, which is
# the only form the API accepts. Encoding it here too would double-encode it.
user_data = file("${path.module}/cloud-init.yaml")
# Interfaces declared here are created with the machine and live and die with
# it. Add one afterwards with dtcloud_vm_network_interface instead.
network {
uuid = dtcloud_network.app.id
security_groups = [dtcloud_security_group.web.id]
fixed_ip {
ip_version = 4
}
}
# The boot disk is boot_index 0.
block_device {
boot_index = 0
volume_size = 40
source_type = "image"
device_type = "disk"
destination_type = "volume"
uuid = var.image_id
volume_type = "standard"
delete_on_termination = true
}
}
At least one of key_name, user_data or script is required. They are the only ways
credentials or a provisioning payload reach the guest. user_data and script cannot both be set:
the platform builds cloud-init from script only when user_data is absent, so the plan refuses
the combination instead of silently dropping the script.
On a Linux image, set username, hostname and disable_root in script. They are optional
only because Windows template images ignore them, and the apply warns when a Linux script leaves
any of them out.
Leave fixed_ip out for the usual case: the provider asks for one address and the platform
allocates it. The addresses actually assigned are reported back into the network blocks.
Schema
Required
flavor_id(String) ID of the flavor (sizing). Changing this resizes the instance in place. Unless enable_hot_plug is true the platform requires the instance to be stopped first, so the provider stops it, resizes and returns it to the configured power state — a plan that does this is the one wherestatusalso shows as (known after apply).name(String) Name of the virtual machine. Can be changed in place.
Optional
block_device(Block List) Block devices to attach at boot. The boot disk is the entry with boot_index 0. At least one is required. Changing this forces a new resource to be created. (see below for nested schema)enable_hot_plug(Boolean) Allow live vCPU/memory resize on the instance. With this on, changing flavor_id does not power-cycle the instance. Can be toggled after creation.graceful_shutdown(Boolean) When stopping, ask the guest to shut down (softStop) instead of cutting power (hardStop).is_gpu_image(Boolean) Set when booting a GPU image. Changing this forces a new resource to be created.key_name(String) Name of an existing SSH key to inject, e.g. a dtcloud_ssh_key resource's name. Changing this forces a new resource to be created.network(Block List) Network interfaces to attach at boot. At least one is required. Changing this forces a new resource to be created. (see below for nested schema)script(Block List, Max: 1) Initial credentials applied to the guest at first boot. On a Linux image, set username, hostname and disable_root as well — they are optional only because Windows template images ignore them. Changing this forces a new resource to be created. (see below for nested schema)state(String) Desired power state: running, stopped or shelved. Shelving releases compute resources while keeping the VM and its disks.timeouts(Block, Optional) (see below for nested schema)user_data(String) Cloud-init user data, written as it should reach the guest. The API only accepts it base64-encoded and the provider encodes it, so passing base64encode() output here would encode it twice and the guest would receive the encoded text. Changing this forces a new resource to be created.
Read-Only
created_at(String) When the VM was created, in RFC 3339 format.flavor_name(String) Human-readable name of the VM's flavor.id(String) The ID of this resource.image(String) Name of the image the VM was built from.image_os_type(String) OS family of the image, e.g. linux or windows.last_modified(String) When the VM was last modified, in RFC 3339 format.metadata(Map of String) Metadata the platform attaches to the instance, e.g. ha_enabled.network_interface(List of Object) Network interfaces currently attached to the VM. (see below for nested schema)primary_ip(String) Convenience shortcut: the primary IP of the first public interface, falling back to the first interface with an address.ram(String) Memory as reported by the API, e.g. "512 MB".ssh_key(String) Name of the SSH key injected into the VM.status(String) Current power/provisioning state, e.g. ACTIVE, SHUTOFF, ERROR.task_state(String) In-flight platform task, empty when the VM is settled.vcpus(Number) Number of virtual CPUs.volume(List of Object) Volumes currently attached to the VM, including the boot disk. (see below for nested schema)
Nested Schema for block_device
Required:
boot_index(Number) Boot order. The boot disk is 0. Changing this forces a new resource to be created.delete_on_termination(Boolean) Whether the device is deleted with the VM. Changing this forces a new resource to be created.destination_type(String) One of: volume, local. Changing this forces a new resource to be created.device_type(String) One of: cdrom, disk. Changing this forces a new resource to be created.source_type(String) Where the device comes from. One of: blank, image, volume, backup. Changing this forces a new resource to be created.volume_size(Number) Size in GB (1-8192). Can be increased in place; decreasing is not supported.volume_type(String) Storage policy / volume type the disk is created on. Can be changed in place.
Optional:
uuid(String) ID of the source image, volume or backup. Omitted for blank devices. Changing this forces a new resource to be created.
Nested Schema for network
Required:
uuid(String) ID of the network to attach to. Changing this forces a new resource to be created.
Optional:
fixed_ip(Block List) Fixed IPs on this interface. Omit to have one address allocated. Can be changed in place. (see below for nested schema)port_security_enabled(Boolean) Whether port security (and therefore security groups) applies to this interface. Defaults to the network's own setting. Changing this forces a new resource to be created.security_groups(List of String) Security group IDs bound to this interface. Can be changed in place. Defaults to the project's default group.
Nested Schema for network.fixed_ip
Optional:
ip_address(String) Specific address to request. Allocated by the platform when omitted, and reported back here either way.ip_version(Number) IP version, 4 or 6. Advisory on write — the platform allocates from the attached network; pin ip_address to choose an address. Reported back from the assigned address.
Nested Schema for script
Required:
os(String) Guest OS family. One of: linux, windows. Changing this forces a new resource to be created.password(String, Sensitive) Initial password for the guest account. Changing this forces a new resource to be created.
Optional:
disable_root(Boolean) Disable direct root login. Required in practice on Linux images; ignored by Windows template images. Changing this forces a new resource to be created.hostname(String) Hostname to set inside the guest. Required in practice on Linux images; ignored by Windows template images. Changing this forces a new resource to be created.username(String) Account to create. Required in practice on Linux images; ignored by Windows template images. Changing this forces a new resource to be created.
Nested Schema for timeouts
Optional:
create(String)delete(String)update(String)
Nested Schema for network_interface
Read-Only:
is_public(Boolean)mac_address(String)network_id(String)network_name(String)port_id(String)primary_ip(String)secondary_ips(List of String)security_groups(List of Object) (see below for nested schema)spoofing_protection(Boolean)
Nested Schema for network_interface.security_groups
Read-Only:
id(String)name(String)
Nested Schema for volume
Read-Only:
delete_on_termination(Boolean)id(String)name(String)size(Number)storage_policy(String)
Behaviour worth knowing
- What changes in place.
name,flavor_id,state,enable_hot_plug, and inside the blocksnetwork.security_groups,network.fixed_ip,block_device.volume_size(increase only) andblock_device.volume_type. Adding or removing a wholenetworkorblock_deviceblock,network.uuid,network.port_security_enabled, the otherblock_devicefields and the boot-time argumentskey_name,user_data,scriptandis_gpu_imagebuild a new machine. - Resizing. With
enable_hot_plug = truethe flavor changes while the machine keeps running. Without it the platform refuses to resize a running instance, so the provider stops it, resizes it and returns it to the configuredstate. In a plan, the resize that power-cycles the machine is the one wherestatusalso shows as known after apply, and the apply warns that the machine was restarted. - Growing a disk does not grow the filesystem. After
volume_sizeincreases, extend the partition and the filesystem inside the guest (growpartandresize2fs, or your filesystem's equivalent); the apply warns about it.volume_sizecannot be decreased. - The guest does not see a changed
fixed_ipat once. The address moves on the port, but the operating system keeps the old one until its DHCP lease renews, and for good if the interface is configured statically. Renew the lease or reboot; the apply warns about it. port_security_enabledhas no default. Left unset it is not sent, and the network decides. It cannot befalsewhilesecurity_groupsis set on the same block.- Extra disks are matched by size and storage policy. Beyond the boot disk the platform reports no
order, so a
block_devicechange is refused when two attached volumes look the same. Manage such disks withdtcloud_vm_volume_attachment. - What drift Terraform can see.
name,flavor_id,state,key_name,enable_hot_plug, thenetworkblocks and the size, storage policy and delete-on-termination setting of eachblock_deviceare read back.user_data,scriptandis_gpu_imageare not reported by any endpoint, so a change made to them outside Terraform stays invisible. network_interfaceandvolumeare a snapshot from the last refresh. Interfaces and volumes attached by other resources in the same apply appear after the next refresh.- One resource is one machine. The API can create several machines in one call; this resource
does not expose that. Use Terraform's
countorfor_each.
state is the power state Terraform keeps the machine in; a machine always boots running first.
| From | To | What the provider does |
|---|---|---|
running | stopped | softStop, or hardStop when graceful_shutdown = false |
stopped | running | start |
| any | shelved | shelve, which releases the compute resources and keeps the machine and its disks |
shelved | running | unshelve |
shelved | stopped | unshelve, then stop |
Timeouts
create defaults to 20 minutes, update to 10 minutes and delete to 15 minutes. Creating waits
for the machine to reach ACTIVE, and a resize stops and restarts it, so an update can take several
minutes. Override them with a timeouts block:
resource "dtcloud_vm" "web" {
# ...
timeouts {
create = "30m"
}
}
Import
# user_data, script and is_gpu_image are not reported by any endpoint: read the
# import notes before the first apply.
terraform import dtcloud_vm.web 4c9a1f37-8d25-4e60-b13f-6a7c2e5b9d88
Read back on import: name, flavor_id, state, key_name, enable_hot_plug, every interface as
a network block, and the boot disk as a block_device block. The boot disk's source_type,
device_type and destination_type are inferred, because the platform does not report them. Not
read back: user_data, script, is_gpu_image, graceful_shutdown, and disks attached after boot.
user_data, script and is_gpu_image force a new machine, so if the configuration sets them the
first plan after an import proposes a rebuild. Ignore them to keep the imported machine:
resource "dtcloud_vm" "web" {
# ...
lifecycle {
ignore_changes = [user_data, script, is_gpu_image]
}
}
Import a machine before attaching extra interfaces to it. An import has no blocks to match
against, so every interface the machine has becomes a network block. If some of them belong to
dtcloud_vm_network_interface resources, the configuration declares fewer blocks than were
imported, and the first plan proposes to replace the machine.