Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
ansible_user_dir как он получается?
Начнем с чтения сорцов и разберемся что такое ansible_user_dir
ansible использует https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/setup.py для сбора фактов, это и так все знаю. Внутри модуля импортятся коллекторы https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/setup.py#L195
fact_collector = ansible_collector.get_ansible_collector(all_collector_classes=all_collector_classes,
namespace=namespace,
filter_spec=filter_spec,
gather_subset=gather_subset,
gather_timeout=gather_timeout,
minimal_gather_subset=minimal_gather_subset)
Нас интересует UserFactCollector
https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/facts/default_collectors.py#L117
_general = [
PythonFactCollector,
SystemCapabilitiesFactCollector,
PkgMgrFactCollector,
OpenBSDPkgMgrFactCollector,
ServiceMgrFactCollector,
CmdLineFactCollector,
DateTimeFactCollector,
EnvFactCollector,
SshPubKeyFactCollector,
UserFactCollector
]
...
collectors = _base + _restrictive + _general + _virtual + _hardware + _network + _extra_facts
Теперь смотрим код коллектора https://github.com/ansible/ansible/blob/9c2f44b8848a317a2304254eba0b9b348d5034ad/lib/ansible/module_utils/facts/system/user.py#L46
class UserFactCollector(BaseFactCollector):
name = 'user'
_fact_ids = set(['user_id', 'user_uid', 'user_gid',
'user_gecos', 'user_dir', 'user_shell',
'real_user_id', 'effective_user_id',
'effective_group_ids'])
def collect(self, module=None, collected_facts=None):
user_facts = {}
user_facts['user_id'] = getpass.getuser()
try:
pwent = pwd.getpwnam(getpass.getuser())
except KeyError:
pwent = pwd.getpwuid(os.getuid())
user_facts['user_uid'] = pwent.pw_uid
user_facts['user_gid'] = pwent.pw_gid
user_facts['user_gecos'] = pwent.pw_gecos
user_facts['user_dir'] = pwent.pw_dir
user_facts['user_shell'] = pwent.pw_shell
user_facts['real_user_id'] = os.getuid()
user_facts['effective_user_id'] = os.geteuid()
user_facts['real_group_id'] = os.getgid()
user_facts['effective_group_id'] = os.getgid()
return user_facts
видим 2 интересные вещи
определение ID пользователя
os.setegid
- Set the current process’s effective group id.getpass.getuser()
- Return the “login name” of the user.
pwent.pw_dir
- User home directory
Вроде понятно. получили пользователя и вернули его домашнюю директорию
Есть же ~
Зачем так сложно? можно же просто взять ~
. Можно, но не всегда, Т.к. ~
это сущность shell и разворачивается им. Может выстрелить когда shell явно не используется и/или требуется абсолютный путь.
Но, давайте глянем пример, что ~
и ansible_user_dir
иногда могут выдать разный результат.
- tasks:
- shell: eval echo "~"
register: stdout
- name: ansible_user_dir - ~ without become in play
debug:
msg: "{{ ansible_user_dir }} - {{ stdout.stdout_lines | join(' ') }}"
- shell: eval echo "~"
become: true
become_user: lgonchar
register: stdout
- name: ~ without become in play with become in task
debug:
msg: "{{ ansible_user_dir }} - {{ stdout.stdout_lines | join(' ') }}"
become: true
become_user: lgonchar
- become: true
become_user: lgonchar
tasks:
- shell: eval echo "~"
register: stdout
- name: ansible_ansible_user_dir - ~ user_dir with become in task
debug:
msg: "{{ ansible_user_dir }} - {{ stdout.stdout_lines | join(' ') }}"
А вот и результат работы:
TASK [ansible_user_dir - ~ without become in play]
ok: [lindev-lgonchar2.imagemaster.local] => {
"msg": "/home/deploy - /home/deploy"
}
TASK [~ without become in play with become in task]
changed: [lindev-lgonchar2.imagemaster.local]
TASK [ansible_ansible_user_dir - ~ user_dir with become in task]
ok: [lindev-lgonchar2.imagemaster.local] => {
"msg": "/home/deploy - /home/ms/lgonchar"
}
поведение логичное. на момент сбора фактов у нас пользователь deploy
поэтому он и сохраняется в ansible_user_dir
Вместо выводов
Выводов не будет. Это просто рассказ, что даже простая задача может скрывать подводные камни.