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 }))
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:
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:
Observe que a linguagem de modelo do Terraform trata apenas
${
como especial, enquanto o Bash suporta ambos$foo
e${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.sh
você poderá gerar a pequena parte dinâmica separadamente dentro dauser_data
expressão, evitando tratá-lacart.sh
como um modelo do Terraform:Observe que isso usa
file
em vez detemplatefile
para ler ocart.sh
arquivo 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.sh
pode ser escrito para se referir à variávelcart_config
, que é declarada usando odeclare
comando 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 nocart.sh
arquivo.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/bash
que sabe como gerardeclare
instruçõ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:
A chamada para
provider::bash::script
neste 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:
O acima significa que haverá uma variável Bash chamada
environment
cujo valor é uma matriz associativa com os três elementos fornecidos, que você pode então iterar dentro do próprio script Bash:É 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.)