Як отримати довільний домашній каталог віддаленого користувача в Ansible?


80

Я можу зробити це з оболонкою, використовуючи комбінацію getentі awkтак:

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

Для довідки в «Ляльковому» я можу використовувати власний факт, наприклад:

require 'etc'

Etc.passwd { |user|

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

}

що робить домашній каталог користувача доступним як home_<user name>факт.

Як отримати домашній каталог довільного віддаленого користувача?

Відповіді:


71

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

Як і всі в анзібль, якщо ви не можете отримати модуль , щоб дати вам те , що ви хочете , то ви завжди можете обстрілювати з (хоча це слід використовувати з обережністю , оскільки це може бути крихким і менш описовий) , використовуючи що - щось на зразок цього :

- 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

Можливо, це чистіший спосіб зробити це, і я трохи здивований, що використання become_userперемикання на вказаного користувача, схоже, не впливає на envпошук, але це повинно дати вам те, що ви хочете.


Я це знаю, але це працює лише для поточного користувача. Я хочу отримати домашній каталог будь-якого іншого користувача (наприклад, для налаштування спільних робочих станцій)
Адам Ричковський,

Схоже become_user, не оновлюється, envтому я не впевнений, чи є більш чистий підхід, ніж просто обстріл, але це повинно спрацювати
ydaetskcoR

Це не буде працювати навколо для хостів, які підключені до LDAP або якогось іншого сервера каталогів. Для цього вам потрібно буде використовувати getentзамість цього.
TrinitronX

sudo_userі become_userвони не такі портативні у різних версіях Ansible. getentмені все ще здається найкращим рішенням тут.
TrinitronX

3
Спробував це сьогодні (ansible 2.5). ansible_env.HOMEповертає HOME віддаленого користувача (але це не впливає become). Однак lookup('env','HOME')повертає HOME користувача, який запускає книгу відтворення на контролері.
jsantander

35

Я думаю, що тут наведено кілька відповідей, які могли б працювати, але я думав показати, що ви можете отримати це з модуля користувача ansible , зареєструвавши його як змінну.

- user:
    name: www-data
    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

Це має бути прийнятою правильною відповіддю, оскільки це єдине міжплатформене рішення, яке також є досить елегантним. getentрішення навіть з модулем ansible getent не працює на MacOS (принаймні High Sierra), оскільки інформація про несистемного користувача видаляється з бази даних passwd. І рішення у прийнятій відповіді працює лише для керованого хостом Linux.
Дрю

Я мав на увазі, що він "досить елегантний", тому що він короткий, і ви отримуєте об'єкт або навіть список об'єктів з красиво названими властивостями, як .nameі .home.
Дрю

Мені це подобається, але я переживаю, що userмодуль створить користувача, якщо він не існує, замість того, щоб вийти з ладу. Це було б дуже дивною справою, і я думаю, ви могли б зробити щось на зразок використання невдалого завдання з, when: user.changedале це не скасує створення користувача. Я думаю, ви могли б обернути його в блок і врятувати несправність командою, яка видалила користувача, а потім додати ще одну помилку в рятувальному блоці? Якось незручно: /
ydaetskcoR

@ydaetskcoR Так, за замовчуванням для stateє present, тому, як написано, він створить користувача, якщо він не існує. Однак немає сенсу отримувати домашній каталог неіснуючого користувача, тому, якщо його створення спричинить проблеми, то вам доведеться пильнувати це.
Tom H

Це найелегантніший спосіб пошуку домашнього каталогу у вже існуючого користувача Linux.
Айдан Мелен,

25

Ansible 1.8 представив getentмодуль . Він реєструє гетентний результат як основний факт - у цьому випадку це так getent_passwd.

приклади:

Роздрукуйте домашню папку для заданого user:

---

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

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

Накопичити таблицю пошуку ( user_homes), використання set_factта combine()фільтр Jinja2 :

---

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

Хоча було б краще з користувацьким модулем фактів.


getentбуло введено в Ansible 1.8
myrdd

15

Проблема

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

Приклад відповідального гетента

Створіть простий посібник із назвою: 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"

getent не на Mac OSX 10.12.6
AnneTheAgile

