It looks like you have three different languages nested here, all of which have an interpolation syntax which uses similar characters but an entirely different source for the data:
- Terraform’s own template language in strings uses
${ ... }
for interpolation, referring to symbols from the current Terraform module.
- Unix shells typically use
$...
for interpolation, except in single quotes or when escaped, referring to environment variables.
- Perl’s regular expression replace syntax allows
$...
for interpolation into the result value, referring to values in the current Perl scope.
The resulting confusion is why I typically recommend avoiding using one language to generate another, and instead to keep all of these things separate. In your case, you could do that by moving this complicated shell script out into a separate .sh
file which you run from command
, and ideally also moving the three perl statements into a separate .pl
file which you can then run from your .sh
file. Something like this:
# Terraform configuration
resource "null_resource" "kubespray" {
provisioner "local-exec" {
command = "cd '${path.module}' && bash kubespray.sh"
environment = {
KI = var.kubespray_inventory
KV = var.kubernetes_version
}
}
}
# kubespray.sh
if [ ! -d ~/kubespray ]; then
git clone https://github.com/kubernetes-sigs/kubespray.git ~/kubespray
sudo apt-get autoremove -y
sudo apt-get update
sudo apt-get install python3-pip -y
sudo -H pip3 install -r ~/kubespray/requirements.txt
fi
if [ -d ~/kubespray/inventory/"$KI"]; then
mv ~/kubespray/inventory/"$KI" ~/kubespray/inventory/"$KI.$(date "+%Y%m%d-%H%M%S")"
fi
cp -r ~/kubespray/inventory/sample ~/kubespray/inventory/"$KI"
perl kubespray.pl
# kubespray.pl
# (my perl is rusty and I've not tested this, but hopefully
# it's a good enough approximation of your one-liners.)
my $KV = $ENV{'KV'};
my $KI = $ENV{'KI'};
open my $fh, '<', "$KI/group_vars/k8s-cluster/k8s-cluster.yml" or die "Can't open file $!";
my $content = do { local $/; <$fh> };
$content =~ s/# kubectl_localhost: false/kubectl_localhost: true/g;
$content =~ s/# kubeconfig_localhost: false/kubeconfig_localhost: true/g;
$content =~ s/kube_version: v[0-9].[0-9][0-9].[0-9]/kube_version: v$KV/g;
open my $fh, '>', "$KI/group_vars/k8s-cluster/k8s-cluster.yml" or die "Can't open file $!";
print $fh $content;
Through the exercise of de-embedding these I think I found the cause of your problem along the way: your last perl
call has the following argument:
-pe's/kube_version: v[0-9].[0-9][0-9].[0-9]/kube_version: v$KV/g'
Here the $KV
sequence is inside single quotes '
and so the shell will just treat it literally. Therefore Perl sees literally $KV
and so thinks you intend to interpolate a Perl variable called $KV
, which doesn’t exist and so (because you aren’t in use strict
mode) evaluates to an empty string.
You could potentially address that while keeping this nested pile by taking the $KV
part outside of the '
quotes so that the shell can evaluate it, but I think this situation is a pretty good example of why not to use one programming language to generate another programming language, and instead to let each layer be a separate static program that accepts input from the previous one.