IT 3110: System Automation

Advanced Automated Configuration with Ansible

Advanced usage - loops

Sometimes you want to repeat a task multiple times. (I.e. add 5 different users).

    - name: Add several users
      ansible.builtin.user:
        name: "{{ item }}"
        state: present
        groups: "wheel"
      loop:
         - testuser1
         - testuser2

Advanced usage

You can define the list in a variables file, or in the ‘vars’ section of your play, then refer to the name of the list in the task:

    loop: "{{ somelist }}"

Advanced usage

You can pass a list directly to a parameter for some plugins. Most of the packaging modules, like yum and apt, have this capability. When available, passing the list to a parameter is better than looping over the task. For example:

    - name: Optimal yum
      ansible.builtin.yum:
        name: "{{  list_of_packages  }}"
        state: present
    
    - name: Non-optimal yum, slower and may cause issues with interdependencies
      ansible.builtin.yum:
        name: "{{  item  }}"
        state: present
      loop: "{{  list_of_packages  }}"

Advanced usage - A list of hashes

    - name: Add several users
      ansible.builtin.user:
        name: "{{ item.name }}"
        state: present
        groups: "{{ item.groups }}"
      loop:
        - { name: 'testuser1', groups: 'wheel' }
        - { name: 'testuser2', groups: 'root' }

Advanced usage - loop over a dict

    - name: Using dict2items
      ansible.builtin.debug:
        msg: "{{ item.key }} - {{ item.value }}"
      loop: "{{ tag_data | dict2items }}"
      vars:
        tag_data:
          Environment: dev
          Application: payment

Advanced usage - loop until

    - name: Retry a task until a certain condition is met
      ansible.builtin.shell: /usr/bin/foo
      register: result
      until: result.stdout.find("all systems go") != -1
      retries: 5 #runs up to 5 times (default is 3)
      delay: 10  #10 seconds between each attempt (default is 5)

Advanced usage - conditionals

Often you want to execute or skip a task based on facts. Facts are attributes of individual hosts, including IP address, operating system, the status of a filesystem, and many more. With conditionals based on facts:

  • You can install a certain package only when the operating system is a particular version.
  • You can skip configuring a firewall on hosts with internal IP addresses.
  • You can perform cleanup tasks only when a filesystem is getting full.

Advanced usage - conditional example

    tasks:
      - name: Shut down Debian flavored systems
        ansible.builtin.command: /sbin/shutdown -t now
        when: ansible_facts['os_family'] == "Debian"

Advanced usage - grouping conditions

    tasks:
      - name: Shut down CentOS 6 and Debian 7 systems
        ansible.builtin.command: /sbin/shutdown -t now
        when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or
              (ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")

Advanced usage - other conditionals

You can selectively:

  • import (include) other playbooks or tasks or roles
  • use conditionals in a loop
  • base on some other variables