Loops

To repeat a single task multiple times, you can use with_items.

with_items:

  • goes at the same level of the task
  • loops through iterable types (dict, list, ..)
  • puts each value in the item variable
- hosts: localhost
  tasks:    
  - name: Put with_items ad the same level of "debug" and "name"
    debug: 
      msg: "{{ item }}"
    with_items:          
    - one
    - two
    - three

You can use variables or facts

- hosts: localhost
  tasks:
  - name: Save ls output in result
    shell: |
      ls /etc/host*
    register: result

  - debug: 
      msg: "{{ item }}"
    with_items: >
      {{result.stdout_lines}}

with_items flattens list

- hosts: localhost
  tasks:
  - name: Save ls output in result
    shell: |
      ls /etc/host*
    register: result

  - debug: 
      msg: "{{ item }}"
    with_items: 
    - "{{result.stdout_lines}}"
    - foo
    - bar

In [ ]:
cd /notebooks/exercise-03

Conditions and Assertions

Conditions: when, end_meta

Ansible supports basic condition checking via when:

- hosts: localhost
  tasks:    
  - debug: msg="This always happens"
    when: true
  - debug: msg="This never does"
    when: false

You can use when with variables and conditions too:

- hosts: localhost  
  tasks:    
  - debug: msg="This is {{ansible_kernel}}!"
    when: ansible_system == 'Linux'

To graceful end a play, use meta: end_play

- hosts: localhost
  tasks:
  - stat:
      path: /opt/tomcat
    register: has_tomcat

  - name: Stop this playbook if /opt/tomcat exists.  
    meta: end_play
    when: has_tomcat.stat.isdir

  ... continue installing tomcat...

Remember on when and with_items

when statements should not include jinja2 templating delimiters such as {{ }} or {% %}

with_items requires proper templating and braces. Do it for all expressions everywhere except conditionals (when):


In [ ]:
!ansible-playbook conditions.yml --tags when

assertions: assert

The fail module is used to make assertions. Unless told otherwise, ansible playbooks stops when a task fail.

- hosts: localhost  
  tags: assert
  tasks:    
  - fail: msg="This is Linux!"
    when: ansible_system != 'Linux'

  - fail: msg="Stop processing now!"
    when: ansible_architecture == 'x86_64'

In [ ]:
!ansible-playbook conditions.yml --tags assert

Exercise

Edit conditions.yml and add a check on free disk size > 75%.

  • get informations from gather_facts
  • iterate thru partition with_items
  • use when and fail module

In [ ]:
!ansible-playbook conditions.yml --tags exercise

Predefined variables

There is a set of predefined variables too:

  • group_names
  • groups
  • environment

When using playbooks, we'll get this one too:

  • hostvars

In [ ]:
!ansible all[0] -i ../web -m debug -a "var=groups"

Exercise

Show the content of all 4 variables:

  • is every variable defined?
  • is every variable not empty?

In [ ]:
# Use this cell for the exercise

Shell environment & Files

Ansible can iterate thru local files using

- name: >
    Ansible can use globbing only on local system.
  debug:
    msg: >
      I live on the local system {{item}}
  with_fileglob:
  - "/etc/host*"

AFAIK There's not a remote version of with_fileglob, so you cannot loop over remote fileglob. This is because:

  • with_fileglob is implemented via executing code
  • ansible won't implicitly execute code on the remote host
  • a more complex implementation will be shown in the template lesson
- name: You can implement a remote fileglob in 2 steps
  shell: >
    ls /etc/host*
  register: fileglob_remote

- name: Here we go
  debug: msg="{{item}}"
  with_items: "{{fileglob_remote.stdout_lines}}"

In [ ]:
!ansible-playbook   -i web fileglob.yml --tags fileglob

You can pass environment variables (eg: /proc/PID/environ) to ansible plays via

- hosts: all
  environment:
    LD_LIBRARY_PATH: /usr/local/lib
  tasks:
    - name: >
        Set at taskgroup level, 
        but you can do it at task level too.
      shell: >
         echo $LD_LIBRARY_PATH

In [ ]:
!ansible-playbook  -vvv -i web fileglob.yml --tags environment

In [ ]: