Provision a Standby via Terraform

Provision a Standby via Terraform

A focused, step-by-step tutorial for provisioning an additional MongoDB standby node in an existing replicaset on 123cluster using Terraform with the Mastercard/restapi provider, demonstrating how to extract the REST API curl command from the UI, parse its JSON payload, map each field to Terraform variables and resources, and produce a reproducible CI/CD–ready workflow.

Step 1: Copy the curl Command from the UI
On the Add a new standby node 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":         "<MONGO_HOST_IP>",
      "ssh_port":     <SSH_PORT>,
      "username":     "<SSH_USERNAME>",
      "password":     "<SSH_PASSWORD>",
      "private_key":  "<OPTIONAL_PRIVATE_KEY>"
    },
    "cluster": {
      "name":         "<CLUSTER_NAME>"
    },
    "ex_params": {
      "replicaset_name": "<REPLICASET_NAME>",
      "mongo_master_id":  <MONGO_MASTER_ID>,
      "voting":           true
    },
    "name":              "<NODE_NAME>",
    "auto_delete":       false,
    "version":           "<MONGODB_VERSION>",
    "auto_delete_days":  1,
    "port":              <MONGO_PORT>,
    "sizing":            "SMALL",
    "cluster_role":      "STANDBY",
    "dir_123Cluster":    "<DATA_DIRECTORY>",
    "drop_inventories":  false,
    "rest_api":          true
  }' \
  <API_BASE_URL>/create_mongo_node/

Step 2: Parse the curl Command

  • JWT Token: Copy the string following Bearer.
  • Headers: Retain both Content-Type: application/json and Accept: application/json.
  • Payload fields:
    • host.name / host.ssh_port / host.username / host.password / host.private_key
    • cluster.name
    • ex_params.replicaset_name / ex_params.mongo_master_id / ex_params.voting
    • name
    • auto_delete / auto_delete_days
    • version / port / sizing / cluster_role
    • dir_123Cluster / drop_inventories
    • rest_api
  • Endpoint:
    • Base URI: <API_BASE_URL>
    • Resource path: /create_mongo_node/

Step 3: Translate into Terraform

  • Create directory & file
integration/
└── terraform/
    └── create_standby_node/
        └── main.tf
  • Provider block
// Terraform configuration for automating the creation of a MongoDB standby node in 123cluster
terraform {
  required_providers {
    restapi = {
      source  = "Mastercard/restapi"
      version = "1.19.1" // Always specify a stable provider version for reproducibility
    }
  }
}

/*
  REST API provider configuration:
  - uri: Base API endpoint for 123cluster.
  - headers: HTTP headers needed for authentication and JSON content negotiation.
  - write_returns_object: Enables response as an object for downstream usage.
  - debug: Turns on verbose request/response logging.
  - HTTP methods: POST is used for create, update, and destroy operations, as required by the API.
*/
provider "restapi" {
  uri                  = "<API_BASE_URL>"
  write_returns_object = true
  debug                = true
  headers = {
    Authorization = "Bearer <YOUR_JWT_TOKEN>" // Use a secure JWT for authenticated API access
    Content-Type  = "application/json"
    Accept        = "application/json"
  }
  create_method  = "POST"
  update_method  = "POST"
  destroy_method = "POST"
}
  • Variable declarations
/*
  All critical configuration values are exposed as variables.
  This approach ensures the code is reusable in different environments and automatable in CI/CD pipelines.
*/

variable "mongo_host_ip" {
  description = "IP address of the MongoDB host"
  type        = string
  default     = "<MONGO_HOST_IP>"
}

variable "ssh_port" {
  description = "SSH port for host access"
  type        = number
  default     = <SSH_PORT>
}

variable "ssh_user" {
  description = "SSH username"
  type        = string
  default     = "<SSH_USERNAME>"
}

variable "ssh_password" {
  description = "SSH password"
  type        = string
  default     = "<SSH_PASSWORD>"
}

variable "cluster_name" {
  description = "Name of the MongoDB cluster"
  type        = string
  default     = "<CLUSTER_NAME>"
}

variable "replicaset_name" {
  description = "Name of the replicaset"
  type        = string
  default     = "<REPLICASET_NAME>"
}

variable "mongo_master_id" {
  description = "ID of the master node to which this standby will connect"
  type        = number
  default     = <MONGO_MASTER_ID>
}

variable "node_name" {
  description = "Identifier for this standby node"
  type        = string
  default     = "<NODE_NAME>"
}

variable "mongodb_version" {
  description = "Desired MongoDB version for the standby node"
  type        = string
  default     = "<MONGODB_VERSION>"
}

variable "mongo_port" {
  description = "MongoDB port on the standby node"
  type        = number
  default     = <MONGO_PORT>
}

variable "data_directory" {
  description = "Data directory for MongoDB data files"
  type        = string
  default     = "<DATA_DIRECTORY>"
}
  • Resource definition
/*
  This resource maps all required parameters from variables to the API payload.
  - Uses jsonencode() to serialize the request data.
  - All required fields from the original curl command are present and parameterized.
  - Sensitive values should be handled securely in production.
*/
resource "restapi_object" "create_standby" {
  path = "/create_mongo_node/"
  data = jsonencode({
    host = {
      name        = var.mongo_host_ip
      ssh_port    = var.ssh_port
      username    = var.ssh_user
      password    = var.ssh_password
      private_key = "" // Optionally use a variable for private_key if required
    }
    cluster = {
      name = var.cluster_name
    }
    ex_params = {
      replicaset_name = var.replicaset_name
      mongo_master_id = var.mongo_master_id
      voting          = true // This standby node will participate in voting for the replicaset
    }
    name              = var.node_name
    auto_delete       = false // Prevent automatic deletion of the node
    version           = var.mongodb_version
    auto_delete_days  = 1
    port              = var.mongo_port
    sizing            = "SMALL"
    cluster_role      = "STANDBY" // Designate this node as a standby (secondary)
    dir_123Cluster    = var.data_directory
    drop_inventories  = false
    rest_api          = true // Allows future API management
  })
}
  • Output block
/*
  Output the full JSON response from the API.
  This is helpful for debugging, logging, or extracting details for further automation.
*/
output "standby_response" {
  description = "Raw JSON response from create_mongo_node"
  value       = restapi_object.create_standby.data
}

Step 4: Initialize & Apply

cd integration/terraform/create_standby_node

# Initialize the Terraform working directory and download necessary providers
terraform init

# Apply the configuration, review the planned actions, and confirm execution
terraform apply

# Output the API response for logging or integration with other tools
terraform output standby_response

Additional Guidance & Best Practices

  • Parameterization: By defining all configuration details as Terraform variables, you ensure the setup is modular, reusable, and easy to maintain across different clusters or environments.
  • Security: Always store sensitive credentials (such as passwords, SSH keys, tokens) securely—use environment variables, a secret manager, or mark variables as sensitive within Terraform.
  • CI/CD Integration: Integrate these Terraform steps into your CI/CD pipeline for automated, consistent, and auditable standby node provisioning.
  • API Compatibility: Regularly check 123cluster API documentation for any updates to endpoints or payloads to avoid compatibility issues.
  • Logging & Outputs: Use Terraform outputs to capture the full API response for tracking, debugging, or triggering downstream processes.
  • Isolation: Utilize Terraform workspaces to separate resources and manage deployments for dev, test, and production environments independently.
  • Error Handling: Implement validation and error handling in your pipeline to catch API errors early and prevent misconfigurations or partial deployments.