Cloud Services

Enterprise Marketplace

Kyndryl Terraform Engine
Published On Jun 17, 2024 - 9:30 AM

Kyndryl Terraform Engine

Learn the providers supported in Kyndryl Terraform Engine.
Terraform is an open-source infrastructure-as-code software tool that provides a consistent CLI workflow to manage hundreds of cloud services across many cloud providers. Terraform codifies cloud APIs into declarative configuration files.
The Kyndryl Terraform Engine supports infrastructure build, change, and destroy actions on your preferred cloud provider using Terraform. The latest version of Terraform supported is 1.5.7. The following public cloud provider versions are supported on the Kyndryl Terraform Engine:
  • IBM Cloud: 1.13.0
  • Microsoft Azure: All versions
  • Google Cloud: All versions
  • Alibaba Cloud: All versions
  • Amazon Web Service: All versions
This document is intended for users who want to import a service written in HashiCorp Configuration Terraform language, which is infrastructure as a code written using declarative configuration files.

Supported features

The Kyndryl Terraform Engine supports the following features:
  • Import and publish the template in the Enterprise Marketplace Catalog
  • Catalog configuration
  • Estimated pricing (for certain Terraform resources)
  • Provisioning and De-provisioning (New and Delete Order)
  • View inventory stack offering component
  • Template output params (if specified in the Terraform configuration file during import)

Overview of steps

The overall set of steps to be followed are mentioned below (with detailed descriptions in the forthcoming sections):
  • Create a Terraform configuration file (written in HashiCorp Configuration Language (HCL) with a
    .tf
    extension).
  • Create an
    icb_catalog_metadata.json
    containing the provider code to be used.
  • Create a zip file containing the
    icb_catalog_metadata.json
    at the root level and tf file in a directory (this can be nested based on how you want to structure your directories).
  • Import this zip file.
  • Publish that catalog, after which the catalog will be visible on the Catalog for configuring and provisioning.

Onboard a new provider

If you want to onboard a new cloud provider, complete the following steps:
  1. Register the Provider Adapter to enable the provider in the Catalog using this API:
    • Endpoint:
      http://cb-catalog-api:5080/catalog/v3/providers_adapters
    • Method:
      POST
    • Payload:
      https://github.kyndryl.net/MCMP-Integrations/cb-int-configurations/blob/master/IBMCLOUD/provider-adapter/provider_adapter.json
  2. Use one of the following options to enable the provider:
    • Create a new Content Server MicroService as per the provider
    • Modify an existing microservice to support a new provider
    • Use GCS
  3. Expose the following required APIs:
    • GET/POST configurations
    • GET/POST the templates and catalogs
    • POST nativeTemplate
    • GET/POST pricingTemplate
  4. Register the queue subscriptions with the Kyndryl Terraform Engine using the following API:
    • Endpoint:
      http://cb-consume-common-api:7080/emp/common/clients
    • Method:
      POST
    • Payload:
      https://github.kyndryl.net/MCMP-Integrations/cb-int-configurations/tree/master/IBMCLOUD/queue-subscriptions
  5. Create
    provider_tf
    files with the credential keys for the provider.
  6. Add the provider binary with the require version in the InitContainer.

Creating Terraform configuration files

Terraform configuration files can contain the following blocks:
  • A provider block
  • Optional terraform block
  • Single or multiple resource blocks
  • Optional data block
  • Optional output block
  • Optional depends_on attribute that manages the execution of Terraform resource provisioning if one resource needs to wait for another one to complete
  • Optional dependency of a resource attribute on another attribute in a different resource (dependency graph)
  • Optional nested blocks inside a resource
  • Optional local-exec, remote-exec, and connection provisioners
  • Variables in a separate configuration file
  • Multiple resources in separate configuration files

Terraform block

The Terraform block is part of the configuration file which is used to specify the Terraform version that a user might want to use. However, on the application this is not needed because the default version of Terraform (1.5.7) is used for all provisioning requests.

