I’m trying to write an ansible playbook to install my application. I’m trying to detect that an environment variable is unset. I know I can use the lookup
plugin to find an environment variable like this: lookup('env', 'FOO')
.
My problem is that if the environment variable is not set, lookup
returns a blank string. However if the environment variable is set, and happens to be a blank string, I won’t be able to tell if the environment variable is actually set to ""
or entirely unset.
# my task:
- name:
when: lookup('env', 'FOO') == ''
ansible.builtin.debug:
msg: "FOO is unset!"
This task will print the debug message if FOO is unset, but also if FOO is actually a blank string.
According to the documentation, lookup
supports a default
parameter. Also according to the documentation, setting default=Undefined
or default=undef()
will cause the playbook to fail — which is true, it throws a templating error.
Since this is basically Python under the covers, I tried setting default=None
and checking like that:
- name:
when: lookup('env', 'FOO', default=None) is None
ansible.builtin.debug:
msg: "FOO is unset!"
However that returned a templating error because apparently Jinja doesn’t understand None.
fatal: [localhost]: FAILED! => {
"msg": "The conditional check 'lookup('env', 'FOO', default=None) is None' failed. The error was: template error while templating string: Could not load "None": 'None'. ..."
}
How do I go about identifying that an environment variable is actually undefined/unset? (Not a blank string. A blank string is allowed, but it’s set in that case. This variable is literally allowed to be set to anything; I just want to detect when it’s not.)
The jinja value for None
is none
, but that won’t help you; given:
- hosts: localhost
gather_facts: false
tasks:
- debug:
msg: >-
{{ lookup('env', 'TESTVAR', default=none) }}
When TESTVAR
is unset, the we get:
TASK [debug] **********************************************************************************************************************************************
ok: [localhost] => {
"msg": ""
}
I think the syntax of the lookup()
function isn’t terribly useful in this case. I think your best option to check for an unset environment variable is to ask the shell, something like this:
- hosts: localhost
gather_facts: false
tasks:
- register: res
failed_when: false
changed_when: res.rc != 0
shell: |
[ -z ${TESTVAR+x} ] && exit 1 || exit 0
- when: res is changed
debug:
msg: "TESTVAR is unset"
When TESTVAR
is unset, we get:
TASK [shell] **********************************************************************************************************************************************************************************************************************************************************************************************************
changed: [localhost]
TASK [debug] **********************************************************************************************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "TESTVAR is unset"
}
When TESTVAR
is set — even to an empty string — we get:
TASK [shell] **********************************************************************************************************************************************************************************************************************************************************************************************************
ok: [localhost]
TASK [debug] **********************************************************************************************************************************************************************************************************************************************************************************************************
skipping: [localhost]
The module setup subset env provides you with the dictionary ansible_env. See gather_subset
- setup:
gather_subset: env
- debug:
var: ansible_env
gives, for example, if you set FOO=bar
ansible_env:
BROWSER: /usr/bin/chromium-browser
CLUTTER_BACKEND: x11
COLORTERM: truecolor
DBUS_SESSION_BUS_ADDRESS: unix:path=/run/user/1000/bus
DEBUGINFOD_URLS: 'https://debuginfod.ubuntu.com '
DESKTOP_SESSION: xubuntu
DISPLAY: :0.0
EDITOR: emacs
FOO: bar
...
Declare the variable to make the code cleaner. (You can use a literal if you want to.)
my_env_var: FOO
You can test it first
- assert:
that: my_env_var in ansible_env
This will fail if FOO is missing, otherwise display the value
- debug:
var: ansible_env[my_env_var]
gives
ansible_env[my_env_var]: bar
If FOO is not set you’ll see
ansible_env[my_env_var]: None
As a result, you can’t set the string None as a valid value. Proceed if you can live with this limitation.
You have to test None to find out whether FOO is set or not
- debug:
msg: "{{ my_env_var }} is unset!"
when: ansible_env[my_env_var] == 'None'
Notes:
- lookup works only on the Ansible controller.
- See Setting the remote environment
Test all three options in the playbook below:
environment:
FOO: bar
environment:
FOO:
environment:
# FOO: bar
Example of a complete playbook for testing
- hosts: localhost
environment:
FOO: bar
vars:
my_env_var: FOO
tasks:
- setup:
gather_subset: env
- debug:
var: ansible_env
- assert:
that: my_env_var in ansible_env
- debug:
var: ansible_env[my_env_var]
- debug:
var: ansible_env[my_env_var] | type_debug
- debug:
msg: "{{ my_env_var }} is unset!"
when: ansible_env[my_env_var] == 'None'