Error when installing package with 'apt' module, not so when installing directly

Dear list,

I’ve run into a puzzling issue. I’m creating a playbook to install Crashplan on my Raspberry Pi. On of the steps involves installing the Java lib “libjna-java”. This does not work:

PLAY [pi] *********************

GATHERING FACTS *********************
REMOTE_MODULE setup
ok: [pi]

TASK: [install java packages] *********************
REMOTE_MODULE apt pkg=libjna-java state=installed
failed: [pi] => {“failed”: true}
msg: 'apt-get install ‘libjna-java’ ’ failed: E: Sub-process /usr/bin/dpkg returned an error code (2)

FATAL: all hosts have already failed – aborting

PLAY RECAP *********************
pi : ok=1 changed=0 unreachable=0 failed=1

Going to the machine via SSH and issueing: ‘apt-get install libjna-java’ works without a hitch. I’m a bit at a loss here. How do I debug this?

During the playbook execution I ran ‘ps ax’ to see what commands where issued, nothing strange as far as I can tell. For completeness sake:
/bin/sh -c DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical /usr/bin/apt-get --option Dpkg::Options::=–force-confold -q -y install ‘libjna-java’

I hope someone knows what’s up.

With kind regards,

Something in the package script wanted a real TTY?

– Michael

When running apt-get local it just installed. Quite literally ‘no questions asked’. It’s just a lib. That is how you’d know there was a TTY right? When some user input is required?

no idea, java famously required X for years. Maybe someone else can take a look at the package source.

– Michael

I tried installing the libjna-java package using ansible on an ubuntu virtual machine, and I didn’t have any issues. This is what I did:

$ ansible vm -s -m apt -a “pkg=libjna-java”
vm | success >> {
“changed”: true
}

Then, checked inside the machine to see if it was installed:

vagrant@precise64:~$ dpkg -l | grep libjna-java
ii libjna-java 3.2.7-4 Dynamic access of native libraries from Java without JNI

Take care,

Lorin

Looking at the output, I wonder why there is an additional quoting in that msg. I would have expected:

   msg: 'apt-get install libjna-java '
   failed: E: Sub-process /usr/bin/dpkg

Somehow it feels as if you added quotes that shouldn't be there. In YAML, strings don't have to be quoted !

Thanks for all the responses! I’ve made some headway but the mystery deepens.

I’m starting to suspect that it has something to do with the fact that the Pi is an ARM machine, seeing that Lorin is able to install without issues.
The quoting isn’t it. I double checked my YAML file.

