how can I declare a variable to be able to accessible by all the tasks?

Viewed 47

I have situation where I have micro node server of different architectures so in ansible I wrote this approach to build the download path based on platform architecture and download and install to disk

---
- name: download node exporter
  tags: ["node_exporter"]
  vars:
    node_hosts:
      x86_64:
        archi: amd64
      aarch64:
        archi: arm64
      armv6l:
        archi: armv6
  get_url:
    url: https://github.com/prometheus/node_exporter/releases/download/v{{ node_exporter_version }}/node_exporter-{{ node_exporter_version }}.linux-{{node_hosts[ansible_architecture]['archi']}}.tar.gz
    dest: /tmp

- name: unarchive node exporter
  tags: ["node_exporter"]
  vars:
    node_hosts:
      x86_64:
        archi: amd64
      aarch64:
        archi: arm64
      armv6l:
        archi: armv6
  unarchive:
    remote_src: yes
    src: /tmp/node_exporter-{{ node_exporter_version }}.linux-{{node_hosts[ansible_architecture]['archi']}}.tar.gz
    dest: /tmp

- name: move node exporter to /usr/local/bin
  tags: ["node_exporter"]
  vars:
    node_hosts:
      x86_64:
        archi: amd64
      aarch64:
        archi: arm64
      armv6l:
        archi: armv6
  copy:
    src: /tmp/node_exporter-{{ node_exporter_version }}.linux-{{node_hosts[ansible_architecture]['archi']}}/node_exporter
    dest: /usr/local/bin/node_exporter
    remote_src: yes
    owner: root
    group: root
    mode: 0755

- name: remove repo.
  tags: ["node_exporter"]
  vars:
    node_hosts:
      x86_64:
        archi: amd64
      aarch64:
        archi: arm64
      armv6l:
        archi: armv6
  file:
    state: absent
    path: /tmp/node_exporter-{{ node_exporter_version }}.linux-{{node_hosts[ansible_architecture]['archi']}}

- name: install unit file to systemd
  tags: ["node_exporter"]
  template:
    src: templates/node_exporter.service.j2
    dest: /etc/systemd/system/node_exporter.service
    owner: root
    group: root
    mode: 0600

- name: configure systemd to use service
  tags: ["node_exporter"]
  systemd:
    daemon_reload: yes
    enabled: yes
    state: started
    name: node_exporter.service

My question here is: how can I create the node_hosts variable only once and access the value each time in all the tasks instead if recreating them in each task.

2 Answers

Given the tree

shell> tree .
.
├── ansible.cfg
├── group_vars
│   └── all
│       └── node_hosts.yml
├── hosts
└── pb.yml

Put the dictionary into the file in the directory group_vars/all. Such variables will be available to all hosts

shell> cat group_vars/all/node_hosts.yml 
node_hosts:
  x86_64:
    archi: amd64
  aarch64:
    archi: arm64
  armv6l:
    archi: armv6

Given the inventory

shell> cat hosts
host_1
host_2

and the playbook

shell> cat pb.yml 
- hosts: host_1,host_2
  gather_facts: false
  tasks:
    - debug:
        var: node_hosts

gives

shell> ansible-playbook pb.yml 

PLAY [host_1,host_2] *************************************************************************

TASK [debug] *********************************************************************************
ok: [host_1] => 
  node_hosts:
    aarch64:
      archi: arm64
    armv6l:
      archi: armv6
    x86_64:
      archi: amd64
ok: [host_2] => 
  node_hosts:
    aarch64:
      archi: arm64
    armv6l:
      archi: armv6
    x86_64:
      archi: amd64

You can use the set_fact module to define the variable node_hosts.

There is another improvement possibility: You can wrap all your tasks in one block, so it is sufficient to set the tag only once for this block. (more in Ansible Docs)

---
- name: node_exporter block
  tags: ["node_exporter"]
  block:
    - name: define node_hosts
      set_fact:
        node_hosts:
          x86_64:
            archi: amd64
          aarch64:
            archi: arm64
          armv6l:
            archi: armv6

    - name: download node exporter
      get_url:
        url: https://github.com/prometheus/node_exporter/releases/download/v{{ node_exporter_version }}/node_exporter-{{ node_exporter_version }}.linux-{{node_hosts[ansible_architecture]['archi']}}.tar.gz
        dest: /tmp

    - name: unarchive node exporter
      unarchive:
        remote_src: yes
        src: /tmp/node_exporter-{{ node_exporter_version }}.linux-{{node_hosts[ansible_architecture]['archi']}}.tar.gz
        dest: /tmp

    - name: move node exporter to /usr/local/bin
      copy:
        src: /tmp/node_exporter-{{ node_exporter_version }}.linux-{{node_hosts[ansible_architecture]['archi']}}/node_exporter
        dest: /usr/local/bin/node_exporter
        remote_src: yes
        owner: root
        group: root
        mode: 0755

    - name: remove repo.
      file:
        state: absent
        path: /tmp/node_exporter-{{ node_exporter_version }}.linux-{{node_hosts[ansible_architecture]['archi']}}

    - name: install unit file to systemd
      template:
        src: templates/node_exporter.service.j2
        dest: /etc/systemd/system/node_exporter.service
        owner: root
        group: root
        mode: 0600

    - name: configure systemd to use service
      systemd:
        daemon_reload: yes
        enabled: yes
        state: started
        name: node_exporter.service

There are many other ways to define variables.

For example, you can use vars: in your playbook to define variables that apply to the entire execution of the playbook.

---
- name: my Playbook
  hosts: all

  vars:
    first_variable: Hello World!
    some_variable: some other content

  tasks:
    - name: print first_variable
      debug:
        msg: "{{ first_variable }}"
Related