Home > front end >  Ansible set_facts by localhost json file and copy to remote hosts
Ansible set_facts by localhost json file and copy to remote hosts

Time:04-26

I'm trying to copy a json file from my localhost to remote hosts, and use the json "version" key value as a parameter in the destination file name.

JSON:

{"name": "test", "version": 3}

YML:

---
- name: Get json file version
  hosts: locahost
  become: true
  tasks:
    - name: Register licenses file
      command: "cat conf/licenses.json"
      register: result

    - name: Save the json data
      set_fact:
        jsondata: "{{ result.stdout | from_json }}"

    - name: Save licenses file version
      set_fact:
        file_version: "{{ jsondata | json_query(jmesquery) }}"
      vars:
        jmesquery: 'version'

- name: Deploy Licenses File
  hosts: hosts
  become: true
  tasks:
    - name: Copy licenses file
      copy:
        src: "conf/licenses.json"
        dest: "/tmp/licenses_{{ file_version }}.json"

When I run the playbook above, the Deploy Licenses File key doesn't find the file_version fact, even though I can see it is successfully saved in the Get json file version key.

Set file_version fact:

ok: [localhost] => {
    "ansible_facts": {
        "file_version": "1"
    },
    "changed": false
}

Error:

The task includes an option with an undefined variable. The error was: 'file_version' is undefined

I think the facts are saved on the given host granularity and are not global facts per playbook initiation.

My current workaround is to combine the keys to a single task and then it works correctly, but I prefer to get the version once instead of repeating it for each remote host.

CodePudding user response:

To access facts of another host, you can always use the hostvars special variable.

So, in your case:

dest: "/tmp/licenses_{{ hostvars.localhost.file_version }}.json"

Now, you actually do not need that level of complication with two plays and could well do:

- name: Deploy Licenses File
  hosts: hosts
  become: true

  tasks:
    - name: Copy licenses file
      copy:
        src: "{{ _licence_file }}"
        dest: "/tmp/licenses_{{ file_version }}.json"
      vars:
        _licence_file: conf/licenses.json
        file_version: >-
          {{ (lookup('file', _licence_file) | from_json).version }}

CodePudding user response:

The first play runs at localhost only. Therefore the variables declared in the first play are available to localhost only. This is the reason that the variables are not available to host in the second play

The error was: 'file_version' is undefined

Run once the tasks in a block of the first play at all hosts. This way the variables will be available to all hosts in the second play. For example, the simplified playbook below does the job

- hosts: all
  tasks:
    - block:
        - include_vars:
            file: licenses.json
            name: jsondata
        - set_fact:
            file_version: "{{ jsondata.version }}"
      run_once: true

- hosts: test_11
  tasks:
    - copy:
        src: licenses.json
        dest: "/tmp/licenses_{{ file_version }}.json"

Created file at the remote host

shell> ssh admin@test_11 cat /tmp/licenses_3.json
{"name": "test", "version": 3}
  • Related