从 Ansible 寄存器中选择特定数据

Selecting specific data from an Ansible register

我真的很感激能在 ansible 中正确 selecting 从寄存器中获取数据的帮助。 以下代码 almost 有效...:)

我这里创建一个AWS VPC,我在'vpc'注册信息。 然后我参考vpc。

  - name: Create VPC and Subnets
    ec2_vpc:
      state: present
      cidr_block: '{{ ip-range}}'
      resource_tags: { "Name": "{{ vpc_name }}" }
      region: '{{ region }}'
      subnets:
        - cidr: '{{ pub-subneta }}'
          az: '{{ region }}a'
          resource_tags: { "Name": "Public Subnet 1" }

        - cidr: '{{ pub-subnetb }}'
          az: '{{ region }}b'
          resource_tags: { "Name": "Public Subnet 2" }

        - cidr: '{{ priv-subnet1 }}'
          az: '{{ region }}a'
          resource_tags: { "Name": "Private Subnet 1" }

        - cidr: '{{ priv-subnet2 }}'
          az: '{{ region }}b'
          resource_tags: { "Name": "Private Subnet 2" }
      internet_gateway: True
    register: vpc

效果很好。它创建具有 4 个子网的 VPC。 然后我想在一个特定的子网中启动一个 NAT 实例,我试图通过如下指定子网来做到这一点:

- name: Create NAT instance
  ec2:
    state: present
    key_name: '{{ ssh_key_name }}'
    instance_type: '{{ nat_instance_type }}'
    image: '{{ nat_ami }}'
    region: '{{ region }}'
    wait: yes
    instance_tags:
      Name: "natsrv01"
      Description: "NAT Server"
    assign_public_ip: yes
    source_dest_check: false
    vpc_subnet_id: '{{ vpc.subnets[0].id }}'

这是它没有按预期工作的地方。 我假设寄存器将按照 defined/created 的顺序包含信息,但事实并非如此。

使用调试我可以看到这 4 个子网在寄存器中的顺序是随机的。例如在一次尝试中,"Public Subnet 2" 被 'vpc.subnets[0].id' 识别,而在另一次尝试中,"private Subnet 2" 是列表中的第一个。

有人可以建议我如何从寄存器可靠地重复 select "Public Subnet 1" 吗?

vpc寄存器的完整输出为:

 ok: [localhost] => {
 "vpc": {
     "changed": true,
     "invocation": {
         "module_args": "",
         "module_name": "ec2_vpc"
     },
     "subnets": [
         {
             "az": "eu-west-1b",
             "cidr": REDACTED,
             "id": "subnet-REDACTED",
             "resource_tags": {
                 "Name": "Private Subnet B"
             }
         },
         {
             "az": "eu-west-1c",
             "cidr": REDACTED,
             "id": "subnet-REDACTED",
             "resource_tags": {
                 "Name": "Private Subnet C"
             }
         },
         {
             "az": "eu-west-1a",
             "cidr": REDACTED,
             "id": "subnet-REDACTED",
             "resource_tags": {
                 "Name": "Public Subnet A"
             } 
         },
         {
             "az": "eu-west-1c",
             "cidr": REDACTED,
             "id": "subnet-REDACTED",
             "resource_tags": {
                 "Name": "Public Subnet C"
             }
         },
         {
             "az": "eu-west-1b",
             "cidr": REDACTED,
             "id": "subnet-REDACTED",
             "resource_tags": {
                 "Name": "Public Subnet B"
             }
         },
         {
             "az": "eu-west-1a",
             "cidr": REDACTED,
             "id": "subnet-REDACTED",
             "resource_tags": {
                 "Name": "Private Subnet A"
             }
         }
     ], 
     "vpc": {
         "cidr_block": "REDACTED",
         "dhcp_options_id": "dopt-53eb0f36",
         "id": "vpc-REDACTED",
         "region": "eu-west-1",
         "state": "pending"
     },
     "vpc_id": "vpc-REDACTED"
 }
}

类似这样的方法可能有效:

- name: Find the first public subnet
  set_fact: vpc_subnet_id="{{ item.id }}"
  when: item.resource_tags.Name == "Public Subnet 1"
  with_items: vpc.subnets

您也可以尝试如下编写子网过滤器:

vpc_subnet_id: "{{ vpc.subnets | subnet_name_filter() }}"

创建一个文件 /ansible_plugins/filter_plugins/core.py 用这个:

def subnet_name_filter(list):
  return [x for x in list if x.resource_tags.Name == "Public Subnet 1"]

class FilterModule(object):
  def filters(self):
    return {          
      'subnet_name_filter': subnet_name_filter
    }

编辑 ansible.cfg 和 uncomment the line 我们启用自定义 filter_plugins 的地方。该路径可以是相对的,ansible 将查找相对于 ansible.cfg 所在位置的插件。例如,我的 ansible.cfg 和所有插件都已签入我的 git 存储库。

编辑:

如果重构如下,您还可以删除自定义插件中的硬编码:

def subnet_name_filter(list, restagname):
  return [x for x in list if x.resource_tags.Name == restagname]

并使用

vpc_subnet_id: "{{ vpc.subnets | subnet_name_filter('Public Subnet 1') }}"