Note: The description in this article is based on Terraform version 1.14.4, VMware Cloud Director Provider version 3.14, and VMware Cloud Director 10.6.
Existing Objects and Terraform
Terraform can work with objects that are defined in its configuration (the resource block) and stored in the state file. If they do not exist in the State, it will attempt to create them.
Our infrastructure may contain a number of resources that were not created using Terraform. They were either created before we started using Terraform, or were later created in a different way (for example, by cloning a vApp). If we do not want to change the attributes of existing objects, we do not need to have them managed by Terraform.
If we only want to read some information, we can use data sources (the data block). The loaded data can be referenced in the code, but no changes can be made to it (it is read-only).
If we want to make changes to existing objects that Terraform does not know about, we must import them. We need to obtain their configuration and data in the State.
Import Using Terraform CLI
The oldest option is to use the Terraform CLI command terraform import. We must create a resource configuration (the resource block) and the command will then perform the import into the State. It is better suited for importing a single object. The command requires a number of parameters. It is complicated and inefficient.
Import Using HCL
To import existing infrastructure resources into Terraform, we can manually create an import block. We also need a resource block to go with it. We can create it manually, or alternatively have it generated using terraform plan -generate-config-out. All resource attributes are stored in the state file, but it is not necessary to define all of them in the resource block.
Additional options are described in Import existing resources in bulk.
General Procedure
- define the configuration (the
resourceblock) for each resource we want to import - add a corresponding
importblock for each resource we want to import - run
terraform planand verify the import plan - run
terraform applyto import the resources and update the Terraform State (only imports should occur, not resource creation) - we can remove the
importblock from the configuration (even though re-running it does not perform the import again)
The Import Block
We must specify the target resource address (to), which consists of the resource type and label (how we reference the resource in the configuration). This must match the resource block we have prepared. And the identity of the existing resource (id), which depends on the provider. For VMware Cloud Director, this is a path composed of component names, for example for a VM: Org.vDC.vApp.VM.
import {
to = TYPE.LABEL
id = "<RESOURCE-ID>"
}
To import multiple objects (instances) of the same type, we can use the meta-arguments for_each and count in the target resource.
Generating Configuration
Note: This feature has been available in Terraform since version 1.5, but is still marked as experimental.
Terraform generates code for resources defined in import blocks that do not yet exist in our configuration. It creates HCL containing Terraform's best guess at the appropriate value for each resource argument. It is recommended to review and adjust the generated content (remove some arguments, fix values, etc.).
To generate the configuration, the Terraform CLI command is used with a parameter specifying the name of the new file (path) where the configuration will be saved.
terraform plan -generate-config-out="generated_resources.tf"
Problem with Specifying the Parameter
When running the Terraform CLI from the terminal in Visual Studio Code (i.e. within PowerShell), I was getting an error.
PS D:\VCD-terraform> terraform plan -generate-config-out=generated.tf - Error: Too many command line arguments - - To specify a working directory for the plan, use the global -chdir flag. For more help on using this command, run: terraform plan -help
The solution is to specify the parameter with two dashes --.
PS D:\VCD-terraform> terraform plan --generate-config-out=generated.tf
The vcd_resource_list Data Source
The VMware Cloud Director provider offers a special data source called vcd_resource_list. It allows you to retrieve a list of existing resources of a specific type and represent them in various formats. One option is to generate an import file.
data "vcd_resource_list" "list_of_nets" {
name = "list_of_nets"
resource_type = "network"
list_mode = "import"
import_file_name = "network-import.tf"
}
Importing All Existing VMs from a Given vApp
Let us walk through an example that demonstrates the most automated import solution possible for all existing VMs from a given vApp.
Individual Steps
- create the file
import.tfwith thevcd_resource_listdata source - use the Terraform CLI command
terraform planto generate the import fileimport-vms_from_vapp.tf - use the Terraform CLI command
terraform plan --generate-config-out=generated.tfto generate the configuration filegenerated.tf - use the Terraform CLI command
terraform applyto import into the state file - we can delete the files
import.tfandimport-vms_from_vapp.tf - we can use the Terraform CLI command
terraform planto verify that the infrastructure matches the configuration, confirming the import was successful - we can modify the configuration and apply changes; if we want to perform operations sequentially (by default, 10 operations are performed in parallel), we can use
terraform apply -parallelism=1

The Import.tf File
Our Terraform project requires a basic configuration for connecting to the VMware Cloud Director provider. We create a file, which we name import.tf here, and add the vcd_resource_list configuration to it. The important fields are the resource type (VM), the parent name (vApp), the import mode, and the filename for saving the import blocks.
data "vcd_resource_list" "import_vms_from_vapp" {
name = "import_vms_from_vapp"
resource_type = "vcd_vapp_vm"
parent = "Demo-vApp"
list_mode = "import"
import_file_name = "import-vms_from_vapp.tf"
}
Generating the Import File
Once we have the data source ready, we simply use the Terraform CLI command to generate the import file.
PS D:\VCD-terraform> terraform plan data.vcd_resource_list.import_vms_from_vapp: Reading... data.vcd_resource_list.import_vms_from_vapp: Read complete after 6s [id=import_vms_from_vapp] No changes. Your infrastructure matches the configuration. Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
In the current directory, we will find the generated file import-vms_from_vapp.tf, whose contents may look roughly as follows.
import {
to = vcd_vapp_vm.Demo-VM-2537464da65e
id = "Firma.Firma vDC.Demo-vApp.Demo-VM"
}
import {
to = vcd_vapp_vm.Next-VM-36979c7d5244
id = "Firma.Firma vDC.Demo-vApp.Next-VM"
}
Generating the Configuration File
In the next step, we use the import file and have the configuration generated for the individual objects.
PS D:\VCD-terraform> terraform plan --generate-config-out=generated.tf
data.vcd_resource_list.import_vms_from_vapp: Reading...
vcd_vapp_vm.Next-VM-36979c7d5244: Preparing import... [id=Firma.Firma vDC.Demo-vApp.Next-VM]
vcd_vapp_vm.Demo-VM-2537464da65e: Preparing import... [id=Firma.Firma vDC.Demo-vApp.Demo-VM]
vcd_vapp_vm.Demo-VM-2537464da65e: Refreshing state... [id=urn:vcloud:vm:4415c19d-a813-40ca-b2a3-2537464da65e]
vcd_vapp_vm.Next-VM-36979c7d5244: Refreshing state... [id=urn:vcloud:vm:da0d2be9-3117-464e-88ab-36979c7d5244]
data.vcd_resource_list.import_vms_from_vapp: Read complete after 5s [id=import_vms_from_vapp]
Terraform will perform the following actions:
# vcd_vapp_vm.Demo-VM-2537464da65e will be imported
# (config will be generated)
resource "vcd_vapp_vm" "Demo-VM-2537464da65e" {
...
Plan: 2 to import, 0 to add, 0 to change, 0 to destroy.
- Warning: Config generation is experimental
-
- Generating configuration during import is currently experimental, and the generated configuration format may change in future
versions.
----------------------------------------------------------------------------------
Terraform has generated configuration and written it to generated.tf. Please review the configuration and edit it as necessary
before adding it to version control.
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run
"terraform apply" now.
In the current directory, we will find the generated file generated.tf, which contains resource blocks for the individual VMs with complete arguments.
Importing into the State File
Finally, we apply the changes, during which the combined import and resource blocks are used and the resources are imported.
PS D:\VCD-terraform> terraform apply
vcd_vapp_vm.Demo-VM-2537464da65e: Preparing import... [id=Firma.Firma vDC.Demo-vApp.Demo-VM]
vcd_vapp_vm.Next-VM-36979c7d5244: Preparing import... [id=Firma.Firma vDC.Demo-vApp.Next-VM]
data.vcd_resource_list.import_vms_from_vapp: Reading...
vcd_vapp_vm.Demo-VM-2537464da65e: Refreshing state... [id=urn:vcloud:vm:4415c19d-a813-40ca-b2a3-2537464da65e]
vcd_vapp_vm.Next-VM-36979c7d5244: Refreshing state... [id=urn:vcloud:vm:da0d2be9-3117-464e-88ab-36979c7d5244]
data.vcd_resource_list.import_vms_from_vapp: Read complete after 5s [id=import_vms_from_vapp]
Terraform will perform the following actions:
# vcd_vapp_vm.Demo-VM-bb229083e6ec will be imported
resource "vcd_vapp_vm" "Demo-VM-bb229083e6ec" {
...
Plan: 2 to import, 0 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
vcd_vapp_vm.Next-VM-36979c7d5244: Importing... [id=Firma.Firma vDC.Demo-vApp.Next-VM]
vcd_vapp_vm.Next-VM-36979c7d5244: Import complete [id=Firma.Firma vDC.Demo-vApp.Next-VM]
vcd_vapp_vm.Demo-VM-2537464da65e: Importing... [id=Firma.Firma vDC.Demo-vApp.Demo-VM]
vcd_vapp_vm.Demo-VM-2537464da65e: Import complete [id=Firma.Firma vDC.Demo-vApp.Demo-VM]
Apply complete! Resources: 2 imported, 0 added, 0 changed, 0 destroyed.
There are no comments yet.