Provision a Cluster via Terraform

Provision a Cluster via Terraform

A focused, step-by-step tutorial for automating the provisioning of a MongoDB replicaset master node on 123cluster using Terraform with the Mastercard/restapi provider, demonstrating how to capture the REST API curl command from the UI, deconstruct its headers and payload, translate them into Terraform variables and resources, and integrate the process into a repeatable CI/CD workflow.

Step 1: Copy the curl Command from the UI

On the Create a new replicaset (Master) screen, click { REST API }. The following example is copied:

curl -v \
  -H "Authorization: Bearer <YOUR_JWT_TOKEN>" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "host": {
      "name":            "<HOST_NAME>",
      "ssh_port":        <SSH_PORT>,
      "username":        "<SSH_USERNAME>",
      "password":        "<SSH_PASSWORD>",
      "private_key":     "<OPTIONAL_PRIVATE_KEY_CONTENT>"
    },
    "cluster": {
      "name":            "<CLUSTER_NAME>"
    },
    "ex_params": {
      "replicaset_name": "<REPLICASET_NAME>",
      "repository":      "<BACKUP_REPOSITORY>",
      "ssl":             <USE_SSL>
      "service_name":    "proxmox",
      "proxmox":         true,
      "distributor":     "<OS_DISTRIBUTOR>",
      "release":         "<OS_VERSION>"
    },
    "name":              "<NODE_NAME>",
    "auto_delete":       false,
    "version":           "<DB_VERSION>",
    "auto_delete_days":  1,
    "port":              <DB_PORT>,
    "sizing":            "<SIZING>",
    "dir_123Cluster":    "<DATA_DIRECTORY>",
    "drop_inventories":  false,
    "database_user":     "<DB_ADMIN_USER>",
    "database_pwd":      "<DB_ADMIN_PASSWORD>",
    "rest_api":          true
  }' \
  <API_BASE_URL><API_PATH>

Step 2: Parse the curl Command

  • Authorization header: Extract your JWT token from Bearer <YOUR_JWT_TOKEN>.
  • Content-Type & Accept: Preserve both application/json headers.
  • Payload fields
  • host.name / host.ssh_port / host.username / host.password / host.private_key
  • cluster.name
  • ex_params.replicaset_name / ex_params.repository / ex_params.ssl / ex_params.distributor / ex_params.release
  • name (node identifier)
  • auto_delete / auto_delete_days
  • version / port / sizing / dir_123Cluster / drop_inventories
  • database_user / database_pwd
  • rest_api
  • Endpoint
  • Base URI: <API_BASE_URL>

Step 3: Translate into Terraform

Directory Structure

├── locals.tf

├── main.tf

├── outputs.tf

├── terraform.tfvars

└── variables.tf

Terraform Parameters

Replace fields in corner brackets <> in parameters file with values extracted from the URL.

File terraform.tfvars:

api_uri = "<API_BASE_URL>"
api_path = "<API_PATH>"
api_ssl_insecure = true
auth_key = "Bearer <YOUR_JWT_TOKEN>"
ssh_password = "<SSH_PASSWORD>"
ssh_private_key = "<OPTIONAL_PRIVATE_KEY_CONTENT>"
os_distro = "<OS_DISTRIBUTOR>"
os_release = <OS_VERSION>
database_user = "<DB_ADMIN_USER>"
database_pwd = "<DB_ADMIN_PASSWORD>"
cluster_name = "<CLUSTER_NAME>"
replicaset_name = "<REPLICASET_NAME>"
host_name = "<HOST_NAME>"
create_cluster_in_one_click = true
db_version = "<DB_VERSION>"
port = <DB_PORT>

Terraform Input Variables

Copy contents as is.

File variables.tf:

File variables.tf:
variable "api_uri" {
    description = "REST API base URL"
    type        = string
}

variable "api_path" {
    description = "REST API URI path for creating and object"
    type        = string
}

variable "api_ssl_insecure" {
    description = "Skip SSL cert checks on API calls"
    type        = bool
    default     = false
}

variable "auth_key" {
    description = "REST API Auth key"
    type        = string
    sensitive   = true
}

variable "ssh_port" {
    description = "SSH port for initial host setup"
    type        = number
    default     = 22
}

variable "ssh_user" {
    description = "SSH username"
    type        = string
    default     = "root"
}

variable "ssh_password" {
    description = "SSH password"
    type        = string
    sensitive   = true
}

variable "ssh_private_key" {
    description = "SSH private key"
    type        = string
    sensitive   = true
    default     = ""
}

variable "host_name" {
    description = "Host name"
    type        = string
}

variable "cluster_name" {
    description = "Name of the new DB cluster"
    type        = string
    default     = ""
}

variable "replicaset_name" {
    description = "Internal replicaset identifier"
    type        = string
    default     = ""
}

variable "repository" {
    description = "Backup repository location"
    type        = string
    default     = "network"
}

variable "use_ssl" {
    description = "Configure SSL"
    type        = bool
    default     = false
}

variable "service_name" {
    description = "Hosting service name"
    type        = string
    default     = "proxmox"
}

variable "is_proxmox" {
    description = "Is Proxmox used"
    type        = bool
    default     = true
}

