Как получить произвольный домашний каталог удаленного пользователя в Ansible?

Я могу сделать это с помощью оболочки, используя комбинацию getent а также awk как это:

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> факт.

Как получить домашний каталог произвольного удаленного пользователя?

10 ответов

Решение

Ansible (начиная с версии 1.4) уже показывает переменные окружения для пользователя под ansible_env переменная.

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

Кроме того, вы можете получить доступ к переменным среды с помощью поиска на env:

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

ВЫХОД:

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 ищите, но это должно дать вам то, что вы хотите.

Я думаю, что здесь дано несколько ответов, которые сработают, но я подумал, что покажу, что вы можете получить это из пользовательского пользовательского модуля, зарегистрировав его как переменную.

# 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: 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

Ansible 1.8 представил getent модуль. Он регистрирует полученный результат как факт хоста - в данном случае это getent_passwd,

Примеры:

Распечатать домашнюю папку для данного user:

---

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

- debug:
    msg: "{{ getent_passwd[user][4] }}"

Накопить справочную таблицу (user_homes), используя set_fact и Джинджа2 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]}) }}"

Было бы лучше с модулем пользовательских фактов, хотя.

Эта проблема

lookup() или ENV var методы для поиска дома произвольного пользователя, к сожалению, не будут надежно работать с Ansible, потому что он работает как пользователь, указанный в --user=REMOTE_USERи, возможно, с sudo (если sudo: yes в пьесе или --sudo прошло). Эти два режима запуска (sudo или no sudo) изменят среду оболочки, в которой работает Ansible, и даже тогда вы будете ограничены пользователем, указанным как -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

Запустите это с:

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

Я думаю, что лучше сделать это «изначально» в Ansible, а не вызывать внешнюю команду: в основном ответ @Tom сuser:в сочетании с комментарием @Tomáš Pospíšek к этому ответу, чтобы предотвратить создание пользователя, если он еще не существует:

      - ansible.builtin.user:
    name: www-data
    state: present
  register: user_info
  check_mode: true  # Important, otherwise user will be created

Теперь допроситьuser_info: Атрибут сообщит вам, был ли пользователь создан, т.е. он еще не существует. Если не задано (значит, пользователь уже существует), домашний каталог будет вuser_info.home,

      - ansible.builtin.debug:
    var: user_info.home

В качестве альтернативы, если не гарантируется, что пользователь уже существует, вы можете найти один из следующих полезных способов, используяchangedатрибут для управления вашими действиями,

      - ansible.builtin.debug:
    var: user_info.home
  when:
    not user_info.changed

- ansible.builtin.debug:
    msg: "{% if user_info.changed|bool %}user doesn't exist{% else %}{{ user_info.home }}{% endif %}"

- ansible.builtin.fail:
    msg: "User doesn't exist. Create user before using this playbook."
  when: user_info.changed

Я знаю, что это довольно старая тема, но я думаю, что это немного более простой способ получить домашний каталог пользователей

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

В системах Linux (или Unix) знак тильды указывает на домашний каталог пользователей.

В каждом ответе говорится о том, как распечатать информацию о домашнем каталоге при запуске playbook и отобразить его на экране, используя debug и 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 будет содержать детали задачи "Получить домашний каталог". Теперь мы перебираем этот массив и извлекаем значение stdout, которое содержит путь к домашнему каталогу.

Я поставил loop_control только для печати домашнего каталога, иначе он распечатает весь массив.

Посредством этого процесса мы можем гарантировать, что если существует n пользователей, мы можем следовать этому методу и обо всем позаботимся.

Примечание: я начал изучать Ansible, в случае, если какая-либо терминология, которую я использовал, неверна, извините. Я потратил некоторое время на то, чтобы понять, как это сделать, и подумал о том, чтобы поделиться тем же.

Ты можешь использовать expanduser,

Например, во время цикла по списку пользователей:

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

Я пришел в эту ветку, потому что мне нужно было распечатать переменную env PGDATA от пользователя postgres, я не нашел, как сделать это более "родно" в недоступном, но у меня получилось, что это работает:

    - name: Find postgresql data directory
        shell: 'echo $PGDATA'
        become: yes
        become_user: postgres
        become_flags: "-i "
        register: pgdata_dir

Тогда я могу ссылаться на это в другом задании, используя "{{ pgdata_dir.stdout }}"

В Ansible сейчас нет простого способа сделать это, и поэтому вы должны добавить свои голоса к этому вопросу.

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

Хотя вы можете использовать этот обходной путь: /questions/2350838/kak-poluchit-proizvolnyij-domashnij-katalog-udalennogo-polzovatelya-v-ansible/2350851#2350851 вы не должны забывать отправлять отзывы, которые вы хотите, чтобы это было легко использовать.

Другие вопросы по тегам