Ansible - Add an apt-repository on Debian and Ubuntu

15-05-2016 | Remy van Elst


Table of Contents


This is a guide that shows you how to add an apt repository to Debian and Ubuntu using Ansible. It includes both the old way, when the apt modules only worked on Ubuntu, and the new way, now that the apt-modules also support Debian, plus some other tricks.

ansible

If you like this article, consider sponsoring me by trying out a Digital Ocean VPS. With this link you'll get a $5 VPS for 2 months free (as in, you get $10 credit). (referral link)

Introduction

Ansible allows you to add apt repositories and apt repository signing keys easily using the two modules apt_repository and apt_key. You can use this when you need to install packages from an external location, for example, nginx or goaccess. Both of these packages are in the repositories, but not the latest version.

Using Ansible you can add the repository and the signing key, and then install the package from the new repo. This guide will show you a few ways to do that in playbooks.

The new way

The easy way is to first add the repository key, then add the repository and finally install the package. Here's an example for nginx:

# always try to use HTTPS. I'm not sure why the nginx folks don't provide it.
- apt_key: url=http://nginx.org/keys/nginx_signing.key state=present 

- apt_repository: repo='deb deb http://nginx.org/packages/mainline/ubuntu/ xenial nginx' state=present filename='nginx' update_cache='yes'

- apt: name='nginx' state='present' update_cache='yes'

This is a three line playbook which will download and install the repository key, add the repository to a seperate file in /etc/apt/sources.list.d/ and install the package while also doing an apt-get update to refresh the apt cache with the new repository.

This is the recommended way to add a repo and install packages from there. Read on to find out the workarounds in ye olden days.

The old way

In the past the apt_key module and behaved wonky on Debian installations, but not on Ubuntu. The apt_key module also did not support downloading keys from external locations and was tailored more to PPA's, which are nonexistent on Debian. Here's the same NGINX example, using the older way, which still works by the way.

- name: 'add nginx repository'
  template: src='nginx.list.j2' dest='/etc/apt/sources.list.d/nginx.list'

- name: 'make sure folder /var/keys exists'
  file: path='/var/keys' state='directory' owner='root'

- name: 'get nginx package signing key'
  get_url: url='http://nginx.org/keys/nginx_signing.key' dest='/var/keys/nginx_signing.key'
  register: result

- name: 'add nginx apt-key'
  command: "apt-key add '/var/keys/nginx_signing.key'"
  when: result.changed

- name: 'apt-get update'
  apt: update_cache=yes

- name: 'install nginx'
  action: apt name='nginx' state='latest'

The nginx repository template contains the following:

# {{ ansible_managed }}
deb http://nginx.org/packages/mainline/{{ ansible_lsb.id|lower }}/ {{ ansible_lsb.codename|lower }} nginx

deb-src http://nginx.org/packages/mainline/{{ ansible_lsb.id|lower }}/ {{ ansible_lsb.codename|lower }} nginx

This is quite a nice trick, because it works on both Debian and Ubuntu, all versions. On the latest Ubuntu 16.04 the resulting repository line is this:

deb http://nginx.org/packages/mainline/ubuntu/ xenial nginx

But on an onder Debian installation, the result is this:

deb http://nginx.org/packages/mainline/debian/ wheezy nginx

You do need to make sure the upstream repository also follows this structure. In the nginx case, it does.

First a directory is created for the keyfile. The apt-key is downloaded manually to there, the result is registered. If the key already exists or is the same, we don't do anything. If the key isn't there or has changed, we execute the apt-key add command manually to add the repository signing key. If that's all done, we update the apt-cache and install nginx.

That's quite a bit more steps and ways to break stuff, plus, less idempotent due to the manual command. My playbook was so old, it still used the action: apt instead of just apt:.

This is not the recommended way, but it still works just fine. If you add repositories this way, no problem, but you might want to consider rewriting the playbooks to the newer way.

If you like this article, consider sponsoring me by trying out a Digital Ocean VPS. With this link you'll get a $5 VPS for 2 months free (as in, you get $10 credit). (referral link)

More documentation

The official documentation for the two modules can be found on the Ansible docs site: apt_repository and apt_key.

You can also check out my other Ansible articles


Tags: ansible, apt, deb, nginx, packages, python, repo,