Ansible playbooks

From wikinotes

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, or item['item'].

play variables

- hosts : databases
  vars  :

    var1: zero

    var2:
      field1: one
      field2: two
      HOME  : "{{ lookup('env','HOME') }}"         ## lookup environment variable $HOME on remote host

include 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 }}.txt

saving 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 The include keyword imports/runs any variables or tasks that it contains.

---
- hosts: droplets
  tasks:
    - include: some_tasks.yml
    - include: other_tasks.yml
    - include: more_tasks.yml

Define 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_var

Conditional 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