Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ansible set_fact across plays

I have to run an ansible playbook to execute the following tasks

1) Calculate date in YYYY_MM_DD format and then use this prefix to download some file from aws to my local machine. The filename is of the following format 2015_06_04_latest_file.csv

2) I have to then create a folder by the name 2015_06_04 into multiple hosts and upload this file there.

This is my current playbook -

---
- hosts: 127.0.0.1
  connection: local
  sudo: yes
  gather_facts: no
  tasks:
  - name: calculate date
    shell: date "+%Y_%m_%d" --date="1 days ago"
    register: output
  - name: set date variable
    set_fact: latest_date={{ item }}
    with_items: output.stdout_lines
  - local_action: command mkdir -p /tmp/latest_contracts/{{ latest_date }}
  - local_action: command /root/bin/aws s3 cp s3://primarydatafolder/data/{{ latest_date }}_latest_data.csv  /tmp/latest_contracts/{{ latest_date }}/ creates=/tmp/latest_contracts/{{ latest_date }}/latest_data.csv
    register: result
    ignore_errors: true
  - local_action: command /root/bin/aws s3 cp s3://secondarydatafolder/data/{{ latest_date }}_latest_data.csv  /tmp/latest_contracts/{{ latest_date }}/ creates=/tmp/latest_contracts/{{ latest_date }}/latest_data.csv
    when: result|failed
# remove the date prefix from the downloaded file
  - local_action: command ./rename_date.sh {{ latest_date }}
    ignore_errors: true 
- hosts: contractsServers
  sudo: yes
  gather_facts: no
  tasks:
  - name: create directory
    file: path={{item.path}} state=directory mode=0775 owner=root group=root
    with_items:
    - {path: '/var/mukul/contracts/{{ latest_date }}' }
    - {path: '/var/mukul/contracts/dummy' }
  - name: copy dummy contracts
    copy: src=dummy dest=/var/mukul/contracts/
  - name: delete previous symlink
    shell: unlink /var/mukul/contracts/latest
    ignore_errors: true
  - name: upload the newly created latest date folder to the host
    copy: src=/tmp/latest_contracts/{{ latest_date }} dest=/var/mukul/contracts/
  - name: create a symbolic link to the folder on the host and call it latest
    action: file state=link src=/var/mukul/contracts/{{ latest_date }} dest=/var/mukul/contracts/latest

As per ansible's documentation on set_fact variable, this variable latest_date should be available across plays. However, ansible fails with the following message

failed: [192.168.101.177] => (item={'path': u'/var/mukul/contracts/{# latest_date #}'}) => {"failed": true, "item": {"path": "/var/mukul/contracts/{# latest_date #}"}}
msg: this module requires key=value arguments (['path=/var/mukul/contracts/{#', 'latest_date', '#}', 'state=directory', 'mode=0775', 'owner=root', 'group=root'])

It looks as if the second playbook is unable to get the value of the latest_date fact. Can you please tell me where i'm making a mistake?

like image 418
Mukul Jain Avatar asked Jun 05 '15 06:06

Mukul Jain


2 Answers

Facts are host specific. As the documentation about set_fact says, "[v]ariables [set with set_fact] are set on a host-by-host basis".

Instead, I'd try using run_once as defined in Delegation, rolling updates, and local actions, like this:

- hosts: contractsServers
  tasks:
    - name: Determine date
      local_action: shell: date "+%Y_%m_%d" --date="1 days ago"
      register: yesterday
      always_run: True
      changed_when: False
      run_once: True
    - name: Do something else locally
      local_action: ...
      register: some_variable_name
      always_run: True
      changed_when: False
      run_once: True

    - name: Do something remotely using the variables registered above
      ...
like image 80
Antonis Christofides Avatar answered Oct 17 '22 19:10

Antonis Christofides


You could enable fact-caching. You will need to set up a local redis instance where facts then will be stored.

like image 29
udondan Avatar answered Oct 17 '22 19:10

udondan