Skip to content

Ansible basics

Ansible tips

Below are some tips on using Ansible if you are unfamiliar with it. These are not best practices but will point you in the right direction and give you an idea of how things work.

Installing packages

Ansible allows you to use yum, apt or whatever else you need. However, this is not useful if you are going to reuse roles or playbook tasks. If you want to make sure that you will be able to install something across different Linux distributions, then you can use the following. This example is for installing varnish:

- name: install varnish
   package:
     name: varnish
     state: latest
Names do not matter to a playbook apart from keeping humans aware of what everything is doing. Everything else however does matter.

Change lines in files

Take a look at this from ansible's own documentation

known hosts

Very useful to have this in your playbook for when you need to add known hosts. This could be when cloning a new repo for example. It saves you from having to add extra bits to your tasks. Below is an example of adding github and bitbucket. You would change the user to whatever makes sense to you.

- name: Add github and bitbucket to jekins known hosts
      lineinfile:
        dest: "home/user/.ssh/known_hosts"
        create: yes
        state: present
        line: "{{ lookup('pipe', 'ssh-keyscan -t rsa {{ item.domain }}') }}"
        regexp: "{{ item.regex }}"
      with_items:
        - { domain: 'github.com', regex: '^github\\.com'}
        - { domain: 'bitbucket.org', regex: '^bitbucket\\.org'}

Bash scripts

Ansible is capable of running bash scripts and you can add a task to do so wherever you want in a playbook.

Here is an example below of a playbook with a run the Bash script task:

tasks:
  - name: Copy and Execute the script
    script: "bash file name or location"
You can give the name as a location and a file name. You can also just give it a file name on its own if the playbook is in the same directory.

Bash script causes Ansible to stop running and shows that there is an error.

When I was working with a bash script, Ansible did not like the script at all despite it actually being fine for its intended purpose. If you find that your bash script is not at fault but want Ansible to use it and keep on going with the rest of the playbook, we can simply change the above task to the following:

tasks:
  - name: Copy and Execute the script
    script: "bash file name or location"
    ignore_errors: yes
This is a quick way around the problem if this is a one off playbook. Otherwise....you should probably try fix it.

Run tasks before any roles or tasks (pre tasks)

If you need to run some tasks before anything else in your playbook (you might refer to these as dependencies) then we would put These under "pre_tasks" like I have in the example below. Take note of the packages and the command as these are a pretty common requirements for some tasks.

---
- hosts: all

  pre_tasks:

    - name: install libselinux-python
      become: yes
      package:
       name: libselinux-python
       state: present


    - name: Install pexpect
      become: yes
      command: pip install pexpect

PHP and Ansible

Use these roles

ansible-galaxy install geerlingguy.php

Make sure you have the right repo as well. Do your research and use one of the following depending on the OS

epel ansible-galaxy install geerlingguy.repo-epel

or

remi ansible-galaxy install geerlingguy.repo-remi

variables to use:

php_enablerepo: "the repo you are using above"

php_version: "version of php you want"

php_packages_state: "latest"

php_packages:
    - list
    - packages
    - like
    - this

Ansible Lint

sudo pip install ansible-lint

ansible-lint playbook-main.yml

Viewing Vaulted Passwords

If you want to view a vaulted password, you can do this (for example):

ansible localhost -m debug -a 'var=rmq_admin_pass'

If "geerlingguy.php : Ensure PHP packages are installed." fails at all in your playbook then you will not have php installed correctly. Don't ignore this task failing.

Paths in playbooks

If you want a reliable abs path, you should use the {{ playbook_dir }} variable, which behaves like __DIR__ in PHP.

For example - playbooks are in a subfolder and we want to access files in the project root:

    - name: Install Galaxy Roles in the requirements.yml file
      local_action:
        command ansible-galaxy install -r {{ playbook_dir }}/../requirements.yml --roles-path {{ playbook_dir }}/../roles

Run a command as a playbook task.

tasks:
  - name: do the command
    command: "the terminal command you want"
If you use a command that could of been done with an Ansible module, Ansible will let you know in the output when you run the playbook. For keeping things tidy and also to allow for tasks to work on various builds, use a module.

You may be better off using shell if you want to do bash things, e.g

  tasks:
    - name: Remove any none git folders from the roles directory. We assume that if it is a git repo, its being developed on locally and should not be removed.
      shell: find roles -mindepth 1 -maxdepth 1 -type d '!' -exec test -e '{}/.git' ';' -print | xargs rm -rf
https://docs.ansible.com/ansible/latest/modules/shell_module.html#shell-module

Copying over files.

For a lot of the above packages it's also good to copy over configuration files that you know you will need. Simply create a configuration file, fill it with everything you need and use the following module to copy it across. Below is an example for php.ini

 - name: Create php.ini
   template: src=templates/php/php.ini dest=//etc/php.ini`
The above uses a template and then a destination. src=the file we need to copy and the dest=where that file is going to live.

Install ansible role

To install a role we can use the following command: ansible-galaxy install "ansible.role" -p

useful ansible roles: geerlingguy.php geerlingguy.nginx geerlingguy

SSH Keys with Ansible

The following tasks will create SSH keys

tasks:
- name: Generate /etc/ssh/ RSA host key
  command : ssh-keygen -q -t rsa -f /etc/ssh/ssh_host_rsa_key -C "" -N ""
  creates: /etc/ssh/ssh_host_rsa_key

- name: Generate /etc/ssh/ DSA host key
  command : ssh-keygen -q -t dsa -f /etc/ssh/ssh_host_dsa_key -C "" -N ""
  creates: /etc/ssh/ssh_host_dsa_key

- name: Generate /etc/ssh/ ECDSA host key
  command : ssh-keygen -q -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -C "" -N ""
  creates: /etc/ssh/ssh_host_ecdsa_key

'''

Bitbucket and Ansible

Below is an example of cloning a bitbucket repo. I will mention this now to save confusion, if you do not have the "accept_hostkey: true" like you can see below, you will not be able to clone from a repo for the first time from what I have seen so far.

- name: cloning the repo into the directory we just created
    git:
      repo: "project_repo_url"
      dest: "destination of where the repo is going"
      accept_hostkey: true
      key_file: "location of key file"
    become: true
    become_user: "user"

ssh key variables

When it comes to writing out variables in your variable file or in the playbook itself, you need to be aware of how to write it out for it to work. The following is how I have done this:

ssh-key: |
  -----BEGIN RSA PRIVATE KEY-----
  somelongkeythatwithloadsofmultiplelinesforyou
  fjioefiejfjeoifjioejfiejfjeofjejfojefjoejffjd
  doepojdejdjejdjeidpjdjpdjwopdjwpedjpwdjwopjdo
  -----END RSA PRIVATE KEY-----

Debug Output

To be able to better read Ansible output it is a good idea to set the correct plugin callback in your ansible.cfg file. Below the [defaults] area add the following:

[defaults]
...
stdout_callback = yaml
bin_ansible_callbacks = true
...

This will make your error output display in a much more readable state - errors will no longer be output on the same line and wrap across your terminal.

Variables in Ansible

Ansible gives you a few options when it comes to Variables. We explore these below.

User prompts

You can set variables with user prompts. This is very useful for when information is not going to be the same when you use the playbook again. This could be a password for a ssh key for example which you can see below:

vars_prompt:
  - name: "pass"
    prompt: "Password for SSH Key?"

tasks:

- name: Generate /etc/ssh/ RSA host key
  command : ssh-keygen -q -t rsa -f /home/ec/.ssh/id_rsa/ssh_host_rsa_key -N "{{ pass }}"
In the above, the name is what the variable will be called and can then be used again using in the play book using {{ "vairable" }}. For example the above is {{ pass }} because the name is "pass".

Automatically respond to prompts

To automate things we have to respond to promps that will come our way. Ansible can automatically respond to prompts for you which makes things nice and easy.

Below is an example of this.

Chdir = the directory for the command to be executed in.

expect = this is what we need to put in the playbook for prompt responses.

command = The command that will be executed responses = this is where we place the exact phrase that the terminal would normally ask you. In this case the terminal prompt was going to be "Password for 'https://edmondscommerce@bitbucket.org" I then followed this with ' on both sides. The answer below is a variable set earlier in the playbook by the user as passwords should not be stored anywhere.

- name: pull snippets library
    chdir: /opt/Projects
    expect:
      command: git clone https://edmondscommerce@bitbucket.org/edmondscommerce/snippets-library.git
      responses:
        (?i)Password for 'https://edmondscommerce@bitbucket.org': '{ password }'

Example of variables and roles

When you use roles in your playbook you need to sometimes give them extra information. The way I have done it so far is to do the following:

---
- hosts: all
  become: true
  vars:
     php_enablerepo: "remi-php70,epel"
  roles:
    - geerlingguy.php

In the above example I have read what variables are available in the README file of the role and have placed them in he playbook using vars:. I was able to select a repo so that I could install a specific version of php. Although this is how I have done it it's worth mentioning that I have read you can also point your playbook to a file with all of your variables in it instead using

vars_files
    - /vars/external_vars.yml
reference: http://docs.ansible.com/ansible/latest/playbooks_variables.html#variable-file-separation

Debugging

Pass in -vvv when running ansible-playbook to get much more details about what is going on, eg:

[root@host ansible-project]# ansible-playbook plays/playbook-installLxcOnContainerHost.yml -vvv
ansible-playbook 2.7.5
  config file = /vagrant/ansible-project/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /bin/ansible-playbook
  python version = 2.7.5 (default, Oct 30 2018, 23:45:53) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]
Using /vagrant/ansible-project/ansible.cfg as config file
/vagrant/ansible-project/hosts.ini did not meet host_list requirements, check plugin documentation if this is unexpected
/vagrant/ansible-project/hosts.ini did not meet script requirements, check plugin documentation if this is unexpected
/vagrant/ansible-project/hosts.ini did not meet yaml requirements, check plugin documentation if this is unexpected
Parsed /vagrant/ansible-project/hosts.ini inventory source with ini plugin
statically imported: /vagrant/ansible-project/roles/edmondscommerce.copr-repository/tasks/centos/install.yml
statically imported: /vagrant/ansible-project/roles/edmondscommerce.copr-repository/tasks/centos/remove.yml
statically imported: /vagrant/ansible-project/roles/edmondscommerce.copr-repository/tasks/fedora/install.yml
statically imported: /vagrant/ansible-project/roles/edmondscommerce.copr-repository/tasks/fedora/install-dnf.yml
statically imported: /vagrant/ansible-project/roles/edmondscommerce.copr-repository/tasks/fedora/install-yum.yml
statically imported: /vagrant/ansible-project/roles/edmondscommerce.copr-repository/tasks/fedora/remove.yml
statically imported: /vagrant/ansible-project/roles/edmondscommerce.copr-repository/tasks/fedora/remove-dnf.yml
statically imported: /vagrant/ansible-project/roles/edmondscommerce.copr-repository/tasks/fedora/remove-yum.yml

Researching the server

When we are going to build a server based on one that already exists, we need to do some research in order to make sure we replicate what we can. What you may notice is that it can be hard to get the exact specific version of something, for example, a server may have php 7.0.23 but you are installing 7.0.24. As long as the 7.0.2 part is there then it should be ok. Every package is different though and the above is an example.

Some of the main packages we need to look into are:

php

To look at php version simply type php -v

to find out php modules

yum list installed | grep php

or

php -m

Mysql

mysql -v make sure to read the output as mysql does not just have different version numbers. For example, mysql percona.

\q to quit when you have read the version.

Varnish

varnish requires the following command

varnishd -V that's a capital V unlike the previous commands.

nginx

nginx -v will tell you what you need to know.