Передавать переменные Ansible из одной роли (выполняющейся на одном хосте) в другую роль, выполняющуюся на другом хосте в рамках одного сценария воспроизведения.

У меня есть сценарий, который выполняет разные роли на разных хостах. Можно ли передать переменную от одной роли, работающей на одном хосте, к другой роли на другом хосте, работающей в одном и том же запуске playbook? Или какой-нибудь обходной путь?

playbook
   host1
     role1
       here I get some variables: var1 var2 ...etc
   host2
     role2
       here I need to use var1 var2 ... etc from the above host/role

Задача в role1, которая устанавливает переменную db, выглядит так:

- shell: cd /ACE/conf && grep ^db.url local1.properties | awk -F/ '{print $4}' | awk -F? '{print $1}'
  register: db

ОБНОВЛЕНИЕ: на первом хосте значения динамические, это как файл конфигурации, который всегда обновляется. После того, как я сохраню значения в переменных на host1 с ролью 1, я перехожу к host2, запускаю role2 и выполняю какие-то действия с этими значениями из переменных, хранящихся на host1.

Я пробовал с hostvars:

{{ hostvars.LBL.db.stdout }}
{{ hostvars['LBL']['db'] }}
{{ hostvars['LBL']['db']['stdout'] }}

и я получаю ошибку:

in get_variables raise Exception("host not found: %s" % hostname) Exception: host not found: LBL

LBL существует в hosts, так как на нем я запускаю первую роль

Я устанавливаю переменную на одном хосте и хочу, чтобы эта переменная была доступна для другого хоста. Все это в рамках единого сценария. Это можно сделать?

hostvars не работает, используя его вот так:

---   
- name: test hostvars host1
  hosts: LBL
  tasks:
    - command: "ls /bin"
        register: ls_out

- name: test hostvars host2
  hosts: LM
  tasks:
    - debug:
        var: "{{ hostvars['LBL']['ls_out']['stdout'] }}"

ошибка:

fatal: [10.104.148.138] => host not found: LBL

/ и т. д. / ansible / хосты

[root@NS1 ansible]# cat /etc/ansible/hosts
[LBL]
10.104.148.136
[LM]
10.104.148.138

person ady8531    schedule 31.03.2015    source источник
comment
Можете ли вы опубликовать часть playbook, которая устанавливает переменные var1 / 2? hostvars.LBL.* должно было сработать. Если переменные 1/2 определены в файле инвентаризации, опубликуйте и это.   -  person Kashyap    schedule 31.03.2015
comment
Это первая роль - name: bla bla shell: cd /ACE/conf && grep ^db.url local1.properties | awk -F/ '{print $4}' | awk -F? '{print $1}' register: db Если я использую и повторяю {{do.stdout}} в одной и той же роли, это отлично работает. Я не использую инвентарь. Во второй роли, если я делаю shell: echo "{{ hostvars['LBL']['db']['stdout'] }}", выдает ошибку   -  person ady8531    schedule 31.03.2015
comment
hostvars не работает, используя его вот так: это невозможно. Эти две задачи отлично подходят для меня и печатают ls_out, как и ожидалось. Написал неправильный код что ли ...? Пожалуйста, уточните, что не работает   -  person Kashyap    schedule 31.03.2015
comment
Я добавил результат этого единственного сценария в вопрос выше. Версия Ansible - 1.9.0.1 ... такой же вывод для 1.8.4   -  person ady8531    schedule 31.03.2015


Ответы (5)


Проблема в вашем инвентаре.

Это сообщение:

fatal: [10.104.148.138] => host not found: LBL

потому что LBL - это группа, а не хост. В группе LBL есть один хост: 10.104.148.136

Выполните одно из следующих действий:

1. Измените свой инвентарь (/etc/ansible/hosts) на:

LBL ansible_ssh_host=10.104.148.136
LM ansible_ssh_host=10.104.148.138

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

{{ hostvars['10.104.148.136']['db']['stdout'] }}

Опять же LBL - это группа, а не хост. Дополнительная информация.

person Kashyap    schedule 31.03.2015
comment
На самом деле я изменил файл hosts и добавил: [ow.hosts] LBL LM, и он работает. большое спасибо! - person ady8531; 31.03.2015
comment
можно ли использовать что-то подобное: with_items: "{{ hostvars['LBL']['db_*'] }}" для цикла? Пример: на хосте LBL я храню несколько переменных с именами: db_ace, db_abc и т. Д. Как я могу вызвать их в цикле с другого хоста? hostvars.LBL.db_ *? - person ady8531; 01.04.2015
comment
@ ady8531 ничего из моей головы .. проверьте, есть ли какой-нибудь фильтр Jinja2 для фильтрации списка .. Если он есть, вы можете отфильтровать hostvars['LBL'].keys(), назначить его какой-либо другой переменной, используя set_fact или в разделе vars: .. - person Kashyap; 01.04.2015

Это сложная тема, и в зависимости от того, что вы хотите, есть два разных ответа.

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

Пример:

---
- hosts: host1
- roles:
    - role1
    - role2

Цель: вы хотите получить доступ к некоторой переменной из role1 внутри role2.

Используйте set_fact модуль.

Внутренняя роль1:

name: save precious value
set_fact: 
  pantsu: shiroi

Внутренняя роль2:

name: Nozoki...
debug: msg="Color is {{ pantsu }}"

Доступ к статической переменной для одного хоста (или группы) другому

Пример:

[group_foo]
host1
host2
[group_bar]
host3
host4

group_vars / group_foo

important_value=bla-bla-ba

Цель: вы хотите использовать его в учебнике для группы 2.

Это сделать гораздо сложнее.

Внутри group_vars / group_bar

other_var: '{{hostvars[groups["group_foo"][0]].important_value}}'

Вы можете использовать другие индексы, кроме «0».

person George Shuklin    schedule 31.03.2015
comment
Первый пример - это базовая переменная для распределения значений, здесь она не применяется, потому что я использую два разных хоста. На первом хосте значения являются динамическими, как файл конфигурации, который всегда обновляется. После того, как я сохраню значения в переменных на этом первом хосте с первой ролью, я перехожу ко второму хосту, запускаю вторую роль и выполняю какие-то действия с этими значениями из переменных, хранящихся на первом хосте. Я устанавливаю переменную на одном хосте и хочу, чтобы эта переменная была доступна для другого хоста. Все это в рамках единого сценария. Обычно оба хоста находятся в одной группе. - person ady8531; 31.03.2015
comment
вы можете установить_fact в одной пьесе, а затем получить к нему доступ через hostvars: {{ hostvars['serv1']['saved_fact'] }} - person George Shuklin; 31.03.2015
comment
--- - name: test hostvars host1 hosts: LBL tasks: - shell: echo hostname register: ls_out - set_fact: ls_down='{{ ls_out.stdout }}' - name: test hostvars host2 hosts: LM tasks: - shell: echo {{ hostvars['LBL']['ls_down'] }} ошибка: fatal: [10.104.148.138] => host not found: LBL - person ady8531; 31.03.2015
comment
@ ady8531, вы неправильно используете set_fact. Он не использует нотацию foo = bar, он требует списка dicts. См. Примеры здесь: docs.ansible.com/set_fact_module.html. Вот рабочий пример для приведенного выше кода: gist.github.com/amarao/5ebe4d9c2fd04dfaf287 - person George Shuklin; 02.04.2015
comment
Спасибо за четкое предложение, как заглянуть в Широи Панцу. :П - person Taro Sato; 13.10.2017

Вот мое решение. Моя задача заключалась в синхронизации данных между двумя серверами, и я хотел передать имена серверов следующим образом: ansible-playbook sync.yaml -e "source = host1 destination = host2"

Вот основная инструкция:

---

- name: get_sync_facts
  hosts: "{{ source }}"
  roles:
    - set_sync_facts

- name: sync
  hosts: "{{ destination }}" 
  roles:
    - get_sync_facts
    - sync

Вот роль set_sync_facts:

---

- set_fact: src_media_dir='/some/dir/'
- set_fact: src_user='myuser'
- set_fact: src_host='1.1.1.1'
- set_fact: src_port=12345
- set_fact: src_db_user='dbuser'
- set_fact: src_db_password='something'
- set_fact: src_db_name='some_db'

(Я фактически получил некоторые из них из задач, а другие из переменных хоста, но вы поняли)

А вот роль get_sync_facts:

---

