Ansible 1.9.4 : Failed to lock apt for exclusive operation - ansible

I bumped into Failed to lock apt for exclusive operation issue:
https://github.com/geerlingguy/ansible-role-apache/issues/50
I posted a lot of details in GitHub.
I googled a lot of "Failed to lock apt for exclusive operation" Ansible complaints, but no simple answer. Any help?

I'm also getting this error, while setting up a couple of new boxes. I'm connecting as root, so I didn't think it was necessary, but it is:
become: yes
Now everything works as intended.

I know this question has been answered a long time ago, but for me, the solution was different.
The problem was the update_cache step. I had this with every install step, and somehow that caused the "apt failed lock error".
the solution was adding the update_cache as a seperate step, like so:
- tasks:
- name: update apt list
apt:
update_cache: yes

Running the following commands in the same sequence as below should resolve this issue :
sudo rm -rf /var/lib/apt/lists/*
sudo apt-get clean
sudo apt-get update

In my case, ansible was trying to lock /var/lib/apt/lists/ which did not exist.
The error ansible gave me was Failed to lock apt for exclusive operation: Failed to lock directory /var/lib/apt/lists/: E:Could not open lock file /var/lib/apt/lists/lock - open (2: No such file or directory)
Adding the lists directory fixed the issues:
- name: packages | ensure apt list dir exists
file:
path: /var/lib/apt/lists/
state: directory
mode: 0755

The answer from #guaka was entirely correct for me. It lacks only one thing-- where to put become: yes.
In the following, there are three places the become might go. Only one of them is correct:
- name: setup nginx web server
#1 become: yes
include_role:
name: nginx
#2 become: yes
vars:
ansible_user: "{{ devops_ssh_user }}"
#3 become: yes
In position #2 you will get an unexpected parameter error, because become is not a parameter for the include_role module.
In position #3 the play will run, but will not execute as sudo.
Only in position #1 does become: yes do any good. become is a parameter for the task, not for the module. It is not a variable like ansible_user. Just to be clear, here's a working configuration:
- name: setup nginx web server
become: yes
include_role:
name: nginx
vars:
ansible_user: "{{ devops_ssh_user }}"

I had remote_user: root in my playbook, and this happened a lot. I couldn't figure out why, it was happening only on some roles but not others (but always at the same place.) I removed remote_user: root and it stopped happening. I just use --become and --become-user=root. (Which I was using, but it still was randomly failing to get a lock for some reason.)

On my hosts file, I have some hosts that use a different user for sudo than the one Ansible uses for SSH so I had ansible_user and ansible_become_user specified for every host in the inventory.
In those hosts where ansible_user == ansible_become_user I got Failed to lock apt for exclusive operation.
The solution for me was to remove ansible_become_user line for those cases where the user is the same in both parameters.

Ok, so there is nothing wrong with Ansible, SSH or the role. It is just that apt in Debian can get really confused and lock itself out. As I was using a home-brewed Docker VM, I only had to recreate my image and container to get APT working again.

I faced the same error while using ansible to set up a ceph cluster. Just running the ansible-playbook without sudo did the trick for me!

adding become: yes to the task is solved my problem.
- name: Install dependencies
apt:
name: "{{ packages }}"
state: present
update_cache: yes
vars:
packages:
- package1
- package2
- package3
become: yes

In my case, the silly problem was that I had the same host in my inventory, but under two different DNS names.
So, apt was legitimately locked in my case, because I had multiple ansible connections to the same host doing the same thing at the same time. Hah! Doh!

https://serverfault.com/questions/716260/ansible-sudo-error-while-building-on-atlas
Check ps aux | grep apt output for suspicious processes.

Related

How to become a user with root priveleges in ansible

I am setting up a playbook that automatically configures my workstation. This will hopefully allow me to quickly install linux somewhere and automatically have all the resources I need.
One of the steps is installing homebrew and I cannot figure out how to do it.
I have created this playbook
- hosts: localhost
become: yes
become_user: myUser
tasks:
- name: Download homebrew install script from source
get_url:
url: https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh
dest: ~/Downloads/install_homebrew.sh
mode: 'u+rwx'
- name: Install homebrew
shell: ~/Downloads/install_homebrew.sh
and run it with ansible-playbook myplaybook.yaml.
However, when I execute it, there is a permission denied error. Apparently this is because of how the copy-module works (here). So I thought I'd just run the sudo ansible-playbook myplaybook.yaml instead. This leads to the exact same permission error. I guess this is because I have become_user: myUser.
However, when i remove become_user, I obviously get another error Destination /root/Downloads does not exist because my destination is coded to the users download-directory.
So how can I execute the playbook as the user myUser but with root privileges? This would allow me to access the root-stuff but still refer to my home-directory. In theory this should be possible since I can run
sudo ls -a /root && ls ~/
and get both the content of the root-folder and of my home directory. But I don't know how to do this in ansible.

package installation not considered in playbook

I got some trouble with automating an installation using ansible.
I use this role (https://github.com/elastic/ansible-elasticsearch) to install elasticsearch on my ubuntu 16.04 server.
The role depends on the package python-jmespath, as mentioned in the documentation.
The role DOES NOT install the package itsself, so i try to install it before role execution.
- hosts: elasticsearch_master_servers
become: yes
tasks:
- name: preinstall jmespath
command: "apt-get install python-jmespath"
- name: Run the equivalent of "apt-get update" as a separate step
apt:
update_cache: yes
- hosts: elasticsearch_master_servers
become: yes
roles:
- role: elastic.elasticsearch
vars:
...
When running the playbook i expect the python-jmespath package to be installed before execuction of role takes place, but role execution fails with
You need to install \"jmespath\" prior to running json_query filter"
When i check if the package is installed manually using dpkg -s python-jmespath i can see the package is installed correctly.
A second run of the playbook (with the package already installed) doesnt fail.
Do I miss an ansible configuration, that updates the list of installed packages during the playbook run ?
Am I doing something wrong in general ?
Thanks in advance
FWIW. It's possible to tag installation tasks and install the packages in the first step. For example
- name: install packages
package:
name: "{{ item.name }}"
state: "{{ item.state|default('present') }}"
state: present
loop: "{{ packages_needed_by_this_role }}"
tags: manage_packages
Install packages first
shell> ansible_playbook my-playbook.yml -t manage_packages
and then run the playbook
shell> ansible_playbook my-playbook.yml
Notes
This approach makes checking of the playbooks with "--check" much easier.
Checking idempotency is also easier.
With tags: [manage_packages, never] the package task will be skipped when not explicitly selected. This will speed up the playbook.

How to force Ansible to use sudo to install packages?

I have a playbook than run roles, and logs in the server with a user that has the sudo privileges. The problem is that, when switching to this user, I still need to use sudo to, say, install packages.
ie:
sudo yum install httpd
However, Ansible seems to ignore that and will try to install packages without sudo, which will result as a fail.
Ansible will run the following:
yum install httpd
This is the role that I use:
tasks:
- name: Import du role 'memcacheExtension'
import_role:
name: memcacheExtension
become: yes
become_method: sudo
become_user: "{{become_user}}"
become_flags: '-i'
tags:
- never
- memcached
And this is the tasks that fails in my context:
- name: Install Memcached
yum:
name: memcached.x86_64
state: present
Am I setting the sudo parameter at the wrong place? Or am I doing something wrong?
Thank you in advance
You can specify become: yes a few places. Often it is used at the task level, sometimes it is used as command line parameter (--become, -b run operations with become). It can be also set at the play level:
- hosts: servers
become: yes
become_method: enable
tasks:
- name: Hello
...
You can also enable it in group_vars:
group_vars/exmaple.yml
ansible_become: yes
For your example, using it for installing software I would set it at the task level. I think in your case the import is the problem. You should set it in the file you are importing.
I ended up specifying Ansible to become root for some of the tasks that were failing (my example wasn't the only one failing, and it worked well. The tweak in my environment is that I can't login as root, but I can "become" root once logged in as someone else.
Here is how my tasks looks like now:
- name: Install Memcached
yum:
name: memcached.x86_64
state: present
become_user: root
Use shell module instead of yum.
- name: Install Memcached
shell: sudo yum install -y {{ your_package_here }}
Not as cool as using a module, but it will get the job done.
Your become_user is ok. If you don't use it, you'll end up trying to run the commands in the playbook, by using the user used to stablish the ssh connection (ansible_user or remote_user or the user used to execute the playbook).

Ansible yum disablerepo does not work if repo is not installed

I have a number of different Centos7 servers running. I like to use ansible to update them all at once.
As one of my servers has an additional repository enabled, which I do not want to update. I've added to the playbook the option to disable this repo. This works as expected.
However, on my other servers, I did not install and enable this repo. When using the disablerepo in my ansible playbook, I get an error: repository not found.
How do I solve this in the ansible-playbook? Is it possible to add an condition like, if repo installed; then disablerepo; else do nothing?
Is it possible to ignore these errors?
ansible-playbook:
---
- hosts: [all]
tasks:
- name: update all packages to lastest version
yum:
name: '*'
state: latest
disablerepo: sernet-samba-4.2
you can put ignore_errors: yes as in the link from the comment, or you can put when, only if certain package is installed, sure you have to register them to variables first, I'm thinking something like:
- name: check if installed
shell: rpm -qa sernet-samba-4.2
register: is_installed
- name: update all packages to lastest version
yum:
name: '*'
state: latest
disablerepo: sernet-samba-4.2
when: is_installed.rc == 1
Warning: Untested.
After a day of research in internet and experiments finally found a solution that worked. Try to use wildcard.. then it will not fail when repo is missing.
yum:
name: ''
state: latest
disablerepo: sernet-samba

Ansible: apt - format of commands

These Ansible tasks seem different:
- name: Ensure Nginx is installed
apt: name=nginx update_cache=yes
and
- name: Install Nginx
apt: pkg=nginx state=installed update_cache=true
but looking at http://docs.ansible.com/ansible/latest/apt_module.html I see:
pkg is an alias of name so can ignore
However, what about:
update_cache=true - this doesn't seem to be valid in the 2nd example. Is that correct?
the first example is missing a state=installed. However, it does seem to work when I run it. Why's that?
true and yes are interchangeable so both examples are correct. Same goes for false and no.
The default value for state is present so an equivalent task to the first example would be apt: pkg=nginx state=present update_cache=yes. The ansible docs don't mention the installed state but it looks like that's an alias for present.

Resources