General Page
Terraform patterns
Let's define a new pattern for IBM Cloud Virtual Server Instance. The pattern will allow users to provision an environment with customizable options (e.g. OS type, CPU, RAM, and local storage size).
The Terraform pattern should contain at least 3 config files: variables.tf, main.tf, output.tf, and 2 optional: input.tf and options.tf.
Let's create a new Terraform module with the following config files: 1) variables.tf Variables serve as parameters for a Terraform module, allowing aspects of the module to be customized without altering the module's own source code, and allowing modules to be shared between different configurations. The variable declaration can also include a default argument. If present, the variable is considered to be optional and the default value will be used if no value is set when calling the module or running Terraform. These variables are not available to users directly via UI, and can be changed only by reservation-ms miscroservice. Each template should contain cloud_provider variable with Cloud Provider ID for proper loading. At this moment, the GitOps pipeline supports: ibmcloud, aws, and azure.
```
Cloud Provider Credentials
variable "ibmcloudapikey" { type = string }
variable "iaasclassicapi_key" { type = string }
variable "iaasclassicusername" { type = string }
#
Cloud Provider ID
variable "cloud_provider" { type = string default = "ibmcloud" }
variable "resourcegroupname" { type = string default = "DTE" }
variable "accessgroupname" { type = string default = "dteroks-users" }
variable "datacenter" { type = string default = "dal13" }
variable "user_email" { type = string }
variable "user_id" { type = string }
variable "requestId" { type = string default = "NoID" }
variable "primarydisksize" { description = "Primary disk size" type = number default = 100 } ``` Here is the set of variables which will be sent to the GitOps Agent from the Reservation microservice: | Cloud Provider | ID | Variable | Description |----------------|-------------|----------|------------- | IBM Cloud | ibmcloud |ibmcloudapikey | API key | | |iaasclassicusername | Classic Infrastructure (SoftLayer) Username | | |iaasclassicapikey | Classic Infrastructure API key | AWS | aws |awsaccesskey | API Access Key | | |awssecretkey | API Secret Key | Azure | azure |subscriptionid | Subscription ID | | |clientid | Client ID | | |clientsecret | Client Secret | | |tenantid | Tenant ID | Any | |useremail | User Email | | |user_id | IBM Cloud User ID | | |requestId | Request ID associated with reservation
2) input.tf The input TF contains variables which are available to users for changing in the reservation forms.
``` variable "osreferencecode" { description = "Operating System" type = string default = "REDHAT864" }
variable "cpu_cores" { description = "CPU Cores" type = number default = 2 }
variable "memory" { description = "RAM" type = number default = 2 }
variable "secondarydisksize" { description = "Secondary disk size" type = number default = 0 } ``` Its variable descriptions will be rendered as labels for UI components (text box and drop-down list).
3) options.tf This file contains options for corresponding input variables. Please append input variable with _options part. They will be rendered as drop-down lists. ``` variable "osreferencecodeoptions" { type = list(object({ value = string prettyName = string })) default = [ { value = "REDHAT764" prettyName = "RHEL 7" }, { value = "REDHAT864" prettyName = "RHEL 8" }, { value = "UBUNTU20_64" prettyName = "Ubuntu 20.04 LTS" } ] }
variable "cpucoresoptions" { type = list(object({ value = number prettyName = string })) default = [ { value = 2 prettyName = "2" }, { value = 4 prettyName = "4" }, { value = 8 prettyName = "8" } ] }
variable "memory_options" { type = list(object({ value = number prettyName = string })) default = [ { value = 2 prettyName = "2 GB" }, { value = 4 prettyName = "4 GB" }, { value = 8 prettyName = "8 GB" }, { value = 16 prettyName = "16 GB" }, { value = 32 prettyName = "32 GB" } ] }
variable "secondarydisksize_options" { type = list(object({ value = number prettyName = string })) default = [ { value = 0 prettyName = "None" }, { value = 500 prettyName = "500 GB" }, { value = 1000 prettyName = "1 TB" }, { value = 2000 prettyName = "2 TB" }, { value = 5000 prettyName = "5 TB" } ] } ``` Results:

4) main.tf
The main config file consists the resources to be provisioned. ``` data "ibmresourcegroup" "resourcegroup" { name = var.resourcegroup_name }
resource "random_string" "suffix" { length = 5 special = false upper = false }
locals { vmname = "ibm-classic-${randomstring.suffix.result}" }
resource "random_string" "password" { length = 8 special = false upper = false }
data "ibmcomputesshkey" "publickey" { label = "gen1rsa" }
data "ibmsecuritygroup" "allowssh" { name = "allowssh" }
data "ibmsecuritygroup" "allowall" { name = "allowall" }
data "ibmsecuritygroup" "allowoutbound" { name = "allowoutbound" }
resource "ibmcomputevminstance" "vm" { hostname = local.vmname domain = "dte.demo.ibmcloud.com" osreferencecode = var.osreferencecode datacenter = var.datacenter networkspeed = 100 hourlybilling = true privatenetworkonly = false cores = var.cpucores memory = var.memory * 1024 disks = var.secondarydisksize > 0 ? [var.primarydisksize, var.secondarydisksize] : [var.primarydisksize] localdisk = false publicvlanid = 3103032 privatevlanid = 3103034 sshkeyids = [data.ibmcomputesshkey.publickey.id] tags = [var.userid, var.requestId] usermetadata = jsonencode({ type = { keyname = "USERDATA" name = "User Data" } value = { vncPassword = randomstring.password.result vncUser = "dteuser" } }) }
resource "ibmnetworkinterfacesgattachment" "sgprivate1" { securitygroupid = data.ibmsecuritygroup.allowall.id networkinterfaceid = ibmcomputevminstance.vm.privateinterfaceid softreboot = false }
resource "ibmnetworkinterfacesgattachment" "sgprivate2" { securitygroupid = data.ibmsecuritygroup.allowoutbound.id networkinterfaceid = ibmcomputevminstance.vm.privateinterfaceid softreboot = false }
resource "ibmnetworkinterfacesgattachment" "sgpublic1" { securitygroupid = data.ibmsecuritygroup.allowssh.id networkinterfaceid = ibmcomputevminstance.vm.publicinterfaceid softreboot = false }
resource "ibmnetworkinterfacesgattachment" "sgpublic2" { securitygroupid = data.ibmsecuritygroup.allowoutbound.id networkinterfaceid = ibmcomputevminstance.vm.publicinterfaceid softreboot = false }
data "external" "vsicredentials" { program = ["bash", "${path.module}/scripts/get-vsi-creds.sh"] query = { ibmcloudapikey = var.ibmcloudapikey vmid = ibmcomputevminstance.vm.id } dependson = [ibmcomputevm_instance.vm] } ```
5) output.tf Output values are a way to expose some of that information to the user of your pattern.
``` output "username" { description = "Username" value = data.external.vsi_credentials.result.username }
output "password" { description = "Password" value = data.external.vsi_credentials.result.password }
output "publicip" { description = "Public IP" value = ibmcomputevminstance.vm.ipv4_address }
output "privateip" { description = "Private IP" value = ibmcomputevminstance.vm.ipv4addressprivate }
output "os" { description = "Operating System" value = var.osreferencecode }
output "sharingportalid" { description = "Username" value = data.external.vsi_credentials.result.username }
output "sharingPortalPwd" { description = "Password" value = data.external.vsi_credentials.result.password } `` These output values will be rendered and presented to the user in its reservation card view.  sharingportalidandsharingPortalPwd` will be shown as username and password. 
Example: https://www.ibm.com/support/pages/node/7159447
Contribution
Save your TF files in a new folder. The folder name (e.g. ibm-classic-vm) will be used as your pattern name. Commit changes to https://www.ibm.com/support/pages/node/7159447 The GitOps agent will upload your pattern to Techzone automatically.
Was this topic helpful?
Document Information
Modified date:
19 February 2025
UID
ibm17159446