playbooks

Chapter 5

Learning to write Infrastructure as a Code

concepts

  • YAML PRIMER

  • ANATOMY OF A PLAYBOOK

  • Creating our first playbook

  • Adding Tasks and plays

even though ansible allows us to run ad hoc commands and modules on remote nodes, the real magic starts with the Playbooks

playbooks

Playbooks allow one to describe the state of the infrastructure and the sequence in which it is achieved ....

playbooks

as Infrastructure Code
which can then be version controlled and reused many times for many different environments

playbooks

playbook

Ansible

YAML

Playbooks are written in 

YAML

with intention of being both 

Human Readable 

as well as 

machine Readable 

YAML primer

  • Begin/END Tags

  • Lists

  • Dictionaries

  • Indentation

  • Line Foldings

begin tag

All YAML files to begin with three dashes ---
---
  # This is a YAML Document
  - list item 1
  - list item 2



...
and end with three dots ...
even though its not a must, its a good coding practice to follow this

lists

Ansible plays contain list of items e.g. tasks, hosts, options 
---
  - name 
    hosts
    become
    tasks 
      - package
      - file
      - user


...

lists and dictionaries

Ansible plays contain list of items e.g. tasks, hosts, options 
---
  - name: configure app hosts
    hosts: app
    become: true
    tasks 
      - package: name=apache state=present
      - copy: name=ntp.conf src=files/ntp.conf dest=/etc/ntp.conf
      - user: name=dojo  state=present


...
         with key value pairs commonly known as hashes or dictionaries

all members of the list are at the same indentation level

Style 1

---
  - name: configure app hosts
    hosts: app
    become: true
    tasks 
      - package: name=apache state=present
 
      - copy: > 
          name=ntp.conf 
          src=files/ntp.conf 
          dest=/etc/ntp.conf
 
      - user: |
          name=dojo
          uid=5001
          home=/home/dojo 
          state=present


...
> |
---
  - name: configure app hosts
    hosts: app
    become: true
    tasks 
      - package: name=apache state=present
 
      - copy: 
          name: ntp.conf 
          src: files/ntp.conf 
          dest: /etc/ntp.conf
 
      - user: 
          name: dojo
          uid: 5001
          home: /home/dojo 
          state: present


...

style 2

:

YAML LINTER

http://www.yamllint.com/

EXERCISE

Read about yaml: https://en.wikipedia.org/wiki/YAML

Create a yaml file

src: http://www.india.com/buzz/this-precise-grocery-shopping-list-of-an-indian-wife-for-her-husband-will-make-you-laugh-like-crazy-2496164/

Anatomy of a playbook

plays

WHICH hosts
do WHAT

describe

TASKS

inventory

modules

hosts,  vars, become

plays

name
hosts
become
vars
tasks

plays

name
hosts
become
vars
tasks
- name: App Server Configurations 
    hosts: app
    become: true
    become_user: admin
    become_method: sudo 
    vars: 
      apache_port    = 8080
      max_conections = 4000
      ntp_conf       = /etc/ntp.conf
    tasks:
      - name: create app user
        user: name=app state=present uid=5002

      - name: install git 
        yum:  name=tree  state=present

        

become

think of sudo

used to run tasks as a different user / become another user

introduced in version 1.9 and supercedes sudo / su 

supports sudo, su, pfexec, doas, pbrun, dzdo, ksu and others

tasks

Components of Plays which define the desired state of / action taken  on a system entity
there is a 1-1 mapping between the task and the system entity managed
tasks invoke modules which are encapsulated procedures to take actions. 
 modules are also called as task plugins 

task styles

- name: install ntp package
  yum: name=ntp state=present
-  yum: name=ntp state=present

multi line tasks

- name: create dojo user
  user: > 
    name=dojo
    uid=5001
    home=/home/dojo
    state=present
- name: create dojo user
  user: | 
    name=dojo
    uid=5001
    home=/home/dojo
    state=present
- name: create dojo user
  user:  
    name: dojo
    uid: 5001
    home: /home/dojo
    state: present

playbook example

---
  - name: Base Configurations for ALL hosts
    hosts: all
    become: true
    tasks:
      - name: create admin user
        user: 
          name: admin 
          state: present 
          uid: 5001

      - name: remove dojo
        user: 
          name: dojo  
          state: absent

      - name: install tree
        yum:  
          name: tree  
          state: present

      - name: install ntp
        yum:  
          name: ntp   
          state: present

      - name: start ntp service
        service: 
          name: ntpd 
          state: started 
          enabled: yes

  - name: App Server Configurations
    hosts: app
    become: true
    tasks:
      - name: create deploy user
        user: 
          name: deploy 
          state: present 
          uid: 5003

      - name: install git
        yum:  
          name: git  
          state: present
        
