Безпечно обмежуючи відповідні ігрові книги однією машиною?


227

Я використовую Ansible для деяких простих завдань управління користувачем з невеликою групою комп'ютерів. Наразі у мене встановлені мої ігрові книжки, hosts: allі мій файл хостів - це лише одна група із переліченими всіма машинами:

# file: hosts
[office]
imac-1.local
imac-2.local
imac-3.local

Мені часто доводилося націлювати на одну машину. ansible-playbookМежа команда може грає так:

ansible-playbook --limit imac-2.local user.yml

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

Чи є найкраща практика обмеження пробігу книг на одній машині? В ідеалі ігрові книги повинні бути нешкідливими, якщо якась важлива деталь не залишиться.

Відповіді:


209

Виявляється, можна ввести ім'я хоста безпосередньо в програму, тому запуск ігрової книжки hosts: imac-2.localбуде добре працювати. Але це якось незграбно.

Кращим рішенням може бути визначення хостів ігрової книги за допомогою змінної, а потім передача певної адреси хоста через --extra-vars:

# file: user.yml  (playbook)
---
- hosts: '{{ target }}'
  user: ...

Запуск ігрової книги:

ansible-playbook user.yml --extra-vars "target=imac-2.local"

Якщо {{ target }}це не визначено, ігрова книга не робить нічого. Групу з файлу хостів також можна передати через необхідність. Загалом, це виглядає як набагато безпечніший спосіб побудувати потенційно руйнівну книгу.

Playbook, орієнтований на одного хоста:

$ ansible-playbook user.yml --extra-vars "target=imac-2.local" --list-hosts

playbook: user.yml

  play #1 (imac-2.local): host count=1
    imac-2.local

Книга з групою господарів:

$ ansible-playbook user.yml --extra-vars "target=office" --list-hosts

playbook: user.yml

  play #1 (office): host count=3
    imac-1.local
    imac-2.local
    imac-3.local

Забути визначення хостів безпечно!

$ ansible-playbook user.yml --list-hosts

playbook: user.yml

  play #1 ({{target}}): host count=0

52
Це можна вирішити в 1.5.3 з--limit office[0]
NG.

4
Змінна повинна бути цитується - тобто: '{{ target }}'- згідно docs.ansible.com/…
Limbo Peng

9
Це відповідь "не вдається", на відміну від деяких інших - якщо щось залишити, воно нічого не зробить. Працювати на "лише" одному хості, використовуючи Ansible 1.7, run_onceвсе ще може бути руйнівним, тому це не така гарна ідея.
RichVel

4
Якщо ви хочете більш коротку команду, -eце еквівалент--extra-vars
Вільям Террелл

1
Якщо ваша конфігурація ansible вимагає, щоб хости не могли бути порожніми або невизначеними, тоді використовується змінна, поєднана з фільтром jinja, наприклад:hosts: "{{ target | default('no_hosts')}}"
Zach Weg

178

Існує також милий маленький трюк, який дозволяє вказати одного хоста в командному рядку (або декілька хостів, я думаю), без посередницької інвентаризації:

ansible-playbook -i "imac1-local," user.yml

Зверніть увагу на кому ( , ) наприкінці; це сигналізує, що це список, а не файл.

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


2
Це дивовижно. Я регулярно використовую прапор -l, який працює з etc / ansible / hosts (який заповнюється за допомогою API відкриття EC2), але іноді мені справді потрібна одна машина. Дякую!
Вік

3
Чи повинен цей фокус використовувати файл хостів? Я використовую хости як динамічний інвентарі для нашої системи AWS EC2 і повертає: skipping: no hosts matched. Можливо, цей трюк більше не працює, оскільки --limitпрацює?
hamx0r

1
Цей трюк не спрацював для мене. Але це спрацювало: $ ansible-playbook -kK --limit=myhost1 myplaybook.yml. Дивіться відповідь Марвана.
Донн Лі

2
Слід зазначити, що для цього господарі повинні бути налаштовані на allп'єси - це знадобило мені час, аби розібратися ...
Ремігіус Старший,

83

Цей підхід буде закритий, якщо більше, ніж один хост забезпечений, перевіривши змінну play_hosts . Модуль відмови використовується для виходу, якщо умова єдиного хоста не виконується. У наведених нижче прикладах використовується файл хостів з двома хостами alice та bob.

