Ansible playbooks
A playbook is a file with one or more plays. A play is a collection of related tasks to be performed on a specific group of hosts.
Playbook Anatomy
ansible-playbook my_playbook.yaml ## run a playbook## Example Playbook --- ## Real-World Example Play ## Sample Play, Installs nginx, Copies config, ## starts nginx if there were no errors. ## - hosts: droplets tasks: - name: Installs nginx web server apt: pkg=nginx state=installed update_cache=true when: (ansible_distrobution == "Debian" and ansible_distrobution_major_version == "6") or (ansible_distrobution == "Debian" and ansible_distrobution_major_version == "7") notify: - start nginx - name: Upload default index.html for host copy: src=static_files/index.html dest=/usr/share/nginx/www/ mode=0644 handlers: - name: start nginx service: name=nginx state=started ## example using sudo for all tasks ## - hosts: webservers remote_user: root tasks: - name: ensure apache is at the latest version yum: name=httpd state=latest become: yes become_method: sudo - name: write the apache config file template: src=/srv/httpd.j2 dest=/etc/httpd.conf ## example using sudo for a single task ## - hosts: databases remote_user: root sudo: yes tasks: - name: ensure postgresql is at the latest version yum: name=postgresql state=latest - name: ensure that postgresql is started service: name=postgresql state=running
Playbook FileStructure
File Structure is very important to ansible. Depeinding on your roles/other conditions, it allows you to set default Variables, default plays etc.
## Role File Structure base_ansible_cfg_dir: site.yml role_A.yml role_B.yml roles/ common/ role_A/ role_B/ files/ ## ?? templates/ ## ?? tasks/ handlers/ vars/ defaults/ ## ?? meta/ ## Dependencies main.yml ## main.yml is searched for in all role subfolders, # if discovered, all of it's contents are added # to the play as the subfolder's type (variables, tasks, ...)
Variables
Variables can be either dict, or a nested dict. Nested dicts can be referenced using
item.item
, oritem['item']
.play variables
- hosts : databases vars : var1: zero var2: field1: one field2: two HOME : "{{ lookup('env','HOME') }}" ## lookup environment variable $HOME on remote hostinclude variables files
tasks: - include: wordpress.yml vars: wp_user: timmy ssh_keys: - keys/one.txt ## (including) variables from a file - keys/two.txt
## use variables with {{ var }} tasks: - name: Performing task on host: {{ vhost }} - template: src=file.txt dest=/etc/{{ vhost }}.txtsaving results of command to var
tasks: - name: retrieve the list of home directories ## save result of ``ls`` to variable command: ls /home register: home_dirs # (register command saves output of command) - name: add home dirs to the backup spooler ## for each dir in 'home_dirs', run. file: path=/mnt/bkspool/{{ item }} src=/home/{{ item }} state=link with_items: home_dirs.stdout_lines # ( iter through each line in home_dirs )
Handlers (Events)
In ansible, handlers are like a signal/socket system.
You can signal a handler once a task has completed.
Each handler-event is triggered only once per playbook-run.
Handlers are run after a single block of tasks.
All handlers must have globally unique names.
--- - hosts: droplets tasks: - name: Installs nginx web server apt: pkg=nginx state=installed update_cache=true notify: - start nginx handlers: - name: start nginx service: name=nginx state=started
Roles (Includes)
Tasks/Variables bundled into roles are automatically executed/setup for every task with that role declared.
Task Files Task Files (role-includes, or automatic role-includes) are simply a list of tasks:
--- - name: placeholder foo command: /bin/foo - name: placeholder bar command: /bin/bar
Scripted Include Theinclude
keyword imports/runs any variables or tasks that it contains.--- - hosts: droplets tasks: - include: some_tasks.yml - include: other_tasks.yml - include: more_tasks.ymlDefine Roles (automated include) Any tasks/variables set up for that role will automatically be run.
#### Simple Example - hosts: droplets roles: - role_A - role_B #### Roles with Parameters --- - hosts: droplets roles: - { role: common, some_parameter: 3 } - { role: apache, port: 80 } - { role: postgres, dbname: blarg, other_parameter: 12 } #### Conditional Roles --- hosts: droplets roles: - { role: my_role, when: "ansible_os_family == 'RedHat'" }
Role FileStructure When a role is defined, it looks for and runs files in specific locations (provideded that they exist).## Role File Structure base_ansible_cfg_dir: site.yml role_A/ common/ files/ ## ?? templates/ ## ?? tasks/ handlers/ vars/ defaults/ ## ?? meta/ ## Dependencies main.yml ## main.yml is searched for in all role subfolders, # if discovered, all of it's contents are added # to the play as the subfolder's type (variables, tasks, ...)
Conditionals
Tasks can use the 'when' key to conditionally trigger the task.
when/when not
- hosts: droplets vars: my_var: true tasks: - name: Installs nginx web server apt: pkg=nginx state=installed update_cache=true when: my_varConditional includes/roles
- hosts: droplets tasks: - include: some_tasks.yml when: ansible_os_family == "RedHat" - {include: other_tasks.yml, when: ansible_os_family == "BSD"}
Loops
with_items loop
## The following loops over each item in {{ install_users }}, ## each list-item being referred to throughout as {{ item }}. ## - vars: install_users = [ will, vagrant ] - tasks: copy: src=/home/git/config/unix/.zshrc dest=/home/{{ item }}/.zshrc with_items: '{{ install_users }}'with_nested (nested loops)
- name: Test Run hosts: linux tasks: - raw: echo "sudo -u {{ item[0] }} pkg install -y {{ item[1] }}" with_nested: - [ 'root', 'vagrant', 'will' ] - [ 'zsh' , 'bash', 'sh' ] register: out - debug: msg={{ out.results }}
Special Notes
Tasks must succeed
Plays are executed from top to bottom. Any host that fails a task will not execute any following tasks.
Command/Shell Modules Must Return True## if you have a command that does not have a return value, ## you can still use it with ansible as follows: tasks: - name: run this command and ignore the result shell: /usr/bin/somecommand || /bin/true ## ## or ## tasks: - name: run this command and ignore the result shell: /usr/bin/somecommand ignore_errors: True