Using become in ansible locally - ansible

I am trying to understand --become in order to use ansible to do some local task on my centos. I tried several ansible modules (copy, unarchive) with become that each result with diffetent kind of errors.
Platform used: centos 7
Ansible (installed in a python 3 virtual env) version:
(ansible) [maadam#linux update_centos]$ ansible --version
ansible 2.10.16
config file = None
configured module search path = ['/home/maadam/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/maadam/Sources/python/venv/ansible/lib64/python3.6/site-packages/ansible
executable location = /home/maadam/Sources/python/venv/ansible/bin/ansible
python version = 3.6.8 (default, Nov 16 2020, 16:55:22) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
I tried to reproduice the example provided by #techraf in this issue to test become: Using --become for ansible_connection=local.
I used the same playbook:
---
- hosts: localhost
gather_facts: no
connection: local
tasks:
- command: whoami
register: whoami
- debug:
var: whoami.stdout
So I hope the same result as this:
(ansible) [maadam#linux update_centos]$ sudo whoami
root
Whithout become:
ansible) [maadam#linux update_centos]$ ansible-playbook playbook.yml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost
does not match 'all'
PLAY [localhost] ***************************************************************************************
TASK [command] *****************************************************************************************
changed: [localhost]
TASK [debug] *******************************************************************************************
ok: [localhost] => {
"whoami.stdout": "maadam"
}
PLAY RECAP *********************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
With become I have this error:
(ansible) [maadam#linux update_centos]$ ansible-playbook playbook.yml --become
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost
does not match 'all'
PLAY [localhost] ***************************************************************************************
TASK [command] *****************************************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "module_stderr": "/var/tmp/sclPip796: line 8: -H: command not found\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 127}
PLAY RECAP *********************************************************************************************
localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
So I don't understand what I am missing with become.
Thanks for your helps

in ansible.cfg file check for the become_method. you can use "sudo su -".

I don't know if I handle this correctly but if I run my playbook as root, I have no error:
(ansible) [maadam#linux update_centos]$ sudo ansible-playbook playbook.yml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [localhost] **************************************************************************************************************************************************************************************************
TASK [command] ****************************************************************************************************************************************************************************************************
changed: [localhost]
TASK [debug] ******************************************************************************************************************************************************************************************************
ok: [localhost] => {
"whoami.stdout": "root"
}
PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Not sure it is the right way to doing things in local with ansible. Sure if you are already root, no need for privilege escalation.

Related

How to use the 'package:' module as non-root user?

I want a playbook to validate that some packages are installed and fail that system if they are not. I thought I could use the package: module as a non-root user and have it validate the packages were installed.
I thought that the idempotency of Ansible would permit (actually encourage) this usage. Is this a bug or enhancement that I should escalate, or am I overlooking something simple to achieve this?
Here is my playbook for testing:
---
- name: Show package module non-root usage
hosts: all
become: false
tasks:
- name: Check that a packages is installed
package:
name:
- vim-common
state: installed
As a normal user I can see that vim-common is installed:
$ rpm -qa vim-common
vim-common-8.0.1763-15.el8.x86_64
$ dnf list vim-common
Not root, Subscription Management repositories not updated
Last metadata expiration check: 0:00:29 ago on Thu 21 Jan 2021 12:50:56 PM CST.
Installed Packages
vim-common.x86_64 2:8.0.1763-15.el8 #rhel-8-for-x86_64-appstream-rpms
$
But when I run the playbook I get this error instead of a "success" result:
$ ansible-playbook package_check.yml -i localhost, --connection=local
PLAY [Show package module non-root usage] *********************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************
ok: [localhost]
TASK [Check that a packages is installed] *********************************************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "msg": "This command has to be run under the root user.", "results": []}
PLAY RECAP ****************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
$
As expected, when I run it as root it works properly:
$ sudo ansible-playbook package_check.yml -i localhost, --connection=local
PLAY [Show package module non-root usage] *********************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************
ok: [localhost]
TASK [Check that a packages is installed] *********************************************************************************************
ok: [localhost]
PLAY RECAP ****************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
$
My system is Red Hat Enterprise Linux release 8.3 (Ootpa) with Ansible 2.10:
$ ansible-playbook --version
ansible-playbook 2.10.4
config file = /home/dan/.ansible.cfg
configured module search path = ['/home/dan/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.6/site-packages/ansible
executable location = /usr/local/bin/ansible-playbook
python version = 3.6.8 (default, Aug 18 2020, 08:33:21) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]
Update #1
Searching through the Ansible code, the dnf.py module is where this comes from:
$ egrep -C3 "This command has to be run under the root user." /usr/local/lib/python3.6/site-packages/ansible/modules/dnf.py
# before running it.
if not dnf.util.am_i_root():
self.module.fail_json(
msg="This command has to be run under the root user.",
results=[],
)
self.base = self._base(
$
If I comment out that root check block:
$ egrep -C3 "This command has to be run under the root user." /usr/local/lib/python3.6/site-packages/ansible/modules/dnf.py
# before running it.
# if not dnf.util.am_i_root():
# self.module.fail_json(
# msg="This command has to be run under the root user.",
# results=[],
# )
self.base = self._base(
$
I can now run the playbook and it confirms the package is installed without needing root permissions:
$ ansible-playbook package_check.yml -i localhost, --connection=local
PLAY [Show package module non-root usage] *********************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************
ok: [localhost]
TASK [Check that a packages is installed] *********************************************************************************************
ok: [localhost]
PLAY RECAP ****************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
$
Update #2
Slightly modifying the playbook to check an installed and a missing package:
$ cat package_check.yml
#!/usr/bin/env /usr/local/bin/ansible-playbook
---
- name: Show package module non-root usage
hosts: all
become: false
tasks:
- name: Check that VIM common is installed
package:
name:
- vim-common
state: installed
- name: Check that EMACS is installed
package:
name:
- vim-common
- emacs
state: installed
$
Now we get a success on the first and a failure on the second:
$ ansible-playbook package_check.yml -i localhost, --connection=local
PLAY [Show package module non-root usage] *********************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************
ok: [localhost]
TASK [Check that VIM common is installed] *********************************************************************************************
ok: [localhost]
TASK [Check that EMACS is installed] **************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "module_stderr": "2021-01-21 13:27:23,224 [ERROR] dnf.py:724879:MainThread #logutil.py:194 - [Errno 13] Permission denied: '/var/log/rhsm/rhsm.log' - Further logging output will be written to stderr\n2021-01-21 13:27:23,233 [ERROR] dnf.py:724879:MainThread #identity.py:156 - Reload of consumer identity cert /etc/pki/consumer/cert.pem raised an exception with msg: [Errno 13] Permission denied: '/etc/pki/consumer/key.pem'\nTraceback (most recent call last):\n File \"/home/dan/.ansible/tmp/ansible-tmp-1611257242.3944752-724867-4205539601634/AnsiballZ_dnf.py\", line 102, in <module>\n _ansiballz_main()\n File \"/home/dan/.ansible/tmp/ansible-tmp-1611257242.3944752-724867-4205539601634/AnsiballZ_dnf.py\", line 94, in _ansiballz_main\n invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n File \"/home/dan/.ansible/tmp/ansible-tmp-1611257242.3944752-724867-4205539601634/AnsiballZ_dnf.py\", line 40, in invoke_module\n runpy.run_module(mod_name='ansible.modules.dnf', init_globals=None, run_name='__main__', alter_sys=True)\n File \"/usr/lib64/python3.6/runpy.py\", line 205, in run_module\n return _run_module_code(code, init_globals, run_name, mod_spec)\n File \"/usr/lib64/python3.6/runpy.py\", line 96, in _run_module_code\n mod_name, mod_spec, pkg_name, script_name)\n File \"/usr/lib64/python3.6/runpy.py\", line 85, in _run_code\n exec(code, run_globals)\n File \"/tmp/ansible_ansible.legacy.dnf_payload_ewju4h_n/ansible_ansible.legacy.dnf_payload.zip/ansible/modules/dnf.py\", line 1330, in <module>\n File \"/tmp/ansible_ansible.legacy.dnf_payload_ewju4h_n/ansible_ansible.legacy.dnf_payload.zip/ansible/modules/dnf.py\", line 1319, in main\n File \"/tmp/ansible_ansible.legacy.dnf_payload_ewju4h_n/ansible_ansible.legacy.dnf_payload.zip/ansible/modules/dnf.py\", line 1294, in run\n File \"/tmp/ansible_ansible.legacy.dnf_payload_ewju4h_n/ansible_ansible.legacy.dnf_payload.zip/ansible/modules/dnf.py\", line 1213, in ensure\n File \"/usr/lib/python3.6/site-packages/dnf/base.py\", line 882, in do_transaction\n tid = self._run_transaction(cb=cb)\n File \"/usr/lib/python3.6/site-packages/dnf/base.py\", line 955, in _run_transaction\n tid = self.history.beg(rpmdbv, using_pkgs, [], cmdline, comment)\n File \"/usr/lib/python3.6/site-packages/dnf/db/history.py\", line 473, in beg\n comment)\n File \"/usr/lib64/python3.6/site-packages/libdnf/transaction.py\", line 763, in beginTransaction\n return _transaction.Swdb_beginTransaction(self, *args)\nlibdnf._error.Error: SQLite error on \"/var/lib/dnf/history.sqlite\": Reading a row failed: attempt to write a readonly database\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}
PLAY RECAP ****************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
$
And running as root works as expected:
$ sudo ansible-playbook package_check.yml -i localhost, --connection=local
PLAY [Show package module non-root usage] *********************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************
ok: [localhost]
TASK [Check that VIM common is installed] *********************************************************************************************
ok: [localhost]
TASK [Check that EMACS is installed] **************************************************************************************************
changed: [localhost]
PLAY RECAP ****************************************************************************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
$
This is because state: installed is meant to install the package if it does not exists. So, this is not strictly equal to polling your package manager for a packet.
In order to do this, you will have to use the package_facts gatherer.
Then you can easily use failed_when on that same task if the package(s) you expect are not present.
Here would be an example playbook:
- hosts: all
gather_facts: no
tasks:
- package_facts:
failed_when: "'apache2' not in ansible_facts.packages"
In order to solve the use case you stated in the comment below, you can always use the variable ansible_check_mode:
- hosts: all
gather_facts: no
tasks:
- package_facts:
failed_when: "'apache2' not in ansible_facts.packages"
when: ansible_check_mode
- package:
name: apache2
when: not ansible_check_mode

"apt" module in Ansible playbook execution randomly fails on different hosts each time with message "Failed to lock apt for exclusive operation"

When i try to install a list of packages('apache2', 'libapache2-mod-wsgi', 'python-pip', 'python-virtualenv') on on a group of hosts (app01 and app02),
it fails randomly either on app01 or app02.
After a first few retries the required packages are already installed on the host. Subsequent execution continue to fail randomly on app01 or app02 instead of returning a simple success.
The ansible controller and hosts are all running ubuntu 16.04
The controller has ansible 2.8.4
I have already set "become: yes" in playbook.
I have already tried running apt-get clean and apt-get update. on the hosts
Inventory file
[webserver]
app01 ansible_python_interpreter=python3
app02 ansible_python_interpreter=python3
Playbook
---
- hosts: webserver
tasks:
- name: install web components
become: yes
apt:
name: ['apache2', 'libapache2-mod-wsgi', 'python-pip', 'python-virtualenv']
state: present
update_cache: yes
In the first run , the execution fails on host app01
In the second run, the execution fails on host app02
1 st Run
shekhar#control:~/ansible$ ansible-playbook -v playbooks/webservers.yml
Using /home/shekhar/ansible/ansible.cfg as config file
PLAY [webserver] ******************************************************************************
TASK [Gathering Facts] ******************************************************************************
ok: [app01]
ok: [app02]
TASK [install web components] ******************************************************************************
fatal: [app01]: FAILED! => {"changed": false, "msg": "Failed to lock apt for exclusive operation"}
ok: [app02] => {"cache_update_time": 1568203558, "cache_updated": false, "changed": false}
PLAY RECAP ******************************************************************************
app01 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
app02 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2nd Run
shekhar#control:~/ansible$ ansible-playbook -v playbooks/webservers.yml
Using /home/shekhar/ansible/ansible.cfg as config file
PLAY [webserver] ******************************************************************************
TASK [Gathering Facts] ******************************************************************************
ok: [app01]
ok: [app02]
TASK [install web components] ******************************************************************************
fatal: [app02]: FAILED! => {"changed": false, "msg": "Failed to lock apt for exclusive operation"}
ok: [app01] => {"cache_update_time": 1568203558, "cache_updated": false, "changed": false}
PLAY RECAP ******************************************************************************
app01 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
app02 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
The behavior is a bit strangeā€¦ one succeed, and other failing each time.
My guess is that your app01 and app02 are actually the same host! If so, it sounds normal that the 2 jobs fight against each other.

Not able to execute service restart, copy file from non root user in ansible

---
- hosts: all
become_user: ansible
become: yes
become_method: sudo
tasks:
- name: Restart the sshd service
service: name=sshd state=restarted
### sudoers file entry for user on host ####
ansible ALL=(ALL) NOPASSWD:ALL
PLAY [all] ***************************************************************************
TASK [Gathering Facts] ***************************************************************
ok: [host2.domain.local]
ok: [host1.domain.local]
TASK [Restart the ssh service] *******************************************************
fatal: [host2.domain.local]: FAILED! => {"changed": false, "msg": "Unable to restart service sshd: Failed to restart sshd.service: Interactive authentication required.\n"}
fatal: [host1.domain.local]: FAILED! => {"changed": false, "msg": "Unable to restart service sshd: Failed to restart sshd.service: Interactive authentication required.\n"}
to retry, use: --limit #/root/1stplay.retry
PLAY RECAP ***************************************************************************
host1.domain.local : ok=1 changed=0 unreachable=0 failed=1
host2.domain.local : ok=1 changed=0 unreachable=0 failed=1
Lose the line:
become_user: ansible
Presumably you are logging into the target machine as ansible and want to become root, not ansible? If you do not specify the become_user root is used by default.

Two different version of ansible gives two different outputs for same ansible playbook

- hosts: Ebonding
become: yes
become_method: sudo
tasks
- name: Clearing cache of Server4
file: path=/weblogic/bea/user_projects/domains/tmp state=absent
become: yes
become_user: wls10
Ansible version 2.0.0.0 run the above playbook successfully::
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [ggnqinfa2]
TASK [Clearing cache of Server4] ***********************************************
ok: [ggnqinfa2]
PLAY RECAP *********************************************************************
ggnqinfa2 : ok=2 changed=0 unreachable=0 failed=0
But latest version of ansible 2.5.0rc2 encountered below error::
PLAY [Ebonding] *****************************************************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************************
ok: [ggnqinfa2]
TASK [Clearing cache of Server4] ************************************************************************************************************************************
fatal: [ggnqinfa2]: FAILED! => {"msg": "Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user (rc: 2, err: chown: /var/tmp/ansible-tmp-1520704924.34-191458796685785/: Not owner\nchown: /var/tmp/ansible-tmp-1520704924.34-191458796685785/file.py: Not owner\n}). For information on working around this, see https://docs.ansible.com/ansible/become.html#becoming-an-unprivileged-user"}
PLAY RECAP **********************************************************************************************************************************************************
ggnqinfa2 : ok=1 changed=0 unreachable=0 failed=1
How can i run this playbook by latest version of ansible successfully?
Chances are the user you're using (wls10) does not have write access to the remote temporary directory /var/tmp.
This can be overridden using ansible.cfg and set via remote_tmp to a directory you have write-access to -- or, a "normal temp directory" (like /tmp) that has the sticky bit set.
For more info, see
http://docs.ansible.com/ansible/latest/intro_configuration.html#remote-tmp

Unable to access hosts beside local host in Ansible

I'm self-learning ansible and having the files structure below with my customized ansible.cfg and inventory file:
---ansible (Folder) <---Working level
---ansible.cfg (Customized cfg)
---dev (Inventory File)
---playbooks (Folder) <--Issue level
---hostname.yml
ansible.cfg
[defaults]
inventory=./dev
dev
[loadbalancer]
lb01
[webserver]
app01
app02
[database]
db01
[control]
control ansible_connection=localansible
hostname.yml
---
- hosts: all
tasks:
- name: get server hostname
command: hostname
My question is when I run ansible-playbook playbooks/hostname.yml at ansible (Folder) level, everything works fine
PLAY [all] *********************************************************************
TASK [setup] *******************************************************************
ok: [control]
ok: [app01]
ok: [db01]
ok: [lb01]
ok: [app02]
TASK [get server hostname] *****************************************************
changed: [db01]
changed: [app01]
changed: [app02]
changed: [lb01]
changed: [control]
PLAY RECAP *********************************************************************
app01 : ok=2 changed=1 unreachable=0 failed=0
app02 : ok=2 changed=1 unreachable=0 failed=0
control : ok=2 changed=1 unreachable=0 failed=0
db01 : ok=2 changed=1 unreachable=0 failed=0
lb01 : ok=2 changed=1 unreachable=0 failed=0
Howevery when I go into the playbooks folder and run ansible-playbook hostname.yml it give me warning saying
[WARNING]: provided hosts list is empty, only localhost is available
PLAY RECAP *********************************************************************
Is there anything that prevents playbook from accessing the inventory file?
Ansible does not traverse parent directories in search for the configuration file ansible.cfg. If you want to use a custom configuration file, you need to place it in the current directory and run Ansible executables from there or define an environment variable ANSIBLE_CONFIG pointing to the file.
In your case: changing the directory to ansible and executing is the proper way:
ansible-playbook playbooks/hostname.yml
I don't know where from you got the idea Ansible would check for the configuration file in the parent directory - the documentation is unambiguous:
Changes can be made and used in a configuration file which will be processed in the following order:
ANSIBLE_CONFIG (an environment variable)
ansible.cfg (in the current directory)
.ansible.cfg (in the home directory)
/etc/ansible/ansible.cfg

Resources