Home

Awesome

IMPORTANT - Due to Hashicorp licensing change Terraformize will no longer be able to update to new Terraform versions, as a result I'm pausing all work on Terraformize, this is done in part due to legal concerns as it's unclear if an Open source project would be considered a "competitive offer" and in part due to me not wishing to donate my time to HCP ecosystem now that they stopped giving back to the FOSS community

Terraformize

Apply\Destory Terraform modules via a simple REST API endpoint.

Github actions CI unit tests & auto dockerhub push status: CI/CD

Code coverage: codecov

Features

Possible use cases

Running

Running Terraformize is as simple as running a docker container

docker run -d -p 80:80 -v /path/to/my/terraform/module/dir:/www/terraform_modules/ naorlivne/terraformize

Feel free to skip to the end of the document for a working example that will explain how to use Terraformize

Configuration options

Terraformize uses sane defaults but they can all be easily changed:

valueenvvardefault valuenotes
basic_auth_userBASIC_AUTH_USERNoneBasic auth username to use
basic_auth_passwordBASIC_AUTH_PASSWORDNoneBasic auth password to use
auth_tokenAUTH_TOKENNonebearer token to use
terraform_binary_pathTERRAFORM_BINARY_PATHNoneThe path to the terraform binary, if None will use the default OS PATH to find it
terraform_modules_pathTERRAFORM_MODULES_PATH/www/terraform_modulesThe path to the parent directory where all terraform module directories will be stored at as subdirs
parallelismPARALLELISM10The number of parallel resource operations
rabbit_url_connection_stringRABBIT_URL_CONNECTION_STRINGNoneThe URL paramters string to connect to RabbitMQ with, if unset RabbitMQ will not be used and only API will be possible
rabbit_read_queueRABBIT_READ_QUEUEterraformize_read_queueName of the queue to read messages from
rabbit_reply_queueRABBIT_REPLY_QUEUEterraformize_reply_queueName of the queue to respond with the run result to
CONFIG_DIR/www/configThe path to the directory where configuration files are stored at
HOST0.0.0.0The IP for gunicorn to bind to
PORT80The port for gunicorn to bind to
WORKER_CLASSsyncThe gunicorn class to use
WORKERS1Number of gunicorn workers
THREADS1Number of gunicorn threads
PRELOADFalseIf gunicorn should preload the code
LOG_LEVELerrorThe log level for gunicorn
TIMEOUT600The timeout for gunicorn, if your terraform run takes longer you will need to increase it

The easiest way to change a default value is to pass the envvar key\value to the docker container with the -e cli arg but if you want you can also create a configuration file with the settings you wish (in whatever of the standard format you desire) & place it in the /www/config folder inside the container.

Most providers also allow setting their configuration access_keys\etc via envvars use -e cli args to configure them is ideal as well but should you wish to configure a file you can also easily mount\copy it into the container as well.

Authentication

Terraformize supports 3 authentication methods:

Endpoints

RabbitMQ queue

if you prefer using RabbitMQ instead of the API then you'll need to configure the rabbit_url_connection_string (examples can be seen at https://pika.readthedocs.io/en/stable/examples/using_urlparameters.html#using-urlparameters), Terrafromize will then use 2 Queues on rabbit (defined at the rabbit_read_queue & rabbit_reply_queue params), you don't have to create the queues manually, if need be they will be created.

Now all you need to do in order to have a terraform run is to publish a message to the rabbit_read_queue with the following format:

{
  "module_folder": "module_folder_name",
  "workspace": "workspace_name",
  "uuid": "unique_uuid_you_created_to_identify_the_request",
  "run_type": "apply/destroy/plan",
  "run_variables": {
    "var_to_pass_to_terraform_key": "var_to_pass_to_terraform_value",
    "another_var_to_pass_to_terraform_key": "another_var_to_pass_to_terraform_value"
  }
}

Terraformize will then run terraform for you and will return the result of the terraform run to the rabbit_reply_queue queue in the following format:

{
  "uuid": "unique_uuid_you_created_to_identify_the_request",
  "init_stdout": "...", 
  "init_stderr": "...", 
  "stderr": "...", 
  "stdout": "...", 
  "exit_code": 0
}

It's up to you to ensure the uuid you pass is indeed unique.

Example

  1. First we will need a terraform module so create a folder named terraformize_test:
    mkdir terraformize_test
    
    Make sure not to cd into the folder as we will be mounting it into the container from the parent folder in a couple of steps
  2. Now we need a valid terraform configuration in it, if it works in terraform it will work with terraformize but for this example we will keep it simple with a single terraformize_test/test.tf file:
    resource "null_resource" "test" {
      count   = 1
    }
    
    variable "test_var" {
      description = "an example variable"
      default = "my_variable_default_value"
    }
    
    output "test" {
      value = var.test_var
    }
    
  3. We will also need to add the folder we created into the Terraformize container, this can be done by many different way (for example creating a container that copies our modules into a new image with the FROM base image being Terraformize base image) but for this example we will simply mount the folder path into the container as we run it:
    docker run -d -p 80:80 -v `pwd`:/www/terraform_modules naorlivne/terraformize
    
  4. Now we can run the terraform module by simply calling it which will run terraform apply for us (notice how we are passing variables in the body):
    curl -X POST \
      http://127.0.0.1/v1/terraformize_test/my_workspace \
      -H 'Content-Type: application/json' \
      -H 'cache-control: no-cache' \
      -d '{
        "test_var": "hello-world"
    }'
    
  5. And lets create another copy infra of the same module in another workspace:
    curl -X POST \
      http://127.0.0.1/v1/terraformize_test/my_other_workspace \
      -H 'Content-Type: application/json' \
      -H 'cache-control: no-cache' \
      -d '{
        "test_var": "hello-world"
    }'
    
  6. Now that we are done let's delete them both (this will run terrafrom destroy for us):
    curl -X DELETE \
      http://127.0.0.1/v1/terraformize_test/my_workspace \
      -H 'Content-Type: application/json' \
      -H 'cache-control: no-cache' \
      -d '{
        "test_var": "hello-world"
    }' 
    curl -X DELETE \
      http://127.0.0.1/v1/terraformize_test/my_other_workspace \
      -H 'Content-Type: application/json' \
      -H 'cache-control: no-cache' \
      -d '{
        "test_var": "hello-world"
    }'