Provider block

The Terraform configuration file must contain a provider block that specifies the cloud provider for which the content is being imported. The provider block takes the following format:
provider <provider_name_on_terraform> {}
The following are sample provider blocks for the various providers, specifying the mandatory attributes needed inside the block:
  • Amazon Web Services:
    provider aws { region = “us-east-1” }
  • Google:
    provider google { region = “asia-east-1” }
  • Alibaba Cloud:
    provider alicloud { profile = default region = ap-south-1 }
  • Microsoft Azure:
    provider azurerm { features {} }
  • IBM Cloud:
    provider ibm {}

Resource blocks

Terraform uses resources to manage infrastructure, such as virtual networks, compute instances, and higher-level components such as DNS records. Resource blocks represent one or more infrastructure objects in your Terraform configuration. Resource blocks declare a resource type and name.
The following is an example of an EC2 instance resource:
resource "aws_instance" "web" { ami = "ami-a0cfeed8" instance_type = "t2.micro" user_data = file("init-script.sh") tags = { Name = random_pet.name.id } }
The
aws_instance.web
resource block defines an
aws_instance
resource named
web
to create the AWS EC2 instance. The arguments inside this resource block specify what type of resource to create.

Implicit and explicit dependencies

Dependencies in Terraform can be implicit or explicit. An implicit dependency is specified in the following example, where Terraform makes sure that
aws_instance.example_a
is created before
aws_eip.ip
.
aws_instance.example_b
can be created in parallel with any resource.
resource "aws_instance" "example_a" { ami = data.aws_ami.amazon_linux.id instance_type = "t2.micro" } resource "aws_instance" "example_b" { ami = data.aws_ami.amazon_linux.id instance_type = "t2.micro" } resource "aws_eip" "ip" { vpc = true instance = aws_instance.example_a.id }
An explicit dependency is specified using the
depends_on
attribute, as shown in the following example:
resource "ibm_security_group" "sg_public_lamp" { name = "sg_public_lamp" description = "Public access for LAMP stack to repos" } resource "ibm_security_group_rule" "https-pub" { direction = "egress" ether_type = "IPv4" port_range_min = 443 port_range_max = 443 protocol = "tcp" security_group_id = [ibm_security_group.sg_public_lamp.id] depends_on = [ibm_security_group.sg_public_lamp] }
You can also specify multiple resources in the
depends_on
argument. Terraform will wait until all of them have been created before creating the target resource.

Data sources

Data sources in Terraform are used to read objects while resource blocks can be used to create, update, and delete. This example shows adding a data block in the Terraform configuration file.
data "ibm_dns_domain_registration" "dns-domain-test" { name = "test-domain.com" } resource "ibm_dns_domain_registration_nameservers" "dns-domain-test" { dns_registration_id = data.ibm_dns_domain_registration.dns-domain-test.id name_servers = [ "ns006.name.ibm.cloud.com", "ns017.name.ibm.cloud.com"] }

Provisioners

Provisioners in Terraform are used to execute certain commands/scripts after the desired resource has been provisioned successfully. The tenant supports Generic Provisioners such as “remote-exec”, “local-exec”, and “connection”.
variable private_key { default = "" } resource "ibm_compute_vm_instance" "vm1" { hostname = "vmremote-exec" domain = "example.com" os_reference_code = "CENTOS_8_64" datacenter = "dal09" network_speed = 100 cores = 1 memory = 1024 disks = [25] provisioner "remote-exec" { inline = [ "mkdir -p /root/test-directory" ] connection { type = "ssh" user = "root" host = self.ipv4_address private_key = var.private_key } } }

Importing and publishing Terraform Templates

