首页 文章

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

提问于
浏览
54

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

getent passwd $user | awk -F: '{ print $6 }'

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

require 'etc'

Etc.passwd { |user|

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

}

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

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

8 回答

  • 1

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

    - hosts: all
      tasks:
        - name: debug through ansible.env
          debug: var=ansible_env.HOME
    

    或者,您可以使用 env 上的lookup访问环境变量:

    - hosts: all
      tasks:
        - name: debug through lookup on env
          debug: var=lookup('env','HOME')
    

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

    - 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
    

    和Ansible中的任何内容一样,如果你不能得到一个模块来给你你想要的东西那么你总是可以自由地使用这样的东西(尽管这应该被谨慎使用,因为它可能很脆弱并且不那么描述性)使用这样的东西:

    - hosts: all
      tasks:
        - name: grep and register
          shell: >
                  egrep "^{{ user }}:" /etc/passwd | awk -F: '{ print $6 }'
          changed_when: false
          register: user_home
    
        - name: debug output
          debug: var=user_home.stdout
    

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

  • 51

    问题

    用于查找任意用户's home sadly won'的 lookup() 或ENV var方法可以与Ansible一起可靠地工作,因为它以 --user=REMOTE_USER 指定的用户运行,并且可选地使用 sudo (如果在playbook中 sudo: yes--sudo 已通过) . 这两种运行模式(sudo或no sudo)将改变Ansible正在其中运行的shell环境,即使这样,您也将被限制为指定为 -u REMOTE_USERroot 的用户 .

    您可以尝试一起使用 sudo: yessudo_user: myarbitraryuser ...但是由于certain versions of Ansible中的错误,您可能会发现它的行为不正常 . 如果您使用的是Ansible> = 1.9 ,则可以使用 become: truebecome_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
    

    运行它:

    ansible-playbook -i inventory/racktables.py playbooks/ad-hoc/get-user-homedir.yml -e "user=someuser"
    
  • 14

    Ansible 1.8推出了getent module . 它将getent结果注册为主机事实 - 在这种情况下,它是 getent_passwd .

    示例:

    打印给定 user 的主文件夹:

    ---
    
    - getent:
        database: passwd
        key: "{{ user }}"
        split: ":"
    
    - debug:
        msg: "{{ getent_passwd[user][4] }}"
    

    使用set_fact和Jinja2 combine() filter累积查找表( user_homes ):

    ---
    
    - 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]}) }}"
    

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

  • 8

    我认为这里给出了几个可行的答案,但我想我会证明你可以通过将它注册为变量来从ansible user模块中获取 .

    # The `webserver_user` value will usually be provided by a distro 
    # specific vars file. But for the purposes of demonstration, let's
    # hard code it to something...
    
    - set_fact:
        webserver_user: www-data
      when: ansible_os_family is 'Debian'
    

    然后使用ansible用户模块确保用户在场,并将该属性读入已注册的变量以供以后使用 .

    - user:
        name: "{{ webserver_user }}"
        state: present
      register: webserver_user_registered
    

    所以我们可以使用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
        }
    }
    

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

    - file:
        name: "{{ webserver_user_registered.home }}/.wp-cli"
        state: directory
    
  • 1

    Every answer mentions about how to print the home directory details while running the playbook and displaying it on screen using debug and var .

    适应@TrinitronX answer

    有关将此信息用于新任务的其他信息 .

    我有一个需要提取其主目录的用户列表 . 所以我已将用户详细信息添加到列表中

    - name: Get home directory
      shell: >
             getent passwd {{ item.user }} | cut -d: -f6
      changed_when: false
      with_items:
       - "{{java}}"
      register: user_home
    

    此步骤将遍历所有用户列表,并将该详细信息注册到user_home . 这将是一个数组的形式 .

    然后,下一步是将此信息用于新任务,例如将文件提取到bash配置文件中 . 这只是一个示例,可以是任何场景,但方法将保持不变 .

    - name: Set Java home in .bash_profile
      lineinfile: path="{{ item.stdout }}/.bash_profile" regexp='^source "{{ java_dir }}/.bash_profile_java"' line='source "{{ java_dir }}/.bash_profile_java"' state=present
      with_items:
       - "{{ user_home.results }}"
      loop_control:
        label: "{{ item.stdout }}"
    

    我在同一个剧本中为java_dir设置了/ usr / java / latest的事实 .

    Array user_home.results将包含Get home directory任务的详细信息 . 现在我们遍历这个数组并取出包含主目录路径的stdout值 .

    我已经将loop_control用于打印主目录,否则它将打印整个数组 .

    通过这个过程,我们可以确保如果有n个用户,我们可以遵循这个方法,所有这些都将得到照顾 .

    注意:我已经开始学习Ansible,如果我使用的任何术语有误,请原谅 . 我花了一些时间来弄清楚如何做到这一点并想到分享同样的东西 .

  • 2

    没有简单的方法这时在Ansible中这样做,这就是为什么你应该在这个问题上添加你的投票

    https://github.com/ansible/ansible/issues/15901

    虽然您可以使用此解决方法:https://stackoverflow.com/a/33343455/99834您不应忘记发送您希望这样易于使用的反馈 .

  • 15

    你可以使用 expanduser .

    例如,在循环用户列表时:

    - name: Deploys .bashrc
      template:
        src: bashrc.j2
        dest: "{{ '~' + item | expanduser }}/.bashrc"
        mode: 0640
        owner: "{{ item }}"
        group: "{{ item }}"
      with_items: user_list
    
  • 1

    我知道这是一个很老的线程,但我认为这是获取用户主目录的一种更简单的方法

    - name: Get users homedir
      local_action: command echo ~
      register: homedir
    

    在Linux(或Unix)系统上,波形符号指向用户主目录 .

相关问题