it-swarm.com.ru

Безопасное ограничение Ansible playbooks на один компьютер?

Я использую Ansible для некоторых простых задач управления пользователями с небольшой группой компьютеров. В настоящее время мои списки воспроизведения установлены на hosts: all, а файл hosts - это всего лишь одна группа со всеми перечисленными компьютерами:

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

Мне часто приходилось ориентироваться на одну машину. Команда ansible-playbook может ограничить воспроизведение следующим образом:

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

Но это кажется довольно хрупким, особенно для потенциально разрушительной пьесы. Если оставить флаг limit, книга будет работать везде. Поскольку эти инструменты используются только изредка, кажется, что стоит предпринять шаги для надежного воспроизведения, чтобы мы случайно не взломали что-то через несколько месяцев.

Есть ли лучшая практика для ограничения прогонов playbook на одной машине? В идеале, книги должны быть безвредны, если не учитывать некоторые важные детали.

182
joemaller

Оказывается, можно ввести имя хоста непосредственно в книгу воспроизведения, поэтому запуск книги воспроизведения с помощью hosts: iMac-2.local будет работать нормально. Но это немного неуклюже.

Лучшим решением может быть определение хостов игровой книги с помощью переменной, а затем передача определенного адреса хоста с помощью --extra-vars:

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

Запуск playbook:

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

Если {{ target }} не определен, playbook ничего не делает. Группа из файла hosts также может быть пропущена, если это необходимо. В целом, это кажется гораздо более безопасным способом создания потенциально разрушительной пьесы.

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
175
joemaller

Есть также симпатичный маленький трюк, который позволяет вам указать одного хоста в командной строке (или несколько хостов, я думаю), без промежуточного инвентаря:

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

Запишите запятую (, ) в конце; это говорит о том, что это список, а не файл.

Теперь, это не защитит вас, если вы случайно передадите настоящий файл инвентаря, так что это может быть не лучшим решением этой конкретной проблемы. Но это удобный трюк, чтобы знать!

145
Tybstar

Этот подход завершится, если будет предоставлено более одного хоста путем проверки переменной play_hosts . Модуль fail используется для выхода, если условие одного хоста не выполняется. В приведенных ниже примерах используется файл 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!'

Запустить playbook без фильтров хоста

$ 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

Запустить playbook на одном хосте

$ 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!"
}
69
Marwan Alsabbagh

Там ИМХО более удобный способ. Вы действительно можете в интерактивном режиме запросить у пользователя машину (-ы), к которой он хочет применить playbook, благодаря vars_Prompt:

---

- hosts: "{{ hosts }}"
  vars_Prompt:
    - name: "hosts"
      Prompt: "Which hosts would you like to setup?"
      private: no
  tasks:
    […]
21
Buzut

Чтобы расширить ответ joemailer, если вы хотите иметь возможность сопоставления с образцом для сопоставления с любым подмножеством удаленных машин (так же, как это делает команда ansible), но все же хотите сделать очень трудным случайный запуск playbook на всех машинах, это вот что я придумал:

Тот же playbook, что и в другом ответе:

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

Давайте иметь следующие хосты:

iMac-10.local
iMac-11.local
iMac-22.local

Теперь, чтобы запустить команду на всех устройствах, вы должны явно установить для целевой переменной значение «all».

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
16
deadbeef404

Пользователи AWS, использующие сценарий внешней инвентаризации EC2, могут просто фильтровать по идентификатору экземпляра:

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

Это работает, потому что скрипт инвентаризации создает группы по умолчанию .

7
Frank

Начиная с версии 1.7, ansible имеет параметр run_once . Раздел также содержит некоторые обсуждения различных других методов.

5
Berend de Boer

У нас есть несколько общих сборников, которые могут использовать многие команды. У нас также есть файлы инвентаризации, зависящие от среды, которые содержат несколько групповых объявлений.

Чтобы заставить человека, вызывающего playbook, указать группу, с которой нужно работать, мы вводим пустую запись в верхней части playbook:

[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), то вызывающая сторона не указала группу, и выполнение книги воспроизведения не будет выполнено.

2
mcdowellstl

Я действительно не понимаю, как все ответы настолько сложны, способ сделать это просто:

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

Режим проверки позволяет работать в режиме пробного запуска без каких-либо изменений.

1
knocte

У меня есть скрипт-обертка, называемая Provision, заставляет вас выбирать цель, поэтому мне не нужно обрабатывать ее в другом месте.

Для любопытных я использую переменные ENV для опций, которые использует мой vagrantfile (добавляя соответствующий аргумент arible для облачных систем), и позволяю пройти остальным аргументам. Когда я создаю и инициализирую более 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
iheggie

Это немного сложнее, если вы хотите использовать локальное соединение. Но это должно быть нормально, если вы используете переменную для параметра hosts и в файле hosts создайте специальную запись для localhost.

Во всех плейбуках линия hosts: установлена ​​в:

- 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

И, как упоминалось выше, вы можете настроить таргетинг на одну машину (если она есть в вашем файле hosts) с помощью:

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

или группа с чем-то вроде:

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