I'd like to use conditional statements in the packer template at the "provisioners" stage.
"provisioners": [
{
"execute_command": "echo 'vagrant'|sudo -S sh '{{.Path}}'",
"override": {
"virtualbox-iso": {
"scripts": [
"scripts/base.sh",
"scripts/puppet.sh",
]
}
},
"type": "shell",
}
]
For instance, if the user, at the "packer build" command line, specifies, somehow, a "puppet" parameter then then the "scripts/puppet.sh" will be executed otherwise skipped.
How can I do that?
A Packer template is a configuration file that defines the image you want to build and how to build it. Packer templates use the Hashicorp Configuration Language (HCL).
Provisioners use built-in and third-party software to install and configure the machine image after booting. Provisioners prepare the system, so you may want to use them for the following use cases: installing packages. patching the kernel. creating users.
You can make sure that sensitive variables won't get printed to the logs by adding them to the "sensitive-variables" list within the Packer template: { "variables": { "my_secret": "{{env `MY_SECRET`}}", "not_a_secret": "plaintext", "foo": "bar" }, "sensitive-variables": ["my_secret", "foo"], ... }
Builders are components of Packer that are able to create a machine image for a single platform. Builders read in some configuration and use that to run and generate a machine image. A builder is invoked as part of a build in order to create the actual resulting images.
I don't think that this is possible with packers native template formate, because packer uses the JSON format for configuration which as long as I know does not support flow control mechanisms like the conditional statement. But it should be possible to archive a similar behaviour with a user variables and the shell provisioner.
The easiest way should be to set a user variable from the build command and pass this variables from packer to the shell provisioner script which detects the value of the user variable and calls the appropriate provisioner script e.g. puppet, salt,...
I didn't test this approach, but it should give you a hint to what I mean and maybe you can come up with an even better solution. ;-)
1. Define the variable which indicates the used provisioner:
There are multiple ways to define a user variable,
by calling the packer build command with the -var flag (see end of answere)
define the user variables in the box-template file
The packer box template file: **template.json**
"variables": [
"using_provision_system": "puppet"
]
"provisioners": [
{...}
define a variable definition file and specify the path to it in the build command with -var-file
The variable file: **variables.json**
Is a great alternative if you want to define variables in a seperate file.
{
"using_provision_system": "puppet"
}
2. Calling the shell script which calls the provisioner scripts:
Now modify the execute_command in a way that the 'master' script is called with the defined variable as argument.
"provisioners": [
{
"execute_command": "echo 'vagrant'|sudo -S sh '{{.Path}}' '{{user `using_provision_system`}}'",
"override": {
"virtualbox-iso": {
"scripts": [
call_provisioner_script.sh
]
}
},
"type": "shell",
}
]
Notice, we only need to specify one script. This one 'master' script takes the passed variable as argument and compares the value with some predefined provisioner names in a switch condition. (Short: It chooses which provisioner scripts will be executed.)
master provision script: call_provisioner_script.sh
case $1 in
puppet*) sh puppet_provisioner.sh
*) sh shell_provisioner.sh
Take care!
Because this script will run inside your box, you might need to upload the scripts to the box before this command gets executed.
3. Last step is to build your box :)
Calling packers build command:
#define variable in build command (first option from above)
$ packer build -var 'using_provision_system=puppet' template.json
#define variables in variable file and set path in build command
$ packer build -var-file=variables.json template.json
Instead of using user variables, there should maybe a way to set enviromental variables in your box and use this type of variable to specify the provisioner.
An alternative way is to define 2 different builders which are of the same type but having different names. You can then exclude a provisioning step from a specific build using the only
field:
{
"source": "foo.txt",
"destination": "/opt/foo.txt",
"type": "file",
"only": ["docker-local"]
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With