设为首页 收藏本站
查看: 1382|回复: 0

[经验分享] Ansible Playbook 循环

[复制链接]

尚未签到

发表于 2018-1-2 11:33:28 | 显示全部楼层 |阅读模式
Standard Loops
  为了节省一些打字,重复的任务可以写成如下:
  

- name: add several users  user:
  name: "{{ item }}"
  state: present
  groups: "wheel"
  with_items:
  - testuser1
  - testuser2
  如果您在变量文件或“vars”部分中定义了YAML列表,则还可以执行以下操作:
  

with_items: "{{ somelist }}"  相当于
  

- name: add user testuser1  user:
  name: "testuser1"
  state: present
  groups: "wheel"
  
- name: add user testuser2
  user:
  name: "testuser2"
  state: present
  groups: "wheel"
  yum和apt模块使用with_item来执行较少的包管理器事务。
  请注意,使用“with_items”迭代的项目类型不必是简单的字符串列表。 如果你有一个哈希列表,你可以使用以下的东西来引用子项:
  

- name: add several users  user:
  name: "{{ item.name }}"
  state: present
  groups: "{{ item.groups }}"
  with_items:
  - { name: 'testuser1', groups: 'wheel' }
  - { name: 'testuser2', groups: 'root' }
  还要注意,当与with_items (或任何其他循环语句)组合时 ,对每个项目单独处理when语句。 请参阅When语句为例。
  

  循环实际上是with_ + lookup()的组合,所以任何查找插件都可以用作循环的源,'items'是查找。

Nested Loops(嵌套循环)
  

- name: give users access to multiple databases  mysql_user:
  name: "{{ item[0] }}"
  priv: "{{ item[1] }}.*:ALL"
  append_privs: yes
  password: "foo"
  with_nested:
  - [ 'alice', 'bob' ]
  - [ 'clientdb', 'employeedb', 'providerdb' ]
  与上述'with_items'一样,您可以使用以前定义的变量:
  

- name: here, 'users' contains the above list of employees  mysql_user:
  name: "{{ item[0] }}"
  priv: "{{ item[1] }}.*:ALL"
  append_privs: yes
  password: "foo"
  with_nested:
  - "{{ users }}"
  - [ 'clientdb', 'employeedb', 'providerdb' ]
  

Looping over Hashes
  1.5版新功能
  假设你有以下变量:
  

---  
users:
  alice:
  name: Alice Appleworth
  telephone: 123-456-7890
  bob:
  name: Bob Bananarama
  telephone: 987-654-3210
  

并且您想打印每个用户的名字和电话号码。 您可以使用with_dict循环遍历哈希的元素,如下所示:  

tasks:  - name: Print phone records
  debug:
  msg: "User {{ item.key }} is {{ item.value.name }} ({{ item.value.telephone }})"
  with_dict: "{{ users }}"
  

Looping over Files
  with_file遍历文件列表的内容, 项目将按顺序设置为每个文件的内容。 它可以像这样使用:
  

---  
- hosts: all
  

  tasks:
  

  # emit a debug message containing the content of each file.
  - debug:
  msg: "{{ item }}"
  with_file:
  - first_example_file
  - second_example_file
  假设first_example_file包含文本“hello”,而second_example_file包含文本“world”,这将导致:
  

TASK [debug msg={{ item }}] ******************************************************  
ok: [localhost] => (item=hello) => {
  
    "item": "hello",
  
    "msg": "hello"
  
}
  
ok: [localhost] => (item=world) => {
  
    "item": "world",
  
    "msg": "world"
  
}
  

Looping over Fileglobs
  with_fileglob匹配单个目录中的所有文件,非递归地匹配模式。 它调用Python的glob库 ,可以这样使用:
  

---  
- hosts: all
  

  tasks:
  

  # first ensure our target directory exists
  - name: Ensure target directory exists
  file:
  dest: "/etc/fooapp"
  state: directory
  

  # copy each file over that matches the given pattern
  - name: Copy each file over that matches the given pattern
  copy:
  src: "{{ item }}"
  dest: "/etc/fooapp/"
  owner: "root"
  mode: 0600
  with_fileglob:
  - "/playbooks/files/fooapp/*"
  

Looping over Parallel Sets of Data
  假设你有以下变量数据被加载到某处:
  

---  
alpha: [ 'a', 'b', 'c', 'd' ]
  
numbers:  [ 1, 2, 3, 4 ]
  你想要一套“(a,1)”和“(b,2)”等等。 使用'with_together'得到这个:
  

tasks:  - debug:
  msg: "{{ item.0 }} and {{ item.1 }}"
  with_together:
  - "{{ alpha }}"
  - "{{ numbers }}"
  

Looping over Subelements
  假设你想做一些像循环遍历用户列表,创建它们,并允许他们通过一组SSH密钥登录。
  怎么可能实现? 假设你有以下定义并通过“vars_files”或“group_vars / all”文件加载:
  

---  
users:
  - name: alice
  authorized:
  - /tmp/alice/onekey.pub
  - /tmp/alice/twokey.pub
  mysql:
  password: mysql-password
  hosts:
  - "%"
  - "127.0.0.1"
  - "::1"
  - "localhost"
  privs:
  - "*.*:SELECT"
  - "DB1.*:ALL"
  - name: bob
  authorized:
  - /tmp/bob/id_rsa.pub
  mysql:
  password: other-mysql-password
  hosts:
  - "db1"
  privs:
  - "*.*:SELECT"
  - "DB2.*:ALL"
  可能会发生如此:
  

- name: Create User  user:
  name: "{{ item.name }}"
  state: present
  generate_ssh_key: yes
  with_items:
  - "{{ users }}"
  

  
- name: Set authorized ssh key
  authorized_key:
  user: "{{ item.0.name }}"
  key: "{{ lookup('file', item.1) }}"
  with_subelements:
  - "{{ users }}"
  - authorized
  给出mysql主机和privs子项列表,还可以遍历一个嵌套子项中的列表:
  

- name: Setup MySQL users  mysql_user:
  name: "{{ item.0.name }}"
  password: "{{ item.0.mysql.password }}"
  host: "{{ item.1 }}"
  priv: "{{ item.0.mysql.privs | join('/') }}"
  with_subelements:
  - "{{ users }}"
  - "{{ mysql.hosts }}"
  或者,您可以将第三个元素添加到子元素列表,该列表包含标志的字典。 目前您可以添加'skip_missing'标志。 如果设置为True,查找插件将跳过不包含给定子项的列表项。 没有这个标志,或者如果该标志设置为False,插件将产生一个错误,并抱怨丢失的子项。
  

  authorized_key模式正是它最多出现的地方。

Looping over Integer Sequences
  with_sequence生成一个项目序列。 您可以指定起始值,结束值,可选的“stride”值,该值指定增加序列的步数,以及可选的printf样式格式字符串。
  参数应指定为key = value对字符串。
  参数string的简单快捷方式也被接受: [start-]end[/stride][:format] 。
  数值可以十进制,十六进制(0x3f8)或八进制(0600)指定。 不支持负数。 这样做的工作如下:
  

---  
- hosts: all
  

  tasks:
  

  # create groups
  - group:
  name: "evens"
  state: present
  - group:
  name: "odds"
  state: present
  

  # create some test users
  - user:
  name: "{{ item }}"
  state: present
  groups: "evens"
  with_sequence: start=0 end=32 format=testuser%02x
  

  # create a series of directories with even numbers for some reason
  - file:
  dest: "/var/stuff/{{ item }}"
  state: directory
  with_sequence: start=4 end=16 stride=2
  

  # a simpler way to use the sequence plugin
  # create 4 groups
  - group:
  name: "group{{ item }}"
  state: present
  with_sequence: count=4
  

Random Choices
  

'random_choice'功能可以随机选择一些东西。 虽然它不是一个负载平衡器(有模块的那些),它可以有点被用作一个穷人的负载平衡器在MacGyver像情况:  

- debug:  msg: "{{ item }}"
  with_random_choice:
  - "go through the door"
  - "drink from the goblet"
  - "press the red button"
  - "do nothing"
  所提供的字符串之一将随机选择。
  

  在更基础的层面上,它们可以用来增加混乱和兴奋,以达到另外可预测的自动化环境。

Do-Until Loops
  版本1.4中的新功能。
  有时你想重试一个任务,直到满足一定的条件。 这里有一个例子:
  

- shell: /usr/bin/foo  register: result
  until: result.stdout.find("all systems go") != -1
  retries: 5
  delay: 10
  上述示例递归运行shell模块,直到模块的结果在其stdout中具有“所有系统”,或者任务已经重试了5次,延迟了10秒。  “重试”的默认值为3,“延迟”为5。
  

  任务返回最后一个任务运行返回的结果。 单独重试的结果可以通过-vv选项查看。 注册的变量还将有一个新的密钥“attempts”,它将具有任务的重试次数。

Finding First Matched Files
  这不是一个循环,但是很接近。 如果要根据与给定条件匹配的第一个文件使用对文件的引用,并且某些文件名由变量名称决定? 是的,你可以这样做:
  

- name: INTERFACES | Create Ansible header for /etc/network/interfaces  template:
  src: "{{ item }}"
  dest: "/etc/foo.conf"
  with_first_found:
  - "{{ ansible_virtualization_type }}_foo.conf"
  - "default_foo.conf"
  此工具还具有允许可配置搜索路径的长格式版本。 这里有一个例子:
  

- name: some configuration template  template:
  src: "{{ item }}"
  dest: "/etc/file.cfg"
  mode: 0444
  owner: "root"
  group: "root"
  with_first_found:
  - files:
  - "{{ inventory_hostname }}/etc/file.cfg"
  paths:
  - ../../../templates.overwrites
  - ../../../templates
  - files:
  - etc/file.cfg
  paths:
  - templates
  

Iterating Over The Results of a Program Execution
  有时你可能想执行一个程序,并根据该程序的输出,逐行循环结果。 尽管应该记住,这可以提供一个整洁的方式来实现,但这总是在控制机器上执行,而不是远程机器:
  

- name: Example of looping over a command result  shell: "/usr/bin/frobnicate {{ item }}"
  with_lines:
  - "/usr/bin/frobnications_per_host --param {{ inventory_hostname }}"
  好的,那有点随意 实际上,如果您正在做一些与库存相关的内容,您可能只想编写一个动态库存源代码(请参阅动态库存 ),但这对于快速和脏的实现可能会偶尔有用。
  

  如果您需要远程执行命令,则不能使用上述方法。 这样做:
  

- name: Example of looping over a REMOTE command result  shell: "/usr/bin/something"
  register: command_result
  

  
- name: Do something with each result
  shell: "/usr/bin/something_else --param {{ item }}"
  with_items:
  - "{{ command_result.stdout_lines }}"
  

Looping Over A List With An Index
  1.3版新功能
  如果你想循环一个数组,并且还可以在数组中获得数组的数字索引,你也可以这样做。 这是不常用的:
  

- name: indexed loop demo  debug:
  msg: "at array position {{ item.0 }} there is a value {{ item.1 }}"
  with_indexed_items:
  - "{{ some_list }}"
  

Using ini file with a loop
  2.0版新功能
  ini插件可以使用regexp来检索一组键。 因此,我们可以循环这个集合。 这是我们将使用的ini文件:
  

[section1]  
value1=section1/value1
  
value2=section1/value2
  

  
[section2]
  
value1=section2/value1
  
value2=section2/value2
  以下是使用with_ini的示例:
  

- debug:  msg: "{{ item }}"
  with_ini:
  - value[1-2]
  - section: section1
  - file: "lookup.ini"
  - re: true
  这里是返回的值:
  

{  "changed": false,
  "msg": "All items completed",
  "results": [
  {
  "invocation": {
  "module_args": "msg=\"section1/value1\"",
  "module_name": "debug"
  },
  "item": "section1/value1",
  "msg": "section1/value1",
  "verbose_always": true
  },
  {
  "invocation": {
  "module_args": "msg=\"section1/value2\"",
  "module_name": "debug"
  },
  "item": "section1/value2",
  "msg": "section1/value2",
  "verbose_always": true
  }
  ]
  }
  

Flattening A List(展开列表)
  在极少数情况下,您可能有几个列表列表,您只需要迭代所有列表中的每个项目。 假设一个真正疯狂的假设数据结构:
  

----  
# file: roles/foo/vars/main.yml
  
packages_base:
  - [ 'foo-package', 'bar-package' ]
  
packages_apps:
  - [ ['one-package', 'two-package' ]]
  - [ ['red-package'], ['blue-package']]
  您可以看到这些列表中的软件包的格式是完整的。 我们如何在两个列表中安装所有的包:
  

- name: flattened loop demo  yum:
  name: "{{ item }}"
  state: present
  with_flattened:
  - "{{ packages_base }}"
  - "{{ packages_apps }}"
  

Using register with a loop
  在使用register循环后,放置在变量中的数据结构将包含一个results属性,该属性是模块中所有响应的列表。
  以下是使用with_items register的with_items :
  

- shell: "echo {{ item }}"  with_items:
  - "one"
  - "two"
  register: echo
  这与使用没有循环的register时返回的数据结构不同:
  

{  "changed": true,
  "msg": "All items completed",
  "results": [
  {
  "changed": true,
  "cmd": "echo \"one\" ",
  "delta": "0:00:00.003110",
  "end": "2013-12-19 12:00:05.187153",
  "invocation": {
  "module_args": "echo \"one\"",
  "module_name": "shell"
  },
  "item": "one",
  "rc": 0,
  "start": "2013-12-19 12:00:05.184043",
  "stderr": "",
  "stdout": "one"
  },
  {
  "changed": true,
  "cmd": "echo \"two\" ",
  "delta": "0:00:00.002920",
  "end": "2013-12-19 12:00:05.245502",
  "invocation": {
  "module_args": "echo \"two\"",
  "module_name": "shell"
  },
  "item": "two",
  "rc": 0,
  "start": "2013-12-19 12:00:05.242582",
  "stderr": "",
  "stdout": "two"
  }
  ]
  
}
  对注册变量进行后续循环以检查结果可能如下所示:
  

- name: Fail if return code is not 0  fail:
  msg: "The command ({{ item.cmd }}) did not have a 0 return code"
  when: item.rc != 0
  with_items: "{{ echo.results }}"
  在迭代过程中,当前项目的结果将被放在变量中:
  

- shell: echo "{{ item }}"  with_items:
  - one
  - two
  register: echo
  changed_when: echo.stdout != "one"
  

Looping over the inventory
  如果您希望循环查看广告资源,或只是其中的一部分,则有多种方法。 可以使用常规的with_items与play_hosts或groups变量,如下所示:
  

# show all the hosts in the inventory  
- debug:
  msg: "{{ item }}"
  with_items:
  - "{{ groups['all'] }}"
  

  
# show all the hosts in the current play
  
- debug:
  msg: "{{ item }}"
  with_items:
  - "{{ play_hosts }}"
  还有一个特定的查找插件inventory_hostnames可以这样使用:
  

# show all the hosts in the inventory  
- debug:
  msg: "{{ item }}"
  with_inventory_hostnames:
  - all
  

  
# show all the hosts matching the pattern, ie all but the group www
  
- debug:
  msg: "{{ item }}"
  with_inventory_hostnames:
  - all:!www
  

Loop Control
  2.1版新功能
  在2.0中,您再次可以使用with_循环和任务包括(但不包括playbook)。 这增加了在一次镜像中循环该任务集的能力。 默认情况下可以设置每个循环的循环变量项 ,这会导致这些嵌套循环从“外部”循环覆盖项的值。 从Ansible 2.1开始, loop_control选项可用于指定要用于循环的变量的名称:
  

# main.yml  
- include: inner.yml
  with_items:
  - 1
  - 2
  - 3
  loop_control:
  loop_var: outer_item
  

  
# inner.yml
  
- debug:
  msg: "outer item={{ outer_item }} inner item={{ item }}"
  with_items:
  - a
  - b
  - c
  新版本2.2。
  

  当使用复杂的数据结构来循环显示可能会有点太忙,这就是C(label)指令来帮助的:
  

- name: create servers  digital_ocean:
  name: "{{ item.name }}"
  state: present
  with_items:
  - name: server1
  disks: 3gb
  ram: 15Gb
  network:
  nic01: 100Gb
  nic02: 10Gb
  ...
  loop_control:
  label: "{{item.name}}"
  现在,它将只显示“label”字段而不是每个“item”的整个结构,它默认为“{{item}}”'以照常显示。
  

  新版本2.2。
  循环控制的另一个选项是C(暂停),它允许您控制任务循环中项目执行之间的时间(以秒为单位):
  

# main.yml  
- name: create servers, pause 3s before creating next
  digital_ocean:
  name: "{{ item }}"
  state: present
  with_items:
  - server1
  - server2
  loop_control:
  pause: 3
  

Loops and Includes in 2.0
  因为loop_control在Ansible 2.0中不可用,当使用带循环的include时,应该使用set_fact来保存项的“outer”循环值:
  

# main.yml  
- include: inner.yml
  with_items:
  - 1
  - 2
  - 3
  

  
# inner.yml
  
- set_fact:
  outer_item: "{{ item }}"
  

  
- debug:
  msg: "outer item={{ outer_item }} inner item={{ item }}"
  with_items:
  - a
  - b
  - c
  

Writing Your Own Iterators
  虽然通常不需要,如果您希望编写自己的方法来循环任意数据结构,则可以阅读开发插件以获取一些启动器信息。 以上每个功能都实现为可插入的插件,因此有很多实现可供参考。
  

  

  

  

  

  

  

  

  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-430772-1-1.html 上篇帖子: Ansible 创建用户 Playbook 脚本 下篇帖子: ansible playbook
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表