1
@AnneTheAgile: Ви праві, схоже, OSX 10.12.6не має цієї утиліти. Альтернативами є `dscacheutil -q user -a name {{user}} , sudo dscl. -ls / Users`, щоб перерахувати користувачів і dscl . -read /Users/{{ user }}скинути інформацію про користувача. Для однокористувацьких користувачів і груп існує також завжди /etc/passwdі /etc/groupтому, що OSX принаймні є Unix сумісним із цими файлами, коли працює в однокористувацькому режимі. Інші користувачі містять opendirectorydкоментарі у верхній частині цих файлів.
TrinitronX

1
@AnneTheAgile: З іншого боку, схоже, хтось створив getentутиліту командного рядка, яку ви можете скомпілювати та використовувати на OSX тут . git clone https://github.com/petere/getent-osx.git && cd getent-osx make ; make install
TrinitronX

менше стосується надійності програмного забезпечення, а більше передбачуваної поведінки. коли певна функція працює так, як вона була розроблена, тоді вона чудова. але якщо ви очікуєте чогось іншого, тоді існує розбіжність між вами та дизайном. можливо, конструкція не узгоджується, і, отже, вона, ймовірно, запрошує кодерів застрягти у таких не дуже очевидних підводних комах, які виникають через відсутність послідовності.
Alexander Stohr

3

Можна використовувати expanduser.

Наприклад, під час циклічного перегляду списку користувачів:

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

7
Зверніть увагу, що це розширює користувачів на хості контролера, а не на цільовому хості.
Маріус Гедмінас,

3

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

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

У системах Linux (або Unix) знак тильди вказує на домашній каталог користувачів.


Використання імені користувача echo ~ - це, мабуть, один із найбільш портативних способів досягнення того, що було задане оригінальним запитанням. Одна велика перевага полягає в тому, що немає необхідності возитися з використанням цього методу.
Брайан Акер,

"~ ім'я користувача" не вдасться завершити, якщо цей субдир не вдається вирішити, а повертає лише рядок, ідентичний вхідному запиту
Олександр Стор,

3

У кожній відповіді згадується про те, як надрукувати деталі домашнього каталогу під час запуску книги і відображення її на екрані за допомогою налагодження та змінної .

Адаптація до відповіді @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 / останнього в тій самій книзі.

Масив user_home.results міститиме деталі завдання «Отримати домашній каталог». Тепер ми прокручуємо цей масив і виймаємо значення stdout, яке містить шлях до домашнього каталогу.

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

За допомогою цього процесу ми можемо гарантувати, що якщо буде n користувачів, ми зможемо слідувати цьому методу, і про все буде подбано.

Примітка: Я почав вивчати Ansible, якщо будь-яка термінологія, яку я використав, є неправильною, прошу вибачення. Я витратив трохи часу, щоб придумати, як це зробити, і думав поділитися тим самим.


2
getent не є портативним. OSX - найочевидніший приклад того, де ви не знайдете гетенту.
Брайан Акер,

використання "вирізати" замість "awk" корисно в тих випадках, коли awk не встановлено. cut набагато частіше присутній у більшості випадків, тому я б віддав перевагу цьому.
Alexander Stohr

2

Я дійшов до цієї теми, тому що мені потрібно було надрукувати змінну PGDATA env від користувача postgres, я не знайшов, як це зробити більш "рідно" в ansible, але я закінчив, маючи це, що працює:

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

Тоді я можу посилатися на це в іншому завданні, використовуючи "{{pgdata_dir.stdout}}"


хороший момент, використовуючи опцію "-i". це може мати деякі додаткові ефекти на параметри оболонки, такі як скасування поведінки або підказка - але якщо це не виявиться заважаючим руйнівним способом, ви просто будете використовувати його для обслуговування своєї конкретної роботи.
Alexander Stohr

1

На даний момент у Ansible немає простого способу зробити це, і тому вам слід додати свої голоси до цього питання

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

Хоча ви можете використовувати це обхідне рішення: https://stackoverflow.com/a/33343455/99834, ви не повинні забути надіслати відгук про те, що ви хочете, щоб це було легко використовувати.


Питання досі не вирішено, і Ansible закрило це питання та заблокувало його від коментарів та голосування ...: /
Hubro,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.