AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 79595799
Accepted
N-CODER
N-CODER
Asked: 2025-04-28 12:27:31 +0800 CST2025-04-28 12:27:31 +0800 CST 2025-04-28 12:27:31 +0800 CST

Como fazer com que o templatefile do Terraform ignore as variáveis ​​bash padrão?

  • 772

Este é meu script Bash:

#!/bin/bash

#Colors for terminal

#RED
R="\e[31m"

#GREEN
G="\e[32m"

#YELLOW
Y="\e[33m"

#NORMAL
N="\e[0m"

validation(){

    if [ $1 -eq 0 ];
    then 
        echo -e "${G}$2 is successful${N}"
    else 
        echo -e "${R}$2 has Failed${N}"
        exit 1;
    fi
}

echo -e "${Y}Configuring Cart Service${N}"

cart_config="/etc/systemd/system/cart.service"

cat << EOF >$cart_config

Environment=REDIS_HOST="${redis_ip}" #I want TF to only substitute these
Environment=CATALOGUE_HOST="${app_lb_dns}"

Environment=CATALOGUE_PORT=8082

EOF

validation $? "Configuring Cart Service"

Receberei meu endereço IP do Redis e o DNS do balanceador de carga após criá-los no Terraform, e quero passar um script bash como dados do usuário com esses valores substituídos. O problema é que o Terraform tenta substituir todas as variáveis ${}​​dentro do script bash, mas eu só quero que ele substitua ${redis_ip}e ${app_lb_dns}nos dados do usuário. Tentei escapar todas as variáveis ​​usando \${}e $${}, mas sem sucesso.

Erro:

20: user_data = base64encode(templatefile("../userdata/cart.sh", { redis_ip = data.aws_ssm_parameter.redis_ip.value, app_lb_dns = data.aws_ssm_parameter.app_lb_dns.value })) ao chamar templatefile(path, vars) Valor inválido para o parâmetro "vars": o mapa vars não contém a chave "G", referenciado em ../userdata/cart.sh:16,21-22.

Conforme o erro, o TF está tentando substituir uma variável relacionada ao script bash.

Este é meu código Terraform:

user_data = base64encode(templatefile("../userdata/cart.sh", { redis_ip = data.aws_ssm_parameter.redis_ip.value, app_lb_dns = data.aws_ssm_parameter.app_lb_dns.value }))
terraform
  • 2 2 respostas
  • 47 Views

