Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Loading variables from .env files in Ansible

Loading variables from .env files in Ansible

Ansible has various ways of looking up data from outside sources, including plain text password files, CSV files and INI files. But it doesn't seem to have a lookup for .env files, as used in Laravel projects, also available for PHP, Ruby, Node.js, Python and others.

One option is to launch Ansible with the Ruby dotenv command line script... But that requires Ruby, which seems like overkill to me.

So here is a simpler solution that I use. It consists of:

  1. The .env file itself
  2. A small shell script that loads the .env file into environment variables - ansible-playbook.sh
  3. The playbook, which reads from the environment variables into Ansible variables
SUDO_PASSWORD='correct battery horse staple'
HOSTNAME='example.com'
INSTALL_APACHE=true
# etc.
#!/bin/bash
set -o nounset -o pipefail -o errexit
# Load all variables from .env and export them all for Ansible to read
set -o allexport
source "$(dirname "$0")/.env"
set +o allexport
# Run Ansible
exec ansible-playbook "$@"
- hosts: all
become: true # Need sudo for most tasks
# These variables are needed to bootstrap Ansible
vars:
ansible_sudo_password: '{{ lookup("env", "SUDO_PASSWORD") }}'
# etc.
# Use 'set_fact' not 'vars' for the rest of the variables to ensure they are are evaluated immediately, to avoid getting this warning later:
# "[WARNING]: when statements should not include jinja2 templating delimiters" (see https://github.com/ansible/ansible/issues/22397)
pre_tasks:
- name: Loading environment variables
tags: always
set_fact:
# I write the variables in uppercase so they match the .env file - but you don't have to
# For booleans I use the strings "true" and "false", and convert them to booleans at this point
HOSTNAME: '{{ lookup("env", "HOSTNAME") }}'
INSTALL_APACHE: '{{ lookup("env", "INSTALL_APACHE") == "true" }}'
# etc.
@asfaltboy

This comment has been minimized.

Copy link

asfaltboy commented Jul 23, 2018

There's also python-dotenv if you already have python installed (and if you're using Ansible you probably do):

$ pip install -U "python-dotenv[cli]"
$ dotenv run ansible-playbook ...
@dkossako

This comment has been minimized.

Copy link

dkossako commented Oct 18, 2018

dotenv is not perfect solution while it waits for command finish before sending output to stdout, so you are not able to track logs in real time

@vigohe

This comment has been minimized.

Copy link

vigohe commented May 9, 2019

export $(cat .env | xargs)

@willww64

This comment has been minimized.

Copy link

willww64 commented May 30, 2019

export $(cat .env | xargs)

Can't deal with comment.

@uhurusurfa

This comment has been minimized.

Copy link

uhurusurfa commented Jun 19, 2019

Since you are writing a shell script to help you out, surely it is easier to just write the shell script to produce a yaml file that you can read using vars_files mechanism to import the file?

cat my_file.env | sed 's/[ ]*#[^$]*//;/^[[:space:]]*$/d' | awk -F= 'BEGIN{OFS="";} { print $1,": ","\"",$2,"\""; }' > ext_envs.yml

That way you do not need to manually enter the names of the variables in the environment file into the YAML file and you just use this in your playbook:
vars_files:
- ext_envs.yml

Put the below as a script file named convert_env_to_yml.sh:

#!/bin/sh
x=basename $0
out_file=ext_envs.yml
if test $# -lt 1; then
echo "ERROR :: Insufficient parameters."
echo "usage: ${x} [optional output file - defaults to ${out_file}]"
exit 1
fi

in_file=$1
if test $# -eq 2; then
out_file=$2
fi
cat ${in_file} | sed 's/[ ]#[^$]//;/^[[:space:]]*$/d' | awk -F= 'BEGIN{OFS="";} { print $1,": ",""",$2,"""; }' > ${out_file}
echo "Converted $in_file to $out_file"
exit 0

Then you can run the palybook using this:
convert_env_to_yml.sh myvars.env myvars.yml && ansible-playbook my_playbook.yml --extra-vars "@myvars.yml"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.