使用 Ansible 在 Route 53 中列出超过 100 条记录
Listing more than 100 records in Route 53 using Ansible
我目前正在项目中使用 route53_facts 模块。我在一个托管区域中有 250 个记录集。我很难列出该区域中的所有记录集。 Route 53 API 通过一次 return 页面 最多 100 条记录 来工作。为了检索下一页,您必须将 NextRecordName 响应值传递给 route53_facts 模块的 start_record_name: 字段(非常简单)。
我遇到的具体问题是让 Ansible 执行此操作。大概有人会使用循环来做到这一点,例如在伪代码中:
start
get 100 records
do until response does not contain NextRecordName:
get 100 records (start_record_name=NextRecordName)
end
在 Ansible 中,我编写了以下任务来执行此操作:
- block:
- name: List record sets in a given hosted zone
route53_facts:
query: record_sets
hosted_zone_id: "/hostedzone/ZZZ1111112222"
max_items: 100
start_record_name: "{{ record_sets.NextRecordName | default(omit) }}"
register: record_sets
until: record_sets.NextRecordName is not defined
when: "'{{ hosted_zone['Name'] }}' == 'test.example.com.'"
...但是,这并没有按预期工作。它不是不断翻阅响应直到没有更多记录,而是重复 return 前 100 条记录 ("the first page")。
正如我从 Ansible 调试输出中看到的那样,start_record_name: 重复 null:
"attempts": 2,
"changed": false,
"invocation": {
"module_args": {
"aws_access_key": null,
"aws_secret_key": null,
"change_id": null,
"delegation_set_id": null,
"dns_name": null,
"ec2_url": null,
"health_check_id": null,
"health_check_method": "list",
"hosted_zone_id": "/hostedzone/ZZZ1111112222",
"hosted_zone_method": "list",
"max_items": "100",
"next_marker": null,
"profile": null,
"query": "record_sets",
"region": null,
"resource_id": null,
"security_token": null,
"start_record_name": null,
"type": null,
"validate_certs": true
}
},
...我的猜测是 |默认(省略) 过滤器始终被执行。换句话说,record_sets.NextRecordName 从未在任务的此时初始化。
我希望有人可以帮助我让 Ansible return 来自 Route 53 中一个区域的所有记录。我想我已经被 Ansible 的循环行为所困扰。谢谢!
请注意 "as best I can tell:"
为了回答您的问题,until:
和 register:
的交互方式似乎与 when:
和 register:
的交互方式不同。我得到的最好的解释是 until:
的行为就像一个数据库事务:如果条件为假,它会回滚 register:
赋值,这意味着当再次尝试 until:
任务的主体时,它使用与第一次相同的参数。唯一使 until:
块不成为无限循环的是 retries:
值。
因此,在您的具体情况下,我认为这可以完成工作:
- name: initial record_set
route53_facts:
# bootstrap so the upcoming "when:" will evaluate correctly
register: record_facts
- set_fact:
# capture the initial answer
records0: '{{ record_facts.ResourceRecordSets }}'
- name: rest of them
route53_facts:
start_record_name: '{{ record_facts.NextRecordName }}'
register: record_facts
when: record_facts.NextRecordName | default("")
with_sequence: count=10
- set_fact:
all_records: >-
{{ record0 + (record_facts.results |
selectattr("ResourceRecordSets", "defined") |
map(attribute="ResourceRecordSets") | list) }}
with_sequence:
是一个 hack,因为 loop:
(with_*
是语法糖)需要一个要迭代的项目列表,但考虑到返回的响应没有 NextRecordName
将导致 when:
失败,跳过它们,使(在您的情况下)3 到 10 项几乎立即解决。
那么您只需要从现在 list
的 route53_facts:
回复中提取实际响应数据,并将它们粘贴到初始回复中以获得完整列表。
综上所述,我现在确信 route53_facts:
(以及将迭代负担推入剧本的任何其他 AWS 模块)行为是一个 bug.模块调用者已经有一个 max_items:
可供他们使用,但这是一个实现细节,即任何值都不能大于某个随机分页截止值。
我目前正在项目中使用 route53_facts 模块。我在一个托管区域中有 250 个记录集。我很难列出该区域中的所有记录集。 Route 53 API 通过一次 return 页面 最多 100 条记录 来工作。为了检索下一页,您必须将 NextRecordName 响应值传递给 route53_facts 模块的 start_record_name: 字段(非常简单)。
我遇到的具体问题是让 Ansible 执行此操作。大概有人会使用循环来做到这一点,例如在伪代码中:
start
get 100 records
do until response does not contain NextRecordName:
get 100 records (start_record_name=NextRecordName)
end
在 Ansible 中,我编写了以下任务来执行此操作:
- block:
- name: List record sets in a given hosted zone
route53_facts:
query: record_sets
hosted_zone_id: "/hostedzone/ZZZ1111112222"
max_items: 100
start_record_name: "{{ record_sets.NextRecordName | default(omit) }}"
register: record_sets
until: record_sets.NextRecordName is not defined
when: "'{{ hosted_zone['Name'] }}' == 'test.example.com.'"
...但是,这并没有按预期工作。它不是不断翻阅响应直到没有更多记录,而是重复 return 前 100 条记录 ("the first page")。
正如我从 Ansible 调试输出中看到的那样,start_record_name: 重复 null:
"attempts": 2,
"changed": false,
"invocation": {
"module_args": {
"aws_access_key": null,
"aws_secret_key": null,
"change_id": null,
"delegation_set_id": null,
"dns_name": null,
"ec2_url": null,
"health_check_id": null,
"health_check_method": "list",
"hosted_zone_id": "/hostedzone/ZZZ1111112222",
"hosted_zone_method": "list",
"max_items": "100",
"next_marker": null,
"profile": null,
"query": "record_sets",
"region": null,
"resource_id": null,
"security_token": null,
"start_record_name": null,
"type": null,
"validate_certs": true
}
},
...我的猜测是 |默认(省略) 过滤器始终被执行。换句话说,record_sets.NextRecordName 从未在任务的此时初始化。
我希望有人可以帮助我让 Ansible return 来自 Route 53 中一个区域的所有记录。我想我已经被 Ansible 的循环行为所困扰。谢谢!
请注意 "as best I can tell:"
为了回答您的问题,until:
和 register:
的交互方式似乎与 when:
和 register:
的交互方式不同。我得到的最好的解释是 until:
的行为就像一个数据库事务:如果条件为假,它会回滚 register:
赋值,这意味着当再次尝试 until:
任务的主体时,它使用与第一次相同的参数。唯一使 until:
块不成为无限循环的是 retries:
值。
因此,在您的具体情况下,我认为这可以完成工作:
- name: initial record_set
route53_facts:
# bootstrap so the upcoming "when:" will evaluate correctly
register: record_facts
- set_fact:
# capture the initial answer
records0: '{{ record_facts.ResourceRecordSets }}'
- name: rest of them
route53_facts:
start_record_name: '{{ record_facts.NextRecordName }}'
register: record_facts
when: record_facts.NextRecordName | default("")
with_sequence: count=10
- set_fact:
all_records: >-
{{ record0 + (record_facts.results |
selectattr("ResourceRecordSets", "defined") |
map(attribute="ResourceRecordSets") | list) }}
with_sequence:
是一个 hack,因为 loop:
(with_*
是语法糖)需要一个要迭代的项目列表,但考虑到返回的响应没有 NextRecordName
将导致 when:
失败,跳过它们,使(在您的情况下)3 到 10 项几乎立即解决。
那么您只需要从现在 list
的 route53_facts:
回复中提取实际响应数据,并将它们粘贴到初始回复中以获得完整列表。
综上所述,我现在确信 route53_facts:
(以及将迭代负担推入剧本的任何其他 AWS 模块)行为是一个 bug.模块调用者已经有一个 max_items:
可供他们使用,但这是一个实现细节,即任何值都不能大于某个随机分页截止值。