Назад | Перейти на главную страницу

Совместное использование доступной переменной между пьесами

Это продолжение этот вопрос.

У меня есть игра, которая предоставляет кучу инстансов 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