Need help

Hi All,

I am declaring an environment variables in a playbook as shown below:

Hi All,

I am declaring an environment variables in a playbook as shown below:


  • hosts: localhost
    environment:
    script_var1: hi
    script_var2: there
    tasks:
  • name: List
    shell: bash test.sh

I want to test the existence of the above environment variables in a separate task.yml file. How do I test their existence ? What is the syntax ?

Testing for existence means (in ansible terms) that you check if they’re defined.
If you just want to make sure they’re defined, you could use the assert module: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/assert_module.html

ansible.builtin.assert:
that:

  • script_var1 is defined
  • script_var2 is defined

etc

You say “separate task.yml file” - but what you have is not a task file but a playbook.

If you want to have the assert task in another file, then you should create that and then import that in your main playbook.
For example:

  • tasks:
  • import_tasks: separate.yml

You can run a shell task, echo the variables, register the result, and examine that. Otherwise:

**[utoddl@tango ansible]$ cat ygkumar0.yml** 
---
# Playbook ygkumar0.yml
- name: Test environment variables in included tasks file
  hosts: localhost
  gather_facts: false
  environment:
    script_var1: hi
    script_var2: there
  tasks:
    - name: Run tasks file
      ansible.builtin.include_tasks:
        file: tasks/ygkumar0.yml
**[utoddl@tango ansible]$ cat tasks/ygkumar0.yml** 
---
# tasks/ygkumar0.yml
- name: Test environment variables by shell script
  ansible.builtin.shell: |
    echo "We're here."
    echo "script_var0: '${script_var0-missing}'"
    echo "script_var1: '${script_var1-missing}'"
    echo "script_var2: '${script_var2-missing}'"
    echo "script_var3: '${script_var3-missing}'"

- name: Examine env vars directly
<i>  # THIS WON'T WORK! ansible.builtin.env allows you to query
  # the environment variables available on the controller when you invoked Ansible,
  # not the environment that tasks on the remote nodes see.</i>
  ansible.builtin.debug:
    msg:
      - "script_var0: {{ lookup('ansible.builtin.env', 'script_var0:') | default('missing') }}"
      - "script_var1: {{ lookup('ansible.builtin.env', 'script_var1:') | default('missing') }}"
      - "script_var2: {{ lookup('ansible.builtin.env', 'script_var2:') | default('missing') }}"
      - "script_var3: {{ lookup('ansible.builtin.env', 'script_var3:') | default('missing') }}"
**[utoddl@tango ansible]$ ansible-playbook ygkumar0.yml -vv**
ansible-playbook [core 2.14.10]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/utoddl/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.11/site-packages/ansible
  ansible collection location = /home/utoddl/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible-playbook
  python version = 3.11.5 (main, Aug 28 2023, 00:00:00) [GCC 13.2.1 20230728 (Red Hat 13.2.1-1)] (/usr/bin/python3)
  jinja version = 3.0.3
  libyaml = True
Using /etc/ansible/ansible.cfg as config file
redirecting (type: callback) ansible.builtin.yaml to community.general.yaml
redirecting (type: callback) ansible.builtin.yaml to community.general.yaml
Skipping callback 'default', as we already have a stdout callback.
Skipping callback 'minimal', as we already have a stdout callback.
Skipping callback 'oneline', as we already have a stdout callback.

PLAYBOOK: ygkumar0.yml *****************************************************************************
1 plays in ygkumar0.yml

PLAY [Test environment variables in included tasks file] *******************************************

TASK [Run tasks file] ******************************************************************************
task path: /home/utoddl/ansible/ygkumar0.yml:10
included: /home/utoddl/ansible/tasks/ygkumar0.yml for localhost

TASK [Test environment variables by shell script] **************************************************
task path: /home/utoddl/ansible/tasks/ygkumar0.yml:3
changed: [localhost] => changed=true 
  cmd: |-
    echo "We're here."
    echo "script_var0: '${script_var0-missing}'"
    echo "script_var1: '${script_var1-missing}'"
    echo "script_var2: '${script_var2-missing}'"
    echo "script_var3: '${script_var3-missing}'"
  delta: '0:00:00.002717'
  end: '2023-10-12 11:12:48.601248'
  msg: ''
  rc: 0
  start: '2023-10-12 11:12:48.598531'
  stderr: ''
  stderr_lines: <omitted>
  stdout: |-
    We're here.
    script_var0: 'missing'
    script_var1: 'hi'
    script_var2: 'there'
    script_var3: 'missing'
  stdout_lines: <omitted>

TASK [Examine env vars directly] *******************************************************************
task path: /home/utoddl/ansible/tasks/ygkumar0.yml:11
ok: [localhost] => 
  msg:
  - 'script_var0: '
  - 'script_var1: '
  - 'script_var2: '
  - 'script_var3: '

PLAY RECAP *****************************************************************************************
localhost                  : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Another thing you might consider is using a YAML reference to duplicate the environment in a regular playbook variable. Then you can use plain old variable references to see those values. See the example below:

**[utoddl@tango ansible]$ cat ygkumar1.yml** 
---
# Playbook ygkumar1.yml
- name: Copy environment to testable variables using YAML reference
  hosts: localhost
  gather_facts: false
  <b>environment: &environment
    script_var1: hi
    script_var2: there</b>
  vars:
    pb_dict:
      not_env_var1: foo
      not_env_var2: bar
      <b>env_vars: *environment</b>
      other_stuff: bas
  tasks:
    - name: Dump pb_dict to the job log
      ansible.builtin.debug:
        var: pb_dict

    - name: Shell script to loop over pb_dict.env_vars
      changed_when: false
      ansible.builtin.shell: |
        for vname in {{ pb_dict.env_vars.keys() | map('quote') | join(' ') }} ; do
            printf -- "Environment variable %s: %s\n" "$vname" "$(eval echo \${$vname} )"
        done
**[utoddl@tango ansible]$ ansible-playbook ygkumar1.yml -vv**
ansible-playbook [core 2.14.10]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/utoddl/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.11/site-packages/ansible
  ansible collection location = /home/utoddl/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible-playbook
  python version = 3.11.5 (main, Aug 28 2023, 00:00:00) [GCC 13.2.1 20230728 (Red Hat 13.2.1-1)] (/usr/bin/python3)
  jinja version = 3.0.3
  libyaml = True
Using /etc/ansible/ansible.cfg as config file
redirecting (type: callback) ansible.builtin.yaml to community.general.yaml
redirecting (type: callback) ansible.builtin.yaml to community.general.yaml
Skipping callback 'default', as we already have a stdout callback.
Skipping callback 'minimal', as we already have a stdout callback.
Skipping callback 'oneline', as we already have a stdout callback.

PLAYBOOK: ygkumar1.yml **********************************************************************
1 plays in ygkumar1.yml

PLAY [Copy environment to testable variables using YAML reference] **************************

TASK [Dump pb_dict to the job log] **********************************************************
task path: /home/utoddl/ansible/ygkumar1.yml:16
ok: [localhost] => 
  pb_dict:
    <b>env_vars:
      script_var1: hi
      script_var2: there</b>
    not_env_var1: foo
    not_env_var2: bar
    other_stuff: bas

TASK [Shell script to loop over pb_dict.env_vars] *******************************************
task path: /home/utoddl/ansible/ygkumar1.yml:20
ok: [localhost] => changed=false 
  cmd: |-
    for vname in script_var1 script_var2 ; do
        printf -- "Environment variable %s: %s\n" "$vname" "$(eval echo \${$vname} )"
    done
  delta: '0:00:00.003708'
  end: '2023-10-13 07:58:40.898459'
  msg: ''
  rc: 0
  start: '2023-10-13 07:58:40.894751'
  stderr: ''
  stderr_lines: <omitted>
  stdout: |-
    Environment variable script_var1: hi
    Environment variable script_var2: there
  stdout_lines: <omitted>

PLAY RECAP **********************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Hi All,

Thanks for the responses. I am facing another issue with env variables.

I want to register a variable to capture the output of a shell command as shown below. So far its fine…
But I also want to save that command result in a remote environment variable and that is not working. My playbook is as follows:

This is because the expression in the environment parameter is evaluated before the task, and at that time it is not yet known.
In general, if you need the output of a command to actually run the command, that seems like a circular dependency to me.

Ansible will not help you fix that.

So, you mean to say that we can’t achieve this in ansible ?

It might help if you can describe what you’re trying to achieve more broadly.

Typically, if you’re trying to do something complicated, and propagate state from task to task with loads of ansible.builtin.shell, you are likely to be approaching the task from the wrong angle.

What Dick’s tried to explain is that the environment keyword used in the way you’ve used it in your example, sets the environment for the task at the level it’s running. Not for future tasks, which seems to be what you want/expect.

You presumably want to use disk_count.stdout in a subsequent task. So you would set disk_count.stdout in the environment clause for a subsequent task. (And you’d need to format it for use as an environment variable. Read the docs.)

Ultimately though, if you’re jumping through a bunch of hoops like this you probably want to step back from shell and environment variables and think about 1) what you’re trying to achieve end-to-end and 2) how you might do that using native modules rather than shell/command.?