- set_fact: src_media_dir={{ hostvars[source]['src_media_dir'] }}
- set_fact: src_user={{ hostvars[source]['src_user'] }}
- set_fact: src_host={{ hostvars[source]['src_host'] }}
- set_fact: src_port={{ hostvars[source]['src_port'] }}
- set_fact: src_db_user={{ hostvars[source]['src_db_user'] }}
- set_fact: src_db_password={{ hostvars[source]['src_db_password'] }}
- set_fact: src_db_name={{ hostvars[source]['src_db_name'] }}

Вы могли бы обойтись без этого и просто ссылаться на hostvars прямо в ваших играх, но это казалось более простым в обслуживании, поскольку оно напрямую соответствует роли set_sync_facts.

person Andy Baker    schedule 15.08.2015
comment
По сути, мне нужно решить ту же проблему, однако ваше решение, похоже, мне не подходит. Я получаю: fatal: [1.2.3.4]: FAILED! => {"failed": true, "msg": "'ansible.vars.hostvars.HostVars object' has no attribute u'source'"} где источник - моя переменная (например, постановка). В моей первой пьесе я заканчиваю с set_fact: blah={{somvar}}, а во второй я начинаю с set_fact: blah={{hostvars[source][blah]}}. Что я делаю неправильно? - person seeafish; 09.07.2016
comment
Ах, я совершил ошибку, буквально передав staging hostvars. Выгрузил всю структуру hostvars и увидел, что она организована (очевидно) по фактическому имени хоста. Дает мне то, с чем можно поработать, однако мне, возможно, придется изменить группировку инвентаря, поскольку я не могу гарантировать, что staging[0], например, всегда будет релевантным веб-хостом (может быть узлом db). Как устроен ваш инвентарь, если вы не возражаете, если я спрошу? - person seeafish; 09.07.2016
comment
@seeafish Мой инвентарь полностью динамичен. Я вызываю скрипт Python, который возвращает все мои хосты, а затем делаю что-то вроде: ansible-playbook -i dynamic_inventory / get_hosts playbook.yaml -e group = $ {DESTINATION} $ {SOURCE} - person Andy Baker; 12.07.2016
comment
Спасибо. В итоге я реструктурировал свой статический инвентарь, чтобы разделить среду и роли и выбрать с помощью: children там, где это необходимо. Затем я делаю две дополнительные переменные -e source=[source_group] и -e target=[target_group], а затем устанавливаю хосты в playbook, например, как {{source}}-web. - person seeafish; 13.07.2016

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

Для использования этой «целевой» группа должна содержать только 1 имя хоста.

Хосты моего инвентаря:

[ansible_local]
localhost

[machine1]
machine1.domain.tld

upgrade_packages.yml

---
- hosts: '{{ target }}'
  sudo: yes
  tasks:
  - name: check for Debian system
    shell: /bin/false
    when: ansible_pkg_mgr != "apt"

  - name: full-upgrade all packages
    apt: update_cache=yes upgrade=full
    register: upgrade_result

- hosts: ansible_local
  tasks:
  - name: find out host from target
    shell: /bin/sed -n -e '/^\[{{ target }}\]$/,/^\[.*\]$/ { /^\[/d; /^$/d; p; }' {{ inventory_file }}
    register: target_inventory

  - name: Display all facts from target machine (change when to true if needed)
    debug: var=hostvars[target_inventory.stdout]
    when: false

  - name: Display upgrade result on ansible_local node
    debug: var=hostvars[target_inventory.stdout].upgrade_result.msg

Вызвать с помощью: ansible-playbook ./upgrade-packages.yml -e "target=machine1" -v

person Quoing    schedule 06.12.2015
comment
Используйте модуль fail: вместо / bin / false. - person Matthias Urlichs; 19.12.2017

У меня была аналогичная установка, где есть три хоста h1, h2, h3, и на каждом из них я хотел определить факт { "important_fact": "foo" } (и bar, и baz соответственно)

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

- set_fact:
    important_facts_list: "{{ hostvars | json('*.important_fact') }}"
  run_once: yes
  delegate_to: h1

important_facts_list будет содержать [ 'foo', 'bar', 'baz' ], и теперь вы можете перебирать их, используя with_items.

person Johannes Meixner    schedule 23.03.2018