Ansible - Debian Based Gotchas - Part-1

5 minute read

As I am currently running through some Docker setups between Debian Jessie and Ubuntu Trusty using Ansible I ran into a few gotchas. Now I would have assumed that everything SHOULD be identical but not so much. With this being said, I figured I would begin to start putting some context around some gotchas that I run into from time to time. And hopefully this will help out others as well.

Docker

When using the following task which is part of this Ansible role for Docker. ansible-docker

---
- name: debian | updating apt-cache
  apt:
    update_cache: yes
    cache_valid_time: 86400
  become: true

- name: debian | installing pre-reqs
  apt:
    name: "{{ item }}"
    state: present
  become: true
  with_items:
    - 'apt-transport-https'
    - 'ca-certificates'
    - 'software-properties-common'

## We are removing the old Docker info
- name: debian | Removing Legacy Docker apt-key
  apt_key:
    keyserver: "hkp://p80.pool.sks-keyservers.net:80"
    id: "58118E89F3A912897C070ADBF76221572C52609D"
    state: "absent"
  become: true

## We are removing the old Docker info
- name: debian | Removing Legacy Docker Repo
  apt_repository:
    repo: "deb https://apt.dockerproject.org/repo {{ ansible_distribution | lower }}-{{ ansible_distribution_release }} main"
    state: "absent"
  become: true

- name: debian | adding docker apt-key
  apt_key:
    url: "{{ docker_ubuntu_repo_info['url'] }}"
    id: "{{ docker_ubuntu_repo_info['id'] }}"
    state: "present"
  become: true

- name: debian | adding docker repo
  apt_repository:
    repo: "{{ docker_ubuntu_repo_info['repo'] }}"
    state: present
  become: true

## We remove docker-engine as this is old package to install. The new package is
## docker-ce
- name: debian | uninstalling old docker package (if exists)
  apt:
    name: "{{ item }}"
    state: "absent"
    purge: yes
  become: true
  with_items:
    - 'docker-engine'
    - 'lxc-docker'

- name: debian | installing docker pre-reqs
  apt:
    name: "linux-image-extra-{{ ansible_kernel }}"
    state: present
  become: true
  when: >
        ansible_distribution == "Ubuntu" and
        (ansible_distribution_version >= '14.04')

- name: debian | installing docker
  apt:
    name: "docker-ce={{ docker_version_debian }}"
    state: "present"
  become: true

- name: debian | setting grub memory limit (if set)
  lineinfile:
    dest: /etc/default/grub
    regexp: "^GRUB_CMDLINE_LINUX_DEFAULT"
    line: 'GRUB_CMDLINE_LINUX_DEFAULT="cgroup_enable=memory swapaccount=1"'
  register: grub_updated
  become: true
  when: >
        docker_set_grub_memory_limit is defined and
        docker_set_grub_memory_limit

- name: debian | updating grub (if updated)
  command: update-grub
  become: true
  when: grub_updated['changed']

- name: debian | installing additonal packages
  apt:
    name: "{{ item }}"
    state: "present"
  become: true
  with_items:
    - bridge-utils
```jinja2


First thing I found was that for some reason when installing python-pip
using APT it caused issues with Debian Jessie. It would throw and error
when executing PIP commands. This does not happen on Ubuntu Trusty. So
to get around this I had to add the following bit of logic to the
Ansible task(s). Notice the `when: ansible_distribution == ""`. We use
this Ansible fact that is gathered to determine if we are running Debian
or Ubuntu, do not confuse this with `ansible_os_family == "Debian"` as
both Debian and Ubuntu will report this.

Ubuntu:

```yaml
when: ansible_distribution == "Ubuntu"
```yaml

Debian:

```yaml
when: ansible_distribution == "Debian"
```jinja2

Below is the code that is part of the task mentioned above.


```yaml
- name: uninstall python-pip (If installed) - Debian
  apt:
    name: python-pip
    state: absent
  when: ansible_distribution == "Debian"

- name: debian | installing python packages
  apt:
    name: "{{ item }}"
    state: present
  with_items:
    - python-pip
  when: ansible_distribution == "Ubuntu"

- name: debian | installing python packages
  easy_install:
    name: "{{ item }}"
##    state: present
  with_items:
    - pip
  when: ansible_distribution == "Debian"
```jinja2


Now we could change both to use easy_install: as our module to use from
an Ansible perspective but...

Another little cool fact that can be used when adding the Docker APT
repositories for Debian and Ubuntu is to use the following Ansible facts
gathered:

```yaml
ansible_distribution
ansible_distribution_release
```jinja2

And we can use these as the following defined var in: (adding **\|
lower** will ensure that the ansible_distribution will be ubuntu/debian
instead of Ubuntu/Debian so that it does not cause issues with adding
the APT repositories)

**_defaults/main.yml_**


```yaml
docker_ubuntu_repo_info:  #defines docker ubuntu repo info for installing from
  - id: 58118E89F3A912897C070ADBF76221572C52609D
    keyserver: hkp://p80.pool.sks-keyservers.net:80
    repo: "deb https://apt.dockerproject.org/repo {{ ansible_distribution | lower }}-{{ ansible_distribution_release }} main"
```jinja2


**tasks/debian.yml**


```yaml
- name: debian | adding docker repo
  apt_repository:
    repo: "{{ item.repo }}"
    state: present
  with_items: docker_ubuntu_repo_info
```jinja2


Using these variables will yield the following based on OS.

`Ubuntu`:


```yaml
{{ ansible_distribution }} will be Ubuntu
{{ ansible_distribution_release }} will be trusty
```jinja2


`Debian`:


```yaml
{{ ansible_distribution }} will be Debian
{{ ansible_distribution_release }} will be jessie
```jinja2



## UFW

When I began to configure the UFW (Uncomplicated Firewall) for some
firewall rules to be used with Docker I ran into an issue on Debian
Jessie stating that an invalid syntax error occurred when defining the
routed default policy. Again, this works just fine on Ubuntu but not so
much on Debian Jessie. After attempting a few different approaches to
using the ufw Ansible module I finally pulled up the man page on UFW for
Debian Jessie and Ubuntu. Well there is the issue right there. For some
reason on Debian Jessie the UFW settings do not allow defining the
default routed policy whereas on Ubuntu it does. Go figure.
[ansible-ufw](https://github.com/mrlesmithjr/ansible-ufw)

So how do we get around this one? It ended up being fairly simple but
then again...Why do I need to do this?

Below is the bit of code that allows us to get around this (for now).
Again we will use the ansible_distribution fact to determine if we are
running Ubuntu or Debian when our policy direction is set to routed.\
**defaults/main.yml**

```yaml
ufw_policies:  #defines default policy for incoming, outgoing and routed (forwarded) traffic...allow, deny or reject
  - direction: incoming
    policy: deny
  - direction: outgoing
    policy: allow
  - direction: routed
    policy: deny
```jinja2

**tasks/configure_firewall.yml**


```yaml
- name: configure_firewall | setting default UFW policies (incoming, outgoing)
  ufw:
    direction: "{{ item.direction }}"
    policy: "{{ item.policy }}"
  with_items: ufw_policies
  when: item.direction != "routed"

- name: configure_firewall | setting default UFW policies (routed)
  ufw:
    direction: "{{ item.direction }}"
    policy: "{{ item.policy }}"
  with_items: ufw_policies
  when: item.direction == "routed" and ansible_distribution != "Debian"

And that is all for now. I will be returning to this post and updating from time to time as I find additional gotchas.

Enjoy!