The article Terraform + vRA. Quickstart a new deployment is created from an item published in the vRA directory. This is the easiest way to work with vRA from Terraform, but it is not flexible enough – there is no way to change the template schema, the deployments will be the same as the Cloud Assembly administrator decided. Terraform allows you to create your own cloud templates and deploy deployments from them.
Terraform offers two ways to work with vRA 8 cloud templates (formerly called blueprints).
Dynamic template description from Terraform
The cloud template is generated on the fly during infrastructure deployment via Terraform:
# main.tf
provider "vra" {
url = var . url
refresh_token = var . refresh_token
insecure = var . insecure
}
data "vra_project" "this" {
name = var . project_name
}
resource "random_id" "this" {
byte_length = 4
}
resource "vra_blueprint" "this" {
name = "$ {var.blueprint_name} ($ {random_id.this.hex})"
description = "Created by vRA terraform provider"
project_id = data . vra_project . this . id
content = << - EOT
formatVersion : 1
inputs :
vmCount :
type : integer
minimum: 1
maximum: 5
vmSize:
type: string
title: VM size
enum:
- micro
- small
- medium
- large
default: small
imageName:
type: string
enum:
- CentOS_7
- CentOS_8
- Debian_9
- Ubuntu_16
- Ubuntu_18
- Windows_2012
- Windows_2016
default: CentOS_7
description: OS type
resources:
Cloud_Network_1:
type: Cloud.Network
properties:
networkType: existing
Cloud_vSphere_Machine_1:
type: Cloud.vSphere.Machine
properties:
count: '$${input.vmCount}'
image: '$${input.imageName}'
flavor: '$${input.vmSize}'
cloudConfig: null
name: 'vra-tf'
customizationSpec: '$${starts_with(input.imageName, "Windows") ? "tmp-windows-vra" : "tmp-linux-vra"}'
networks:
- network: '$${resource.Cloud_Network_1.id}'
assignment: static
EOT
}
data "vra_blueprint" "this" {
name = vra_blueprint.this.name
depends_on = [vra_blueprint.this]
}
resource "vra_blueprint_version" "this" {
blueprint_id = data.vra_blueprint.this.id
change_log = "First version"
description = "Released from vRA terraform provider"
release = true
version = "1.0.1"
}
resource "vra_deployment" "this" {
name = "${var.deployment_name} - ${random_id.this.hex}"
description = var.deployment_descr
project_id = data.vra_project.this.id
blueprint_id = data.vra_blueprint.this.id
blueprint_version = "1.0.1"
inputs = {
vmCount = var.vm_count
vmSize = var . vm_flavor
imageName = var . image
}
timeouts {
create = "60m" delete = "20m"
update = "30m"
}
}
All files are available for download at https://github.com/isas2.
In this example, a new template is created and its ID is obtained, the template code is set in the content parameter , then the deployment is expanded from the template. Note that variables inside the template code are escaped with an extra ‘ $ ‘ character .
If you later change this template (via Terraform or the web interface), then deployments deployed from it will not be updated, only the cloud template itself will be updated. To apply updates, use the description of the template version: resource “vra_blueprint_version” . I also recommend putting all possible template parameters into input parameters. Changing the values of the input parameters and the version number of the template in the deployment description leads to its reconfiguration.
Using vra_blueprint has a clear advantage over deployments from catalog items : the user gets more freedom, he independently describes the composition and parameters of his templates.

Using out-of-the-box vRA templates
Describing a template within a Terraform configuration makes the code very complex. Using ready-made cloud templates is a more convenient way to work.
# main.tf
provider "vra" {
url = var.url
refresh_token = var.refresh_token
insecure = var.insecure
}
data "vra_project" "this" {
name = var.project_name
}
resource "random_id" "this" {
byte_length = 4
}
resource "vra_blueprint" "this" {
name = "${var.blueprint_name} (${random_id.this.hex})"
description = "Created by vRA terraform provider"
project_id = data.vra_project.this.id
content = <<-EOT
formatVersion: 1
inputs:
vmCount:
type: integer
minimum: 1
maximum: 5
vmSize:
type: string
title: VM size
enum:
- micro
- small
- medium
- large
default: small
imageName:
type: string
enum:
- CentOS_7
- CentOS_8
- Debian_9
- Ubuntu_16
- Ubuntu_18
- Windows_2012
- Windows_2016
default: CentOS_7
description: OS type
resources:
Cloud_Network_1:
type: Cloud.Network
properties:
networkType: existing
Cloud_vSphere_Machine_1:
type: Cloud.vSphere.Machine
properties:
count: '$${input.vmCount}'
image: '$${input.imageName}'
flavor: '$${input.vmSize}'
cloudConfig: null
name: 'vra-tf'
customizationSpec: '$${starts_with(input.imageName, "Windows") ? "tmp-windows-vra" : "tmp-linux-vra"}'
networks:
- network: '$${resource.Cloud_Network_1.id}'
assignment: static
EOT
}
data "vra_blueprint" "this" {
name = vra_blueprint.this.name
depends_on = [vra_blueprint.this]
}
resource "vra_blueprint_version" "this" {
blueprint_id = data.vra_blueprint.this.id
change_log = "First version"
description = "Released from vRA terraform provider"
release = true
version = "1.0.1"
}
resource "vra_deployment" "this" {
name = "${var.deployment_name} - ${random_id.this.hex}"
description = var.deployment_descr
project_id = data.vra_project.this.id
blueprint_id = data.vra_blueprint.this.id
blueprint_version = "1.0.1"
inputs = {
vmCount = var.vm_count
vmSize = var.vm_flavor
imageName = var.image
}
timeouts {
create = "60m"
delete = "20m"
update = "30m"
}
}
All files are available for download at https://github.com/isas2.
This example adds Terraform output parameters to the code:
- addresses_by_vmname after execution will contain the names of all VMs and their IP addresses:
addresses_by_vmname = {
"vra-tf-752" = "192.168.203.45"
"vra-tf-753" = "192.168.203.44"
}
- resource_properties_by_name – contains properties of all deployment resources.
Attention! For these examples to work, the vRA user will need the “Service Broker User” and “Cloud Assembly User” roles.
If you need to generate cloud templates on the fly without overloading Terraform code with them, then vRA 8 can use GitLab as an external template repository. When working with GitLab, you might find the following REST requests useful:
- / content / api / sourcecontrol / sync-all-requests – synchronization of all external sources for this project (s);
- / content / api / sourcecontrol / sync-requests – synchronization of one data source;
- / content / api / sourcecontrol / sync-requests / {id} – getting the sync status by its ID. Returned status values: “REQUESTED”, “STARTED”, “PROCESSING”, “COMPLETED”, “FAILED”, “SKIPPED”.
Translated by Google Translate