Ansible 小手冊系列 十三(Jinja2)

完整的jinja2說明文檔,請(qǐng)移步:http://docs.jinkan.org/docs/jinja2/

用于playbook中的jinja 2過濾器


更改數(shù)據(jù)格式,其結(jié)果是字符串

{{  some_variable | to_json  }} 
{{  some_variable | to_yaml  }}

對(duì)于人類可讀的輸出

{{  some_variable | to_nice_json  }} 
{{  some_variable | to_nice_yaml  }}

還可以增加參數(shù)( new in 2.2)

{{ some_variable | to_nice_json(indent=2) }}
{{ some_variable | to_nice_yaml(indent=8) }}

從json字符串讀取,其結(jié)果為json類型

{{ some_variable | from_json }}

從yaml字符串讀取,其結(jié)果為yaml類型

{{ some_variable | from_yaml }}

常用示例:

tasks:
  - shell: cat /some/path/to/file.json
    register: result
- set_fact: myvar="{{ result.stdout | from_json }}"

強(qiáng)制定義變量

如果變量未定義,則來自ansible和ansible.cfg的默認(rèn)行為為失敗,但您可以將其關(guān)閉。

{{ variable | mandatory }}

使用未定義的變量

{{ result.cmd|default(5) }}

result.cmd 如果沒由定義的話,則其默認(rèn)值為5

省略參數(shù)

- name: touch files with an optional mode
  file: dest={{item.path}} state=touch mode={{item.mode|default(omit)}}
  with_items:
    - path: /tmp/foo
    - path: /tmp/bar
    - path: /tmp/baz
      mode: "0444"

對(duì)于列表中的前兩個(gè)文件,默認(rèn)mode將由系統(tǒng)的umask確定,因?yàn)閙ode=parameter 不會(huì)發(fā)送到文件模塊,而最后得文件將接收mode=0444選項(xiàng)。

列表過濾

取最小的值

{{ list1 | min }}

取最大的值

{{ [3, 4, 2] | max }}

數(shù)據(jù)集過濾

對(duì)列表唯一過濾

{{ list1 | unique }}

對(duì)兩個(gè)列表去重合并

{{ list1 | union(list2) }}

對(duì)兩個(gè)列表做交集

{{ list1 | intersect(list2) }}

找到兩個(gè)列表差異部分(在list1 不在list2 的差異)

{{ list1 | difference(list2) }}

找到兩個(gè)列表都互相不在對(duì)方列表的部分

{{ list1 | symmetric_difference(list2) }}

隨機(jī)數(shù)過濾

從列表中隨機(jī)獲取元素

{{ ['a','b','c','d','e','f']|random }}

從0-59 的整數(shù)中隨機(jī)獲取一個(gè)數(shù)

{{ 59 |random}}

從0-100 中隨機(jī)獲取能被10 整除的數(shù)(可以理解為0 10 20 30 40 50 ...100 的隨機(jī)數(shù))

{{ 100 |random(step=10) }}

從0-100 中隨機(jī)獲取1 開始步長為10 的數(shù)(可以理解為1 11 21 31 41...91 的隨機(jī)數(shù))

{{ 100 |random(1, 10) }}
{{ 100 |random(start=1, step=10) }}

合并散列

{{ {'a':1, 'b':2}|combine({'b':3}) }}

結(jié)果

{'a':1, 'b':3}

支持遞歸合并

{{ {'a':{'foo':1, 'bar':2}, 'b':2}|combine({'a':{'bar':3, 'baz':4}}, recursive=True) }}

結(jié)果

{'a':{'foo':1, 'bar':3, 'baz':4}, 'b':2}

提取過濾器

{{ groups['x']|map('extract', hostvars, 'ec2_ip_address')|list }}

這需要組“x”中的主機(jī)列表,在hostvars中查找它們,然后查找結(jié)果中的ec2_ip_address。 最終結(jié)果是組“x”中的主機(jī)的IP地址列表。

注釋過濾器

{{ "Plain style (default)" | comment }}

輸出

#
# Plain style (default)
#

輸出各種語言的注釋風(fēng)格

{{ "C style" | comment('c') }}
{{ "C block style" | comment('cblock') }}
{{ "Erlang style" | comment('erlang') }}
{{ "XML style" | comment('xml') }}

還可以自定義

{{ "Custom style" | comment('plain', prefix='#######\n#', postfix='#\n#######\n   ###\n    #') }}

正則匹配

when: ansible_os_family | match("Red[Hh]at" )
when: url | search("/users/.*/resources/.*")

** 其他的常用過濾**

為shell增加雙引號(hào)

- shell: echo {{ string_value | quote }}

根據(jù)True,F(xiàn)alse來返回值

{{ ('name' == 'John') | ternary('Mr','Ms') }}

列表轉(zhuǎn)換字符

{{ list | join(" ") }}

獲取路徑的文件名

{{ path | basename }}

windows平臺(tái)下獲取路徑的文件名

{{ path | win_basename }}

獲取路徑中的目錄

{{ path | dirname }}

獲取軟連接的真實(shí)路徑

{{ path | realpath }}

獲取文件名的名稱和擴(kuò)展名

{{ path | splitext }}

base64編碼

{{ encoded | b64decode }}
{{ decoded | b64encode }}

從字符串創(chuàng)建UUID(1.9版中的新功能)

{{ hostname | to_uuid }}

將轉(zhuǎn)換為布爾類型,如"True" 字符串轉(zhuǎn)換為True

- debug: msg=test
  when: some_string_value | bool

查看變量的python類型

{{ myvar | type }}

隨機(jī)列表過濾

給已存在的列表隨機(jī)排序

{{ ['a','b','c']|shuffle }} => ['c','a','b']
{{ ['a','b','c']|shuffle }} => ['b','c','a']

數(shù)學(xué)

獲取對(duì)數(shù)

{{ myvar | log }}
{{ myvar | log(10) }}

獲取n次冪

{{ myvar | pow(2) }}
{{ myvar | pow(5) }}

獲取平方根

{{ myvar | root }}
{{ myvar | root(5) }}

ip地址過濾

字符串轉(zhuǎn)ip地址

{{ myvar | ipaddr }}

字符串轉(zhuǎn)ip協(xié)議地址

{{ myvar | ipv4 }}
{{ myvar | ipv6 }}

從cidr中獲取地址信息

{{ '192.0.2.1/24' | ipaddr('address') }}

哈希過濾器

獲取字符串得hash值

{{ 'test1'|hash('sha1') }}
{{ 'test1'|hash('md5') }}

獲取字符串校驗(yàn)和

{{ 'test2'|checksum }}

獲取sha512密碼哈希

{{ 'passwordsaresecret'|password_hash('sha512') }}
{{ 'secretpassword'|password_hash('sha256', 'mysecretsalt') }}

playbook中的測試


除了過濾器,所謂的“測試”也是可用的。測試可以用于對(duì)照普通表達(dá)式測試一個(gè)變量。 要測試一個(gè)變量或表達(dá)式,你要在變量后加上一個(gè) is 以及測試的名稱。例如,要得出 一個(gè)值是否定義過,你可以用 name is defined ,這會(huì)根據(jù) name 是否定義返回 true 或 false 。
測試也可以接受參數(shù)。如果測試只接受一個(gè)參數(shù),你可以省去括號(hào)來分組它們。例如, 下面的兩個(gè)表達(dá)式做同樣的事情:

{% if loop.index is divisibleby 3 %}
{% if loop.index is divisibleby(3) %}

測試字符串

vars:
  url: "http://example.com/users/foo/resources/bar"

tasks:
    - shell: "msg='matched pattern 1'"
      when: url | match("http://example.com/users/.*/resources/.*")

    - debug: "msg='matched pattern 2'"
      when: url | search("/users/.*/resources/.*")

    - debug: "msg='matched pattern 3'"
      when: url | search("/users/")

'match'需要在字符串中完全匹配,而'search'只需要匹配字符串的子集。匹配成功返回True,任務(wù)則執(zhí)行。

版本比較

檢查ansible_distribution_version版本是否大于或等于'12 .04',條件成立返回True。

{{ ansible_distribution_version | version_compare('12.04', '>=') }}

進(jìn)行嚴(yán)格的版本檢查

{{ sample_version_var | version_compare('1.0', operator='lt', strict=True) }}

可接受的運(yùn)算符

<, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne

包含測試
測試一個(gè)列表是否包含另一個(gè)列表。

vars:
    a: [1,2,3,4,5]
    b: [2,3]
tasks:
    - debug: msg="A includes B"
      when: a|issuperset(b)

    - debug: msg="B is included in A"
      when: b|issubset(a)

路徑測試

- debug: msg="path is a directory"
  when: mypath|is_dir
- debug: msg="path is a file"
  when: mypath|is_file
- debug: msg="path is a symlink"
  when: mypath|is_link
- debug: msg="path already exists"
  when: mypath|exists
- debug: msg="path is {{ (mypath|is_abs)|ternary('absolute','relative')}}"
- debug: msg="path is the same file as path2"
  when: mypath|samefile(path2)
- debug: msg="path is a mount"
  when: mypath|ismount

任務(wù)測試

以下playbook是檢查任務(wù)狀態(tài)的測試。

tasks:
- shell: /usr/bin/foo
    register: result
    ignore_errors: True
- debug: msg="it failed"
    when: result|failed
  - debug: msg="it changed"
    when: result|changed
- debug: msg="it succeeded in Ansible >= 2.1"
    when: result|succeeded
- debug: msg="it succeeded"
    when: result|success
- debug: msg="it was skipped"
    when: result|skipped

用于 jinja2 模版中的一些語法


變量

變量可以通過 過濾器 修改。過濾器與變量用管道符號(hào)( | )分割,并且也 可以用圓括號(hào)傳遞可選參數(shù)。多個(gè)過濾器可以鏈?zhǔn)秸{(diào)用,前一個(gè)過濾器的輸出會(huì)被作為 后一個(gè)過濾器的輸入。

下面2種方式效果是一樣的

{{ foo.bar }}
{{ foo['bar'] }}

如果變量或?qū)傩圆淮嬖冢瑫?huì)返回一個(gè)未定義值。

** 注釋**

要把模板中一行的部分注釋掉,默認(rèn)使用 {# ... #} 注釋語法。

轉(zhuǎn)義

簡單的使用單引號(hào)進(jìn)行轉(zhuǎn)義
對(duì)于較大的段落,使用raw進(jìn)行轉(zhuǎn)義

{% raw %}
    <ul>
    {% for item in seq %}
        <li>{{ item }}</li>
    {% endfor %}
    </ul>
{% endraw %}

包含 > 、 < 、 & 或 " 字符的變量,必須要手動(dòng)轉(zhuǎn)義

 {{ user.username|e }} 

控制結(jié)構(gòu)

控制結(jié)構(gòu)指的是所有的那些可以控制程序流的東西 —— 條件(比如 if/elif/ekse )、 for 循環(huán)、以及宏和塊之類的東西??刂平Y(jié)構(gòu)在默認(rèn)語法中以 {% .. %} 塊的形式 出現(xiàn)。

For

遍歷序列

{% for user in users %}
  <li>{{ user.username|e }}</li>
{% endfor %}

迭代字典

{% for key, value in my_dict.iteritems() %}
    <dt>{{ key|e }}</dt>
    <dd>{{ value|e }}</dd>
{% endfor %}

循環(huán) 10 次迭代之后會(huì)終止處理

{% for user in users %}
    {%- if loop.index >= 10 %}{% break %}{% endif %}
{%- endfor %}

{% for user in users if loop.index <= 10 %}
    {{ loop.index }}
{%- endfor %}

注:使用break, 需要開啟輪詢控制. 具體是在ansible.cfgjinja2_extensions變量加上jinja2.ext.loopcontrols.

在一個(gè) for 循環(huán)塊中你可以訪問這些特殊的變量:

變量 描述
loop.index 當(dāng)前循環(huán)迭代的次數(shù)(從 1 開始)
loop.index0 當(dāng)前循環(huán)迭代的次數(shù)(從 0 開始)
loop.revindex 到循環(huán)結(jié)束需要迭代的次數(shù)(從 1 開始)
loop.revindex0 到循環(huán)結(jié)束需要迭代的次數(shù)(從 0 開始)
loop.first 如果是第一次迭代,為 True 。
loop.last 如果是最后一次迭代,為 True 。
loop.length 序列中的項(xiàng)目數(shù)。
loop.cycle 在一串序列間期取值的輔助函數(shù)。見下面的解釋。

if 語句

Jinja 中的 if 語句可比 Python 中的 if 語句。

{% if kenny.sick %}
    Kenny is sick.
{% elif kenny.dead %}
    You killed Kenny!  You bastard!!!
{% else %}
    Kenny looks okay --- so far
{% endif %}

** 過濾器**

過濾器段允許你在一塊模板數(shù)據(jù)上應(yīng)用常規(guī) Jinja2 過濾器。只需要把代碼用 filter 節(jié)包裹起來:

{% filter upper %}
    This text becomes uppercase
{% endfilter %}

賦值

在代碼塊中,你也可以為變量賦值。在頂層的(塊、宏、循環(huán)之外)賦值是可導(dǎo)出的,即 可以從別的模板中導(dǎo)入。

賦值使用 set 標(biāo)簽,并且可以為多個(gè)變量賦值:

{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% set key, value = call_something() %}

** 表達(dá)式**

{% ... %} 用于執(zhí)行諸如 for 循環(huán) 或賦值的語句
{{ ... }} 把表達(dá)式的結(jié)果打印到模板上

if 表達(dá)式
一般的語法是
<do something> if <something is true> else <do something else>
例如:

{{ '[%s]' % page.title if page.title is defined else 'undefined' }}

字面量

表達(dá)式最簡單的形式就是字面量。字面量表示諸如字符串和數(shù)值的 Python 對(duì)象。下面 的字面量是可用的:

字面量 說明
"Hello World" 雙引號(hào)或單引號(hào)中間的一切都是字符串。無論何時(shí)你需要在模板中使用一個(gè)字 符串(比如函數(shù)調(diào)用、過濾器或只是包含或繼承一個(gè)模板的參數(shù)),它們都是 有用的。
42/42.23 直接寫下數(shù)值就可以創(chuàng)建整數(shù)和浮點(diǎn)數(shù)。如果有小數(shù)點(diǎn),則為浮點(diǎn)數(shù),否則為 整數(shù)。記住在 Python 里, 42 和 42.0 是不一樣的。
['list','of','objects'] 一對(duì)中括號(hào)括起來的東西是一個(gè)列表。列表用于存儲(chǔ)和迭代序列化的數(shù)據(jù)。
('tuple','of','values') 元組與列表類似,只是你不能修改元組。如果元組中只有一個(gè)項(xiàng),你需要以逗號(hào) 結(jié)尾它。元組通常用于表示兩個(gè)或更多元素的項(xiàng)。更多細(xì)節(jié)見上面的例子。
{dict':'of','key':'and','value':'pairs'} Python 中的字典是一種關(guān)聯(lián)鍵和值的結(jié)構(gòu)。鍵必須是唯一的,并且鍵必須只有一個(gè) 值。字典在模板中很少使用,罕用于諸如 xmlattr() 過濾器之類。
true/false true 永遠(yuǎn)是 true ,而 false 始終是 false 。

特殊常量 true 、 false 和 none 實(shí)際上是小寫的。因?yàn)檫@在過去會(huì)導(dǎo)致 混淆,過去 True擴(kuò)展為一個(gè)被認(rèn)為是 false 的未定義的變量。所有的這三個(gè) 常量也可以被寫成首字母大寫( True 、 False 和 None )。盡管如此, 為了一致性(所有的 Jinja 標(biāo)識(shí)符是小寫的),你應(yīng)該使用小寫的版本。

算術(shù)

Jinja 允許你用計(jì)算值。這在模板中很少用到,但是為了完整性允許其存在。支持下面的 運(yùn)算符:

運(yùn)算符 說明
+ 把兩個(gè)對(duì)象加到一起。通常對(duì)象是素質(zhì),但是如果兩者是字符串或列表,你可以用這 種方式來銜接它們。無論如何這不是首選的連接字符串的方式!連接字符串見 ~ 運(yùn)算符。 {{ 1 + 1 }} 等于 2 。
- 用第一個(gè)數(shù)減去第二個(gè)數(shù)。 {{ 3 - 2 }} 等于 1 。
/ 對(duì)兩個(gè)數(shù)做除法。返回值會(huì)是一個(gè)浮點(diǎn)數(shù)。 {{ 1 / 2 }} 等于 {{ 0.5 }} 。
// 對(duì)兩個(gè)數(shù)做除法,返回整數(shù)商。 {{ 20 // 7 }} 等于 2 。
% 計(jì)算整數(shù)除法的余數(shù)。 {{ 11 % 7 }} 等于 4 。
* 用右邊的數(shù)乘左邊的操作數(shù)。 {{ 2 * 2 }} 會(huì)返回 4 。也可以用于重 復(fù)一個(gè)字符串多次。 {{ ‘=’ * 80 }} 會(huì)打印 80 個(gè)等號(hào)的橫條。
** 取左操作數(shù)的右操作數(shù)次冪。 {{ 2**3 }} 會(huì)返回 8 。

比較

比較符 說明
== 比較兩個(gè)對(duì)象是否相等。
!= 比較兩個(gè)對(duì)象是否不等。
> 如果左邊大于右邊,返回 true 。
>= 如果左邊大于等于右邊,返回 true 。
< 如果左邊小于右邊,返回 true 。
<= 如果左邊小于等于右邊,返回 true 。

邏輯

對(duì)于 if 語句,在 for 過濾或 if 表達(dá)式中,它可以用于聯(lián)合多個(gè)表達(dá)式:

邏輯符 說明
and 如果左操作數(shù)和右操作數(shù)同為真,返回 true 。
or 如果左操作數(shù)和右操作數(shù)有一個(gè)為真,返回 true 。
not 對(duì)一個(gè)表達(dá)式取反(見下)。
(expr) 表達(dá)式組。

is 和 in 運(yùn)算符同樣支持使用中綴記法: foo is not bar 和 foo not in bar 而不是 not foois bar 和 not foo in bar 。所有的 其它表達(dá)式需要前綴記法 not (foo and bar) 。

其它運(yùn)算符

下面的運(yùn)算符非常有用,但不適用于其它的兩個(gè)分類:

運(yùn)算符 說明
in 運(yùn)行序列/映射包含檢查。如果左操作數(shù)包含于右操作數(shù),返回 true 。比如 {{ 1 in[1,2,3] }} 會(huì)返回 true 。
is 運(yùn)行一個(gè) 測試 。
應(yīng)用一個(gè) 過濾器 。
~ 把所有的操作數(shù)轉(zhuǎn)換為字符串,并且連接它們。 {{ "Hello " ~ name ~ "!" }} 會(huì)返回(假設(shè) name 值為 ''John' ) Hello John! 。
() 調(diào)用一個(gè)可調(diào)用量:{{ post.render() }} 。在圓括號(hào)中,你可以像在 python 中一樣使用位置參數(shù)和關(guān)鍵字參數(shù): {{ post.render(user, full=true) }} 。
. / [] 獲取一個(gè)對(duì)象的屬性。

更多文章請(qǐng)看 Ansible 專題文章總覽

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,695評(píng)論 19 139
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程,因...
    小菜c閱讀 7,388評(píng)論 0 17
  • 《裕語言》速成開發(fā)手冊3.0 官方用戶交流:iApp開發(fā)交流(1) 239547050iApp開發(fā)交流(2) 10...
    葉染柒丶閱讀 28,805評(píng)論 5 20
  • 《ilua》速成開發(fā)手冊3.0 官方用戶交流:iApp開發(fā)交流(1) 239547050iApp開發(fā)交流(2) 1...
    葉染柒丶閱讀 11,583評(píng)論 0 11
  • 第十三章 激勵(lì)與自信 行為主義:胡蘿卜(利誘)、大棒(威逼) 我們試著把胡蘿卜清洗干凈、精心烹制,而且提供更大的胡...
    1ffc48c9c19f閱讀 297評(píng)論 0 0

友情鏈接更多精彩內(nèi)容