Import the Terraform native zip file using the Catalog Admin UI. For more information, see Template management using the Bring Your Own Catalog Item tool.
Keep the following in mind when importing a Terraform configuration file:
  • The directories inside the zip file uploaded for a provider must contain either Terraform configuration files or provider native templates, but not both. When importing a Terraform template, the directories must contain only Terraform configuration files with a .tf extension.
  • When importing multiple Terraform files in a single folder, only one of them should contain the provider block.
  • When importing Terraform configuration files, each folder is considered as one catalog. A single folder can contain multiple .tf files (for example, resource_1.tf, resource_2.tf, variables.tf). When there are multiple terraform configuration files in a folder, they are combined and then used to generate the metadata required.
  • The cloud provider codes for Terraform and those for the tenant are different. Make sure to add the valid provider code in the provider block of the Terraform configuration file and the provider code in the
    icb_catalog_metadata.json
    file. Incorrect mapping would result in failure when Catalog Admin tries to import that template.
  • The following are the corresponding codes for the tenant and Terraform:
    Tenant code
    Terraform code
    ibmcloud
    ibm
    aws
    aws
    azure
    azurerm
    alicloud
    alicloud
    gcp
    google
  • The provider block in the Terraform configuration file should contain an empty provider block whenever possible. Sample provider blocks for each provider are specified in theProvider block. In any case, the provider block should NOT contain any keys/credential information. Credentials are picked up from the payload during order provisioning and therefore must not be provided in the Terraform configuration files.

Imported service details

When the Terraform configuration file is imported, the syntax and structure of the file is validated. In case of failure, the import also fails. The Import status can be viewed by the Catalog Admin in the
History
section of the
Catalog Management
page.
Config Names and IDs for the catalog are generated using the resource type, resource name, and attribute name in that resource to make sure that it is unique across resources. For example, take the following Terraform configuration file (
test_vm.tf
).
provider ibm {} resource ibm_compute_vm_instance vm1 { hostname = “test1” domain = “test.co” } resource ibm_compute_vm_instance vm2 { hostname = “test2” domain = “test.co” } resource ibm_security_group secGrp { name = “testSecGrp” }
The metadata would be generated as follows:
Configuration Group Name: Ibm compute vm instance vm1 Config Name: Ibm compute vm instance vm1 hostname Config ID: ibm_compute_vm_instance-vm1-hostname Config Name: Ibm compute vm instance vm1 domain Config ID: ibm_compute_vm_instance-vm1-domain ============================================= Configuration Group Name: Ibm compute vm instance vm2 Config Name: Ibm compute vm instance vm2 hostname Config ID: ibm_compute_vm_instance-vm2-hostname Config Name: Ibm compute vm instance vm2 domain Config ID: ibm_compute_vm_instance-vm2-domain ============================================= Configuration Group Name: Ibm security group secGrp Config Name: Ibm security group secGrp name Config ID: ibm_security_group-secGrp-name
The Resource Name (such as
vm1
) must always be unique, regardless of the Resource Type to which it is bound.
All configurations are of freetext inputType and are marked as required. If you want the optional fields to not be marked as required, do not add them in the Terraform configuration file itself because Terraform will compute those fields during provisioning.
No explicit validations are applied on the configs/attributes generated using Servicification. If there are any errors in the specified values, this would be validated after order submission. After approval, the order would fail stating the reason for failure. Terraform resources that contain no keys (all keys are optional) cannot be converted into the tenant format, such as the older
ibm_object_storage_account
.
When the status of the catalog is changed to Published, the values provided in the Terraform configuration files are visible as the default values of the fields. Attributes that have no values provided in the Terraform configuration file are displayed as empty in the UI.

Pricing information based on Terraform resource types

Pricing support is currently available for the following Terraform resources:
Microsoft Azure
  • Virtual Machine
  • Virtual Network
  • Storage Account
Google Cloud Provider
  • Compute Engine
  • Compute Disk
  • Cloud Storage
  • Spanner
  • Cloud DNS
Amazon Web Services
  • EC2 (aws_instance)
  • S3 (aws_s3_bucket)
Alibaba Cloud
  • instance (alicloud_instance)
  • db (alicloud_db_database)
  • vpc (alicloud_vpc)
IBM Cloud

Inventory details

After successful provisioning, the details of the resource (provisioned using Terraform) are visible on the
Inventory
page in Enterprise Marketplace.
While expanding the stack components, if you see the message
Resource is already deleted from provider side
, the resource you have provisioned is no longer available on the cloud provider and therefore will be removed from the Enterprise Marketplace inventory.
Terraform also supports output attributes in the Terraform configuration file. If this attribute is specified during Servicification, Terraform will add it in the
tfState
file in the output attributes.
The
sensitive
attribute can be set as
true
to control the visibility of the Terraform output attributes in the UI.
The Output Attributes (if added by user) are visible in the
View Details
option of each stack component.

Usage of modules

The following are preferred practices when working with modules:
  • The parent terraform template that is using modules should be at the root level (not inside a folder). Example:
    - icb_catalog_metadata.json - Temp - rich-value-types - main.tf - network - main.tf - outputs.tf - variables.tf
  • Variables that need to be configurable also have to be at the root level where the parent terraform template is placed, from inside which the modules are referenced. Example:
    - icb_catalog_metadata.json - Temp - rich-value-types - main.tf - network - main.tf - outputs.tf - variables.tf
  • Modules that are present inside a catalog should be used for that catalog alone. To use the same module for another catalog, it should be inside the other catalog's folder. Example:
    - icb_catalog_metadata.json - templates - Service1 - main.tf - output.tf - provider.tf - variables.tf - MODULE1 //used in main.tf - Service2 - pool.tf - provider.tf - variables.tf - MODULE1 //used in pool.tf
  • If
    required_providers
    is used in the
    terraform block
    of the module (
    main.tf
    ) and also the parent template that uses the module, then both should use the same block. The following block must be present in both
    pool.tf
    and
    main.tf
    of the module.
    terraform { required_version = ">=0.13" required_providers { ibm = { source = "IBM-Cloud/ibm" } } }
    For a catalog structure use the following directory structure:
    - icb_catalog_metadata.json - templates - Service1 - pool.tf - output.tf - provider.tf - variables.tf - example // module used in pool.tf - main.tf - variables.tf
For more examples, see the following links:

Preferred practices

Consider the following preferred practices when using the Kyndryl Terraform Engine:
  • To attach system-generated tags like SOIID and SID to the provisioned resource, declare tags as variables in the Terraform template because implicit tagging of resources is not supported.
  • Ensure that no sensitive information is present if the return type of output parameter is an object because whatever JSON object is being returned as output param will be JSON STRINGIFied and shown on the
    Ordered Services
    page (inventory).
  • When data type in the variables is map(<>), the value that is present against the default value of the variable with map data type in the Terraform template is carried and shown in a text area in the UI after servicification. If the map data type is used, then the value against default must be supplied in the text area on the
    Additional parameters
    page.
  • Importing a Terraform configuration file takes the folder name as the catalog name for the catalog.
  • Check the features supported by Terraform 1.5.7 and 1.0.9.x version for the Terraform configuration file being created.
  • Make sure to provide only mandatory attributes in the provider block. Credentials should not be present. References are provided in the Provider block.
  • One single directory inside the zip file uploaded for a particular provider must contain either Terraform configuration files or provider native templates, but not both.
  • When importing a Terraform template, a single directory must contain files with a .tf extension.
  • If there are multiple .tf files in a directory, add the provider block only in one of those files.
  • Check the mapping of Terraform providers and the tenant provider code when creating the
    icb_catalog_metadata.json
    file.
  • Any issues/errors during import can be checked in the Catalog Discovery History.
  • All configurations on the UI are of freetext inputType and are marked as required. If you want the optional fields to not be marked as required, do not add them in the Terraform configuration file because Terraform will compute those fields during provisioning.
  • While importing the zip file (containing terraform files) from the
    Catalog Admin
    page as part of the servicification process, it is a best practice to abstract all the attributes used in your resource section as variables declarations. Doing so will abstract all those attributes and the same attributes will be transformed as configuration attributes for buyers while submitting an order