The playbook defines 2 packages to be installed, one ‘libjna-java’, the other ‘openjdk-6-jre’ (see it in a Gist: https://gist.github.com/4141972). I’ve added line 8: “-name: install JNA”. Now the playbook fails on the ‘openjdk-6-jre’ package! With the same error (aside from the package name).

This is getting weird.

Harm

I found the issue; installing as root works, with sudo it doesn’t. I’ve tested with a random other package, in this case ‘curl’.

With sudo:

TASK: [install curl] *********************
ESTABLISH CONNECTION FOR USER: pi on PORT 22 TO pi
EXEC /bin/sh -c ‘mkdir -p $HOME/.ansible/tmp/ansible-1353806171.19-173008960117788 && chmod a+rx $HOME/.ansible/tmp/ansible-1353806171.19-173008960117788 && echo $HOME/.ansible/tmp/ansible-1353806171.19-173008960117788’
REMOTE_MODULE apt pkg=curl state=installed
PUT /var/folders/rd/8nngsjnd0ds0y690_x0j18k80000gn/T/tmpaYtqFr TO /home/pi/.ansible/tmp/ansible-1353806171.19-173008960117788/apt
EXEC /bin/sh -c ‘sudo -k && sudo -p “[sudo via ansible, key=prcrexrotbynmicxjtowyyhldqrigudq] password: " -u root /bin/sh -c '”’“‘/usr/bin/python -tt /home/pi/.ansible/tmp/ansible-1353806171.19-173008960117788/apt; rm -rf /home/pi/.ansible/tmp/ansible-1353806171.19-173008960117788/ >/dev/null 2>&1’”‘"’’
failed: [pi] => {“failed”: true}
msg: 'apt-get install ‘curl’ ’ failed: E: Sub-process /usr/bin/dpkg returned an error code (2)

FATAL: all hosts have already failed – aborting

With root:

TASK: [install curl] *********************
ESTABLISH CONNECTION FOR USER: root on PORT 22 TO pi
EXEC /bin/sh -c ‘mkdir -p $HOME/.ansible/tmp/ansible-1353806498.34-90561343419662 && echo $HOME/.ansible/tmp/ansible-1353806498.34-90561343419662’
REMOTE_MODULE apt pkg=curl state=installed
PUT /var/folders/rd/8nngsjnd0ds0y690_x0j18k80000gn/T/tmpF1zDoj TO /root/.ansible/tmp/ansible-1353806498.34-90561343419662/apt
EXEC /bin/sh -c ‘/usr/bin/python -tt /root/.ansible/tmp/ansible-1353806498.34-90561343419662/apt; rm -rf /root/.ansible/tmp/ansible-1353806498.34-90561343419662/ >/dev/null 2>&1’
changed: [pi] => {“changed”: true}

I’m not sure what the problem is… Some unbalanced quotes perhaps?

Harm

I was having the exact problem on Wheezy Debian 7 x64 - using a normal user to install packages with sudo. I was however able to reproduce the problem by logging in via ssh to the machine and executing apt-get on the command line. In my case, I was trying to install rsync:

apt-get -y install rsync

The problem was that dpkg was not in the normal user’s path as were all the normal root paths: /usr/local/sbin:/usr/sbin:/sbin. So to solve the problem you need to explicitly set the path for the apt module as follows

  • name: install debian packages
    apt: pkg=rsync state=latest
    environment:
    PATH: /usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin

Hope this helps!

karl | karl@ostendorf.com | https://ostendorf.com/

This is indeed a case that happens on Debian, as Ubuntu tends to put sbin paths also in a regular user’s folder.
You might consider extending the path for your sudo user also.

The best solution would be to let the apt module look for the apt-get|aptitude binaries and execute them with full absolute path, whereas it now just calls the binary by name without path.

Yes, this should definitely use the find module code in lib/ansible/module_common.

We should not be relying on user paths.

Please file a ticket and (if you are feeling generous) look around some of the other modules for how they do it and apply a fix :slight_smile:

–Michael

This path is normally set correctly in the sudoers file (by default).

Brian Coca

This path is normally set correctly in the sudoers file (by default).

​Seems so, yes. According to sudoers(5)​:

* By default, the env_reset option is enabled. This causes commands to

be executed with a new, minimal environment. On AIX (and Linux systems
without PAM), the environment is initialized with
** the contents of the /etc/environment file. The new environment
contains the TERM, PATH, HOME, MAIL, SHELL, LOGNAME, USER, USERNAME and
SUDO_* variables in addition to variables from the
** invoking process permitted by the env_check and env_keep options.
This is effectively a whitelist for environment variables.*

​on my system (ubuntu) /etc/environments contains:

*​serge@cyberlab:~$ cat /etc/environment

**
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"
*

However, on a Debian 6, I see that environment file is empty.

So validating executables with the common_module methods would still be a
good idea.

Serge

I would almost qualify this as a 'bug' in Debian 6

or you should have it set in sudoers file itself:

Defaults secure_path=“/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin”

Repeating myself… :slight_smile:

We need to use the find module code and not rely on the users path.

agreed, but this should still work ‘as is’ in most cases. Will patch apt tonight, should be quick one.

refraining from rewriting the whole thing to avoid ‘global’, but this is what patch should look like:

diff --git a/library/packaging/apt b/library/packaging/apt
index 41380e6…1a0ea84 100644
— a/library/packaging/apt
+++ b/library/packaging/apt
@@ -117,8 +117,6 @@ import os
import datetime

APT related constants

-APTITUDE_CMD = “aptitude”
-APT_GET_CMD = “apt-get”
APT_ENVVARS = “DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical”
DPKG_OPTIONS = ‘-o “Dpkg::Options::=–force-confdef” -o “Dpkg::Options::=–force-confold”’
APT_GET_ZERO = “0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.”
@@ -265,6 +263,9 @@ def main():
except:
module.fail_json(msg=“Could not import python modules: apt, apt_pkg. Please install python-apt package.”)

  • global APTITUDE_CMD = module.get_bin_path(“aptitude”)
  • global APT_GET_CMD = module.get_bin_path(“apt-get”)

Testing this on my Debian 6 box, i was actually not able to reproduce this (OK, the OP did mention Debian 7…):

serge@cyberlab:~/src/ansible$ ansible debian6 -u serge -K -m apt -a “pkg=sshpass state=latest” -vvv
sudo password:
debian6 | success >> {
“changed”: true
}
serge@cyberlab:~/src/ansible$ ansible debian6 -u serge -K -m shell -a “echo $PATH” -vvv
sudo password:
debian6 | success | rc=0 >>
/home/serge/bin:/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
serge@cyberlab:~/src/ansible$ ansible debian6 -u serge -K -m shell -a “which apt-get; which dpkg” -vvv
sudo password:
debian6 | success | rc=0 >>
/usr/bin/apt-get
/usr/bin/dpkg

I’m also puzzled by the OP mentioning this error:

msg: 'apt-get install ‘curl’ ’ failed: E: Sub-process /usr/bin/dpkg returned an error code (2)

which seems to tell us apt-get is ran fine, and the path to dpkg is no problem either.

Are we looking at some other bug than this $PATH thing?

Serge

​Brian,​

+ global APTITUDE_CMD = module.get_bin_path("aptitude")
+ global APT_GET_CMD = module.get_bin_path("apt-get")

Ii see one problem with this:

Whilst apt-get can be expected to be installed on any debian based system,
​aptitude cannot. A very bare system won't have it (which was the reason
for one of my previous patches on this module), so this should remain
optional, and only checked if explicitly chosen a option needing aptitude.

(PS: unrelated, we might also consider letting users choose between apt-get
and aptitude for other tasks besides upgradingn wchis is now the only case
where aptitude gets used)

Serge