Writing Terraform Configurations

Overview

Using Terraform, you can describe your Oracle Cloud Infrastructure using the HashiCorp Configuration Language format (HCL) in Terraform configuration files (see Configuration Syntax). Terraform configuration files can use either of two formats: Terraform domain-specific language (HashiCorp Configuration Language format [HCL]), which is the recommended approach, or JSON format if the files need to be machine-readable. Configuration files that use the HCL format end with the .tf file extension; those using JSON format end with the .tf.json file extension. The Terraform format is human-readable, while the JSON format is machine readable.

Use Terraform configurations to define your Oracle Cloud Infrastructure resources, variable definitions, data sources, and a great deal more. Terraform, then, converts your Oracle Cloud Infrastructure configurations into a set of API calls against Oracle Cloud Infrastructure API endpoints. The key to writing Terraform configuration is understanding how to abstract the desired infrastructure conceptually into Terraform configuration syntax.

Important

While the Oracle Cloud Infrastructure API uses camelCase extensively, Terraform does not support camelCase in configuration files. For this reason, in the configurations you see underscores rather than capitalization as separators. For example, where the API uses availabilityDomain, the Terraform configuration uses availability_domain.

Configuration File Requirements

Terraform configuration (.tf) files have specific requirements, depending on the components that are defined in the file. For example, you might have your Terraform provider defined in one file (provider.tf), your variables defined in another (variables.tf), your data sources defined in yet another.

Note

For example configuration files, see Terraform Provider Examples on the Oracle Cloud Infrastructure GitHub.

Provider Definitions

The following example using Terraform syntax illustrates the requirements for an Oracle Cloud Infrastructure Terraform provider definition, and also shows associated variable definitions. The provider definition relies on variables so that the configuration file itself does not contain sensitive data. Including sensitive data creates a security risk when exchanging or sharing configuration files.

variable "tenancy_ocid" {}
variable "user_ocid" {}
variable "fingerprint" {}
variable "private_key_path" {}
variable "region" {}

provider "oci" {
   tenancy_ocid = "${var.tenancy_ocid}"
   user_ocid = "${var.user_ocid}"
   fingerprint = "${var.fingerprint}"
   private_key_path = "${var.private_key_path}"
   region = "${var.region}"
}

The region attribute specifies the geographical region in which your provider resources are created. To target multiple regions in a single configuration, you simply create a provider definition for each region and then differentiate by using a provider alias, as shown in the following example. Notice that only one provider, named "oci" is defined, and yet the oci provider definition is entered twice, once for the us-phoenix-1 region (with the alias "phx"), and once for the region us-ashburn-1 (with the alias "iad").

variable "tenancy_ocid" {}
variable "user_ocid" {}
variable "fingerprint" {}
variable "private_key_path" {}
variable "compartment_ocid" {}

provider "oci" {
   region = "us-phoenix-1"
   alias = "phx"
   tenancy_ocid = "${var.tenancy_ocid}"
   user_ocid = "${var.user_ocid}"
   fingerprint = "${var.fingerprint}"
   private_key_path = "${var.private_key_path}"
}

provider "oci" {
   region = "us-ashburn-1"
   alias = "iad"
   tenancy_ocid = "${var.tenancy_ocid}"
   user_ocid = "${var.user_ocid}"
   fingerprint = "${var.fingerprint}"
   private_key_path = "${var.private_key_path}"
}

For more information, see Provider Configuration.

Variable Definitions

Variables in Terraform represent parameters for Terraform modules. In variable definitions, each block configures a single input variable, and each definition can take any or all of three optional arguments:

  • type (optional): Defines the variable type as one of three allowed values: string, list, and map. If this argument is not used, the variable type is inferred based on default. If no default is provided, the type is assumed to be string.
  • default (optional): Sets the default value for the variable. If no default value is provided, the caller must provide a value or Terraform throws an error.
  • description (optional): A human-readable description of the variable.

Following are examples of several variable definitions. Some definitions include optional parameters.

variable "tenancy_ocid" {}
variable "user_ocid" {}
variable "fingerprint" {}
variable "private_key_path" {}
variable "region" {}

variable "AD" {
    default     = "1"
    description = "Availability Domain"
}

variable "CPUCoreCount" {
    default = "2"
    type    = "string"
}

For more information, see Input Variable Configuration. See also Input Variables.

Output Configuration

Output variables provide a means to support Terraform end-user queries. This allows users to extract meaningful data from among the potentially massive amount of data associated with a complex infrastructure. For example, you might be interested only in a handful of key values at any given time and defining output variables allows you to extract exactly the information that you need.

Following is a simple example in which only a few output variables (instance IP addresses and boot volume IDs) are defined:

# Output the private and public IPs of the instance
output "InstancePrivateIPs" {
value = ["${oci_core_instance.TFInstance.*.private_ip}"]
}

output "InstancePublicIPs" {
value = ["${oci_core_instance.TFInstance.*.public_ip}"]
}

# Output the boot volume IDs of the instance
output "BootVolumeIDs" {
  value = ["${oci_core_instance.TFInstance.*.boot_volume_id}"]
}

For more information, see Output Variables. See also Output Configuration.

Resource Configuration

Resources are components of your Oracle Cloud Infrastructure. These resources include everything from low-level components such as physical and virtual servers, to higher-level components such as email and database providers, your DNS record.

Declaring Resources

Following is a simple example of a resource definition that illustrates their basic structure.

resource "oci_core_virtual_network" "vcn1" {
   cidr_block = "10.0.0.0/16"
   dns_label = "vcn1"
   compartment_id = "${var.compartment_ocid}"
   display_name = "vcn1"
}

The resource declaration on the first line of the example uses the keyword "resource" and takes two parameters, resource type and resource name ("oci_core_virtual_network" and "vcn1" in the example). Inside the code block, then, is the resource configuration.

For more information, see Resource Configuration.

Referencing Resources in Another Stack

You can reference resources that exist in other stacks. The Terraform remote_state data source allows you to read output variables from state files.

For example, when writing a Terraform configuration for a new web application, you can make the web application use the subnet previously created from your network stack, as long as the required subnet values were output in the network stack state file. In the Terraform configuration for your new web application, do the following: 

  • Pull the state file of the existing network stack into the context of your current Terraform configuration.
  • Load the pulled state file to a data source for remote state files.
  • Populate the subnet data source in your current configuration with values from the relevant output variables of the referenced state file.
  • Optionally print the identifying information for the populated data source to confirm expected values.

Note

In addition to permissions required for Resource Manager operations, you'll need appropriate permissions for resource types you're referencing, in the compartment that you're referencing them. In this example, you need read permissions for network resources in the compartment where they're located.

The following Terraform configuration excerpt references a subnet in another stack.

# The following example assumes that the source stack (defined by `stack_id`) has output a value named `subnet_id`
# Terraform v0.12 is assumed variable "stack_id" {} # Pull the state file of the existing Resource Manager stack (the network stack) into this context data "oci_resourcemanager_stack_tf_state" "stack1_tf_state" { stack_id = "${var.stack_id}" local_path = "stack1.tfstate" } # Load the pulled state file into a remote state data source data "terraform_remote_state" "external_stack_remote_state" { backend = "local" config = { path = "${data.oci_resourcemanager_stack_tf_state.stack1_tf_state.local_path}" } } # Populate a data source in this configuration using a value from the remote state data source data "oci_core_subnet" "subnet1" { subnet_id = "${data.terraform_remote_state.external_stack_remote_state.outputs.subnet_id}" } # Print the values of the populated data source output "print-subnet1" { value = "${data.oci_core_subnet.subnet1}" }

Data Source Configuration

Data sources represent read-only views of existing infrastructure intended for semantic use in Terraform configurations. Following is a simple example of a data source configuration to illustrate its basic structure:

# Gets a list of Availability Domains
data "oci_identity_availability_domains" "ADs" {
  compartment_id = "${var.tenancy_ocid}"
}

# Get DB node list
data "oci_database_db_nodes" "DBNodeList" {
  compartment_id = "${var.compartment_ocid}"
  db_system_id = "${oci_database_db_system.TFDBNode.id}"
}

# Get DB node details
data "oci_database_db_node" "DBNodeDetails" {
  db_node_id = "${lookup(data.oci_database_db_nodes.DBNodeList.db_nodes[0], "id")}"
}

# Gets the OCID of the first (default) vNIC
data "oci_core_vnic" "DBNodeVnic" {
  vnic_id = "${data.oci_database_db_node.DBNodeDetails.vnic_id}"
}

For more information, see Data Source Configuration.

Enabling Instance Principal Authorization

Instance principal authorization allows your provider to make API calls from an Oracle Cloud Infrastructure compute instance without needing the tenancy_ocid, user_ocid, fingerprint, and private_key_path attributes in your provider definition.

Note

Instance principle authorization applies only to instances that are running in the Oracle Cloud Infrastructure.

To enable instance principal authorization for Oracle Cloud Infrastructure Terraform providers, set the auth attribute to "InstancePrincipal" in your provider definition, as shown in the following example:

variable "region" {}

provider "oci" {
   auth = "InstancePrincipal"
   region = "${var.region}"
}

Example Terraform Providers

For Oracle Cloud Infrastructure Terraform provider examples, see Terraform Provider Examples. Examples are are grouped by service, including Compute, Database, Networking, Load Balancing, and several others.

For More Information