play1
play2

GE

Writing our first Playbook

cd ansible-bootcamp-code/chap5

ansible all -m ping

switch to chap5 code and validate

 

You have to create a playbook for base systems configuration. Common configurations for all hosts are, 

GE

  • admin user should be present with uid 5001
  • user dojo should not have an account on any host
  • install tree  utility 
  • install ntp 

Problem Statement

on all systems which belong to  prod group in the inventory
Lets now create  systems.yml  file and start adding our first play 
---
  - name: Base Configurations for ALL hosts
    hosts: all
    become: true
    tasks:
      - name: create admin user
        user: 
          name: admin 
          state: present 
          uid: 5001

      - name: remove dojo
        user: 
          name: dojo  
          state: absent

      - name: install tree
        package:  
          name: tree  
          state: present

      - name: install ntp
        package:  
          name: ntp   
          state: present

file: systems.yml

GE

GE

validate yaml

ansible-playbook systems.yml --syntax-check

Syntax Check

Exercise:  Break the syntax, run playbook with --syntax check again, and learn how it works. 

GE

http://www.yamllint.com

validate yaml

Another way to validate syntax

ansible playbook utility

# ansible-playbook --help
Usage: ansible-playbook playbook.yml

Options:
  --ask-vault-pass      ask for vault password
  -C, --check           don't make any changes; instead, try to predict some
                        of the changes that may occur
  -D, --diff            when changing (small) files and templates, show the
                        differences in those files; works great with --check
  -e EXTRA_VARS, --extra-vars=EXTRA_VARS
                        set additional variables as key=value or YAML/JSON
  --flush-cache         clear the fact cache
  --force-handlers      run handlers even if a task fails
  -f FORKS, --forks=FORKS
                        specify number of parallel processes to use
                        (default=5)
  -h, --help            show this help message and exit
  -i INVENTORY, --inventory-file=INVENTORY
                        specify inventory host path (default=myhosts.ini) or
                        comma separated host list.
  -l SUBSET, --limit=SUBSET
                        further limit selected hosts to an additional pattern
  --list-hosts          outputs a list of matching hosts; does not execute
                        anything else
  --list-tags           list all available tags
  --list-tasks          list all tasks that would be executed
 ansible-playbook --help

listing hosts and tasks

GE

ansible-playbook systems.yml --list-tasks

List Hosts to which this playbook applies

ansible-playbook systems.yml --list-hosts

List Tasks

ansible-playbook systems.yml --list-tags

List Tags

Apply

 

root@control:/workspace/ansible-bootcamp-code/chap5# ansible-playbook systems.yaml 
[WARNING]: Found both group and host with same name: db
[WARNING]: Found both group and host with same name: lb

PLAY [Base Configurations for ALL hosts] **************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************
ok: [db]
ok: [lb]
ok: [app1]
ok: [app2]
[DEPRECATION WARNING]: Distribution Ubuntu 18.04 on host localhost should use /usr/bin/python3, but is using /usr/bin/python 
for backward compatibility with prior Ansible releases. A future Ansible release will default to using the discovered platform
 python for this host. See https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more 
information. This feature will be removed in version 2.12. Deprecation warnings can be disabled by setting 
deprecation_warnings=False in ansible.cfg.
ok: [localhost]

TASK [create admin user] ******************************************************************************************************
changed: [app1]
changed: [app2]
changed: [lb]
changed: [db]
changed: [localhost]

TASK [remove dojo] ************************************************************************************************************
ok: [localhost]
ok: [app1]
ok: [lb]
ok: [app2]
ok: [db]

TASK [install tree] ***********************************************************************************************************
changed: [app2]
changed: [db]
changed: [app1]
changed: [lb]
[WARNING]: Updating cache and auto-installing missing dependency: python-apt
changed: [localhost]

TASK [install ntp] ************************************************************************************************************
ok: [app1]
ok: [app2]
changed: [lb]
changed: [db]
changed: [localhost]

PLAY RECAP ********************************************************************************************************************
app1                       : ok=5    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
app2                       : ok=5    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
db                         : ok=5    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
lb                         : ok=5    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
localhost                  : ok=5    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

root@control:/workspace/ansible-bootcamp-code/chap5# 
ansible-playbook systems.yaml

adding a new task

GE

Lets now add a new task to systems.yml to 
  • start ntpd service
