在剧集之间共享 ansible 变量

在剧集之间共享 ansible 变量

这是这个问题

我有一个剧本,它配置了一堆 EC2 实例。根据需要,值为hostslocalhost因为运行时没有主机),并且剧本会组装一个名为 的新主机列表ec2hosts,并生成主机 ip 到主机名的映射因为这是第一次也是唯一一次公开信息,并使用 保存它set_fact。然后,此主机列表将成为后续游戏的主题。问题是,我需要hostname_map在第二个游戏中使用在配置游戏中创建的字典,但我不知道该怎么做。

以下是第一场比赛:

- 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"
}

通过阅读 ansible 文档中关于变量范围的内容,它指出,除非将 play 中定义的变量应用于同一组主机,否则该变量在该 play 之外不可用。在这种情况下,这是不可能的,所以我需要使用具有全局范围的 var,从我所读的内容来看,这set_fact是适当的方法。因此,我在 中创建了一个空变量/group_vars/all,以便所有 play 都可以访问该变量:

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 实例并为它们分配从静态列表中获取的主机名。

答案1

您设置的值set_fact将在不同的游戏中可用。请记住 set_fact 是为特定主机设置. 你的第一场比赛是本地主机因此事实是 localhosts 变量的一部分。因此,在下一个游戏中,您应该能够使用类似这样的任务来访问它。

- debug:
    var: hostvars['localhost']['hostmap']

答案2

你可以使用虚拟主机它将存储您想要共享的所有变量添加主机.然后只需使用主机变量

- hosts: "18.184.109.70"
  user: ubuntu
  tasks:
    - name: set a variable
      set_fact:
        shared_variable: "Some value"
    - name: add variables to dummy host
      add_host:
        name: "variable_holder"
        shared_variable:  "{{ shared_variable }}"

- hosts: "18.196.135.59"
  user: ubuntu
  vars:
    shared_variable: "{{ hostvars['variable_holder']['shared_variable'] }}"
  tasks:
    - debug:
        msg: "{{ shared_variable }}"

答案3

取决于你如何定义 play。如果你在一次 ansible 运行中有多个 play,它就可以工作。但是,它不适用于多个连续的 play。我的意思是,当你运行 ansible-playbook playbook1.yml,然后运行 ​​ansible-playbook playbook2.yml 时,它不起作用

相关内容