Line continuation within a variable

Is there a way to store multiple lines of bash commands into a variable? I’ve not found any examples of how to do this anywhere and have failed to come up with it on my own so far.

use case - i’m trying to use a null_resource to call provisioner “local-exec” and then pass in multiple commands. i can do this using <<EOT if i do it directly in the null_resource itself, but if i try to put the commands into a variable, terraform will fail on PLAN or APPLY because it “failed to load root config module, error parsing (path/variables.tf)” with illegal characters usually as the reason.

i’d like to be able to create a couple of different variables with different commands, then do a lookup in the actual null_resource to call the proper variable based on my lookup criteria. i just am struggling to figure out how to pass in multiple lines via a variable. Any help would be appreciated.

Hi @kylecompassion!

Could you please share exactly what you tried that led to the error “failed to load root config module, error parsing (path/variables.tf)”? That should help clarify what exactly you are trying to do here.

I’ll try to explain the outcome i’m looking for as it may be i’m going the completely wrong direction in the first place. Below is a null_resource with multiple commands in the local-exec piece. I’m trying to get everything within {} of local-exec into a variable so that i can maintain multiple variables with unique commands in each variable, and then use a LOOKUP within the null_resource so i can call different variables based on different ${terraform.workspace} values. So I’m trying to figure out how to properly write the variable so that it works when called by the local-exec provisioner.

  1. if there’s a better way to do this, let me know
  2. if this is a good way to reach my desired outcome, how do i do it?

Thanks!

resource “null_resource” “datadog_metrics” {
depends_on = [“null_resource.platform_auth”]
provisioner “local-exec” {
command = <<EOT
sudo runuser -l user -c ‘kubectl apply -f /home/terraform/kube-state-metrics/’;
sudo runuser -l user -c ‘kubectl apply -f /home/terraform/datadog_cluster_agent’/
EOT
}
}

Hi @kylecompassion! Here’s one way to do what you’re trying to do:

locals {
  per_workspace_commands = {
    workspace_a = <<-EOT
      sudo runuser -l user -c ‘kubectl apply -f /home/terraform/kube-state-metrics/’
      sudo runuser -l user -c ‘kubectl apply -f /home/terraform/datadog_cluster_agent/'
    EOT
    workspace_b = <<-EOT
      sudo runuser -l user -c ‘kubectl apply -f /home/terraform/kube-state-metrics/’
    EOT
  }
}

resource "null_resource" "datadog_metrics" {
  depends_on = [null_resource.platform_auth]

  provisioner "local-exec" {
    command = local.per_workspace_commands[terraform.workspace]
  }
}

I used a local value here because it didn’t sound from your description like this is something that should be overridden by a calling module, but if you do need the calling module to customize this then you could use a variable block instead, with the default value set to the same map expression:

variable "per_workspace_commands" {
  type = map(string)
  default = {
    workspace_a = <<-EOT
      sudo runuser -l user -c ‘kubectl apply -f /home/terraform/kube-state-metrics/’
      sudo runuser -l user -c ‘kubectl apply -f /home/terraform/datadog_cluster_agent/'
    EOT
    workspace_b = <<-EOT
      sudo runuser -l user -c ‘kubectl apply -f /home/terraform/kube-state-metrics/’
    EOT
  }
}
1 Like

Hi,
I have almost the same issue with local-exec. Please take a look at below.

resource "null_resource" "kops" {
  provisioner   "local-exec" {
      command    = <<EOT
kops create cluster 
--cloud ${var.cloud_provider} 
--name=${var.region}-${var.environment}-${var.city}.${var.k8s_domain} 
--state=s3://${var.bucket_name} 
--zones=${join(",",var.azs)} 
--node-count ${var.node_count} 
--node-size ${var.node_size} 
--master-count ${var.master_count} 
--master-size ${var.master_size} 
--master-zones ${element(var.azs, 0)},${element(var.azs, 1)},${element(var.azs, 2)} 
--vpc=${var.vpc_id.vpc_id} 
--networking=${var.networking_type} 
--subnets=${var.subnet_ids} 
--out=${var.region}-${var.environment}-${var.city}.${var.k8s_domain} 
--target=${var.target} 
--topology ${var.topology} 
--ssh-public-key ~/.ssh/kubernetes-poc.pub 
--yes
EOT
  }
}

I am getting the error below.

null_resource.cluster_folder: Creating...
null_resource.cluster_folder: Provisioning with 'local-exec'...


Error: 6 problems:

- Invalid function argument: Invalid value for "lists" parameter: list of string required.
- Error in function call: Call to function "element" failed: cannot read elements from string.
- Error in function call: Call to function "element" failed: cannot read elements from string.
- Error in function call: Call to function "element" failed: cannot read elements from string.
- Unsupported attribute: This value does not have any attributes.
- local-exec provisioner command must be a non-empty string

So any idea about the issue or how to guide me to the correct path?

Thank you

I found the issue and it’s already fixed.