How to get an arbitrary remote user's home directory in Ansible?
Ansible (from 1.4 onwards) already reveals environment variables for the user under the ansible_env
variable.
- hosts: all
tasks:
- name: debug through ansible.env
debug: var=ansible_env.HOME
Unfortunately you can apparently only use this to get environment variables for the connected user as this playbook and output shows:
- hosts: all
tasks:
- name: debug specified user's home dir through ansible.env
debug: var=ansible_env.HOME
become: true
become_user: "{{ user }}"
- name: debug specified user's home dir through lookup on env
debug: var=lookup('env','HOME')
become: true
become_user: "{{ user }}"
OUTPUT:
vagrant@Test-01:~$ ansible-playbook -i "inventory/vagrant" env_vars.yml -e "user=testuser"
PLAY [all] ********************************************************************
GATHERING FACTS ***************************************************************
ok: [192.168.0.30]
TASK: [debug specified user's home dir through ansible.env] *******************
ok: [192.168.0.30] => {
"var": {
"/home/vagrant": "/home/vagrant"
}
}
TASK: [debug specified user's home dir through lookup on env] *****************
ok: [192.168.0.30] => {
"var": {
"/home/vagrant": "/home/vagrant"
}
}
PLAY RECAP ********************************************************************
192.168.0.30 : ok=3 changed=0 unreachable=0 failed=0
As with anything in Ansible, if you can't get a module to give you what you want then you are always free to shell out (although this should be used sparingly as it may be fragile and will be less descriptive) using something like this:
- hosts: all
tasks:
- name: get user home directory
shell: >
getent passwd {{ user }} | awk -F: '{ print $6 }'
changed_when: false
register: user_home
- name: debug output
debug:
var: user_home.stdout
There may well be a cleaner way of doing this and I'm a little surprised that using become_user
to switch to the user specified doesn't seem to affect the env
lookup but this should give you what you want.
I think there are several answers given here that would work, but I thought I'd show that you can get this from the ansible user module, by registering it as a variable.
- user:
name: www-data
state: present
register: webserver_user_registered
Note: it will create the user if it doesn't exist...
So we can use debug to show the values of that var, including the path...
- debug:
var: webserver_user_registered
TASK [wordpress : debug] ******************
ok: [wordpresssite.org] => {
"webserver_user_registered": {
"append": false,
"changed": false,
"comment": "www-data",
"failed": false,
"group": 33,
"home": "/var/www", <<------ this is the user home dir
"move_home": false,
"name": "www-data",
"shell": "/usr/sbin/nologin",
"state": "present",
"uid": 33
}
}
And you can use those properties in other modules like this;
- file:
name: "{{ webserver_user_registered.home }}/.wp-cli"
state: directory
Ansible 1.8 introduced the getent
module. It registers the getent result as a host fact—in this case, it's getent_passwd
.
examples:
Print the home folder for a given user
:
---
- getent:
database: passwd
key: "{{ user }}"
split: ":"
- debug:
msg: "{{ getent_passwd[user][4] }}"
Accumulate a lookup table (user_homes
), leveraging set_fact
and the Jinja2 combine()
filter:
---
- assert:
that:
- user_name is defined
- when: user_homes is undefined or user_name not in user_homes
block:
- name: getent
become: yes
getent:
database: passwd
key: "{{ user_name }}"
split: ":"
- name: set fact
set_fact:
"user_homes": "{{ user_homes | d({}) | combine({user_name: getent_passwd[user_name][4]}) }}"
Would be better with a custom fact module though.