Because many customers are in the process of building their infrastructure as code, the use cases for Terraform are growing. This is especially true when you’re automating the creation of an environment in Oracle Cloud Infrastructure (OCI) and using OCI Marketplace images. Using Terraform to deploy OCI Marketplace offerings lets you have all of your deployment code in an automated format for deployment and state management.

This post provides the basic necessary code for you to use to add OCI Marketplace images into your infrastructure with Terraform. It doesn’t cover creating any of the network or storage portions.

Required code

You need two resource elements and five data elements. The two resource elements are agreements for using the Marketplace image, and the data elements support the resource agreements.

Resource elements

The key resource elements that you need to use a Marketplace image are oci_marketplace_accepted_agreement and oci_marketplace_listing_package_agreement. These agreements also require several data elements to get the signed agreement.

Resource element: oci_marketplace_accepted_agreement

resource "oci_marketplace_accepted_agreement" "test_accepted_agreement" {
  #Required
  agreement_id    = oci_marketplace_listing_package_agreement.test_listing_package_agreement.agreement_id
  compartment_id  = var.compartment_id
  listing_id      = data.oci_marketplace_listing.test_listing.id
  package_version = data.oci_marketplace_listing.test_listing.default_package_version
  signature       = oci_marketplace_listing_package_agreement.test_listing_package_agreement.signature
}

Resource element: oci_marketplace_listing_package_agreement

resource "oci_marketplace_listing_package_agreement" "test_listing_package_agreement" {
  #Required
  agreement_id    = data.oci_marketplace_listing_package_agreements.test_listing_package_agreements.agreements[0].id
  listing_id      = data.oci_marketplace_listing.test_listing.id
  package_version = data.oci_marketplace_listing.test_listing.default_package_version
}

Data elements

To get the correct data for the resources, you need the following data elements:

  • Agreement ID
  • Compartment ID
  • Listing ID
  • Package version

The compartment ID is the OCID of the compartment in which you plan to install the Marketplace offering.

As a PowerShell user, I like to use the OCI PowerShell toolkit to get the listing ID information. The OCI PowerShell toolkit is in part of the common module, and the command is Get-OCIComputeAppCatalogListingsList. You can also get the display names and IDs of the catalog listings through other means, either from the Marketplace page or through the OCI CLI.

The PowerShell command looks as follows:

Figure 1: PowerShell output for Marketplace listings

You can get the same information with the OCI CLI, although you might have to scroll for a bit if you don’t have the name of the Marketplace offering ahead of time.

Figure 2: CLI output for Marketplace listings

After you have the display name, you’re ready to start looking at the Terraform code. You can use the display name to find the Marketplace image with a Terraform data object.

OCI_marketplace_listing

data "oci_marketplace_listings" "test_listings" {
  name = ["Microsoft SQL 2016 Standard with Windows Server 2016 Standard"]
  compartment_id = var.compartment_id
}

After you have the listing ID, then you can start gathering the rest of the information for the agreement resources.

Data elements

data "oci_marketplace_listing_package_agreements" "test_listing_package_agreements" {
  #Required
  listing_id      = data.oci_marketplace_listing.test_listing.id
  package_version = data.oci_marketplace_listing.test_listing.default_package_version

  #Optional
  compartment_id = var.compartment_id
}

data "oci_marketplace_listing_package" "test_listing_package" {
  #Required
  listing_id      = data.oci_marketplace_listing.test_listing.id
  package_version = data.oci_marketplace_listing.test_listing.default_package_version

  #Optional
  compartment_id = var.compartment_id
}

data "oci_marketplace_listing_packages" "test_listing_packages" {
  #Required
  listing_id = data.oci_marketplace_listing.test_listing.id

  #Optional
  compartment_id = var.compartment_id
}

data "oci_marketplace_listing" "test_listing" {
  listing_id     = data.oci_marketplace_listings.test_listings.listings[0].id
  compartment_id = var.compartment_id
}

data "oci_core_app_catalog_listing_resource_version" "test_catalog_listing" {
  listing_id = data.oci_marketplace_listing_package.test_listing_package.app_catalog_listing_id
  resource_version = data.oci_marketplace_listing_package.test_listing_package.app_catalog_listing_resource_version
}

Now that you have the agreement, you pass it to the instance information so that you can build the Marketplace offering in your OCI compartment. The resource in this example is oci_core_instance, and we pass to it the source ID from the data.oci_core_app_catalog_listing_resource_version.test_catalog_listing.listing_resource_id. This is an example of building a Microsoft SQL Server.

Instance resources

resource "oci_core_instance" "SQLA" {

  availability_domain = var.availability_domain1
  fault_domain        = var.instance_fault_domain_1
  compartment_id      = var.compartment_id
  display_name        = var.hostname_2
  shape               = var.sql_shape
  subnet_id           = oci_core_subnet.subnet2.id
  hostname_label      = var.hostname_2

  metadata = {
    user_data = base64encode(file("Meta Data script of your choosing"))
  }

  source_details {
    source_id   = data.oci_core_app_catalog_listing_resource_version.test_catalog_listing.listing_resource_id
    source_type = "image"
  }

  lifecycle {
    ignore_changes = [
      source_details[0].source_id,
    ]
  }
}

These are all the components that you need to deploy a Marketplace offering with OCI.

Putting it all together

Now that you have all the components for a Marketplace offering, let’s see what it looks like all together.

// Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved.
/*
* This is an example of a marketplace agreement
*/
provider "oci" {
  version          = ">= 3.0"
  tenancy_ocid     = var.tenancy_ocid
  user_ocid        = var.user_ocid
  fingerprint      = var.fingerprint
  private_key_path = var.private_key_path
  region           = var.region
}
/*
    Variables
*/
variable "tenancy_ocid" {
  default = "Your OCI Tenancy OCID"
}
variable "user_ocid" {
  default = "Your OCI user OCID"
}
variable "fingerprint" {
  default = "Your Finger Print"
}
variable "private_key_path" {
  default = "Your path to your .pem file"
}
variable "compartment_id" {
  default = "Enter your compartment OCID"
}
variable "hostname_1" {
  default = "SQLA"
}
variable "sql_shape" {
  default = "VM.Standard2.4"
}
variable "availability_domain1" {
  default = "AaRH:US-ASHBURN-AD-1"
}
variable "instance_fault_domain_1" {
  default = "FAULT-DOMAIN-1"
}
/*
    Resource Elements
*/
resource "oci_marketplace_accepted_agreement" "test_accepted_agreement" {
  #Required
  agreement_id    = oci_marketplace_listing_package_agreement.test_listing_package_agreement.agreement_id
  compartment_id  = var.compartment_id
  listing_id      = data.oci_marketplace_listing.test_listing.id
  package_version = data.oci_marketplace_listing.test_listing.default_package_version
  signature       = oci_marketplace_listing_package_agreement.test_listing_package_agreement.signature
}
resource "oci_marketplace_listing_package_agreement" "test_listing_package_agreement" {
  #Required
  agreement_id    = data.oci_marketplace_listing_package_agreements.test_listing_package_agreements.agreements[0].id
  listing_id      = data.oci_marketplace_listing.test_listing.id
  package_version = data.oci_marketplace_listing.test_listing.default_package_version
}
/*
    Data Elements
*/
data "oci_marketplace_listing_package_agreements" "test_listing_package_agreements" {
  #Required
  listing_id      = data.oci_marketplace_listing.test_listing.id
  package_version = data.oci_marketplace_listing.test_listing.default_package_version

  #Optional
  compartment_id = var.compartment_id
}
data "oci_marketplace_listing_package" "test_listing_package" {
  #Required
  listing_id      = data.oci_marketplace_listing.test_listing.id
  package_version = data.oci_marketplace_listing.test_listing.default_package_version

  #Optional
  compartment_id = var.compartment_id
}
data "oci_marketplace_listing_packages" "test_listing_packages" {
  #Required
  listing_id = data.oci_marketplace_listing.test_listing.id

  #Optional
  compartment_id = var.compartment_id
}
data "oci_marketplace_listing" "test_listing" {
  listing_id     = data.oci_marketplace_listings.test_listings.listings[0].id
  compartment_id = var.compartment_id
}
data "oci_marketplace_listings" "test_listings" {
#  category       = ["Analytics"]
  name = ["Microsoft SQL 2016 Standard with Windows Server 2016 Standard"]
  compartment_id = var.compartment_id
}
data "oci_core_app_catalog_listing_resource_version" "test_catalog_listing" {
  listing_id = data.oci_marketplace_listing_package.test_listing_package.app_catalog_listing_id
  resource_version = data.oci_marketplace_listing_package.test_listing_package.app_catalog_listing_resource_version
}
/*
    Compute Resources
*/
resource "oci_core_instance" "SQLA" {
  availability_domain = var.availability_domain1
  fault_domain        = var.instance_fault_domain_1
  compartment_id      = var.compartment_id
  display_name        = var.hostname_1
  shape               = var.sql_shape
  subnet_id           = oci_core_subnet.subnet1.id
  hostname_label      = var.hostname_1
  metadata = {
    user_data = base64encode(file("Meta Data script of your choosing"))
  }
  source_details {
    source_id   = data.oci_core_app_catalog_listing_resource_version.test_catalog_listing.listing_resource_id
    source_type = "image"
  }
  lifecycle {
    ignore_changes = [
      source_details[0].source_id,
    ]
  }
}

To complete your environment, you’ll need to add resources such as a virtual cloud network (VCN) and subnets.

Wrap-up

After putting it all together, you have code that will let you get an Oracle Cloud Infrastructure Marketplace offering and add it to your Terraform code to help you develop better deployment practices. Good luck and happy coding.