Ansible的循環

一、       前言

有可能在一個任務中,可能要作不少事情,例如建立多個用戶,安裝不少個包等,那麼就有可能用到循環。mysql

二、       標準循環

重複的任務能夠用下面的方式:sql

- name: add several usersshell

  user: name={{ item }} state=present groups=wheelapp

with_items:負載均衡

     - testuser1dom

     - testuser2ssh

 

若是你定義了一個變量文件建立了一個YAML的列表,或者是在var節中,那麼可使用如下的方式:ide

with_items:"{{somelist}}"

 

 

上面的和下面的表示爲相同的含義,以下:oop

-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_items的時候,能夠減小包管理事務。spa

 

在遍歷的各項中,能夠不是簡單的列表,若是是hash列表的時候,你可使用子健,以下:

-name:add several users
user:name={{ item.name }} state=present groups={{ item.groups }}
with_items:
-{name:'testuser1',groups:'wheel'}
-{name:'testuser2',groups:'root'}

 

三、       嵌套循環

嵌套循環以下所示:

-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']

 

四、       遍歷hash

假設存在如下變量:

---
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}}"

 

五、       遍歷文件

「with_file」迭代創建在一系列文件的內容之上,item將被設置爲序列中每一個文件的內容,以下所示:

---
-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"
}

 

六、       遍歷文件夾(fileglobs)

with_fileglob對應於單一目錄下的全部文件,不遞歸的匹配模式,以下:

---
-hosts:all
 
tasks:
 
# first ensure our target directory exists
-file:dest=/etc/fooapp state=directory
 
# copy each file over that matches the given pattern
-copy:src={{ item }} dest=/etc/fooapp/ owner=root mode=600
with_fileglob:
-/playbooks/files/fooapp/*

 

注意:當在role裏使用with_fileglob的時候,ansible會將路徑解析爲

roles/<rolename>/files 路徑

 

七、       遍歷數據的並行集

假設存在如下的變量:

---
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}}"

 

八、       遍歷子元素

假設你想遍歷一個用戶列表,建立他們,而且用特定的ssh key來進行登陸,假設存在如下的變量內容:

---
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"

 

那麼將會像以下所示:

-user:name={{ item.name }} state=present generate_ssh_key=yes
with_items:"{{users}}"
 
-authorized_key:"user={{item.0.name}}key='{{lookup('file',item.1)}}'"
with_subelements:
-users
-authorized

 

給出MySQL的主機而且提供ssh密鑰的列表,那麼將能夠遍歷一個嵌套的子健:

-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

 

子元素會沿着哈希表遍歷而且給出ssh密鑰在記錄以內

九、       遍歷整數系列

with_sequence生成項目數字的序列,也能夠指定開始,結束,或者一個步長值。

參數也能夠指定爲key=value的格式,若是提供了,那麼會格式化爲printf的類型字符串。

數字值能夠指定爲2進制,10進制,16進制,負數不支持,以下:

---
-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_choice表示爲隨機的選擇,可是不是一個負載均衡,在有的程度上至關於負載均衡,以下:

-debug:msg={{ item }}
with_random_choice:
-"gothroughthedoor"
-"drinkfromthegoblet"
-"presstheredbutton"
-"donothing"

 

提供的字符串將會有一個被隨機選中。

十一、  Do-until循環

有的時候會去嘗試一個任務在特定的條件下,以下:

-action:shell /usr/bin/foo
register:result
until:result.stdout.find("all systems go") != -1
retries:5
delay:10

 

在默認狀況下,retries值爲3,delay爲5秒,在查看的時候,可使用-vv的選項來查看變量的值

十二、  找到第一個匹配的文件

這不是一個循環,可是很接近。當你在引用一個文件的時候,取決於上一個文件的內容或者是名稱,那麼能夠以下:

-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

 

1三、  迭代程序執行的結果

在有的時候,須要遍歷執行的結果,須要注意的是,這是在遠程機器上執行的,而不是在本機器上執行的,以下:

-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}}"

 

1四、  在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":"Allitemscompleted",
"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
}
]
}

 

1五、  在循環中使用register

當使用register來存儲變量的時候,那麼保存的是一個列表,整個屬性爲results

以下:

-shell:echo "{{ item }}"
with_items:
-one
-two
register:echo

 

當使用register而不使用循環的時候返回值以下:

{
"changed":true,
"msg":"Allitemscompleted",
"results":[
{
"changed":true,
"cmd":"echo\"one\"",
"delta":"0:00:00.003110",
"end":"2013-12-1912:00:05.187153",
"invocation":{
"module_args":"echo\"one\"",
"module_name":"shell"
},
"item":"one",
"rc":0,
"start":"2013-12-1912:00:05.184043",
"stderr":"",
"stdout":"one"
},
{
"changed":true,
"cmd":"echo\"two\"",
"delta":"0:00:00.002920",
"end":"2013-12-1912:00:05.245502",
"invocation":{
"module_args":"echo\"two\"",
"module_name":"shell"
},
"item":"two",
"rc":0,
"start":"2013-12-1912:00:05.242582",
"stderr":"",
"stdout":"two"
}
]
}

 

使用循環並使用register的結果以下:

-name:Fail if return code is not 0
fail:
msg:"Thecommand({{item.cmd}})didnothavea0returncode"
when:item.rc != 0
with_items:"{{echo.results}}"

 

1六、  在inventory中使用循環

當你想在inventory中進行遍歷,或者是一個子集,那麼能夠以下所示:

# 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_hostname:

# show all the hosts in the inventory
-debug:msg={{ item }}
with_inventory_hostname:all
 
# show all the hosts matching the pattern, ie all but the group www
-debug:msg={{ item }}
with_inventory_hostname:all:!www

 

1七、  在include中使用循環

在include中使用循環以下:

(注意:在included的任務中含有本身的with_loop值,會覆蓋掉特定的item的值,若是既要使用include的item又要使用當前任務的item,必須使用set_fact去建立一個別名

-include:test.yml
with_items:
-1
-2
-3

 

在test.yml中:

-set_fact:outer_loop="{{item}}"
 
-debug:msg="outer item={{outer_loop}} inner item={{item}}"
with_items:
-a
-b
-c
相關文章
相關標籤/搜索