Managing task control
Using with_items
Using Nested Loops
Using the when statement
Registering variables
Working with handlers
Working with tags
Dealing with errors
Using ansible blocks
Optimizing ansible
Selecting hosts with host patterns
Configuring delegation
Delegation outside the inventory
Configuring parallelism
Troubleshooting ansible
Understanding ansible logging
Troubleshooting playbooks
Troubleshooting managed hosts
2. Table of contents
( part A - Basics )
1. History
2. Introduction
a. Why ansible
b. Understanding YAML
3. Basics getting started
a. Setting up ansible
b. Managing configuration and Inventory
c. Ad-hoc commands
d. Working with modules
e. Understanding playbooks
f. Variables, includes, imports and facts
g. Understanding Jinja2 templates
4. Working with roles
○ Understanding role structure
○ Creating roles
○ Deploying roles with ansible galaxy
○ Using the ansible galaxy CLI utility
Iman Darabi
https://www.linkedin.com/in/imandarabi/
3. Table of contents
( part B - Advanced )
1. Managing task control
a. Using with_items
b. Using Nested Loops
c. Using the when statement
d. Registering variables
e. Working with handlers
f. Working with tags
g. Dealing with errors
h. Using ansible blocks
2. Optimizing ansible
a. Selecting hosts with host patterns
b. Configuring delegation
c. Delegation outside the inventory
d. Configuring parallelism
3. Troubleshooting ansible
a. Understanding ansible logging
b. Troubleshooting playbooks
c. Troubleshooting managed hosts
Iman Darabi
https://www.linkedin.com/in/imandarabi/
4. Understanding Loops
● Loops can be used to repeat tasks based on different items
○ For each Item in a list
○ Contents of files in a list
○ Sequence or numbers
● Using loops avoids writing multiple tasks if that’s not necessary
● with_items is a simple looping mechanism
5. Using with_items
● with_items defines a list of items that needs to be processed
● with_items is used as a label, listing the different items
● To refer to an item, {{ item }} is used
○ - name: httpd and vsftpd are running
○ Service:
○ Name: “{{item}}”
○ State: started
○ with_items:
○ - httpd
○ - vsftpd
6. Providing with_items Using Variables
● The list of items can be provided using a variable as well
○ vars:
○ web_services:
○ - httpd
○ - vsftpd
○ tasks:
○ - name: start web services
○ service:
○ name: “{{ item }}”
○ state: started
○ with_items: “{{ web_services }}”
7. Complex Items
● Items can be defined as a hash/dictionary, where each item has multiple keys
● Refer to the items using item.key1 and item.key2
○ - name: manage users and group membership
○ user:
○ name: “{{ item.name }}”
○ state: present
○ groups: “{{ item.groups }}”
○ with_items:
○ - { name: ‘linda’, groups: ‘students’ }
○ - { name: ‘anna’, groups: ‘profs’ }
8. Nested Loops
● A nested loop is a loop inside a loop
● Two lists are used, and tasks will run on item in the first list, combined with items in the
second list
○ tasks:
○ - name: make users member of groups
○ user:
○ name: “{{ item[0] }}”
○ state: present
○ groups: “{{ item[1] }}”
○ with_nested:
○ - [ ‘linda’, ‘anna’]
○ - [ ‘students’, ‘profs’ ]
9. Nested Loops with Variables
● Variables can be used in nested loops to
more clearly identify which items you’re
working with
● ---
○ vars:
○ users:
○ - linda
○ - anna
○ groups:
○ - students
○ - profs
○ tasks:
○ - name: make users member of groups
○ user:
○ name: “{{ item[0] }}”
○ state: present
○ groups: “{{ item[1] }}”
○ with_nested:
○ - “{{ users }}”
○ - “{{ groups }}”
10. Using the when statement
● Conditional allow to run ansible tasks only if minimal conditions have been met
○ Think of a Linux distribution, a minimal amount of RAM, etc.
○ Conditionals often com from facts, but may be set through variables also
● To test conditionals, use string comparison, mathematical operators and/or booleans
●
11. Using the when statement
● When statements can be started based on Booleans
○ ---
○ - hosts: all
○ vars:
○ startme: true
○ tasks:
○ -name: install samba
○ package:
○ name: samba
○ when: startme
12. Conditionals Overview
● Equal on strings ansible_machine == “x86_64”
● Equal on numeric max_memory == 1024
● Less than min_memory < 256
● Greater than max_memory > 2048
● Less than/ equal tomin_memory <= 256
● Greater than/equal to max_memory >= 2048
● Not equal to min_memory != 1024
● Variable exists myvar is defined
● Variables does not exist myvar is not defined
● Variable is boolean true myvar
● Variable is boolean false not myvar
13. Using Variables in when
● More flexible: set the package to install in a variable and only run a task when that
variable is defined
○ ---
○ - hosts: all
○ vars:
○ to_install: samba
○ tasks:
○ - name: installing {{ to_install }}
○ package:
○ name: “{{ to_install }}”
○ when: to_install is defined
14. Using Variable Values in Other Variables
● ---
● - hosts: all
● vars:
● my_user: linda
● superusers:
● - root
● - linda
● tasks:
● - name: run only of linda is superuser
● user:
● name: “{{ my_user }}”
● groups: wheel
● append: yes
● when: my_user in superusers
15. Magic Variables
● A few variables are provided automatically by Ansible and cannot be used by users
○ Hostvars: allows to request variables set on other hosts, including facts
○ group_names: an array of all groups the host currently is in
○ groups: a list of all hosts and groups in the inventory
○ ---
○ - name: install ftp
○ package:
○ name: vsftpd
○ when: inventory_hostname in groups[“ftpservers”]
16. Testing Multiple Conditions
● The when statement can be used on multiple values when using and, or or parenthesis
○ ansible_system_vendor == “VMware, Inc.” and ansible_processor_cores == 1
○ ansible_distribution == “CentOS” or ansible_distribution == “Fedora”
○ (ansible_distribution == “CentOS” and ansible_processor_cores == 1) or (ansible_distribution ==
“Fedora” and ansible_system_vendor == “VMware, Inc.”)
● List ansible_distribution by:
○ # ansible all -m setup -a “filter=ansible_distribution”
17. Combining Loops & Conditionals
● Ansible facts may present a dictionary with multiple values
● In that case, you can iterate through each value until a specific condition is met
○ ---
○ - name: install vsftpd if sufficient space on /var/ftp
○ package:
○ name: vsftpd
○ state: latest
○ with_items: “{{ ansible_mounts }}”
○ when: item.mount ==”/var/ftp” and item.size.available > 100000000
● # ansible all -m setup -a “filter=ansible_mounts”
18. Registered Variables
● Using registered variable, the output of a task is stored in a variable
● This result is multi-value, each value is stored in a key
● To do something with it, you’ll need to refer to a specific value in the varname.value
format
● Example:
○ ---
○ - name: variable registration
○ module:
○ register: <some-variables>
● The output of module would be registered as <some-variable> variable
19. Handlers
● A handler is a conditional task that only runs after being notified by another task
● Handlers have globally unique name and are triggered after all tasks in the playbook
● Apart from that a handler is triggered by one or more other tasks in the playbook; all of its
properties are task properties
● To trigger a handler, the playbook must have a notify; item, that calls the name of the
handler
● More than one handler can be called from a task
20. Handler dependencies
● Handlers always run in the order in
which the handlers section is
written, not in the order of how they
are called in the plays
● Handlers run after all other tasks
● Handler names must be globally
unique, they are defined in the global
area ( like config variables)
● Handlers cannot be included
● ---
● - name: module name
● module:
● action: …
● notify:
● - <handler-name>
● handlers:
● - name: handler-name
● module:
● action: ...
21. Tags
● Tags are used at a resource level to give a name to specific resource
● The --tags option is used with ansible-playbook to run only resources with a specific tag
● When a task file is included in a playbook, it can be tagged in the include statement
● Note that when tagging a role or inclusion, the tag applies to everything in the role or the
inclusion
22. Using Tags
● When ansible-playbook --tags ‘tagname’ is used, only resources marked with those tags
will run
○ That means that if a resource at the same level doesn’t have a tag, it won’t run
● Use --skip-tags ‘tagname’ to exclude resources with a specific tag
● The special tag always can be used to make sure a resource is always executed, unless
specifically excluded with --skip-tags
● The --tags option can take 3 specific tags as argument
○ tagged runs any tagged resource
○ untagged excludes all tagged resources
○ all runs all tasks (which is default behavior and also happens if no tags have been specified)
23. Dealing with errors
● Default behavior: on failure, play execution stops, exceptions are possible
● Use ignore_errors to continue after failure
○ - package
○ name: boris
○ state: latest
○ ignore_errors: yes
24. Executing Handlers after Task Failure
● If a task in a play fails, then no handlers will be executed
● Use force_handlers: yes to execute handlers that were triggered by a previous action
anyway
○ ---
○ - hosts: all
○ force_handlers: yes
○ tasks:
○ - name: task a
○ command: /bin/yes
○ notify: handlera
○ …
○ handlers:
○ - name: handlera
○ command: /bin/true
25. Understanding Blocks
● A block is used to logically group tasks
● Blocks are useful for error handling and when statements: one statement can be applied
to the block so that it affects all the tasks in the block
● Blocks allow for error handling, combined with the rescue and always statements
○ If a task failed, the tasks in the rescue task are executed for recovery
○ Tasks in always will run, regardless of the success or failure of tasks defined in block and rescue
26. Using failed_when
● failed_when can be used to specify when a command is considered failed
● Useful for commands that produce a specific output
○ tasks:
○ - shell: /usr/local/bin/mkusr.sh
○ register: mkusr_result
○ failed_when: “‘password missing’ in mkusr_result.stdout
27. Managing changed_when
● If a module thinks it changed the state of the affected machine, it will report “changed”
status
● This is not always desired and for that reason may be overwritten or further specified
● As a result, the module will not generate a “changed” state
● - shell: wall ‘beep’
● change_when: false
28. Lab
● Create a playbook that is installing web services on Ubuntu as well as CentOS. You need
to have the Apache web server, the vsftpd FTP service as well as the mariaDB database
services on both platforms
● Use custom facts on the local machines to define the names of the packages. Use
with_items to process the custom facts
● Use a handler to write the message “installation succeeded” if all packages installed
successfully
●
30. Understanding Host Patterns
● Host patterns are about what you’re addressing in a playbook or from the command line
while running a playbook
● The simplest host pattern is just the name of the host
● IP addresses may be used, as long as they’re in the inventory
● Groups may also be used
○ group all is implicit
○ group ungrouped is for hosts that are not members of any group
● Use * as a wildcard but don’t forget to quote
○ Quoting is recommended in all cases to ensure the shell doesn’t interpret special characters
○ ansible ‘*.example.com’ -i inventory --list-hosts
● Using comma-separated lists are also allowed
31. ● Use, to specify a logical list
○ Ansible server1.example.com,192.168.1.100 -i inventory --list-hosts
○ Different items like host names, groups, and IP addresses can be used in a logical list
● & can be used as a logical and: hosts must match that item also
○ ansible ‘web,&prod’ -i inventory --lists-hosts will match machines in the group web only if they’re
also in the group prod
● ! can be used as a logical not
○ ansible ‘web,!web1.example.com’ -i inventory --list-hosts will match all hosts that are in the
group web, but not web1.example.com
34. Configuring Ansible Logging
● By default, Ansible doesn’t log anything, sufficient information is written to STDOUT
○ Specify log_path in the default section of ansible.cfg force writing log files
○ Or set the $ANSIBLE_LOG_PATH variable
● Notice that only root can log to /var/log, so consider creating log files in the local playbook
directory, or provide write permissions on /var/log for your ansible user
● Error messages written to STDOUT will be written to the log file
● Also, make sure to configure logrotate on Ansible log files
35. Understanding Common Errors
● Connectivity Issues with managed servers
○ Server not reachable
○ Wrong credentials
● Finding Syntax errors in the playbook
○ Use ansible-playbook --syntax-check file.yml to check
●
36. Analyzing ansible-playbook Output Messages
● The ansible-playbook output messages give a good starting point for troubleshooting
issues
○ The PLAY header shows which play is executed
○ The TASK header shows which task
○ Check PLAY RECAP for play summary
● Use -v for increasing verbosity levels
○ -v shows output data
○ -vv shows output and input data
○ -vvv includes information about connections to managed hosts
○ -vvvv adds information about connection plug-ins, users involved, and scripts that have been
executed
37. Using --syntax-check
● On playbooks with many tasks --syntax check may produce a high volume of messages
○ ansible-playbook myplay.yml --syntax-check
● Add the option --step to execute tasks interactively and one-by-one
○ ansible-playbook myplay.yml --step
● Use the --start-at-task option to start execution at a specific task
○ ansible-playbook myplay.yml --start-at-task=”install vsftpd service”
○
38. Avoiding Errors
● Best practices in playbook development
○ Use name in a task to describe the task purpose
○ Include comments
○ Use whitespace in the playbook for increased readability
○ Work with small manageable playbooks and use includes where necessary
39. Using the Debug Module
● The Debug module can be used in a playbook to analyze what variables are doing
● The msg statement can be used to show any information, for instance regarding Ansible
facts
● - debug:
● msg: “The amount of free memory is {{ ansible_memfree_mb }}”
● The var: output statement can be used to see output of a specific variable
● - debug:
● var: output
● verbosity: 2
40. Using Checks
● Use ansible-playbook --check playbook.yml to perform a test without modifying
anything on the target host
○ The Ansible modules you’re using must offer support for the check mode
○ If no support is offered, nothing will be shown
○ Use --check to check the entire playbook
● Use check_mode (always_run prior to release 2.2) to specify for individual tasks if it needs
to be executed in check mode
○ check_mode: yes if this task needs to be executed
○ check_mode: no if this task doesn’t need to be executed
● Use --check --diff to also see changes that will be applied to managed hosts using
templates
41. Modules for Testing
● Some modules provide additional information about host status
● The uri module can connect to a URL and check for specific content
● The script module supports execution of scripts on managed hosts. Note that the script
must be on the control node and will be transferred and executed on the managed host
● The stat module can check that files are present. Use the assert module to work on the
outcome of stat
42. Using ad hoc Commands
● Ad hoc commands allow you to perform quick test of anything
● ansible server1 package -a ‘name=httpd state=present’
● ansible server1 -a ‘df -h’
● ansible server1 -m user -a ‘name=linda’
●
43. Lab
● Create a playbook that is installing web service on Ubuntu as well as CentOS you need to
have the Apache web server, the vsftpd FTP service as well as the mariaDB database
service on both platforms
● Use custom facts on the local machines to define the names of the packages. Use
with_items to process the custom facts
● Use a handler to write the message “installation succeeded” if all packages installed
successfully