2 respostas

  • Voted
  1. Marko E
    2025-04-28T18:26:09+08:002025-04-28T18:26:09+08:00

    Para que o Terraform ignore quaisquer variáveis ​​bash, você precisa adicionar um $. $Observe as sequências de escape do Terraform .

    Em outras palavras, você precisa corrigir o arquivo de modelo para ficar assim:

    #!/bin/bash
    
    #Colors for terminal
    
    #RED
    R="\e[31m"
    
    #GREEN
    G="\e[32m"
    
    #YELLOW
    Y="\e[33m"
    
    #NORMAL
    N="\e[0m"
    
    validation(){
    
        if [ $$1 -eq 0 ];
        then 
            echo -e "$${G}$$2 is successful$${N}"
        else 
            echo -e "$${R}$$2 has Failed$${N}"
            exit 1;
        fi
    }
    
    echo -e "$${Y}Configuring Cart Service$${N}"
    
    cart_config="/etc/systemd/system/cart.service"
    
    cat << EOF >$$cart_config
    
    Environment=REDIS_HOST="${redis_ip}" #I want TF to only substitute these
    Environment=CATALOGUE_HOST="${app_lb_dns}"
    
    Environment=CATALOGUE_PORT=8082
    
    EOF
    
    validation $$? "Configuring Cart Service"
    
    • 1
  2. Best Answer
    Martin Atkins
    2025-04-29T00:58:03+08:002025-04-29T00:58:03+08:00

    Como o Bash e o Terraform usam ${ ... }pontuação para representar a interpolação, se você usar a sintaxe de modelo do Terraform para gerar um script Bash, precisará usar a sintaxe de escape do Terraform em qualquer situação em que uma sequência de interpolação deva ser interpretada pelo Bash em vez do Terraform.

    Por exemplo:

    echo -e "$${Y}Configuring Cart Service$${N}"
    

    Observe que a linguagem de modelo do Terraform trata apenas ${como especial, enquanto o Bash suporta ambos $fooe ${foo}. Você só precisa escapar a sequência ${em particular; não é necessário escapar um cifrão individual que não seja seguido por uma chave de abertura.

    Tudo depois disso é explorar algumas maneiras diferentes de resolver o problema que têm outras compensações, mas se você estiver satisfeito em apenas escapar de tudo, então tudo bem e você pode parar de ler aqui.


    Você pode evitar esse tipo de conflito reorganizando seu script para que ele tenha apenas uma pequena parte de modelo e seja basicamente um arquivo estático.

    Por exemplo, se você colocar a maior parte do seu script em um arquivo de script bash estático chamado , cart.shvocê poderá gerar a pequena parte dinâmica separadamente dentro da user_dataexpressão, evitando tratá-la cart.shcomo um modelo do Terraform:

      user_data = <<-EOT
        #!/bin/bash
    
        declare -r cart_config=<<EOF
        Environment=REDIS_HOST="${data.aws_ssm_parameter.redis_ip.value}"
        Environment=CATALOGUE_HOST="${data.aws_ssm_parameter.app_lb_dns.value}"
        Environment=CATALOGUE_PORT=8082
        EOF
    
        ${file("${path.module}/../userdata/cart.sh")}
      EOT
    

    Observe que isso usa fileem vez de templatefilepara ler o cart.sharquivo e, portanto, o Terraform levará o conteúdo completamente ao pé da letra e não tentará interpretá-lo como um modelo.

    O código em cart.shpode ser escrito para se referir à variável cart_config, que é declarada usando o declarecomando templated no resultado geral. Como essa é a única variável que precisa incluir dados dinâmicos de outras partes do módulo Terraform, isso evita a necessidade de escapes extras no cart.sharquivo.

    echo >/etc/systemd/system/cart.service "$cart_config"
    

    A solução baseada em modelo embutido acima deve funcionar funcionalmente, mas eu pessoalmente achei seu formato irritante de manter e então escrevi um provedor de utilitário apparentlymart/bashque sabe como gerar declareinstruções adequadas e inseri-las no início de um script Bash.

    O exemplo anterior poderia ser reescrito usando meu provedor de serviços públicos para ficar algo assim:

    # Terraform requires that your module must declare a
    # dependency on this provider in order for its functions
    # to be available for use elsewhere in the module.
    terraform {
      required_providers {
        bash = {
          source = "apparentlymart/bash"
        }
      }
    }
    
    resource "aws_instance" "example" {
      # ...
      user_data = provider::bash::script(file("${path.module}/../userdata/cart.sh"), {
        cart_config = <<-EOT
          Environment=REDIS_HOST="${data.aws_ssm_parameter.redis_ip.value}"
          Environment=CATALOGUE_HOST="${data.aws_ssm_parameter.app_lb_dns.value}"
          Environment=CATALOGUE_PORT=8082
        EOT
      })
    }
    

    A chamada para provider::bash::scriptneste exemplo deve produzir um resultado semelhante ao modelo escrito à mão no meu exemplo anterior.


    Esta função fornecida pelo provedor também pode suportar mapas de strings e declará-los como "matrizes associativas" do Bash, o que permite uma alternativa onde os detalhes da sintaxe do arquivo "cart config" podem ser tratados dentro do script bash, em vez de dentro da configuração do Terraform:

    # (...again, a required_providers block must appear in your module...)
    
    resource "aws_instance" "example" {
      # ...
      user_data = provider::bash::script(file("${path.module}/../userdata/cart.sh"), {
        environment = tomap({
          REDIS_HOST     = data.aws_ssm_parameter.redis_ip.value
          CATALOGUE_HOST = data.aws_ssm_parameter.app_lb_dns.value
          CATALOGUE_PORT = "8082"
        })
      })
    }
    

    O acima significa que haverá uma variável Bash chamada environmentcujo valor é uma matriz associativa com os três elementos fornecidos, que você pode então iterar dentro do próprio script Bash:

    cart_config="/etc/systemd/system/cart.service"
    # Create the file, or truncate it if it already exists
    > $cart_config
    # Append each pair from "environment" as a line in the file
    for k in "${!environment[@]}"; do
        echo >>$cart_config "Environment=${k}=\"${environment["$k"]}\""
    done
    

    É discutível se essa complexidade adicional vale a pena para essa situação simples, mas essa técnica pode ser útil quando as chaves do mapa que serão usadas no script são escolhidas dinamicamente, já que o script reagirá apenas a quaisquer pares chave/valor que lhe forem fornecidos, em vez de esperar um conjunto fixo.

    (A técnica acima é complicada se os nomes ou valores das variáveis ​​puderem incluir caracteres que o Bash interpretaria de forma não literal, como símbolos "globbing". Há algumas ideias sobre isso em Outras dicas de robustez do Bash na documentação do meu provedor. Como isso está usando o Bash para gerar outra linguagem — a linguagem do arquivo de unidade do systemd — você também precisará garantir que as strings de chave e valor não contenham nada que torne isso inválido da perspectiva do systemd.)

    • 0

relate perguntas

  • Gerar JSON dinamicamente no Terraform

  • Crie usuário se ele não existir com Terraform

  • Terraform: copie elementos específicos do mapa onde especificado pela lista

  • O modelo Terraform não substitui variáveis ​​por valor

  • Não é possível recuperar um único ID de instância do EC2 de vários IDs para o módulo ALB

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve