如何使用带有序列和列表的嵌套循环以及如何在 Ansible 中绕过大括号
How to use nested loops with sequence and a list and how get around of curly braces in Ansible
我有一个使用 ios_config 模块备份配置的代码。我使用 ios_facts 来获取设备的主机名,我想用它来将备份文件放在一个类似命名的文件夹中,并在文件名本身中使用它。
在我的代码的最后一个任务中,我需要遍历两个项目 - 从 0 到 1 的序列(或者我的库存中有多少项目),因为我需要访问结果中的主机名并使用它在备份选项中,还循环浏览我从 csv 文件中提取的设备清单。我知道双花括号的规则,但我不知道如何绕过它。
---
- hosts: localhost
gather_facts: false
tasks:
- name: Block
block:
- name: Use CSV
csv_to_facts:
src: '{{playbook_dir}}/NEW/Inventory.csv'
vsheets:
- INFO:
- IP
- OS
- debug:
msg: '{{item.IP}}'
loop: '{{INFO}}'
- name: Create Inventory
add_host:
hostname: '{{item.IP}}'
ansible_network_os: '{{item.OS}}'
ansible_user: cisco
ansible_ssh_pass: cisco
ansible_connection: network_cli
ansible_become: yes
ansible_become_method: enable
groups: group_01
loop: '{{INFO}}'
- name: Gather Facts (IOS)
ios_facts:
register: ios_facts_loop
delegate_to: '{{item}}'
loop: "{{groups['group_01']}}"
- name: Backup Switch (IOS)
ios_config:
backup: yes
backup_options:
dir_path: "tmp/backups/{{ ios_facts_loop.results.{{item[0]}}.ansible_facts.ansible_net_hostname }}"
filename: "{{ios_facts_loop.results.item{{[0]}}.ansible_facts.ansible_net_hostname}} {{ lookup('pipe','date +%Y-%m-%d@%H:%M:%S')}}"
register: backup_ios_location
delegate_to: '{{item[1]}}'
loop:
- with_sequence: "0-{{output|length - 3}}"
- "{{groups['group_01']}}"
TLDR;对于 vars 符号
您不能像上面的代码那样在双花括号内添加双花括号。您当前的 var 参考:
ios_facts_loop.results.{{item[0]}}.ansible_facts.ansible_net_hostname
应该转为
ios_facts_loop.results[item[0]].ansible_facts.ansible_net_hostname
# or equivalent
ios_facts_loop.results[item.0].ansible_facts.ansible_net_hostname
同时,这只会修复您当前的语法错误(您没有在问题中分享),因为循环中的第一个元素是字符串 'with_sequence: "0-X"'
,因此没有索引 0。
尝试修复逻辑
如果我理解正确,对于你的最后一个任务,你只需要遍历你的 ios_facts
注册的结果并将任务委托给从中获取它的服务器。幸运的是,您应该已经在 ios_facts_loop.results
中获得了所需的所有信息
- 这是一个列表,所以你可以直接遍历它
- 每个元素都应包含一个
item
键,其中包含在注册时在前一个 运行 中使用的实际项目(即您的 groups['group_01']
元素之一)。
所以我会尝试像这样写你的最后一个任务。 免责声明这纯属猜测,因为我没有看到您的确切数据结构。
- name: Backup Switch (IOS)
ios_config:
backup: yes
backup_options:
dir_path: "tmp/backups/{{ item.ansible_facts.ansible_net_hostname }}"
filename: "{{ item.ansible_facts.ansible_net_hostname}}{{ lookup('pipe','date +%Y-%m-%d@%H:%M:%S')}}"
register: backup_ios_location
delegate_to: '{{item.item}}'
loop: "{{ ios_facts_loop.results }}"
更进一步。
我不是很熟悉 ios_*
模块,但它们应该非常接近我日常使用的其他东西,我认为你可以利用更多的 ansible 功能(例如多重播放)来真正简化你的剧本在剧本中)。我相信以下内容实际上应该可以完成这项工作:
---
- name: Construct inventory from CSV
hosts: localhost
gather_facts: false
tasks:
- name: Use CSV
csv_to_facts:
src: '{{playbook_dir}}/NEW/Inventory.csv'
vsheets:
- INFO:
- IP
- OS
- name: Create Inventory
add_host:
hostname: '{{item.IP}}'
ansible_network_os: '{{item.OS}}'
ansible_user: cisco
ansible_ssh_pass: cisco
ansible_connection: network_cli
ansible_become: yes
ansible_become_method: enable
groups: group_01
loop: '{{INFO}}'
- name: Backup switches from created inventory
hosts: group_01
gather_facts: false
tasks:
- name: Get facts from network os
ios_facts:
gather_subset: all
- name: Backup Switch (IOS)
ios_config:
backup: yes
backup_options:
dir_path: "tmp/backups/{{ ansible_net_hostname }}"
filename: "{{ ansible_net_hostname }}{{ lookup('pipe','date +%Y-%m-%d@%H:%M:%S') }}"
有关变量的点和括号表示法的更多背景知识
您基本上可以使用两个等效的符号来导航 yaml 数据结构。
- 点符号
a_list_var.index_number
a_hasmap_var.keyname
- 括号表示法
a_list_var[index_number]
a_hashmap_var['key_name']
如果我们举下面的例子:
my_servers:
hostA:
ips:
- x.x.x.x
- y.y.y.y
env:
shell: bash
home: somewhere
hostB:
ips:
- a.a.a.a
- b.b.b.b
env:
shell: sh
home: elsewhere
以下符号都是严格等价的:
# all vars of hostA
hostA_vars: "{{ my_servers.hostA }}"
hostA_vars: "{{ my_server['hostA'] }}"
# first IP of hostB
hostB_ip: "{{ my_servers.hostB.0 }}"
hostB_ip: "{{ my_servers.hostB[0] }}"
hostB_ip: "{{ my_servers['hostB'].0 }}"
hostB_ip: "{{ my_servers['hostB'][0] }}"
如您所见,点符号往往不那么冗长且更易读。同时,您不能使用带点符号的变量标识符。因此,如果你想使用可变服务器的主环境,你将不得不使用:
# set a var for server
server: hostA
# all equivalent again
server_home: "{{ my_servers[server].env.home }}"
server_home: "{{ my_servers[server]['env'].home }}"
server_home: "{{ my_servers[server].env['home'] }}"
server_home: "{{ my_servers[server]['env']['home'] }}"
我有一个使用 ios_config 模块备份配置的代码。我使用 ios_facts 来获取设备的主机名,我想用它来将备份文件放在一个类似命名的文件夹中,并在文件名本身中使用它。
在我的代码的最后一个任务中,我需要遍历两个项目 - 从 0 到 1 的序列(或者我的库存中有多少项目),因为我需要访问结果中的主机名并使用它在备份选项中,还循环浏览我从 csv 文件中提取的设备清单。我知道双花括号的规则,但我不知道如何绕过它。
---
- hosts: localhost
gather_facts: false
tasks:
- name: Block
block:
- name: Use CSV
csv_to_facts:
src: '{{playbook_dir}}/NEW/Inventory.csv'
vsheets:
- INFO:
- IP
- OS
- debug:
msg: '{{item.IP}}'
loop: '{{INFO}}'
- name: Create Inventory
add_host:
hostname: '{{item.IP}}'
ansible_network_os: '{{item.OS}}'
ansible_user: cisco
ansible_ssh_pass: cisco
ansible_connection: network_cli
ansible_become: yes
ansible_become_method: enable
groups: group_01
loop: '{{INFO}}'
- name: Gather Facts (IOS)
ios_facts:
register: ios_facts_loop
delegate_to: '{{item}}'
loop: "{{groups['group_01']}}"
- name: Backup Switch (IOS)
ios_config:
backup: yes
backup_options:
dir_path: "tmp/backups/{{ ios_facts_loop.results.{{item[0]}}.ansible_facts.ansible_net_hostname }}"
filename: "{{ios_facts_loop.results.item{{[0]}}.ansible_facts.ansible_net_hostname}} {{ lookup('pipe','date +%Y-%m-%d@%H:%M:%S')}}"
register: backup_ios_location
delegate_to: '{{item[1]}}'
loop:
- with_sequence: "0-{{output|length - 3}}"
- "{{groups['group_01']}}"
TLDR;对于 vars 符号
您不能像上面的代码那样在双花括号内添加双花括号。您当前的 var 参考:
ios_facts_loop.results.{{item[0]}}.ansible_facts.ansible_net_hostname
应该转为
ios_facts_loop.results[item[0]].ansible_facts.ansible_net_hostname
# or equivalent
ios_facts_loop.results[item.0].ansible_facts.ansible_net_hostname
同时,这只会修复您当前的语法错误(您没有在问题中分享),因为循环中的第一个元素是字符串 'with_sequence: "0-X"'
,因此没有索引 0。
尝试修复逻辑
如果我理解正确,对于你的最后一个任务,你只需要遍历你的 ios_facts
注册的结果并将任务委托给从中获取它的服务器。幸运的是,您应该已经在 ios_facts_loop.results
- 这是一个列表,所以你可以直接遍历它
- 每个元素都应包含一个
item
键,其中包含在注册时在前一个 运行 中使用的实际项目(即您的groups['group_01']
元素之一)。
所以我会尝试像这样写你的最后一个任务。 免责声明这纯属猜测,因为我没有看到您的确切数据结构。
- name: Backup Switch (IOS)
ios_config:
backup: yes
backup_options:
dir_path: "tmp/backups/{{ item.ansible_facts.ansible_net_hostname }}"
filename: "{{ item.ansible_facts.ansible_net_hostname}}{{ lookup('pipe','date +%Y-%m-%d@%H:%M:%S')}}"
register: backup_ios_location
delegate_to: '{{item.item}}'
loop: "{{ ios_facts_loop.results }}"
更进一步。
我不是很熟悉 ios_*
模块,但它们应该非常接近我日常使用的其他东西,我认为你可以利用更多的 ansible 功能(例如多重播放)来真正简化你的剧本在剧本中)。我相信以下内容实际上应该可以完成这项工作:
---
- name: Construct inventory from CSV
hosts: localhost
gather_facts: false
tasks:
- name: Use CSV
csv_to_facts:
src: '{{playbook_dir}}/NEW/Inventory.csv'
vsheets:
- INFO:
- IP
- OS
- name: Create Inventory
add_host:
hostname: '{{item.IP}}'
ansible_network_os: '{{item.OS}}'
ansible_user: cisco
ansible_ssh_pass: cisco
ansible_connection: network_cli
ansible_become: yes
ansible_become_method: enable
groups: group_01
loop: '{{INFO}}'
- name: Backup switches from created inventory
hosts: group_01
gather_facts: false
tasks:
- name: Get facts from network os
ios_facts:
gather_subset: all
- name: Backup Switch (IOS)
ios_config:
backup: yes
backup_options:
dir_path: "tmp/backups/{{ ansible_net_hostname }}"
filename: "{{ ansible_net_hostname }}{{ lookup('pipe','date +%Y-%m-%d@%H:%M:%S') }}"
有关变量的点和括号表示法的更多背景知识
您基本上可以使用两个等效的符号来导航 yaml 数据结构。
- 点符号
a_list_var.index_number
a_hasmap_var.keyname
- 括号表示法
a_list_var[index_number]
a_hashmap_var['key_name']
如果我们举下面的例子:
my_servers:
hostA:
ips:
- x.x.x.x
- y.y.y.y
env:
shell: bash
home: somewhere
hostB:
ips:
- a.a.a.a
- b.b.b.b
env:
shell: sh
home: elsewhere
以下符号都是严格等价的:
# all vars of hostA
hostA_vars: "{{ my_servers.hostA }}"
hostA_vars: "{{ my_server['hostA'] }}"
# first IP of hostB
hostB_ip: "{{ my_servers.hostB.0 }}"
hostB_ip: "{{ my_servers.hostB[0] }}"
hostB_ip: "{{ my_servers['hostB'].0 }}"
hostB_ip: "{{ my_servers['hostB'][0] }}"
如您所见,点符号往往不那么冗长且更易读。同时,您不能使用带点符号的变量标识符。因此,如果你想使用可变服务器的主环境,你将不得不使用:
# set a var for server
server: hostA
# all equivalent again
server_home: "{{ my_servers[server].env.home }}"
server_home: "{{ my_servers[server]['env'].home }}"
server_home: "{{ my_servers[server].env['home'] }}"
server_home: "{{ my_servers[server]['env']['home'] }}"