Known issues

This section lists the current known issues affecting the Kyndryl Terraform Engine divided by provider affected.

Generic known issues

The following known issues affect all providers:
  • Only tags added from Terraform templates are supported.
  • For list(Object)/Set(Object), if there is more than one default value in a template, the user will see only one default value in the Enterprise Marketplace UI.
  • Dynamic modules are only supported with public Git repositories and Terraform registry modules as source. Private Git repositories are not supported.
  • In Bulk VM, per quantity price is not supported.
  • Price will be calculated for single unit even if "count" in the Terraform template contains count in resource.
  • For variables of the type list (object) , the object will show up in the common configuration group.
  • Pricing is 0 for the whole catalog if the Terraform template contains both 0 cost resource (sec-group) and non-zero cost resource (VM) and all configs contributing to the cost are not added as variables.
  • Join and concatenate are not supported together, so the catalog import will fail. For more information, see https://github.com/amplify-education/python-hcl2/issues/72. Example:
    output "instances_ips" { value = join(",", concat(ibm_is_instance.instance_az1.*.primary_network_interface.0.primary_ipv4_address,ibm_is_instance.instance_az2.*.primary_network_interface.0.primary_ipv4_address)) }
  • For a single catalog, the
    resource name
    should be unique regardless of the
    resource type
    to which it is bound. This holds true even if there are multiple terraform configuration files that are part of the same catalog (in a single folder). For example, the following annotation is not allowed. However, there will not be any explicit validation errors, although duplicate configurations might be seen in the UI.
    resource ibm_security_group test {} resource ibm_compute_vm_instance test {}
  • If tag related attributes are specified in the resource as part of the Terraform configuration file, then they will be added in the resource on provider along with the
    ibm_mcmp_soiid
    . There is no mechanism for explicit resource tagging.
  • Terraform configuration files that contain attributes with special characters will not be servicified (such as
    user_metadata = "{\"value\":\"newvalue\"}"
    ).
  • For multiple terraform configuration files in a single folder, only one of them should contain the
    provider
    block. Otherwise the import will fail.
  • For multiple terraform configuration files in a single folder, there is no explicit validation if the configuration files are for different providers. The import might fail/succeed depending on which provider block is processed first.
  • While using the
    object
    and
    map
    data types, servification converts these into free text.
  • Servicification through Terraform Engine supports the
    type = any
    in variable declaration. the variable with
    type = any
    declaration will be transformed into a text area on the UI.
  • For catalogs created from Terraform templates,
    Edit Order
    is not supported on the stack created on the
    Ordered Services
    page because it will not create any change management on the provider side.

Google Cloud Platform known issues

The following issues are specific to Google Cloud Platform:
  • Tags are not supported for GCP. Use user-defined labels instead.
  • GCP Pricing is only supported for OOTB catalogs. For compute instance and compute disk resource types, some key attributes such as machineType, region, image, and preemptible should not be modified in the Terraform template.
  • Currently only the {project}/{family} format is supported for images.
  • For GPU pricing, duplicated keys are generated for type, so those values cannot be fetched.
  • For disks with the
    local-ssd
    parameter set multiple times, the count for
    local-ssd
    cannot be retrieved at the time of pricing.
  • For the Spanner service, location values are typically of the form
    regional- (regional-europe-west1)
    .
  • For MachineType, pricing is supported for only N1 series, f1-micro, and g1-small.
  • For the loadBalancer Service, pricing depends on the number of Forwarding rules being created, which cannot be fetched.
  • Pricing is only supported for a single resource.
  • Pricing cannot be calculated if a resource is part of a section.
  • Only out of the box (OOTB) resources are supported for pricing.
  • Compute Engine templates with tags fail at provisioning.

For more information

The following links are useful for more information about Terraform:
Do you have two minutes for a quick survey?
Take Survey