notes blog about


Entity relationship:



Ansible workflow for each task

  1. generate a Python script
  2. copy the script to the servers (hosts)
  3. execute the script
  4. wait for the script to complete on all hosts

True vs yes

You’re best off writing playbooks for your org rather than trying to reuse generic playbooks.

One liners

$ ansible all -m ping
$ ansible all [-m command] -a uptime
$ ansible host1 -b -a "tail /var/log/syslog" # -b -> become
$ ansible host1 -b -m apt -a name=nginx
$ ansible all -i inventories/dev -b -m apt -a "name=nagios-nrpe-server state=absent"

$ ansible-tools help init

$ ansible -i stage waf1 -m fetch -a "src=/home/ubuntu/03_gen_whitelists \
dest=./roles/nginx-naxsi/templates/events_mngt/ flat=yes"

ansible -m authorized_key -a "key=\"{{lookup('file','/tmp/')}}\" \
user=ubuntu stage=present" all -i inventories/dev

# Viewing all facts associated with a server
ansible server1 -m setup


If you reference a variable right after the module name:

- name: perform some task
  command: "{{ myapp }} -a foo"

If your argument contains a collon:

- name: show a debug msg
  debug: "msg='The debug module will print a message: neat, eh?'"


1) In inventory file

2) In host_vars, group_vars directories

$ cat group_vars/production
# accessed as {{ db_primary_host }}

$ cat group_vars/production_dict
# accessed as {{ }}

3) In role’s defaults directory - have the lowest priority of any variables available

4) In vars section of a playbook - simplest way to define variables

  key_file: /etc/nginx/ssl/nginx.key
  cert_file: /etc/nginx/ssl/nginx.crt
  conf_file: /etc/nginx/sites-available/default
  server_name: localhost

5) In playbooks loaded by vars_file

 - nginx.yml

6) As arguments to a role

7) On the command line

See variables for more.


Primary mechanism for breaking a playbook into multiple files

If you think you might want to change the value of a variable in a role (via vars section of a play or role’s arguments), use a default variable (defaults). If you don’t want it to change, use a regular variable (vars).

Roles with variables:

- name: deploy postgres on vagrant
  hosts: db
    - secrets.yml
    - role: database
      database_name: "{{ mezzanine_proj_name }}"
      database_user: "{{ mezzanine_proj_name }}"

- name: deploy mezzanine on vagrant
  hosts: web
    - secrets.yml
    - role: mezzanine
      database_host: "{{ hostvars.db.ansible_eth1.ipv4.address }}"

See roles for more.

Tips and tricks

Achieve idempotence with a command module:

- name: create a Vagrantfile
  command: vagrant init {{ box }} creates=Vagrantfile

Change the way Ansible identifies that a task has changed state (changed_when):

- name: initialize the database
      command: createdb --noinput --nodata
      app_path: "{{ proj_path }}"
      virtualenv: "{{ venv_path }}"
    register: result
    #changed_when: '"Creating tables" in result.out|default("")'
    changed_when: result.out is defined and "Creating tables" in result.out
- name: Import logs into ES
  become: no
  shell: ./ -c nxapi.json --files=/var/log/nginx/naxsi.log 2>&1 | perl -ne 'print $1 if /Written\s+(\d+)\s+events/'
  register: result
  changed_when: result.stdout != "0"  # NOTE: this was tricky to get right! :-)
    chdir: /home/ubuntu/nginx-naxsi/naxsi-master/nxapi
    - nxapi
- name: Get hostname of the control host
  command: hostname
  register: hostname
  become: no
  # no yellow output :-)
  changed_when: false

View the output of a task:

- name: initialize the database
    command: createdb --noinput --nodata
    app_path: "{{ proj_path }}"
    virtualenv: "{{ venv_path }}"
  failed_when: False # so the execution doesn't stop on failure
  register: result   # save the output to a variable
# print out the variable...
- debug: var=result

# stop the execution...
- fail:

Run a task and print its output, even if it fails:

- name: Run myprog
  command: /opt/myprog
  register: result
  ignore_errors: True

- debug: var=result

- debug: msg="Stop running the playbook if myprog failed"
  failed_when: result|failed # filters for registered variables:
  # - failed
  # - changed
  # - success
  # - skipped
# more tasks here

Have multiple ansible versions on a laptop:

mkdir ansibles
cd ansibles
# see for versions
VER=v2.5.2; git clone -b $VER --recursive $VER
source ./$VER/hacking/env-setup
ansible --version

Deal with unreliable networks or services

The last four lines do the trick:

    - name: Safe-upgrade all system packages
        upgrade: safe
        state: latest
        update_cache: yes
        - sys-upgrade
      register: upgrade
      retries: 3
      delay: 3
      until: upgrade is not failed
    - name: Generate or renew cert
      command: certbot certonly --noninteractive --standalone -d {{ fqdn }}
        - restart container
      register: result
      retries: 3
      delay: 3
      until: result.rc == 0