如何在Ansible中循环调用NetBox API查询各前缀的可用IP?
解决Ansible循环查询NetBox前缀可用IP的问题
问题场景
编写Ansible Playbook时,需先查询NetBox中符合条件的子前缀ID,再逐个用这些ID调用NetBox API查询对应前缀的可用IP(该功能未包含在netbox.netbox模块中)。已通过nb_lookup获取到前缀ID列表,但直接将整个列表传入API URL导致格式错误,无法完成逐个查询。
原Playbook代码
--- - name: NetBox hosts: localhost connection: local gather_facts: no collections: - netbox.netbox tasks: - name: "Get Prefixes" set_fact: prefixes: "{{ query('netbox.netbox.nb_lookup', 'prefixes', api_endpoint='https://url-from-my-nb', api_filter='role=valid status=active', validate_certs=False, token='myToken') }}" - name: Teste debug: msg: "{{ prefixes | json_query('[*].value.id') }}" - name: Teste 2 uri: validate_certs: False url: "https://url-from-my-nb/api/ipam/prefixes/{{ prefixes | json_query('[*].value.id') }}/available-ips/" headers: Authorization: "Token myToken" register: prefix until: prefix - name: Teste debug: msg: "{{ prefix.json[0].address }}"
错误执行结果
PLAY [NetBox] ********************************************************************************************************************************************************************************* TASK [Get Prefixes] ******************************************************************************************************************************************************************************************* /usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py:1045: InsecureRequestWarning: Unverified HTTPS request is being made to host 'url-from-my-nb'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings warnings.warn( ok: [localhost] TASK [Teste] ************************************************************************************************************************************************************************************************** ok: [localhost] => { "msg": [ 2, 4, 5, 6, 11, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 51, 52, 28 ] } TASK [Teste 2] ************************************************************************************************************************************************************************************************ An exception occurred during task execution. To see the full traceback, use -vvv. The error was: http.client.InvalidURL: URL can't contain control characters. '/api/ipam/prefixes/[2, 4, 5, 6, 11, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 51, 52, 28]/available-ips/' (found at least ' ') fatal: [localhost]: FAILED! => {"attempts": 1, "changed": false, "elapsed": 0, "msg": "Status code was -1 and not [200]: An unknown error occurred: URL can't contain control characters. '/api/ipam/prefixes/[2, 4, 5, 6, 11, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 51, 52, 28]/available-ips/' (found at least ' ')", "redirected": false, "status": -1, "url": "https://ipam.getcard.com.br/api/ipam/prefixes/[2, 4, 5, 6, 11, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 51, 52, 28]/available-ips/"} PLAY RECAP **************************************************************************************************************************************************************************************************** localhost : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
解决方案
核心是使用Ansible的loop指令遍历每个前缀ID,逐个发起API请求,同时添加容错和结果过滤逻辑。
修正后的Playbook代码
--- - name: NetBox hosts: localhost connection: local gather_facts: no collections: - netbox.netbox tasks: - name: "Get Prefixes" set_fact: prefixes: "{{ query('netbox.netbox.nb_lookup', 'prefixes', api_endpoint='https://url-from-my-nb', api_filter='role=valid status=active', validate_certs=False, token='myToken') }}" - name: "Extract prefix IDs" set_fact: prefix_ids: "{{ prefixes | json_query('[*].value.id') }}" - name: "Query available IPs for each prefix" uri: validate_certs: False url: "https://url-from-my-nb/api/ipam/prefixes/{{ item }}/available-ips/" headers: Authorization: "Token myToken" register: prefix_available_ips loop: "{{ prefix_ids }}" # 忽略无可用IP的情况,避免任务失败 failed_when: false changed_when: false - name: "Display available IPs" debug: msg: "Prefix ID {{ item.item }} has available IP: {{ item.json[0].address }}" loop: "{{ prefix_available_ips.results }}" # 只输出有可用IP的有效结果 when: item.status == 200 and item.json | length > 0
关键修改说明
- 单独提取ID列表:新增
Extract prefix IDs任务,将前缀ID单独存入prefix_ids变量,简化后续循环逻辑。 - 循环遍历每个ID:在
uri任务中添加loop: "{{ prefix_ids }}",让每个ID单独传入API URL,解决列表格式导致的URL错误。 - 容错处理:通过
failed_when: false和changed_when: false,避免因单个前缀无可用IP导致整个任务失败。 - 过滤有效结果:在debug任务中通过
when条件,只输出HTTP状态码为200且返回IP列表非空的结果,减少无效输出。
内容的提问来源于stack exchange,提问作者Renan Delfino
相关产品推荐
相关产品推荐

