X

Best Practices from Oracle Development's A‑Team

Getting Started Using Terraform with OCI

John Featherly
Cloud Native Architect

Introduction

Standing up infrastructure requires building networks, servers and storage entailing complex build and configuration management processes. Traditionally done with scripts or even manually, Terraform gives you a new alternative. Using Terraform you can write a declarative description of your infrastructure. Using the Terraform "compiler" the declaration is converted to a build plan and then the Terraform "builder" connects to your OCI tenancy and executes the plan. It is actually a bit more sophisticated than just doing the initial build. The builder connects to your tenancy and synchronizes it with the plan. Anything that already exists is left as-is, anything new is created and anything not in the plan is deleted. This allows you to edit your infrastructure by simply editing the Terraform code. Version control becomes only a matter of version control on the Terraform code.

The Shortest Path Example<_h3>

In this example we'll take the shortest path to creating a simple resource in an OCI tenancy using Terraform code to demonstrate the steps involved in getting started with Terraform. To try it out you will need the following.

  • an OCI tenancy<_li>
  • API SSL key pair<_li>
  • Terraform executable<_li>
  • code sample<_li>
  • Terraform OCI provider<_li> <_ul>

    Of course you will also need a personal computer to run Terraform. Pretty much anything will do; Linux, Mac or Windows it just needs a bash shell. Easy enough on Linux and Mac, on Windows I've found MobaXterm or Git Bash to be reasonable choices.

    Your OCI Tenancy<_h4>

    Login to the OCI console for your tenancy and collect the following identifying information

    • tenancy ID<_li>
    • user ID<_li>
    • compartment ID<_li> <_ul>

      These identifiers are all OCID's (pronounced O-sid) that look like ocid1.tenancy.oc1..aaaaaaaawpqblfemtluwxipipubxhioptheej2r32gvf7em7iftkr3vd2r3a<_span> and can be found on the tenancy and user information pages of the OCI console.

      API SSL Key<_h4>

      You will need an SSL key pair to enable Terraform to connect to the OCI API under your identity. Start by generating a key

      user@computer$ openssl genrsa -out oci_api_key.pem 2048<_pre>
      
      

      set file access to owner only read and write

      user@computer$ chmod 600 oci_api_key.pem<_pre>
      
      

      generate the public half of the key pair

      user@computer$ openssl rsa -pubout -in oci_api_key.pem -out oci_api_key_public.pem<_pre>
      
      

      The public key needs to be added to your user account in the OCI console. Open the account page for your user and select the "Add Public Key" button. Copy and paste the contents of the oci_api_key_public.pem file in the box of the "Add Public Key" dialog as shown below.

      Notice that after the public key is added the fingerprint is listed in the "API Keys" list. Copy the fingerprint for later use.

      Terraform Executable<_h4>

      The Terraform executable is available at terraform.io Available for Linux, Mac Windows etc. pick the binary that matches your PC.

      The download contains a single executable file. Unzip it to a directory that is on your PATH for example _home_me_bin. In order to update the executable when a new version is released simply download the new version, unzip and replace the executable.

      The Terraform Code<_h4>

      As a basic example we'll put together Terraform code to make a VCN (Virtual Cloud Network) in OCI. There are a number of ways to get the identifier information we collected into the code but the most common is by using environment variables. The top of our code sample will reference the environment variables as shown. Create a development directory and add the following to a file called vcn.tf.

      variable "tenancy_ocid" {}
      variable "user_ocid" {}
      variable "fingerprint" {}
      variable "private_key_path" {}
      variable "compartment_ocid" {}
      variable "region" {}
      provider "oci" {
        version          = ">= 3.0.0"
        tenancy_ocid     = "${var.tenancy_ocid}"
        user_ocid        = "${var.user_ocid}"
        fingerprint      = "${var.fingerprint}"
        private_key_path = "${var.private_key_path}"
        region           = "${var.region}"
      }<_pre>
      
      

      The corresponding environment variables have the form TF_VAR_* and hold the identity and connection information to the tenancy, user and compartment we collected earlier. Typically, put the following statements in a .sh file and source the file to set the environment values.

      export TF_VAR_tenancy_ocid=ocid1.tenancy.oc1..aaaaaaaawpqblfe ...
      export TF_VAR_user_ocid=ocid1.user.oc1..aaaaaaaacwmzc7bt ...
      export TF_VAR_fingerprint=43:7b:50:07: ...
      export TF_VAR_private_key_path=oci_api_key.pem
      ### Region
      export TF_VAR_region=uk-london-1
      ### Compartment
      export TF_VAR_compartment_ocid=ocid1.compartment.oc1..aaaaaaaaxxj ...<_pre>
      
      

      Now add the following Terraform code that declares a VCN to the bottom of the vcn.tf file.

      resource "oci_core_virtual_network" "simple-vcn" {
        cidr_block     = "10.0.0.0_16"
        dns_label      = "vcn1"
        compartment_id = "${var.compartment_ocid}"
        display_name   = "simple-vcn"
      }<_pre>
      
      

      The code declares a VCN resource named simple-vcn in the compartment identified from the compartment OCID environment variable.

      Terraform OCI Provider<_h4>

      The OCI provider is registered at Hashicorp and Terraform will download and update the plugin automatically as needed. In the directory containing the vcn.tf file run the init command as follows.

      user@computer$ terraform init<_pre>
      
      

      You should see something like the following showing that the provider has been downloaded and installed in the working directory.

      user@computer$ terraform init
      Initializing provider plugins...
      - Checking for available provider plugins on https:__releases.hashicorp.com...
      - Downloading plugin for provider "oci" (3.5.0)...
      Terraform has been successfully initialized!
      You may now begin working with Terraform. Try running "terraform plan" to see
      any changes that are required for your infrastructure. All Terraform commands
      should now work.
      If you ever set or change modules or backend configuration for Terraform,
      rerun this command to reinitialize your working directory. If you forget, other
      commands will detect it and remind you to do so if necessary.<_pre>
      
      

      Executing terraform -version<_span> will confirm the Terraform version and the provider version.

      user@computer$ terraform -version
      Terraform v0.11.10
      + provider.oci v3.5.0<_pre>
      
      

      Running<_h3>

      To create the build plan execute terraform plan<_span> in the working directory.

      user@computer$ terraform plan
      Refreshing Terraform state in-memory prior to plan...
      The refreshed state will be used to calculate this plan, but will not be
      persisted to local or remote state storage.
      ------------------------------------------------------------------------
      An execution plan has been generated and is shown below.
      Resource actions are indicated with the following symbols:
        + create
      Terraform will perform the following actions:
        + oci_core_virtual_network.simple-vcn
            id:                                                                 <computed>
            cidr_block:                                                         "10.0.0.0_16"
            compartment_id:                                                     "ocid1.compartment.oc1..aaaaaaaaxxjdxgyjxqxoiiv7yyb2zgez4pxaubsee4oguejnggwzhokqzhwa"
            default_dhcp_options_id:                                            <computed>
            default_route_table_id:                                             <computed>
            default_security_list_id:                                           <computed>
            display_name:                                                       "simple-vcn"
            dns_label:                                                          "vcn1"
            freeform_tags.%:                                                    <computed>
            state:                                                              <computed>
            time_created:                                                       <computed>
            vcn_domain_name:                                                    <computed>
      Plan: 1 to add, 0 to change, 0 to destroy.
      ------------------------------------------------------------------------
      Note: You didn't specify an "-out" parameter to save this plan, so Terraform
      can't guarantee that exactly these actions will be performed if
      "terraform apply" is subsequently run.<_pre>
      
      

      To create the resource execute terraform apply<_span> in the working directory.

      user@computer$ terraform apply
      An execution plan has been generated and is shown below.
      Resource actions are indicated with the following symbols:
        + create
      Terraform will perform the following actions:
        + oci_core_virtual_network.simple-vcn
            id:                       <computed>
            cidr_block:               "10.0.0.0_16"
            compartment_id:           "ocid1.compartment.oc1..aaaaaaaaxxjdxgyjxqxoiiv7yyb2zgez4pxaubsee4oguejnggwzhokqzhwa"
            default_dhcp_options_id:  <computed>
            default_route_table_id:   <computed>
            default_security_list_id: <computed>
            display_name:             "simple-vcn"
            dns_label:                "vcn1"
            freeform_tags.%:          <computed>
            state:                    <computed>
            time_created:             <computed>
            vcn_domain_name:          <computed>
      Plan: 1 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
      oci_core_virtual_network.simple-vcn: Creating...
        cidr_block:               "" => "10.0.0.0_16"
        compartment_id:           "" => "ocid1.compartment.oc1..aaaaaaaaxxjdxgyjxqxoiiv7yyb2zgez4pxaubsee4oguejnggwzhokqzhwa"
        default_dhcp_options_id:  "" => "<computed>"
        default_route_table_id:   "" => "<computed>"
        default_security_list_id: "" => "<computed>"
        display_name:             "" => "simple-vcn"
        dns_label:                "" => "vcn1"
        freeform_tags.%:          "" => "<computed>"
        state:                    "" => "<computed>"
        time_created:             "" => "<computed>"
        vcn_domain_name:          "" => "<computed>"
      oci_core_virtual_network.simple-vcn: Creation complete after 1s (ID: ocid1.vcn.oc1.uk-london-1.aaaaaaaajnknx...aa3tnnzvkxutb7urmrygugvvfnr77jcg6zy5pa)
      Apply complete! Resources: 1 added, 0 changed, 0 destroyed.<_pre>
      
      

      Checking the network resources in the console we see the VNC has been created.

      Execute terraform destroy<_span> to terminate the resource.

      user@computer$ terraform destroy
      oci_core_virtual_network.simple-vcn: Refreshing state... (ID: ocid1.vcn.oc1.uk-london-1.aaaaaaaajnknx...aa3tnnzvkxutb7urmrygugvvfnr77jcg6zy5pa)
      An execution plan has been generated and is shown below.
      Resource actions are indicated with the following symbols:
        - destroy
      Terraform will perform the following actions:
        - oci_core_virtual_network.simple-vcn
      Plan: 0 to add, 0 to change, 1 to destroy.
      Do you really want to destroy all resources?
        Terraform will destroy all your managed infrastructure, as shown above.
        There is no undo. Only 'yes' will be accepted to confirm.
        Enter a value: yes
      oci_core_virtual_network.simple-vcn: Destroying... (ID: ocid1.vcn.oc1.uk-london-1.aaaaaaaajnknx...aa3tnnzvkxutb7urmrygugvvfnr77jcg6zy5pa)
      oci_core_virtual_network.simple-vcn: Destruction complete after 1s
      Destroy complete! Resources: 1 destroyed.<_pre>
      
      

      Summary

      Terraform provides a powerful tool to create and manage infrastructure as code. Future additions to the tool set will likely include visual layout designers that will produce Terraform code from infrastructure diagrams and spreadsheets. Infrastructure as code is also a great option to rebuild environments in disaster recovery scenarios.