user.yml (playbook)

---
- hosts: all
  tasks:
    - name: Check for single host
      fail: msg="Single host check failed."
      when: "{{ play_hosts|length }} != 1"
    - debug: msg='I got executed!'

Запустіть книгу без хост-фільтрів

$ ansible-playbook user.yml
PLAY [all] ****************************************************************
TASK: [Check for single host] *********************************************
failed: [alice] => {"failed": true}
msg: Single host check failed.
failed: [bob] => {"failed": true}
msg: Single host check failed.
FATAL: all hosts have already failed -- aborting

Запустити ігрову книжку на одному хості

$ ansible-playbook user.yml --limit=alice

PLAY [all] ****************************************************************

TASK: [Check for single host] *********************************************
skipping: [alice]

TASK: [debug msg='I got executed!'] ***************************************
ok: [alice] => {
    "msg": "I got executed!"
}

1
Однозначно найкращий варіант --limit- це шлях
Берто

7
play_hostsзастаріло у відповіді 2.2 та замінено на ansible_play_hosts. Щоб працювати на одному хості, не вимагаючи --limit, ви можете використовувати when: inventory_hostname == ansible_play_hosts[0].
Тревор Робінсон

[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: {{ play_hosts|length }} == ''на відповідь 2.8.4.
Томас

32

ІМХО є більш зручним способом. Ви дійсно можете інтерактивно підказати користувачеві на машинах, на яких він хоче застосувати програму, завдяки vars_prompt:

---

- hosts: "{{ setupHosts }}"
  vars_prompt:
    - name: "setupHosts"
      prompt: "Which hosts would you like to setup?"
      private: no
  tasks:
    […]

2
Дуже круто. Це також має перевагу в тому, що ігрова книга не характерна для файлу інвентаря.
Ерфан

2
Thx для редагування! Мені насправді було цікаво, чому введення за замовчуванням трактується "стиль пароля". Я пропустив це в документах :)
Buzut

Чи можна встановити хостів var з командного рядка, щоб усунути підказку з цією книгою?
andig

1
@andig --extra-varsі звичайний вар у вашій програмі…
Buzut

Власне, я не міг змусити це працювати - здається, {{ hosts }}він оцінюється до введення значення - чи є спеціальний трюк?
Ремігіус Старець

18

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

Та сама книжка, що і в іншій відповіді:

# file: user.yml  (playbook)
---
- hosts: '{{ target }}'
  user: ...

Будемо мати таких хостів:

imac-10.local
imac-11.local
imac-22.local

Тепер, щоб запустити команду на всіх пристроях, вам потрібно буде explicty встановити цільову змінну на "всі"

ansible-playbook user.yml --extra-vars "target=all"

І щоб обмежити його певним шаблоном, ви можете встановити target=pattern_here

або, як варіант, можна залишити target=allта додати --limitаргумент, наприклад:

--limit imac-1*

тобто. ansible-playbook user.yml --extra-vars "target=all" --limit imac-1* --list-hosts

що призводить до:

playbook: user.yml

  play #1 (office): host count=2
    imac-10.local
    imac-11.local

Це схема, яку я дотримувався у ansible-django-postgres-nginx
Ajoy

13

Я дійсно не розумію, наскільки всі відповіді настільки складні, спосіб зробити це просто:

ansible-playbook user.yml -i hosts/hosts --limit imac-2.local --check

checkРежим дозволяє працювати в режимі сухого ходу, без внесення будь - яких змін.


7
Ймовірно, тому, що цікавившись відповідями, ви пропустили запитання, в якому просили спосіб запобігти запуску, коли параметри помилково пропущені. Ви запропонували додати більше параметрів, що суперечать вимозі.
techraf

2
ах, звичайно, але якщо люди викликають мене, це може бути тому, що вони є новичками Ansible (як я був тоді, коли я писав свою відповідь), які навіть не знають про прапор --check, тому я думаю, що це все ще корисна документація. це питання може бути дуже googlable
knocte

6

Користувачі AWS, що використовують сценарій зовнішнього інвентаризації EC2, можуть просто відфільтрувати ідентифікатор ідентифікатора:

ansible-playbook sample-playbook.yml --limit i-c98d5a71 --list-hosts

Це працює, тому що сценарій інвентаризації створює групи за замовчуванням .


4
Варіант - ліміт не обмежується EC2 і його можна використовувати для розміщення назв хостів / груп вашого рекламного ресурсу. Дякую.
martinezdelariva

5

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

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

[ansible-dummy-group]
dummy-server

Потім ми включаємо наступний чек як перший крок у спільній програмі:

- hosts: all
  gather_facts: False
  run_once: true
  tasks:
  - fail:
      msg: "Please specify a group to run this playbook against"
    when: '"dummy-server" in ansible_play_batch'

Якщо фіктивний сервер відображається у списку хостів, для якого ця плейбук планується запустити (ansible_play_batch), то абонент не вказав групу, а виконання ігрової книги не вдасться.


ansible_play_batchперелічує лише поточну партію, тому при використанні пакетної роботи це все ще небезпечно. Краще використовувати ansible_play_hostsзамість цього.
Томас

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


4

Це показує, як запускати книжки на самому цільовому сервері.

Це трохи складніше, якщо ви хочете використовувати локальне з'єднання. Але це повинно бути добре, якщо ви використовуєте змінну для налаштування хостів і у файлі хостів створіть спеціальний запис для localhost.

У (усіх) ігрових книгах є хости: рядок встановлено на:

- hosts: "{{ target | default('no_hosts')}}"

У файл хостів інвентаризації додайте запис для localhost, який встановлює місцеве з'єднання:

[localhost]
127.0.0.1  ansible_connection=local

Потім у командному рядку виконуйте команди, явно встановлюючи ціль - наприклад:

$ ansible-playbook --extra-vars "target=localhost" test.yml

Це також буде працювати при використанні ansible-pull:

$ ansible-pull -U <git-repo-here> -d ~/ansible --extra-vars "target=localhost" test.yml

Якщо ви забудете встановити змінну в командному рядку, команда буде безпечно помилятися (до тих пір, поки ви не створили хост-групу під назвою "no_hosts"!) З попередженням:

skipping: no hosts matched

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

$ ansible-playbook --extra-vars "target=server.domain" test.yml

або група з чимось на зразок:

$ ansible-playbook --extra-vars "target=web-servers" test.yml

0

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

Для тих, хто цікавиться, я використовую ENV vars для параметрів, які використовує мій vagrantfile (додаючи відповідний ангіб аргумент для хмарних систем), а решту відповідні аргументи проходять через. Там, де я створюю і надаю більше 10 серверів одночасно, я включаю автоматичне повторне повторення роботи на помилкових серверах (доки досягнуто прогресу - я виявив, що створює 100 або більше серверів за один раз, часто декілька не вдається вийти з першого разу навколо ).

echo 'Usage: [VAR=value] bin/provision [options] dev|all|TARGET|vagrant'
echo '  bootstrap - Bootstrap servers ssh port and initial security provisioning'
echo '  dev - Provision localhost for development and control'
echo '  TARGET - specify specific host or group of hosts'
echo '  all - provision all servers'
echo '  vagrant - Provision local vagrant machine (environment vars only)'
echo
echo 'Environment VARS'
echo '  BOOTSTRAP - use cloud providers default user settings if set'
echo '  TAGS - if TAGS env variable is set, then only tasks with these tags are run'
echo '  SKIP_TAGS - only run plays and tasks whose tags do not match these values'
echo '  START_AT_TASK - start the playbook at the task matching this name'
echo
ansible-playbook --help | sed -e '1d
    s#=/etc/ansible/hosts# set by bin/provision argument#
    /-k/s/$/ (use for fresh systems)/
    /--tags/s/$/ (use TAGS var instead)/
    /--skip-tags/s/$/ (use SKIP_TAGS var instead)/
    /--start-at-task/s/$/ (use START_AT_TASK var instead)/
'

0

Трохи іншим рішенням є використання спеціальної змінної, ansible_limitяка є змістом --limitопції CLI для поточного виконання Ansible.

- hosts: "{{ ansible_limit | default(omit) }}"

Тут не потрібно визначати додаткову змінну, просто запустіть ігрову книгу з --limitпрапором.

ansible-playbook --limit imac-2.local user.yml
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.