12. Variables

12.1. Variable Definition

  • Variable names should be letters, numbers or underscores and should always start with a letter

  • variable files are in YAML format

  • valid file extensions include .yml, .yaml, .json or no file extension.

  • there are many places to define a variable

    • Inventory
    • Playbook
    • Roles
    • included Files
    • group_vars
    • host_vars
  • If multiple variables of the same name are defined in different places, they get overwritten in a certain order.

  • variables can override another, so the order is important (variable precedence)

  • If multiple groups have the same variable, the last one loaded wins.

  • Child groups variables override parent groups

  • Site wide values should be defined in group_vars/all.yml

Hint

It’s recommended to prefix your role variables with <rolename>_<variablename>.

Important

Variables are overwritten in a certain order!

12.1.1. How to use variables

  • Ansible is using the Jinja2 templating system
  • use {{ }} brackets
  • a variable in a task needs quotes '' -> '{{ myvariable }}'
  • use a variable in a template without quotes {{ myvariable }}

12.1.2. group_vars

  • directory is called group_vars
  • Ansible will pick up the group_vars directories in the same location as the inventory file
  • files can optionally end in .yml, .yaml or .json
  • you can create directories named after your groups and Ansible will read all the files in these directories
  • group_vars/all.yml can be used to define variables for all host groups.
group_vars/<group-name>/ntp.yml
group_vars/<group-name>.yml

Hint

If your group_vars file is big, create a folder for your group_vars. Then split the variables in specified files like ntp.yml

Important

Child groups override parent groups

12.1.3. host_vars

  • folder is called host_vars
  • Ansible will pick up the host_vars folder in the same location as the inventory file
  • all files in directories named after your hosts will be read by Ansible
  • you can create directories named after your hosts and Ansible will read all the files in these directories
  • single file with file exentsion possible (depends on the ansible version)
  • sub-files in directories with file extension
host_vars/<inventory-hostname>/connection.yml
host_vars/<inventory-hostname> / host_vars/<inventory-hostname>.yml

Important

The host_vars file or directory have to match with the inventory hostname.

12.2. Role Variables

12.3. Loops

  • loops are useful to do many things in one task

    • install a lot of packages
    • create a lot of users
  • there are a lot of loops availabe, checkout the links below

  • standard loop over a list works with with_items: btw. loop:

# list values defined in the task
- name: install some packages
  apt:
    name: '{{ item }}'
    state: present
  with_items:
    - apache2
    - python-pip

# list values defined in the task
- name: install some packages
  apt:
    name: '{{ item }}'
    state: present
  loop:
    - apache2
    - python-pip
  • you can define a list in the group_vars and use it
# group_vars/all.yml
mypackages:
  - apache2
  - python-pip

# use the variable mypackages
- name: install some packages
  apt:
    name: '{{ item }}'
    state: present
  with_items: '{{ mypackages }}'

# use the variable mypackages
- name: install some packages
  apt:
    name: '{{ item }}'
    state: present
  loop: '{{ mypackages }}'

12.4. Facts

  • everytime ansible is running on the managed node, it will gather facts from that system
  • the facts are available as variables
  • can be used in templates or playbooks
  • useful for conditions (e.g includes, tasks, variables)
  • facts can be turned off with gather_facts
  • only a subset of facts can be gathered via gather_subset
  • facts can be cached (default is memory -> no caching)

Hint

Facts are a good way for OS specific tasks / variables.

# file: playbook.yml
# turning off facts in a playbook
gather_facts: false
# show all facts
ansible -m setup <host/hostgroup>
  • load os variables based on facts in a playbook with vars_files:

12.5. Conditionals

  • skip or run a task if a condition is given (e.g os compatibilty, requirement)
  • multiple conditions are also allowed (and / or)
  • it’s also possible to negate a condition with !=

Hint

Conditionals in combination with loops -> when evaluates for EACH item

# file: conditional.yml
---
- hosts: web*.pascal.lab
  tasks:
    - name: install epel-release on redhat
      yum:
        name: epel-release
        state: latest
      when: ansible_os_family == "RedHat"

# file: conditional_or.yml
---
- hosts: web*.pascal.lab
  tasks:
    - name: "run on CentOS 7 and Debian 9 systems"
      command: whoami
      when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "7") or
            (ansible_distribution == "Debian" and ansible_distribution_major_version == "9")

# file: conditional_and.yml
---
- hosts: web*.pascal.lab
  tasks:
    - name: "run on CentOS 7 systems""
      command: whoami
      when:
        - ansible_distribution == "CentOS"
        - ansible_distribution_major_version == "7"

# file: conditional_not.yml
---
- hosts: web*.pascal.lab
  tasks:
    - name: "run on all other os systems""
      command: whoami
      when:
        - ansible_distribution != "CentOS"
  • you can import os specified variables with the include_vars module
# load os specific variables
- name: include Debian variables
  include_vars: debian.yml
  when: ansible_os_family == "Debian"
  • you can import os specified tasks with the include_tasks statement
# load os specific task
- name: include Debian task
  include_tasks: debian.yml
  when: ansible_os_family == "Debian"

12.6. Prompting for variables

  • When running a playbook, you may wish to prompt the user for certain input
  • this can be done with a vars_prompt: section.
  • name: defines the variablename

Hint

A common use-case could be asking for sensitive data that you do not want to record.

---
- name: give temporary root access
  hosts: "{{ hostname }}"

  vars_prompt:
    - name: list
      prompt: 'Enter host/host group'
      private: no
    - name: user
      prompt: 'Enter username'
      private: no

  tasks:
    - name: create sudo file
      template:
        src: sudo.j2
        dest: /etc/sudoers.d/temproot
        owner: root
        group: root
        mode: 0640
      become: yes
ansible-playbook prompt.yml
# prompt
Enter host/host group: web1.pascal.lab
Enter username: pascal

12.7. Register Variables

  • The value of a task being executed can be saved in a variable
  • use register: <variablename>
---
- hosts: web1.pascal.lab
  tasks:
    - name: run a command
      command: hostname
      register: myvar

    - name: print registered variable
      debug:
        msg: '{{ myvar }}'

# output
ok: [web1.pascal.lab] => {
    "msg": {
        "changed": true,
        "cmd": [
            "hostname"
        ],
        "delta": "0:00:00.004890",
        "end": "2016-04-21 06:06:20.604805",
        "rc": 0,
        "start": "2016-04-21 06:06:20.599915",
        "stderr": "",
        "stdout": "web1.pascal.lab",
        "stdout_lines": [
            "web1.pascal.lab"
        ],
        "warnings": []
    }
}

12.8. Playbook Blocks