---
  - name: Base Configurations for ALL hosts
    hosts: all
    become: true
    tasks:
      - name: create admin user
        user: 
          name: admin 
          state: present 
          uid: 5001

      - name: remove dojo
        user: 
          name: dojo  
          state: absent

      - name: install tree
        package:  
          name: tree  
          state: present

      - name: install ntp
        package:  
          name: ntp   
          state: present

      - name: start ntp service
        service: 
          name: ntpd
          state: started 
          enabled: yes
File: systems.yml

adding a new task

GE

TASK [start ntp service] ******************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "msg": "Could not find the requested service ntpd: host"}
fatal: [lb]: FAILED! => {"changed": false, "msg": "Could not find the requested service ntpd: host"}
fatal: [db]: FAILED! => {"changed": false, "msg": "Could not find the requested service ntpd: host"}
fatal: [app1]: FAILED! => {"changed": false, "msg": "Could not find the requested service ntpd: host"}
fatal: [app2]: FAILED! => {"changed": false, "msg": "Could not find the requested service ntpd: host"}

error handling

ansible-playbook systems.yml

status = failed

GE

root@control:/workspace/chap5# ansible-playbook systems.yml --step                             
                                                                                                
PLAY [Base Configurations for ALL hosts] ***************************************                
Perform task: TASK: setup (N)o/(y)es/(c)ontinue: y                                              
                                                                                                
                                                                                                
TASK [setup] *******************************************************************                
y                                                                                               
ok: [app1]                                                                                      
ok: [db]                                                                                        
ok: [app2]                                                                                      
ok: [lb]                                                                                        
Perform task: TASK: create admin user (N)o/(y)es/(c)ontinue:                                    
                                                                                                
TASK [create admin user] *******************************************************                
yok: [app2]                                                                                     
ok: [app1]                                                                                      
ok: [db]                                                                                        
ok: [lb]                                                                                        

Perform task: TASK: install tree (N)o/(y)es/(c)ontinue: y                                       
                                                                                                
TASK [install tree] ************************************************************                
ok: [app2]                                                                                      
ok: [lb]                                                                                        
ok: [app1]                                                                                      
ok: [db]                                                  

Step by step execution

ansible-playbook systems.yml --step

GE

You could also do step by step execution of tasks by using --step option

fixing error 

GE

service : ntpd => ntp

