如何在 Ansible 中获取任意远程用户的主目录?
How to get an arbitrary remote user's home directory in Ansible?
我可以通过 shell 使用 getent
和 awk
的组合来做到这一点,如下所示:
getent passwd $user | awk -F: '{ print }'
作为参考,在 Puppet 中我可以使用自定义事实,如下所示:
require 'etc'
Etc.passwd { |user|
Facter.add("home_#{user.name}") do
setcode do
user.dir
end
end
}
这使得用户的主目录作为 home_<user name>
事实可用。
如何获取任意远程用户的主目录?
Ansible(从 1.4 开始)已经在 ansible_env
变量下为用户显示环境变量。
- hosts: all
tasks:
- name: debug through ansible.env
debug: var=ansible_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 }}"
输出:
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 中的任何东西一样,如果您无法获得一个模块来满足您的需求,那么您可以随时 shell 退出(尽管这应该谨慎使用,因为它可能很脆弱并且将较少描述)使用这样的东西:
- hosts: all
tasks:
- name: get user home directory
shell: >
getent passwd {{ user }} | awk -F: '{ print }'
changed_when: false
register: user_home
- name: debug output
debug:
var: user_home.stdout
可能有一种更简洁的方法来执行此操作,令我感到有些惊讶的是,使用 become_user
切换到指定的用户似乎不会影响 env
查找,但这应该给你你想要的。
问题
遗憾的是,用于查找任意用户的家的 lookup()
或 ENV var 方法无法可靠地与 Ansible 一起使用,因为它 运行 是用 --user=REMOTE_USER
指定的用户,并且可选使用 sudo
(如果剧本中 sudo: yes
或 --sudo
通过)。这两种 运行 模式(sudo 或无 sudo)将改变 Ansible 运行 所在的 shell 环境,即使那样你也将被限制为指定为 [=17= 的用户] 或 root
.
您可以尝试将 sudo: yes
和 sudo_user: myarbitraryuser
一起使用...但是由于 certain versions of 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
运行 它与:
ansible-playbook -i inventory/racktables.py playbooks/ad-hoc/get-user-homedir.yml -e "user=someuser"
目前在 Ansible 中没有简单的方法可以做到这一点,这就是为什么你
应该为这个问题投上你的票
https://github.com/ansible/ansible/issues/15901
虽然您可以使用此解决方法:您不应忘记发送您希望它易于使用的反馈。
您可以使用 expanduser
.
例如,在遍历用户列表时:
- name: Deploys .bashrc
template:
src: bashrc.j2
dest: "{{ '~' + item | expanduser }}/.bashrc"
mode: 0640
owner: "{{ item }}"
group: "{{ item }}"
with_items: user_list
我知道这是很老的话题,但我认为这是获取用户主目录的更简单的方法
- name: Get users homedir
local_action: command echo ~
register: homedir
在 Linux(或 Unix)系统上,波浪号指向用户主目录。
Ansible 1.8 引入了 getent
module。它将 getent 结果注册为主机事实——在本例中,它是 getent_passwd
.
示例:
打印给定的主文件夹 user
:
---
- getent:
database: passwd
key: "{{ user }}"
split: ":"
- debug:
msg: "{{ getent_passwd[user][4] }}"
累积查找 table (user_homes
),利用 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]}) }}"
虽然自定义事实模块会更好。
我认为这里给出了几个可行的答案,但我想我会证明你可以从 ansible user 模块中获取它,方法是将其注册为变量。
- user:
name: www-data
state: present
register: webserver_user_registered
Note: it will create the user if it doesn't exist...
因此我们可以使用调试来显示该变量的值,包括路径...
- 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
每个答案都提到如何在 运行 剧本时打印主目录详细信息并使用调试和 var 在屏幕上显示它。
适应@TrinitronX
有关将此信息用于新任务的附加信息。
我有一个需要提取主目录的用户列表。所以我已将用户详细信息添加到列表
- 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。
数组user_home.results 将包含获取主目录任务的详细信息。
现在我们遍历这个数组并取出包含主目录路径的标准输出值。
我设置了 loop_control 仅用于打印主目录,否则它将打印整个数组。
通过这个过程,我们可以保证,如果有n个用户,我们可以按照这个方法,一切都会得到照顾。
注意:我已经开始学习Ansible,如果我使用的术语有误,请多多包涵。我花了一些时间弄清楚如何做到这一点,并想分享相同的东西。
我来到这个线程是因为我需要从 postgres 用户打印 PGDATA env 变量,我还没有找到如何在 ansible 中做更多的事情 "natively",但我结束了这个工作:
- name: Find postgresql data directory
shell: 'echo $PGDATA'
become: yes
become_user: postgres
become_flags: "-i "
register: pgdata_dir
然后我可以在另一份工作中使用“{{ pgdata_dir.stdout }}”引用它“
我可以通过 shell 使用 getent
和 awk
的组合来做到这一点,如下所示:
getent passwd $user | awk -F: '{ print }'
作为参考,在 Puppet 中我可以使用自定义事实,如下所示:
require 'etc'
Etc.passwd { |user|
Facter.add("home_#{user.name}") do
setcode do
user.dir
end
end
}
这使得用户的主目录作为 home_<user name>
事实可用。
如何获取任意远程用户的主目录?
Ansible(从 1.4 开始)已经在 ansible_env
变量下为用户显示环境变量。
- hosts: all
tasks:
- name: debug through ansible.env
debug: var=ansible_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 }}"
输出:
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 中的任何东西一样,如果您无法获得一个模块来满足您的需求,那么您可以随时 shell 退出(尽管这应该谨慎使用,因为它可能很脆弱并且将较少描述)使用这样的东西:
- hosts: all
tasks:
- name: get user home directory
shell: >
getent passwd {{ user }} | awk -F: '{ print }'
changed_when: false
register: user_home
- name: debug output
debug:
var: user_home.stdout
可能有一种更简洁的方法来执行此操作,令我感到有些惊讶的是,使用 become_user
切换到指定的用户似乎不会影响 env
查找,但这应该给你你想要的。
问题
遗憾的是,用于查找任意用户的家的 lookup()
或 ENV var 方法无法可靠地与 Ansible 一起使用,因为它 运行 是用 --user=REMOTE_USER
指定的用户,并且可选使用 sudo
(如果剧本中 sudo: yes
或 --sudo
通过)。这两种 运行 模式(sudo 或无 sudo)将改变 Ansible 运行 所在的 shell 环境,即使那样你也将被限制为指定为 [=17= 的用户] 或 root
.
您可以尝试将 sudo: yes
和 sudo_user: myarbitraryuser
一起使用...但是由于 certain versions of 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
运行 它与:
ansible-playbook -i inventory/racktables.py playbooks/ad-hoc/get-user-homedir.yml -e "user=someuser"
目前在 Ansible 中没有简单的方法可以做到这一点,这就是为什么你 应该为这个问题投上你的票
https://github.com/ansible/ansible/issues/15901
虽然您可以使用此解决方法:
您可以使用 expanduser
.
例如,在遍历用户列表时:
- name: Deploys .bashrc
template:
src: bashrc.j2
dest: "{{ '~' + item | expanduser }}/.bashrc"
mode: 0640
owner: "{{ item }}"
group: "{{ item }}"
with_items: user_list
我知道这是很老的话题,但我认为这是获取用户主目录的更简单的方法
- name: Get users homedir
local_action: command echo ~
register: homedir
在 Linux(或 Unix)系统上,波浪号指向用户主目录。
Ansible 1.8 引入了 getent
module。它将 getent 结果注册为主机事实——在本例中,它是 getent_passwd
.
示例:
打印给定的主文件夹 user
:
---
- getent:
database: passwd
key: "{{ user }}"
split: ":"
- debug:
msg: "{{ getent_passwd[user][4] }}"
累积查找 table (user_homes
),利用 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]}) }}"
虽然自定义事实模块会更好。
我认为这里给出了几个可行的答案,但我想我会证明你可以从 ansible user 模块中获取它,方法是将其注册为变量。
- user:
name: www-data
state: present
register: webserver_user_registered
Note: it will create the user if it doesn't exist...
因此我们可以使用调试来显示该变量的值,包括路径...
- 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
每个答案都提到如何在 运行 剧本时打印主目录详细信息并使用调试和 var 在屏幕上显示它。
适应@TrinitronX
有关将此信息用于新任务的附加信息。
我有一个需要提取主目录的用户列表。所以我已将用户详细信息添加到列表
- 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。
数组user_home.results 将包含获取主目录任务的详细信息。
现在我们遍历这个数组并取出包含主目录路径的标准输出值。
我设置了 loop_control 仅用于打印主目录,否则它将打印整个数组。
通过这个过程,我们可以保证,如果有n个用户,我们可以按照这个方法,一切都会得到照顾。
注意:我已经开始学习Ansible,如果我使用的术语有误,请多多包涵。我花了一些时间弄清楚如何做到这一点,并想分享相同的东西。
我来到这个线程是因为我需要从 postgres 用户打印 PGDATA env 变量,我还没有找到如何在 ansible 中做更多的事情 "natively",但我结束了这个工作:
- name: Find postgresql data directory
shell: 'echo $PGDATA'
become: yes
become_user: postgres
become_flags: "-i "
register: pgdata_dir
然后我可以在另一份工作中使用“{{ pgdata_dir.stdout }}”引用它“