Переопределить переменную 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напрямую?

Спасибо.

luqo33
источник

Ответы:

128

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

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

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

ansible-playbook server.yml --extra-vars "variable_host=newtarget(s)"
Wallydrag
источник
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'

TmTron
источник
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}}"
судо душа
источник