TASK [install ntpd] ************************************************************************************************************
fatal: [app1]: FAILED! => {"changed": false, "failures": ["No package ntpd available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
fatal: [lb]: FAILED! => {"changed": false, "failures": ["No package ntpd available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
fatal: [app2]: FAILED! => {"changed": false, "failures": ["No package ntpd available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
fatal: [db]: FAILED! => {"changed": false, "failures": ["No package ntpd available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
fatal: [localhost]: FAILED! => {"ansible_facts": {"pkg_mgr": "apt"}, "changed": false, "msg": "value of state must be one of: absent, build-dep, fixed, latest, present, got: installed"}

PLAY 

Root Cause  :  NTP service name is ntp and not ntpd on Ubuntu

---
  - name: Base Configurations for ALL Hosts
    hosts: all
    become: true
    tasks:
      - name: create admin user 
        user: 
          name: admin 
          state: present 
          uid: 5001

      - name: remove dojo 
        user: 
          name: dojo
          state: absent

      - name: install tree
        apt: 
          name: tree 
          state: present 

      - name: install ntp
        apt:  
          name: ntp   
          state: present

      - name: start ntp service
        service:  
          name: ntp  
          state: started

File: systems.yml

fixing error 

GE

ntpd => ntp

adding second play

GE

Add a new play to existing playbook  which will,
  • create a deploy user with uid 5003
  • install git 
    

Problem Statement

on all app servers in the inventory
Setup app Servers
---
  - name: Base Configurations for ALL hosts
    hosts: all
    become: true
    tasks:
      - name: create admin user
        user: 
          name: admin 
          state: present 
          uid: 5001

      - name: remove dojo
        user: 
          name: dojo  
          state: absent

      - name: install tree
        package:  
          name: tree  
          state: present

      - name: install ntp
        package:  
          name: ntp   
          state: present

      - name: start ntp service
        service: 
          name: ntp 
          state: started 
          enabled: yes

  - name: App Server Configurations
    hosts: app
    become: true
    tasks:
      - name: create deploy user
        user: 
          name: deploy 
          state: present 
          uid: 5003

      - name: install git
        yum:  
          name: git  
          state: present
        

adding second play

File: systems.yml
play1
play2

GE

PLAY [Base Configurations for ALL hosts] ***************************************

TASK [setup] *******************************************************************
ok: [localhost]
ok: [192.168.61.14]
ok: [192.168.61.13]
ok: [192.168.61.12]
ok: [192.168.61.11]

TASK [create admin user] *******************************************************
ok: [192.168.61.14]
ok: [localhost]
ok: [192.168.61.13]
ok: [192.168.61.12]
ok: [192.168.61.11]

TASK [remove dojo] *************************************************************
ok: [192.168.61.14]
ok: [192.168.61.12]
ok: [192.168.61.11]
ok: [localhost]
ok: [192.168.61.13]

TASK [install tree] ************************************************************
ok: [192.168.61.11]
ok: [192.168.61.12]
ok: [localhost]
ok: [192.168.61.13]
ok: [192.168.61.14]

TASK [install ntp] *************************************************************
ok: [192.168.61.12]
ok: [192.168.61.13]
ok: [192.168.61.14]
ok: [192.168.61.11]
ok: [localhost]

TASK [start ntp service] *******************************************************
ok: [192.168.61.13]
ok: [192.168.61.14]
ok: [localhost]
ok: [192.168.61.11]
ok: [192.168.61.12]

PLAY [App Server Configurations] ***********************************************

TASK [setup] *******************************************************************
ok: [192.168.61.13]
ok: [192.168.61.12]

TASK [create app user] *********************************************************
changed: [192.168.61.12]
changed: [192.168.61.13]

TASK [install git] *************************************************************
ok: [192.168.61.13]
ok: [192.168.61.12]

PLAY RECAP *********************************************************************
192.168.61.11              : ok=6    changed=0    unreachable=0    failed=0
192.168.61.12              : ok=9    changed=1    unreachable=0    failed=0
192.168.61.13              : ok=9    changed=1    unreachable=0    failed=0
192.168.61.14              : ok=6    changed=0    unreachable=0    failed=0
localhost                  : ok=6    changed=0    unreachable=0    failed=0

apply Playbook

ansible-playbook systems.yml

GE

GE

You have to limit execution of the tasks
  • only to  app servers 
    

Problem Statement

irrespective of host groups playbook defines
PLAY [Base Configurations for ALL hosts] ***************************************

TASK [setup] *******************************************************************
ok: [localhost]
ok: [192.168.61.14]
ok: [192.168.61.13]
ok: [192.168.61.12]
ok: [192.168.61.11]

TASK [create admin user] *******************************************************
ok: [192.168.61.14]
ok: [localhost]
ok: [192.168.61.13]
ok: [192.168.61.12]
ok: [192.168.61.11]

TASK [remove dojo] *************************************************************
ok: [192.168.61.14]
ok: [192.168.61.12]
ok: [192.168.61.11]
ok: [localhost]
ok: [192.168.61.13]

TASK [install tree] ************************************************************
ok: [192.168.61.11]
ok: [192.168.61.12]
ok: [localhost]
ok: [192.168.61.13]
ok: [192.168.61.14]

TASK [install ntp] *************************************************************
ok: [192.168.61.12]
ok: [192.168.61.13]
ok: [192.168.61.14]
ok: [192.168.61.11]
ok: [localhost]

TASK [start ntp service] *******************************************************
ok: [192.168.61.13]
ok: [192.168.61.14]
ok: [localhost]
ok: [192.168.61.11]
ok: [192.168.61.12]

PLAY [App Server Configurations] ***********************************************

TASK [setup] *******************************************************************
ok: [192.168.61.13]
ok: [192.168.61.12]

TASK [create app user] *********************************************************
changed: [192.168.61.12]
changed: [192.168.61.13]

TASK [install git] *************************************************************
ok: [192.168.61.13]
ok: [192.168.61.12]

PLAY RECAP *********************************************************************
192.168.61.11              : ok=6    changed=0    unreachable=0    failed=0
192.168.61.12              : ok=9    changed=1    unreachable=0    failed=0
192.168.61.13              : ok=9    changed=1    unreachable=0    failed=0
192.168.61.14              : ok=6    changed=0    unreachable=0    failed=0
localhost                  : ok=6    changed=0    unreachable=0    failed=0

limiting  execution

ansible-playbook systems.yml --limit app 

GE

https://github.com/schoolofdevops/html-sample-app.git
Lab Exercise 2:

 Disable Facts Gathering
  • Run ansible playbook and observe the output
  • Add the following configuration parameter to ansible.cfg gathering = explicit
  • Launch ansible playbook run again, observe the output and compare it with the previous run.
Lab Exercise 3:

While running playbook, execution should start at the following task onwards. Find out and use option applicable to  ansible-playbook which will achieve this. 
  • Task Name: "install ntp"

2021 Ansible - Section 5: Playbooks

By School of Devops

2021 Ansible - Section 5: Playbooks

Learning to Write Infrastructure as a Code

  • 1,054