Выбор конкретных данных из регистра Ansible

Буду очень признателен за помощь в правильном выборе данных из регистра в ansible. Следующий код почти работает...:)

Я создаю 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

Это хорошо работает. Создает VPC с 4 подсетями. Затем я хочу запустить экземпляр 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 }}'

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

Используя отладку, я вижу, что 4 подсети расположены в случайном порядке в регистре. например, с одной попытки "Public Subnet 2" была идентифицирована "vpc.subnets[0].id", а с другой попытки "private Subnet 2" была первой в списке.

Может кто-нибудь подсказать, как я могу надежно и многократно выбрать "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"
 }
}

2 ответа

Решение

Нечто подобное может работать:

- 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 и раскомментируйте строку, в которой мы включаем пользовательские 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') }}"
Другие вопросы по тегам