Home > Back-end >  Reusing environment variables between tasks in Ansible
Reusing environment variables between tasks in Ansible

Time:09-18

I'm running a few tasks in a playbook which runs a bash script and registers its output:

playbook.yml:

- name: Compare FOO to BAZ
  shell: . script.sh
  register: output

- name: Print the generated output
  debug:
    msg: "The output is {{ output }}"
    
- include: Run if BAZ is true
  when: output.stdout == "true"

script.sh:

#!/bin/bash
FOO=$(curl example.com/file.txt)
BAR=$(cat file2.txt)
if [ $FOO == $BAR ]; then
  export BAZ=true
else
  export BAZ=false
fi

What happens is that Ansible registers the output of FOO=$(curl example.com/file.txt) instead of export BAZ.

Is there a way to register BAZ instead of FOO?

I tried running another task that would get the exported value:

- name: Register value of BAZ
  shell: echo $BAZ
  register: output

But then I realized that every task opens a separate shell on the remote host and doesn't have access to the variables that were exported in previous steps.

Is there any other way to register the right output as a variable?

CodePudding user response:

I've come up with a workaround, but there must be an other way to do this...

I added a line in script.sh and cat the file in a seperate task

script.sh:

...
echo $BAZ > ~/baz.txt

then in the playbook.yml:

- name: Check value of BAZ
  shell: cat ~/baz.txt
  register: output

CodePudding user response:

This looks a bit like using a hammer to drive a screw... or a screwdriver to plant a nail. Decide if you want to use nails or screws then use the appropriate tool.

Your question misses quite a few details so I hope my answer wont be too far from your requirements. Meanwhile here is an (untested and quite generic) example using ansible to compare your files and run a task based on the result:

- name: compare files and run task (or not...)
  hosts: my_group

  vars:
    reference_url: https://example.com/file.txt
    compared_file_path: /path/on/target/to/file2.txt

    # Next var will only be defined when the two tasks below have run
    file_matches: "{{ reference.content == (compared.content | b64decode) }}"

  tasks:
    - name: Get reference once for all hosts in play
      uri:
        url: "{{ reference_url }}"
        return_content: true
      register: reference
      delegate_to: localhost
      run_once: true

    - name: slurp file to compare from each host in play
      slurp:
        path: "{{ compared_file_path }}"
      register: compared

    - name: run a task on each target host if compared is different
      debug:
        msg: "compared file is different"
      when: not file_matches | bool 
        

Just in case you would be doing all this just to check if a file needs to be updated, there's no need to bother: just download the file on the target. It will only be replaced if needed. You can even launch an action at the end of the playbook if (and only if) the file was actually updated on the target server.

- name: Update file from reference if needed
  hosts: my_group

  vars:
    reference_url: https://example.com/file.txt
    target_file_path: /path/on/target/to/file2.txt

  tasks:
    - name: Update file on target if needed and notify handler if changed
      get_url:
        url: "{{ reference_url }}"
        dest: "{{ target_file_path }}"
      notify: do_something_if_changed

  handlers:
    - name: do whatever task is needed if file was updated
      debug:
        msg: "file was updated: doing some work"
      listen: do_something_if_changed

Some references to go further on above concepts:

  • Related