Переопределить переменную hosts в Ansible playbook из командной строки


111

Это фрагмент плейбука, который я использую ( server.yml):

- name: Determine Remote User
  hosts: web
  gather_facts: false
  roles:
    - { role: remote-user, tags: [remote-user, always] }

В моем файле hosts есть разные группы серверов, например

[web]
x.x.x.x

[droplets]
x.x.x.x

Теперь я хочу , чтобы выполнить ansible-playbook -i hosts/<env> server.ymlи переопределить hosts: webиз server.ymlзапустить этот сборник пьес для [droplets].

Могу ли я просто переопределить как одноразовый перерыв, не редактируя server.ymlнапрямую?

Спасибо.

Ответы:


128

Я не думаю, что Ansible предоставляет эту функцию, которая должна. Вот что вы можете сделать:

hosts: "{{ variable_host | default('web') }}"

и вы можете перейти variable_hostиз командной строки или из файла vars, например:

ansible-playbook server.yml --extra-vars "variable_host=newtarget(s)"

3
Требуется небольшая поправка. Должно бытьhosts: "{{ variable_host | default('web')}}"
— SPM

16
Вот примечание, которое, как мне кажется, будет полным ответом для новичков, ищущих это решение: Пример:ansible-playbook server.yml --extra-vars "variable_host=newtarget(s)"
— Frobbit

1
Когда (т.е. в каком порядке) делает анзибль разбора переменных Переменные в , как group_vars/allпредставляется , быть разобран после по hosts:линии пьес. Однако переменные в vars:и переменные в vars_files:разбираются перед hosts:строкой? ПРИМЕЧАНИЕ. Я не спрашиваю о приоритете.
— Фелипе Альварес

2
Вы также можете использовать -eвместо --extra-vars.
— существительное

Для получения более подробной информации посмотрите другие ответы
— Ананд Варки Филипс

63

Для всех, кто может прийти в поисках решения.
Играть в книгу

- hosts: '{{ host }}'
  tasks:
  - debug: msg="Host is {{ ansible_fqdn }}"

Инвентарь

[web]
x.x.x.x

[droplets]
x.x.x.x

Команда: ansible-playbook deplyment.yml -i hosts --extra-vars "host=droplets" Таким образом, вы можете указать имя группы в дополнительных переменных


2
Обратите внимание, будьте осторожны с именами переменных. Я тестировал это, используя play_hostsи не получая ожидаемых результатов, потому что я забыл, что play_hostsэто внутренняя Ansible var для всех хостов в текущей игре.
— Райан Фишер

Я полагаю, что по умолчанию следует установить, как в ответе выше.
— kakaz

19

Это немного поздно, но я думаю, вы могли бы использовать эту --limit or -lкоманду, чтобы ограничить шаблон более конкретными хостами. (версия 2.3.2.0)

Ты мог бы иметь - hosts: all (or group) tasks: - some_task

а затем ansible-playbook playbook.yml -l some_more_strict_host_or_pattern используйте --list-hostsфлаг, чтобы увидеть, на каких хостах будет применяться эта конфигурация.


3
Я новичок в анзибле, но считаю это очень эффективным решением, намного более компактным, чем другие. Почему он был отклонен?
— Алессандро Дентелла 05

16
Это опасно. В случае если кто-то забудет limitсписок затронутых хостов, playbook может нанести большой ущерб.
— Александр Щебликин

3
Я считаю, что использование того --extra-vars "variable_host=newtarget(s)"же принятого решения является опасным и более сложным решением. Он использует хосты по умолчанию, webкоторые могут быть применены здесь вместо all. Вы можете использовать строгую группу хостов по умолчанию, чтобы избежать ошибки, и использовать --list-hostsфлаг, чтобы иметь четкое представление о том, какие хосты вы затрагиваете.
— Джонатан Хамель

3
Решение с extra-vars позволяет указать пустую группу (или несуществующую) в качестве значения по умолчанию. Так что, если вы забудете указать переменную через командную строку, ничего плохого не произойдет. Решение с параметром «--limit» более опасно, потому что playbook не может использовать пустую группу в качестве значения по умолчанию для хостов. Параметр «--llmit» применяется к значению хостов, поэтому он будет применен к пустым группам и даст пустой результат. Таким образом, вы ДОЛЖНЫ использовать "все" или какой-либо другой непустой хост в качестве значения по умолчанию. И когда-нибудь вы забудете указать аргумент "--limit", и playbook будет применен ко всем хостам.
— Григорий Петухов

4
Это должно быть объединено с ответом @TmTron, чтобы уловить случай, когда вызывающий абонент не смог предоставить --limit(в противном случае это повлияет на все возможные хосты, что может быть не тем поведением, которое вы хотите)
— ncoghlan

14

Мы используем простую задачу сбоя, чтобы заставить пользователя указать параметр Ansible limit , чтобы мы не выполнялись на всех хостах по умолчанию / случайно.

Самый простой способ, который я нашел, - это:

---
- name: Force limit
  # 'all' is okay here, because the fail task will force the user to specify a limit on the command line, using -l or --limit
  hosts: 'all'

  tasks:
  - name: checking limit arg
    fail:
      msg: "you must use -l or --limit - when you really want to use all hosts, use -l 'all'"
    when: ansible_limit is not defined
    run_once: true

Теперь мы должны использовать параметр -l(= --limit), когда запускаем playbook, например

ansible-playbook playbook.yml -l www.example.com

Ограничить варианты документов :

Ограничение одним или несколькими хостами. Это требуется, когда кто-то хочет запустить playbook для группы хостов, но только против одного или нескольких членов этой группы.

Ограничить одним хостом

ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit "host1"

Ограничить несколькими хостами

ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit "host1,host2"

Отрицательный лимит.
ПРИМЕЧАНИЕ. ДОЛЖНЫ использоваться одинарные кавычки, чтобы предотвратить интерполяцию bash.

ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit 'all:!host1'

Ограничить группу хостов

ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit 'group1'


7

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

ansible-playbook site.yml -e working_host=myhost

Для этого вам понадобится сборник с двумя пьесами:

  • первая игра запускается на локальном хосте и добавляет хост (из заданной переменной) в известную группу в инвентаре памяти
  • Вторая пьеса проходит по этой известной группе

Рабочий пример (скопируйте и запустите предыдущей командой):

- hosts: localhost
  connection: local
  tasks:
  - add_host:
      name: "{{ working_host }}"
      groups: working_group
    changed_when: false

- hosts: working_group
  gather_facts: false
  tasks:
  - debug:
      msg: "I'm on {{ ansible_host }}"

Я использую ansible 2.4.3 и 2.3.3


7

Я изменил свое значение по умолчанию на отсутствие хоста и должен проверить его. Таким образом, пользователь или cron вынуждены предоставлять один хост или группу и т. Д. Мне нравится логика комментария от @wallydrag. В empty_groupинвентаре нет хостов.

- хосты: "{{variable_host | default ('empty_group')}}"

Затем добавьте задачи проверки:

   задачи:
   - name: Ошибка скрипта, если отсутствует обязательный параметр variable_host
     потерпеть поражение:
       msg: "Вы должны добавить --extra-vars = 'variable_host ='"
     когда: (variable_host не определено) или (variable_host == "")

5

Просто наткнулся на этот поиск в Google для решения. Собственно, в Ansible 2.5 он есть. Вы можете указать свой файл инвентаря --inventoryследующим образом:ansible --inventory configs/hosts --list-hosts all


Я считаю, что это наиболее правильный ответ в 2019 году от -i INVENTORY, --inventory=INVENTORY, --inventory-file=INVENTORY specify inventory host path or comma separated host list. --inventory-file is deprecated
— Рождества

3

Если вы хотите запустить задачу, связанную с хостом, но на другом хосте, вам следует попробовать delegate_to .

В вашем случае вы должны делегировать свой localhost (ansible master) и вызывающую ansible-playbookкоманду


2

Я использую ansible 2.5 (точно 2.5.3), и кажется, что файл vars загружается до выполнения параметра hosts. Таким образом, вы можете установить хост в файле vars.yml и просто написать hosts: {{ host_var }}в своей книге воспроизведения

Например, в моем playbook.yml:

---
- hosts: "{{ host_name }}"
  become: yes
  vars_files:
    - vars/project.yml
  tasks:
    ... 

И внутри vars / project.yml:

---

# general
host_name: your-fancy-host-name

1

Другое решение - использовать специальную переменную, ansible_limitкоторая является содержимым параметра --limitCLI для текущего выполнения Ansible.

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

Если --limitопция не указана, Ansible выдает предупреждение, но ничего не делает, поскольку ни один хост не найден.

[WARNING]: Could not match supplied host pattern, ignoring: None

PLAY ****************************************************************
skipping: no hosts matched

0

Вот классное решение, которое я придумал, чтобы безопасно указывать хосты с помощью --limitопции. В этом примере воспроизведение закончится, если playbook был выполнен без каких-либо хостов, указанных с помощью --limitопции.

Это было протестировано на Ansible версии 2.7.10.

---
- name: Playbook will fail if hosts not specified via --limit option.
  # Hosts must be set via limit. 
  hosts: "{{ play_hosts }}"
  connection: local
  gather_facts: false
  tasks:
  - set_fact:
      inventory_hosts: []
  - set_fact:
      inventory_hosts: "{{inventory_hosts + [item]}}"
    with_items: "{{hostvars.keys()|list}}"

  - meta: end_play
    when: "(play_hosts|length) == (inventory_hosts|length)"

  - debug:
      msg: "About to execute tasks/roles for {{inventory_hostname}}"
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.