10

There isn't a module for installing .deb packages directly. When you have to run dpkg as a command, it always mark the installation task as one that has changed. I'd some trouble configuring it correctly, so I'm posting here as a public notebook.

Here is the task to install with dpkg:

- name: Install old python 
  command: dpkg -i {{ temp_dir }}/{{ item }}
  with_items: 
    - python2.4-minimal_2.4.6-6+precise1_i386.deb
    - python2.4_2.4.6-6+{{ ubuntu_release }}1_i386.deb
    - libpython2.4_2.4.6-6+{{ ubuntu_release }}1_i386.deb
    - python2.4-dev_2.4.6-6+{{ ubuntu_release }}1_i386.deb

The files where uploaded to {{temp_dir}} in another task.

udondan
  • 57,263
  • 20
  • 190
  • 175
neves
  • 33,186
  • 27
  • 159
  • 192

3 Answers3

13

The answer below still works, but newer ansible versions have the apt module. Mariusz Sawicki answer is the preferred one now. I've marked it as the accepted answer.

It'll work just with Ansible version 1.3, when changed_when parameter was added. It is a little clumsy, maybe someone can improve the solution. I didn't find the documentation of this "register" object.

- name: Install old python 
  command: dpkg --skip-same-version -i {{ temp_dir }}/{{ item }}
  register: dpkg_result
  changed_when: "dpkg_result.stdout.startswith('Selecting')"
  with_items: 
    - python2.4-minimal_2.4.6-6+precise1_i386.deb
    - python2.4_2.4.6-6+{{ ubuntu_release }}1_i386.deb
    - libpython2.4_2.4.6-6+{{ ubuntu_release }}1_i386.deb
    - python2.4-dev_2.4.6-6+{{ ubuntu_release }}1_i386.deb

Here you can run the same task and it will just install the first time. After the first time, the packages won't be installed.

There were two modifications. One is the parameter --skip-same-version for preventing dpkg to reinstall the software. The other is the register and changed_when attributes. The first time dpkg runs, it prints to stdout a string starting with 'Selecting' and a change is notified. Later it will have a different output. I've tried a more readable condition, but couldn't make it work with a more sofisticated condition that uses "not" or searches for a substring.

neves
  • 33,186
  • 27
  • 159
  • 192
  • 6
    Neat trick! I'd prefer to check STDERR though: `changed_when: "'already installed' not in dpkg_result.stderr"` – tokarev Jan 31 '14 at 07:29
  • 2
    From the Ansible docs: [Overriding The Changed Result](http://docs.ansible.com/playbooks_error_handling.html#overriding-the-changed-result) – user272735 Apr 11 '14 at 12:49
  • Since with_items, with_dict etc. don't work when using 1.6+ deb parameter, this is the best way to loop over multiple local .deb files to install. – senorsmile Oct 16 '15 at 18:31
8

In Ansible 1.6 (and newer), the apt module has a deb option:

- apt: deb=/tmp/mypackage.deb
grahamrhay
  • 2,046
  • 4
  • 19
  • 29
2

You could use apt module with dpkg_options parameter:

- name: Install old python 
  apt: deb={{ temp_dir }}/{{ item }} dpkg_options="skip-same-version"
  register: dpkg_result
  changed_when: dpkg_result.stderr.find("already installed") == -1
  with_items: 
    - python2.4-minimal_2.4.6-6+precise1_i386.deb
    - python2.4_2.4.6-6+{{ ubuntu_release }}1_i386.deb
    - libpython2.4_2.4.6-6+{{ ubuntu_release }}1_i386.deb
    - python2.4-dev_2.4.6-6+{{ ubuntu_release }}1_i386.deb
Mariusz Sawicki
  • 311
  • 3
  • 6
  • I've changed the accepted answer to this one since the new apt module takes care of the problem. – neves Sep 15 '15 at 18:22