一、ansible迭代(循環)
loop循環語句
在寫 playbook
的時候發現了很多 task 都要重復引用某個相同的模塊,比如一次啟動10個服務,或者一次拷貝10個文件,如果按照傳統的寫法最少要寫10次,這樣會使得 playbook
很臃腫。Ansible提供了兩個用於創建循環的關鍵字:loop和with_ (除了with_items,還有其他可用於循環的比如with_dict)
目前我們習慣於用loop替代with_*
格式:
- 對迭代項的引用,固定變量名為
"item"
; - 要在
task
中使用with_items
或loop
關鍵字給定要迭代的元素列表;
實操:
1、使用循環批量安裝軟件
方式1
cat loop.yml - hosts: web remote_user: root tasks: - name: Install Packages yum: name: "{{ item }}" state: present loop: - rsync - glances
有執行結果可知,glances安裝成功,rsync沒有改變是因為軟件已經安裝有了。
方式2:
cat loop1.yml - hosts: web remote_user: root vars: packages: - httpd - glances tasks: - name: Install Packages yum: name: "{{ packages }}" state: present
方式采用變量方方式,顯示上不如loop直觀
方式3:loop調用vars的變量
--- - hosts: web vars: test_name: - test1 - test2 - test3 tasks: - name: delete user user: name: "{{ item }}" state: present loop: "{{ test_name }}"
2、使用循環批量啟動服務
cat loop_service.yml - hosts: NginxWebs remote_user: root tasks: - name: Start Service service: name: "{{ item }}" state: started loop: - httpd - mariadb-server
3、使用循環批量創建用戶
注:此處將loop換成with_items也是一樣
- hosts: web tasks: - name: Create Groups group: name: "{{ item }}" state: present loop: - group1 - group2 - group3 - name: Create Users user: name: "{{ item.user }}" group: "{{ item.group }}" uid: "{{ item.uid }}" state: present create_home: yes loop: - { user: user1,group: group1, uid: 2001 } - { user: user2,group: group2, uid: 2002 } - { user: user3,group: group3, uid: 2003 }
4、使用循環批量拷貝文件
- hosts: web tasks: - name: Copy Configuer File template: src: "{{ item.src }}" dest: "{{ item.dest }}" owner: "{{ item.owner }}" group: "{{ item.group }}" mode: "{{ item.mode }}" loop: - { src: "/root/conf/nginx.conf.j2", dest: "/etc/nginx/nginx.conf", owner: "root", group: "root", mode: "0644" } - { src: "/root/conf/example.com.conf.j2", dest: "/etc/nginx/conf.d/example.con.conf", owner: "root", group: "root", mode: "0644" } - { src: "/root/file/index.html", dest: "/data/nginx/example/index.html", owner: "nginx", group: "nginx", mode: 0644 }
注意:應用template時用法和copy一致,但是此處dest目標路徑需要自己提前創建好、屬主(組)都要有
copy是這樣介紹的:
= dest Remote absolute path where the file should be copied to. If `src' is a directory, this must be a directory too. #如果 `src' 是一個目錄,dest也必須是一個目錄。 If `dest' is a non-existent path and if either `dest' ends with "/" or `src' is a directory, `dest' is created. #如果 `dest' 是不存在的路徑,並且如果 `dest' 以“/”結尾或 `src' 是目錄,則創建 `dest'。 If `dest' is a relative path, the starting directory is determined by the remote host. #如果“dest”是相對路徑,則起始目錄由遠程主機確定。 If `src' and `dest' are files, the parent directory of `dest' is not created and the task fails if it does not already exist. #如果 `src' 和 `dest' 是文件,則不創建 `dest' 的父目錄,如果不存在則任務失敗。 type: path
5、嵌套循環with_nested、with_cartesian
cat loop6.yml --- - hosts: web remote_user: root gather_facts: no tasks: - file: state: directory path: "/testdir/{{item.0}}/{{item.1}}" with_nested: - [ a, b, c ] - [ test1, test2 ]
效果
tree /testdir/ /testdir/ |-- a | |-- test1 | `-- test2 |-- b | |-- test1 | `-- test2 `-- c |-- test1 `-- test2 9 directories, 0 files
分別給用戶授予3個數據庫的所有權限
- 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' ]
6、對哈希表循環(key:value)
--- - hosts: web vars: users: alice: name: Alice Appleworth telephone: 123-456-7890 bob: name: Bob Bananarama telephone: 987-654-3210 tasks: - name: Print phone records debug: msg: "User {{ item.key }} is {{ item.value.name }} {{ item.value.telephone }}" with_dict: "{{users}}"
7、對文件列表使用循環
cat loop7.yml --- - hosts: web tasks: - copy: src: "{{ item }}" dest: /etc/fooapp/ owner: root mode: 600 with_fileglob: - /playbooks/files/fooapp/*
效果
8、對列表循環
如果列表數目不匹配,用None補全
--- - hosts: web tasks: - debug: msg: "{{ item.0 }} and {{ item.1 }}" with_together: - [ 'a', 'b', 'c' ] - [ 1, 2 ]
9、遍歷列表和索引:with_indexed_items
--- - hosts: web tasks: - name: indexed loop demo debug: "msg='at array position {{ item.0 }} there is a value {{ item.1 }}'" with_indexed_items: [1,2,3]
10、重試循環
--- - hosts: web tasks: - action: shell /usr/bin/foo register: result until: result.stdout.find("all systems go") != -1 retries: 5 delay: 10
"重試次數retries" 的默認值為3,"delay"為5
二、循環與when
如果將when與循環一起使用時,ansible會為每個循環項都執行單獨的條件判斷,不滿足條件的項就會跳過。
1、打印大於5的數字
cat loop8.yml --- - hosts: web debugger: on_failed tasks: - name: print items greater than 5 debug: msg: var is {{ item }} loop: [0,1,3,5,6,7,8,10] when: item > 7
效果:大於7的數字被執行
2、指定默認值default,當該集合未定義時,可以按條件跳過
--- - hosts: web debugger: on_failed tasks: - name: print items greater than 5 debug: msg: "mylist is {{item}}" loop: "{{ mylist|default([4,5,6]) }}" when: item > 5
3、與字典循環
--- - hosts: web debugger: on_failed vars: mydict: {"zhangsan":18,"lisi":19,"wangwu":20} tasks: - name: print items greater than 5 debug: msg: "item is {{item.key}}" loop: "{{ query('dict', mydict|default({})) }}" when: item.value > 19
效果大於19歲的只有wangwu
三、注冊變量與loop
--- - hosts: web gather_facts: no tasks: - name: delete user shell: echo '{{ item }}' loop: - test1 - test2 register: result - name: print debug: msg: "{{ result.results }}"
Ansible 小手冊系列 十四(條件判斷和循環) - 簡書 (jianshu.com)