Module to determine home directory for a named user

Hi all,

Have started playing around with Ansible over the last couple of days, and as part of my playbook to set up a new server I wanted to copy files to the home directories of some specific users. I couldn’t find an existing way of reliably determining user home directories – just grepping /etc/passwd isn’t quite enough – and so I knocked together a module to get this for me.

No idea if I’ve done things the “right” way, but thought the code might be useful to someone. Also would appreciate any critique or suggestions from those that know the system better. I’m more of a Perl and Java man, so I don’t promise my Python code is pretty or sensible.

Call method from inside a playbook is:

`

  • name: Get user home directory
    userhomedir: loginid=targetuser
    register: user

  • name: Debug info
    debug: msg=“Home directory for user {{ user.loginid }} is {{ user.dest }}”
    `

Module code:

`
#!/usr/bin/python

-------

Imports

-------

import sys, pwd, re
from ansible.module_utils.basic import *

--------------

Define Globals

--------------

module = AnsibleModule(
argument_spec = dict(
loginid = dict(required=True, type=‘str’)
)
)

if sys.platform.startswith(‘linux’):
default_home = “/home”
default_useradd_file = “/etc/default/useradd”
default_useradd_entry = “HOME”

elif sys.platform.startswith(‘freebsd’):
default_home = “/home”
default_useradd_file = “/etc/adduser.conf”
default_useradd_entry = “homeprefix”

else:
module.fail_json(msg="Module does not know how to handle operating system " + sys.platform)

was_useradd_parsed = False

----------------

Define Functions

----------------

def getDirFromPasswd(check_username):
pwd_homedir = “”
try:
user_entry = pwd.getpwnam(check_username)
pwd_homedir = user_entry[5]
except:
pass

return {‘method’: “Password File”, ‘directory’:pwd_homedir}

def getDirFromUseradd(check_username):
global was_useradd_parsed
def_dir = “”
home_regex = “^” + re.escape(default_useradd_entry) + “=(.*)”
try:
default_file = open(default_useradd_file)
was_useradd_parsed = True
for line in default_file:
match = re.search(home_regex, line)
if match:
def_dir = match.group(1) + “/” + check_username
module.exit_json(changed=False, loginid=“TEST”, homedir=chosen_home[‘directory’], source=chosen_home[‘method’], platform=sys.platform)
break
default_file.close()
except:
pass

return {‘method’: “Useradd Default”, ‘directory’:def_dir}

def getDirFromFallback(check_username):
assumed_directory = default_home + “/” + check_username
return {‘method’: “Fall-back”, ‘directory’: assumed_directory}

-------------

Main Function

-------------

def main():
username = module.params[‘loginid’]

chosen_home = getDirFromPasswd(username)

if chosen_home[‘directory’] == “”:
chosen_home = getDirFromUseradd(username)

if chosen_home[‘directory’] == “”:
chosen_home = getDirFromFallback(username)

module.exit_json(changed=False, loginid=username, dest=chosen_home[‘directory’], source=chosen_home[‘method’], platform=sys.platform, useradd_parsed=was_useradd_parsed)

------

Run Me

------

if name == ‘main’:
main()
`

You can already get this info:
#> ansible -m getent -a ‘database=passwd key=myuser’ localhost -vv

localhost | SUCCESS => {
“ansible_facts”: {
“getent_passwd”: {
“myuser”: [
“x”,
“1000”,
“100”,
“My User”,
“/home/myuser”,
“/bin/bash”
]
}

Great, thanks Brian, that’s really useful to know. Evidently my Google-fu failed me on this one since searching for “ansible getent” returns that module as the first result.

What I didn’t make clear is that my requirement is to determine the home directory for a user, and if that user doesn’t yet exist, provide an educated guess where their home folder would get created. This way I can pre-create the folder and stick authorized_keys and whatever into it on a new machine even before I’ve logged on with a particular account.

Perhaps it’s a very unique requirement to my test lab, but as I said, I thought I’d share in case it’s useful. Also, any general feedback on the module will be helpful if I do create something that has wider application :slight_smile: