Stefan
Stefan

Reputation: 1533

Create Terraform resources out of JSON values

I am looking for a way to generate Terraform code based on JSON values. Imagine I have a JSON file with the following structure:

{
  "settings": [
    {
      "conf": [
        {
          "setting": "DeploymentPolicy",
          "namespace": "aws:elasticbeanstalk:command",
          "value": "AllAtOnce"
        },
        {
          "setting": "BatchSize",
          "namespace": "aws:elasticbeanstalk:command",
          "value": "30"
        },
        {
          "setting": "BatchSizeType",
          "namespace": "aws:elasticbeanstalk:command",
          "value": "Percentage"
        }
      ]
    }
  ]
}

What I want to do is the following: Creating a working Terraform resource based on the JSON file values, e.g. a beanstalk environment like this:

resource "aws_elastic_beanstalk_environment" "app_prod" {
  name                   = "${aws_elastic_beanstalk_application_version.app.name}-prod"
  application            = aws_elastic_beanstalk_application.app.name
  solution_stack_name    = data.aws_elastic_beanstalk_solution_stack.latest_linux_java.name
  wait_for_ready_timeout = "10m"
  version_label          = aws_elastic_beanstalk_application_version.app.name

  # Elastic beanstalk configuration
  setting {
    name      = "DeploymentPolicy"
    namespace = "aws:elasticbeanstalk:command"
    value     = "AllAtOnce"
  }
  setting {
    name      = "BatchSize"
    namespace = "aws:elasticbeanstalk:command"
    value     = "30"
  }

  ...

}

Therefore I have to create the settings block in HCL (Terraform configuration) based on the JSON values. This means the JSON file above should result in:

  setting {
    name      = "DeploymentPolicy"
    namespace = "aws:elasticbeanstalk:command"
    value     = "AllAtOnce"
  }
  setting {
    name      = "BatchSize"
    namespace = "aws:elasticbeanstalk:command"
    value     = "30"
  }
  setting {
    name      = "BatchSizeType"
    namespace = "aws:elasticbeanstalk:command"
    value     = "Percentage"
  }

As you can see, the structure of JSON and HCL is very similar, but not identical. See e.g. settings, conf, or setting instead of name in the JSON.

A possible approach would be to read the JSON values and store them in an array or a map. But I have no idea how I could generate valid HCL and inject it in the desired part of the resource. Furthermore I tried to use a template but Terraform does not support the looping functionality that I need to iterate over the settings.

To sum up:

Does anyone have an idea how to do that? Any other approaches? Thanks a lot!

Upvotes: 6

Views: 9645

Answers (1)

Martin Atkins
Martin Atkins

Reputation: 74064

Assuming that your JSON object were in a file called settings.json inside your module directory, you could do something like this:

locals {
  environment_settings = jsondecode(file("${path.module}/settings.json")).settings[0].conf[0]
}

resource "aws_elastic_beanstalk_environment" "app_prod" {
  name                   = "${aws_elastic_beanstalk_application_version.app.name}-prod"
  application            = aws_elastic_beanstalk_application.app.name
  solution_stack_name    = data.aws_elastic_beanstalk_solution_stack.latest_linux_java.name
  wait_for_ready_timeout = "10m"
  version_label          = aws_elastic_beanstalk_application_version.app.name

  dynamic "setting" {
    for_each = local.environment_settings
    content {
      namespace = setting.value.namespace
      name      = setting.value.setting
      value     = setting.value.value
    }
  }
}

This special dynamic block is a sort of macro to create repeated setting blocks, each one correlating with one element of the collection given in for_each.

You can do whatever transformations of the input you need using Terraform's expression language in the locals block to ensure that the local.environment_settings value contains one element for each setting block you will generate, and then in the content nested block tell Terraform how to populate the setting arguments based on those element values.

Upvotes: 8

Related Questions