variable "os_distro" {
    description = "OS Distributor name"
    type        = string
}

variable "os_release" {
    description = "OS Release (version) name"
    type        = number
}

variable "db_version" {
    description = "Desired DB server version"
    type        = string
}

variable "port" {
    description = "DB service port"
    type        = number
}

variable "mongos_port" {
    description = "MongoDB service port"
    type        = number
    default     = null
}

variable "data_directory" {
    description = "Data directory for DB files"
    type        = string
    default     = "/123cluster/mongo/data1"
}

variable "database_user" {
    description = "Database username"
    type        = string
}

variable "database_pwd" {
    description = "Database password"
    type        = string
    sensitive   = true
}

variable "sizing" {
    description = "Size of the deployment"
    type        = string
    default     = "SMALL"
}

variable "mysql_root_password" {
    description = "MySQL root password"
    type        = string
    sensitive   = true
    default     = ""
}

variable "pg_password" {
    description = "PostgreSQL administrator password"
    type        = string
    sensitive   = true
    default     = ""
}

variable "repmgr_pwd" {
    description = "PostgreSQL replication manager password"
    type        = string
    sensitive   = true
    default     = ""
}

variable "certificate_authentication" {
    description = "Use certificate authentication"
    type        = bool
    default     = null
}

variable "create_cluster_in_one_click" {
    description = "Create cluster in one click"
    type        = bool
    default     = null
}

variable "auto_delete" {
    description = "Delete server automatically"
    type        = bool
    default     = false
}

variable "auto_delete_days" {
    description = "Delete server automatically after N days"
    type        = number
    default     = 1
}
variable "drop_inventories" {
    description = "Delete all backups and exports if exist"
    type        = bool
    default     = false
}

Terraform Output Variables

Copy contents as is.

File outputs.tf:

/*
  Output the full JSON response from the API call.
  - Useful for logging, audit, or passing to downstream workflows.
*/
output "deploy_response" {
    description = "Raw JSON response from API call"
    value       = restapi_object.deploy.data
    sensitive   = true
}

Terraform Local Variables

Copy contents as is.

File locals.tf:

locals {
    call_params = merge(
        {
            host = {
                ssh_port    = var.ssh_port
                username    = var.ssh_user
                password    = var.ssh_password
                private_key = var.ssh_private_key
                name        = var.host_name
            }
            cluster = {
                name = var.cluster_name
            }
            ex_params                   = local.call_params_ex_params
            name                        = "${var.host_name}:${var.port}"
            auto_delete                 = var.auto_delete
            version                     = var.db_version
            auto_delete_days            = var.auto_delete_days
            port                        = var.port
            sizing                      = var.sizing
            dir_123Cluster              = var.data_directory
            drop_inventories            = var.drop_inventories
            database_user               = var.database_user
            database_pwd                = var.database_pwd
            rest_api                    = true
        },
        var.create_cluster_in_one_click != null ? {create_cluster_in_one_click = var.create_cluster_in_one_click} : {},
    )

    call_params_ex_params = merge(
        {
            repository      = var.repository
            ssl             = var.use_ssl
            service_name    = var.service_name
            proxmox         = var.is_proxmox
            distributor     = var.os_distro
            release         = var.os_release
        },
        var.replicaset_name != "" ? {replicaset_name = var.replicaset_name} : {},
        var.mongos_port != null ? {mongos_port = var.mongos_port} : {},
        var.mysql_root_password != "" ? {mysql_root_password = var.mysql_root_password} : {},
        var.pg_password != "" ? {pg_password = var.pg_password} : {},
        var.repmgr_pwd != "" ? {repmgr_pwd = var.repmgr_pwd} : {},
        var.certificate_authentication != null ? {certificate_authentication = var.certificate_authentication} : {},
    )

    ret_object_id = var.cluster_name
}

Terraform Main module

Copy contents as is.

File main.tf:

File main.tf:
terraform {
    required_providers {
        restapi = {
            source  = "Mastercard/restapi"
            version = "1.19.1"
        }
    }
}

provider "restapi" {
    uri                  = var.api_uri
    insecure             = var.api_ssl_insecure
    write_returns_object = true
    debug                = true
    headers = {
        Authorization = var.auth_key
        Content-Type  = "application/json"
        Accept        = "application/json"
    }
    create_method  = "POST"
    update_method  = "POST"
    destroy_method = "POST"
}

resource "restapi_object" "deploy" {
    path = var.api_path
    data = jsonencode(local.call_params)
    object_id = local.ret_object_id
}

Step 4: Deploy the Stack

Use Terraform to deploy the stack

# Download all dependencies
terraform init
# Validate the template
terraform validate
# Create the stack
terraform apply
# Retrieve outputs
terraform output deploy_response

Additional Guidance & Best Practices

Parameterization

All user-specific and environment-specific values are exposed as Terraform variables, making the template portable and reusable across multiple clusters, accounts.

Security

  • Sensitive Parameters: Use sensitive = true for passwords and tokens to prevent them from appearing in console or API responses.

API Versioning

Always verify endpoint and payload requirements with the latest 123cluster API documentation to ensure compatibility. Update the Lambda function code as the API evolves.