如何在Ansible中获取任意远程用户的主目录?

Ada*_*ski 65 ansible ansible-facts

我可以使用shell getentawk这样的组合来做到这一点:

getent passwd $user | awk -F: '{ print $6 }'
Run Code Online (Sandbox Code Playgroud)

作为参考,在Puppet中我可以使用自定义事实,如下所示:

require 'etc'

Etc.passwd { |user|

   Facter.add("home_#{user.name}") do
      setcode do
         user.dir
      end
   end

}
Run Code Online (Sandbox Code Playgroud)

这使得用户的主目录可用作home_<user name>事实.

如何获取任意远程用户的主目录?

yda*_*coR 59

Ansible(从1.4开始)已经在ansible_env变量下显示了用户的环境变量.

- hosts: all
  tasks:
    - name: debug through ansible.env
      debug: var=ansible_env.HOME
Run Code Online (Sandbox Code Playgroud)

另外,您也可以使用访问环境变量查找有关become_user:

- 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 }}"
Run Code Online (Sandbox Code Playgroud)

不幸的是,你可以显然只使用它来获取连接用户的环境变量,因为这个剧本和输出显示:

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
Run Code Online (Sandbox Code Playgroud)

输出:

- 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
Run Code Online (Sandbox Code Playgroud)

正如在Ansible什么,如果你不能得到一个模块,给你想要的东西,那么你总是可以出来(虽然这应谨慎使用,因为它可能是脆弱的,可能会更低描述),使用这样的事情:

- hosts: all
  tasks:
    - name: debug through ansible.env
      debug: var=ansible_env.HOME
Run Code Online (Sandbox Code Playgroud)

可能有一个更简洁的方法来做这个,我有点惊讶,使用env切换到指定的用户似乎不会影响ansible_env查找,但这应该给你你想要的.

  • 今天尝试了这个(ansible 2.5).`ansible_env.HOME`确实返回远程用户的HOME(但它不受`become`的影响).但是`lookup('env','HOME')`返回在控制器上运行playbook的用户的HOME. (2认同)

mas*_*asu 20

Ansible 1.8介绍了该getent模块.它将getent结果注册为主机事实 - 在这种情况下,它是getent_passwd.

例子:

打印给定的主文件夹user:

---

- getent:
    database: passwd
    key: "{{ user }}"
    split: ":"

- debug:
    msg: "{{ getent_passwd[user][4] }}"
Run Code Online (Sandbox Code Playgroud)

累积查找表(user_homes),利用set_fact和Jinja2 combine()过滤器:

---

- 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]}) }}"
Run Code Online (Sandbox Code Playgroud)

但是使用自定义事实模块会更好.


Tom*_*m H 17

我认为这里有几个答案可行,但我想我会证明你可以通过将它注册为变量从ansible用户模块获得.

- user:
    name: www-data
    state: present
  register: webserver_user_registered
Run Code Online (Sandbox Code Playgroud)

注意:如果用户不存在,它将创建用户...

所以我们可以使用debug来显示该var的值,包括路径......

- 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
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以在其他模块中使用这些属性;

- file:
    name: "{{ webserver_user_registered.home }}/.wp-cli"
    state: directory
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢这个,但我担心“user”模块会在用户不存在时创建用户而不是失败。这将是一个非常奇怪的情况,我想你可以做一些事情,比如使用带有“when:user.changed”的失败任务,但它不会撤消用户的创建。我想您可以将其包装在一个块中,并使用删除用户的命令来挽救失败,然后在救援块中添加另一个失败?有点尴尬:/ (4认同)
  • @Tom:如果您添加 `check_mode: yes` 那么您将不会冒险创建(或更改)用户。 (4认同)
  • 这是对现有 Linux 用户进行主目录查找的最优雅的方法。 (3认同)
  • 这应该是一个公认的正确答案,因为这是唯一一个也非常优雅的跨平台解决方案。`getent` 解决方案即使使用 ansible getent 模块也无法在 MacOS(至少是 High Sierra)上运行,因为从 passwd 数据库中删除了非系统用户的信息。已接受答案中的解决方案仅适用于 linux 托管主机。 (2认同)

Tri*_*onX 15

问题

lookup()用于黯然找到一个任意用户的家中或ENV VAR方法将可靠地与Ansible,因为它运行与指定的用户无法正常工作--user=REMOTE_USER,并任选sudo(如果sudo: yes在剧本或--sudo通过).这两种运行模式(sudo或no sudo)将改变Ansible运行的shell环境,即便如此,您将被限制为指定为-u REMOTE_USER或的用户root.

你可以尝试使用sudo: yes,并sudo_user: myarbitraryuser一起......然而由于一个错误Ansible的某些版本中,你可以看到,它不表现为它应该.如果你在Ansible> = 1.9,你可以使用become: true,而become_user: myarbitraryuser不是.但是,这意味着您编写的剧本和角色不适用于以前版本的Ansible.

如果您正在寻找一种可移植的方式来获取用户的主目录,该目录也可以与LDAP或其他目录服务一起使用,请使用getent.

Ansible getent示例

创建一个名为的简单剧本: playbooks/ad-hoc/get-user-homedir.yml

- hosts: all
  tasks:
    - name:
      shell: >
        getent passwd {{ user }} | cut -d: -f6
      changed_when: false
      register: user_home

    - name: debug output
      debug: var=user_home.stdout
Run Code Online (Sandbox Code Playgroud)

运行它:

ansible-playbook -i inventory/racktables.py playbooks/ad-hoc/get-user-homedir.yml -e "user=someuser"
Run Code Online (Sandbox Code Playgroud)


And*_*rds 5

我认为最好在 Ansible 中“本地”执行此操作,而不是调用外部命令:基本上,@Tom 的答案与user:@Tom\xc3\xa1\xc5\xa1 Posp\xc3\xad\xc5\xa1ek 对该答案的评论相结合如果用户尚不存在,则阻止创建该用户:

\n
- ansible.builtin.user:\n    name: www-data\n    state: present\n  register: user_info\n  check_mode: true  # Important, otherwise user will be created\n
Run Code Online (Sandbox Code Playgroud)\n

现在询问user_info:该changed属性将告诉您用户是否已创建 - 即它尚不存在。如果changed未设置(因此用户已存在),则主目录将位于user_info.home,

\n
- ansible.builtin.debug:\n    var: user_info.home\n
Run Code Online (Sandbox Code Playgroud)\n

或者,如果不能保证用户已经存在,您可能会发现以下其中一项很有帮助,使用该changed属性来引导您的操作,

\n
- ansible.builtin.debug:\n    var: user_info.home\n  when:\n    not user_info.changed\n\n- ansible.builtin.debug:\n    msg: "{% if user_info.changed|bool %}user doesn't exist{% else %}{{ user_info.home }}{% endif %}"\n\n- ansible.builtin.fail:\n    msg: "User doesn't exist. Create user before using this playbook."\n  when: user_info.changed\n
Run Code Online (Sandbox Code Playgroud)\n