Join the discussion

Comments ( 6 )
  • Gurudatta N.R Thursday, September 26, 2019
    getting the following error

    Error: can not create client, bad configuration: did not find a proper configuration for private key

    on vcn.tf line 9, in provider "oci":
    9: provider "oci" {
  • naveen chaurasia Thursday, November 14, 2019
    nice example for beginners to understand TF execution
  • Dario Tuesday, November 26, 2019
    I am getting the same error

    Error: can not create client, bad configuration: did not find a proper configuration for private key

    on vcn.tf line 9, in provider "oci":
    9: provider "oci" {
  • John Featherly Wednesday, November 27, 2019
    the private key errors are most likely due to missing or improper path to the key file
  • Helen Friday, January 24, 2020
    That private key error can be caused if you have a passphrase associated to your private key. Generate a private key without a passphrase and try again.
  • John Monday, January 27, 2020
    A note for anyone using Terraform 0.12, string interpolation is no longer required on simple variable references. You can use the "0.12upgrade" command to clean your .tf files. The upgraded vcn.tf file from above looks like:

    provider "oci" {
    version = ">= 3.0.0"
    tenancy_ocid = var.tenancy_ocid
    user_ocid = var.user_ocid
    fingerprint = var.fingerprint
    private_key_path = var.private_key_path
    region = var.region
    }

    resource "oci_core_virtual_network" "simple-vcn" {
    cidr_block = "10.0.0.0/16"
    dns_label = "vcn1"
    compartment_id = var.compartment_ocid
    display_name = "simple-vcn"
    }
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha