Это продолжение этот вопрос.
У меня есть игра, которая предоставляет кучу инстансов EC2. По необходимости hosts
ценность localhost
(потому что при запуске нет хостов), и игра собирает новый список хостов, называемый ec2hosts
, и генерирует IP-адрес хоста для карты имени хоста потому что это первый и единственный раз, когда информация становится доступной, и сохраняет его, используя set_fact
. Этот список хозяев затем является предметом последующей игры. Проблема в том, что мне нужно использовать hostname_map
dict, созданный во время подготовки во втором воспроизведении, и я не вижу, как это сделать.
Вот первый спектакль:
- hosts: localhost
connection: local
gather_facts: False
tasks:
- name: Provision a set of instances
ec2:
key_name: marcus
instance_type: t2.micro
image: "{{ ami_id }}"
wait: true
exact_count: "{{ server_count }}"
count_tag:
Tutorial: "{{ tutorial_name }}"
instance_tags:
Tutorial: "{{ tutorial_name }}"
groups: ['SSH', 'Web']
register: ec2
- name: Add all instance public IPs to host group
add_host:
hostname: "{{ item.public_ip }}"
groups: ec2hosts
loop: "{{ ec2.instances }}"
- name: Build an IP to hostname map
set_fact:
hostname_map: "{{ hostname_map | combine({item.0.public_ip: (item.1 + '.' + tutorial_domain)}) }}"
loop: "{{ ec2.instances|zip(hostnames)|list }}"
- name: Debug hostname_map
debug:
msg: "{{ hostname_map }}"
В конце концов, hostname_map
содержит карту вроде:
{
"18.184.109.70": "host1.example.com",
"18.196.135.59": "host2.example.com"
}
Из чтения доступных документов по области переменных видно, что переменные, определенные в игре, недоступны вне этой игры, если они не применяются к тому же набору хостов. В данном случае это невозможно, поэтому мне нужно использовать var с глобальной областью видимости, и из того, что я прочитал, set_fact
- подходящий способ сделать это. Итак, я создал пустую переменную в /group_vars/all
, чтобы переменная была доступна для всех пьес:
hostname_map: {}
Следующая игра подключается к каждому вновь созданному экземпляру (с использованием списка хостов, который мы создали динамически) и устанавливает его имя хоста изнутри:
- hosts: ec2hosts
gather_facts: yes
tasks:
- name: Debug hostname_map
debug:
msg: "{{ hostname_map }}"
- name: Set hostnames
hostname:
name: "{{ hostname_map[ansible_host] }}"
Однако это не удается, потому что hostname_map
пусто
TASK [Debug hostname_map]
ok: [18.184.109.70] => {
"msg": {}
}
ok: [18.196.135.59] => {
"msg": {}
}
поэтому я получаю эту ошибку:
фатальный: [18.184.109.70]: НЕ ВЫПОЛНЕНО! => {"msg": "Задача включает параметр с неопределенной переменной. Ошибка была: 'dict object' не имеет атрибута u'18.184.109.70 '
Любопытно, что я получаю тот же результат отладки и ошибку даже если я не определяю переменную глобально.
В других статьях, которые я прочитал, предлагается, чтобы значения были явно перечислены в vars
, но я не могу этого сделать, потому что данные динамические и неизвестны до времени выполнения. Точно так же я не могу предоставить его, используя extra_vars
в командной строке по той же причине.
Как я могу сделать эту переменную доступной во второй игре? Я бы хотел избежать неуклюжих решений вроде записи локального файла и последующего чтения его обратно!
Я также открыт для предложений сделать это совершенно другим способом, где «это»: создать произвольное количество экземпляров EC2 и назначить им имена хостов, взятые из статического списка.
Значение, которое вы устанавливаете с помощью set_fact
будут доступны между разными пьесами. Имейте в виду, что set_fact - это набор для конкретного хоста. Ваша первая игра проводится против localhost поэтому факт является частью переменных localhosts. Итак, в следующей игре вы сможете получить к нему доступ с помощью такой задачи.
- debug:
var: hostvars['localhost']['hostmap']
Зависит от того, как вы определяете игру. Если у вас есть несколько игр с одним доступным запуском, это работает. Однако не работает с несколькими последовательными воспроизведениями. Я имею в виду, что это не работает, когда вы запускаете ansible-playbook playbook1.yml, а затем ansible-playbook playbook2.yml