Ansible之路——第九章:Ansible Playbook


 

Playbooks 是Ansible 管理配置、部署應用和編排的語言,可以使用Playbooks 來描述你想在遠程主機執行的策略或者執行的一組步驟過程等。

如果說Ansible 模塊是工作中的工具的話,那么playbooks 就是方案。

Playbooks 采用YAML 語法結構。

 

9.1 Playbooks 組成

  • Target section:定義將要執行playbook 的遠程主機組
  • Variable section:定義playbook 運行時需要使用的變量
  • Task section:定義將要在遠程主機上執行的任務列表
  • Handler section:定義task 執行完成以后需要調用的任務

9.1.1主機和用戶

在playbook 中的每一個play 都可以選擇在哪些機器和以什么用戶身份完成,hosts 一行可以是一個主機組或者主機也可以是多個,中間以冒號分隔,可以參考前面講的通配模式;

remote_user表示執行的用戶賬號,表示以什么用戶來登錄遠程機器並執行任務。

---
  -hosts: webservers
    remote_user: root

 

9.1.2每一個任務都可以定義一個用戶

---
  - hosts: webservers
    remote_user: root
    tasks:
      - name: test connection
        ping:
        remote_user: yourname

 

9.1.3在play 中支持sudo

---
  - hosts: webservers
    remote_user: yourname
    sudo: yes

  

9.1.4在一個任務中支持sudo

---
  - hosts: webservers
    remote_user: yourname
    tasks:
      - service: name=nginx state=started
        sudo: yes

 

9.1.5 登陸后sudo 到其他用戶執行

---
  - hosts: webservers
    remote_user: yourname
    sudo: yes
    sudo_user: postgres

 

9.2 任務列表

每個任務建議定義一個可讀性較強的名字即name,在執行playbook 時會輸出,tasks 的聲明格式,建議使用”module:options”的格式。

下面以service 模塊為例來定義一個任務,service: key=value 參數,請參看模塊的詳細介紹

tasks:
  - name: make sure apache is running
    service: name=httpd state=running

 

command 和shell 模塊關注命令或者腳本執行后返回值,如果命令成功執行返回值不是0 的情況下,可以使用以下方法

tasks:
  - name: run this command and ignore the result
    shell: /usr/bin/somecommand || /bin/true

或者

tasks:
  - name: run this command and ignore the result
    shell: /usr/bin/somecommand
    ignore_errors: True

注:ignore_errors這里的值只要小寫后為true或者yes就可以,所以即使是TRue這種也是正確的。

 

如果在任務中參數過長可以回車使用空格縮進:

---
  - hosts: server
    tasks:
      - name: Copy ansible inventory file to client
        copy: src=/etc/ansible/hosts dest=/tmp/hosts
              owner=root group=root mode=0644

 

9.3 變量的使用

1)      如何創建一個有效的變量名

變量名應該由字母、數組和下划線組成,以字母開頭

2)      在inventory 中定義變量

3)      在playbook 中定義變量

4)      在角色和文件中包含變量

5)      如何使用變量:Jinja2

Jinja2 是一個被廣泛使用的全功能的Python 模板引擎,它有完整的unicode 支持

注釋:Ansible 允許在模板中使用循環和條件判斷,但是在playbook 只使用純粹的YAML 語法

6)      Jinja2 過濾器

變量可以通過過濾器修改。過濾器與變量用管道符號( | )分割,並且也可以用圓括號傳遞可選參數。多個過濾器可以鏈式調用,前一個過濾器的輸出會被作為后一個過濾器的輸入。

如{{ list | join(', ') }},會把一個列表用逗號連接起來。

下面列舉一些在Ansible 使用較多的Filters:

  • 格式化數據:

{{ ansible_devices | join('| ') }}

  • 過濾器和條件一起使用:

 

9.4 register

register 關鍵字的作用是將命令執行的結果保存為變量,結果會因為模塊不同而不同,在運行ansible-playbook 時增加-v 參數可以看到results 可能的值;注冊變量就如同通過setup 模塊獲取facts 一樣。

 

執行結果:

 

9.5 過濾器

場景1:將獲取到的變量的值的所有字母都變成大寫。如:

 

 

 

如上例所示,testvar變量的值中包含3個小寫字母,在使用debug模塊輸出這個變量的時候,我們使用了一個管道符,將testvar變量傳給了一個名為“upper”的東西,“upper”就是一個過濾器,執行playbook的時候將變量中的小寫字母變成了大寫。

過濾器是一種能夠幫助我們處理數據的工具。其實,ansible中的過濾器功能來自於jinja2模板引擎,我們可以借助jinja2的過濾器功能在ansible中對數據進行各種處理。

當我們想要通過過濾器處理數據的時候,只需要將數據通過管道符傳遞給對應的過濾器即可。過濾器有很多,有些是jinja2內置的,有些是ansible特有的。除此之外,jinja2還支持自定義過濾器。

 

跟字符串操作相關的過濾器,示例:

  

跟數字操作相關的過濾器,示例:

 

跟列表操作相關的過濾器,示例:

 

變量未定義相關操作的過濾器,示例:

 

上述的default過濾器,不僅能在變量未定義的時候返回指定的值,還能夠讓模塊的參數變得“可有可無”。

 

關於“可有可無”,通過以下示例來說明其含義。

場景2,創建幾個文件,只有個別文件需要指定權限,可以定義如下:

 

這里只有第一個文件需要指定權限,其余的都是使用系統默認的權限進行創建。在實際工作中,可能需要創建幾十個這樣的文件,有些需要指定權限,有些不需要,因此一般都會使用條件判斷和循環語句來完成,如下:

 

這樣的playbook確實可以很好的解決問題,但是一共循環了兩遍,因為需要對文件的是否有mode屬性進行判斷,並根據判斷結果調整參數設定。

更好的方法有:

這里並沒有對文件是否有mode權限進行判斷,而是直接調用了file模塊的mode參數,將mode的值設置為了{{item.mode | default(omit)}}。這樣表示的含義就是如果item有mode屬性,就把file模塊的mode參數設置為item的mode屬性值,如果item沒有mode屬性,file模塊就省略mode參數。‘omit’的字面意思就是省略,也就是“可有可無”。

 

9.6 pre_tasks and post_tasks

  • pre_tasks: 設置playbook運行之前的tasks,一般用於准備條件或者變量自定義。
  • post_tasks: 設置playbook運行之后的tasks

Playbook中各種task的執行順序: 

pre_task  >  role  >  tasks  >  post_task

 

如果考慮到handler,則執行順序為:

pre_task  >  pre_handler  >  role task  >  task  >  role handler  >  task handler  >  post task  >  post handler

 

如果你想立即執行所有的 handler 命令在1.2及以后的版本,你可以這樣做:

 

9.7 notify 與 handler

notify指定handler的執行機制:“notify”這個action可用於在每個play的最后被觸發,在notify中列出的操作稱為handler,僅在所有的變化發生完成后一次性地執行指定操作。在notify中列出的操作稱為handle,也即notify中調用handler中定義的操作。

handler:用於當關注的資源發生變化時采取一定的操作。handler是task列表,這些task與前述的task並沒有本質上的不同。

另外,handlers 會按照聲明(notify)的順序執行。

例如:修改ironic配置文件后需要重啟相應的ironic服務。

 

9.8 tags

tags:對任務進行“打標簽”操作。當任務存在標簽后,我們就可以在執行playbook的時候,借助標簽,指定執行哪些任務,或者不執行哪些任務。

例如:

 

9.8.1 查看所有tag

ansible-playbook <playbook_yaml> --list-tags

 

9.8.2 指定tag執行任務:

可以指定某個tag:

ansible-playbook test.yml -t/--tags "tag1"

可以指定多個tag(以逗號分隔,可以加空格):

ansible-playbook test.yml -t "tag1, tag2”

 

9.8.3 指定tag跳過任務

可以使用--skip-tags來跳過某些tag:

可以指定某個tag:

ansible-playbook test.yml --skip-tags "tag1"

可以指定多個tag(以逗號分隔,可以加空格):

ansible-playbook test.yml --skip-tags "tag1, tag2”

 

9.9 條件判斷:when

when相當於shell腳本里的if 判斷,when語句就是用來實現這個功能的,它是一個jinja2的語法,但是不需要雙大括號,用法很簡單。

 

 

 

運算比較符有:==、!=、>、<、>=、<=、and、or、not、()、in等

 

9.9.1 判斷目錄或文件是否存在:exists

 

#exists關鍵字,注意檢查的是ansible主機。is not exists表示不存在,也可以用not testpath is exists

 

9.9.2 判斷變量

  • defined:判斷變量是否已經定義,已經定義則為真
  • undefined:判斷變量是否已經定義,未定義則返回真
  • none:判斷變量是否已經定義,如果變量值已經定義,但是變量值為空,則返回真

 

9.9.3 判斷執行結果

  • success或succeeded: 通過任務的返回信息判斷任務的執行狀態,任務執行成功則返回真
  • failure或failed: 通過任務的返回信息判斷任務的執行狀態,任務執行失敗則返回真
  • change或changed: 通過任務的返回信息判斷任務的執行狀態,任務執行狀態為changed則返回真
  • skip或skipped: 通過任務的返回信息判斷任務的執行狀態,當任務沒有滿足條件,而被跳過執行時,則返回真

 

9.9.4 判斷路徑

  • file: 判斷路徑是否是一個文件,如果路徑是一個文件則為真。
  • directory: 判斷路徑是否是一個目錄,如果路徑是一個目錄則為真
  • link: 判斷路徑是否是一個軟連接,如果路徑是一個軟連接則為真
  • mount: 判斷路徑是否是一個掛載點,如果路徑是一個掛載點則為真
  • exists: 判斷路徑是否存在,如果路徑存在則為真

注意:某些版本之前可能需要加上“is_”前綴

 

9.9.5 判斷整除

  • even: 判斷數值是否是偶數,偶數則為真
  • odd: 判斷數值是否是奇數,奇數則為真
  • divisibleby(num): 判斷是否可以整除指定的數值,如果除以指定的值以后余數為0,則返回真

 

9.5.6 版本號比較

 version: 可以用於對比兩個版本號的大小,或者與指定的版本號進行對比,語法version('版本號','比較操作符')。2.5版本此test從version_compare 更名為version。

 

9.5.7 列表比較

  • subset: 判斷一個list是不是另一個list的子集,是則為真
  • siperset: 判斷一個list是不是另一個list的父集,是則為真

注:2.5版本之前是issubset和issuperset

 

9.5.8 字符串與數字判斷

  • string: 判斷對象是否是一個字符串,是則為真
  • number: 判斷對象是否是一個數字,是則為真

 

9.5.9 failed_when 

先看個例子:

 

有些時候,我們需要通過返回的字符串來判斷是否failed。例如:

 

也就是說,我們只有在返回結果中出現字符串‘FAILED’,我們才認為我們的task 失敗了(因為command 命令即使執行成功,返回值才是我們要判斷失敗與否的關鍵)。

 

9.5.10 changed_when

與failed_when類似。示例:

 

在使用command /shell 模塊的時候ansible playbook 會按照自己的判斷來決定是否changed了。

有時候我們僅僅是ls 了一下, ansible-playbook 也會認為是changed了,可能這並不是我們想要的,這個時候我們就要用例子中方法來修改task的狀態了:

 

9.10 循環

9.10.1 標准循環

為了保持簡潔,重復的任務可以用以下簡寫的方式:

 

如果你在變量文件中或者 ‘vars’ 區域定義了一組YAML列表,你也可以這樣做:

with_items: "{{somelist}}"

 

以上寫法與下面是完全等同的:

 

使用 ‘with_items’ 用於迭代的條目類型不僅僅支持簡單的字符串列表。如果你有一個哈希列表,那么你可以用以下方式來引用子項:

 

注:如果同時使用 when 和 with items (或其它循環聲明), when聲明會為每個條目單獨執行。

 

9.10.2嵌套循環

循環也可以嵌套:

 

執行一下:

 

和以上介紹的with items一樣,你也可以使用預定義變量:

 

9.10.3 對哈希表使用循環

哈希表:用於存儲Key-Value鍵值對的集合。

使用with_dict 來循環哈希表中的元素:

 

9.10.4 對文件列表使用循環

with_fileglob 可以以非遞歸的方式來模式匹配單個目錄中的文件

 

注:當在role中對 with_fileglob 使用相對路徑時, Ansible會把路徑映射到`roles/<rolename>/files`目錄。

 

9.10.5 對並行數據集使用循環(不常見)

假設你通過某種方式加載了以下變量數據:

---
alpha: [ 'a', 'b', 'c', 'd' ]
numbers:  [ 1, 2, 3, 4 ]

如果你想得到’(a, 1)’和’(b, 2)’之類的集合.可以使用with_together:

 

不足的數據則為空:

 

注:這種使用方式不常見。

 

9.10.6 對子元素使用循環

假設你想對一組用戶做一些動作,比如創建這些用戶,並且允許它們使用一組SSH key來登錄。

如何實現? 先假設你有按以下方式定義的數據,可以通過”vars_files”或”group_vars/all”文件加載:

 

那么可以這樣實現:

 

根據mysql hosts以及預先給定的privs subkey列表,我們也可以在嵌套的subkey中迭代列表:

 

9.10.7 對整數序列使用循環

with_sequence 可以以升序數字順序生成一組序列。你可以指定起始值、終止值,以及一個可選的步長值。

指定參數時也可以使用key=value這種鍵值對的方式。如果采用這種方式,format是一個可打印的字符串。

字值可以被指定為10進制,16進制(0x3f8)或者八進制(0600)。負數則不受支持。請看以下示例:

 

9.10.8 隨機選擇

random_choice功能可以用來隨機獲取一些值。它並不是負載均衡器(已經有相關的模塊了)。它有時可以用作一個簡化版的負載均衡器,比如作為條件判斷:

 

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

 

9.10.9 Do-Until循環

有時你想重試一個任務直到達到某個條件。比如:

 

上面的例子遞歸運行shell模塊,直到模塊結果中的stdout輸出中包含”all systems go”字符串,或者該任務按照10秒的延遲重試超過5次。retries和delay的默認值分別是3和5。

該任務返回最后一個任務返回的結果。單次重試的結果可以使用-vv選項來查看。被注冊的變量會有一個新的屬性attempts,值為該任務重試的次數。

 

9.10.10 查找第一個匹配的文件(不常見)

這其實不是一個循環,但和循環很相似,如果你想引用一個文件,而該文件是從一組文件中根據給定條件匹配出來的。這組文件中部分文件名由變量拼接而成。

針對該場景你可以這樣做:

 

該功能還有一個更完整的版本,可以配置搜索路徑.請看以下示例:

 

9.10.11 迭代程序的執行結果(不常見)

有時你想執行一個程序,而且按行循環該程序的輸出。Ansible提供了一個優雅的方式來實現這一點。但請記住,該功能始終在本地機器上執行,而不是遠程機器。

例如,find一堆文件出來,copy走。

 

如果你想遠程執行命令,那么以上方法則不行。但你可以這樣寫:

 

9.10.12 使用索引循環列表(不常見)

如果你想循環一個列表,同時得到一個數字索引來標明你當前處於列表什么位置,那么你可以這樣做:

 

9.10.13 循環配置文件(不常見)

ini插件可以使用正則表達式來獲取一組鍵值對。因此,我們可以遍歷該集合。以下是我們使用的ini文件:

  

以下是使用 with_ini 的例子:

 

以下是返回的值:

 

9.10.14 扁平化列表(不常見)

在罕見的情況下,你可能有幾組列表,列表中會嵌套列表。而你只是想迭代所有列表中的每個元素,比如有一個非常瘋狂的假定的數據結構:

 

你可以看到列表中的包到處都是。那么如果想安裝兩個列表中的所有包呢?

 

9.10.15 循環中使用注冊器

當對處於循環中的某個數據結構使用 register 來注冊變量時,結果包含一個 results 屬性,這是從模塊中得到的所有響應的一個列表。

以下是在 with_items 中使用 register 的示例:

 

返回的數據結構如下,與非循環結構中使用 register 的返回結果是不同的,非循環結構的返回結果類似下面:

 

而循環結構的返回結果如:

 

隨后的任務可以用以下方式來循環注冊變量,用來檢查結果值:

 

9.11 包含

在編程的時候,我們一般都會將重復性的代碼提取出來,作為一個邏輯單元,這個邏輯單元通常被稱為“函數”或者“方法”。如果需要修改這段邏輯,只需要修改函數本身即可。而且這樣還使得程序的可讀性更強。

Ansible中也有類似的功能,這種功能被稱為包含,通過包含,我們可以在一個playbook中包含另一個文件,以便實現我們想要的效果。

Ansible有兩種包含的操作模式:動態和靜態。Ansible 2.4引入了include和import的概念。

  • 如果您使用import*包含Task(import_playbook,import_tasks等),它將是靜態的。
  • 如果您使用include*包含Task(include_tasks,include_role等),它將是動態的。

使用include包含Task(用於task文件和Playbook級包括)仍然可用,但現在被認為已被棄用,建議使用 include_tasks和 import_tasks。

 

9.11.1 include_tasks和import_tasks之間的差異

區別一:

  • include_tasks:是動態的,在運行時展開。即在執行play之前才會加載自己變量。when只應用一次, 被include的文件名可以使用變量。
  • import_tasks:是靜態的,在加載時展開。即在playbooks解析階段將父task變量和子task變量全部讀取並加載。因為是加載時展開的,文件名的變量不能是動態設定的。 when在被import的文件里的每個task,都會重新檢查一次。

例:

b.yml

 

y.yml:

 

運行:

 

因為 mode被改變之后, include_tasks不會重新evaluate mode, import_tasks會根據變化后的mode值重新evaluate每個task的條件。

 

區別二:

  • include_tasks方法調用的文件名稱可以加變量
  • import_tasks方法調用的文件名稱不可以有變量

對於include_tasks,導入文件時可以指定變量:

 

當使用import_tasks方法時,執行報錯。ansible也給出了錯誤原因,當使用static include時,是不能使用變量的:

 

9.11.2 include_tasks和import_tasks的優缺點

使用include*語句的主要優點是循環。當循環與include*一起使用時,包含的任務或角色將為循環中的每個項目執行一次。

與import*語句相比,使用include*有一些限制:

  • 僅存在於動態包含內的標簽不會顯示在-list-tags輸出中。
  • 僅存在於動態包含內的任務不會顯示在-list-tasks輸出中。
  • 您不能使用notify來觸發來自動態包含內部的處理程序名稱。
  • 您不能使用--start-at-task開始執行動態包含內的任務。

與include*相比,使用import*也可能有一些限制:

  • 如上所述,循環不能用於導入。
  • 當使用目標文件或角色名稱的變量時,不能使用來自庫存源(主機/組變量等)的變量。

總而言之,沒有使用with的包含,就使用import,使用了with,那就用include。

 

9.11.3 import_playbook

如果想引入整個playbook,則需要使用include_playbook模塊來代替include。在ansible2.8版本之后,include功能就被刪除掉了。

要求:

  • 包含一個帶有要執行的play列表的文件。
  • 帶有play列表的文件必須被包含在頂層
  • 不能在play中執行該操作。

例如:

main.yml

 

otherplays.yaml

 

otherplays.yaml中導入stuff.yaml,由於不是在頂層導入,而是在play中導入,所以執行會失敗。

 

9.11.4 include_vars

include_vars模塊可以包含JSON或YAML文件中的定義變量,覆蓋已定義的主機變量和playbook變量。如:

 

9.11.5 include_role 與 import_role

后續再講。

 

9.12 Roles

上述已經講過tasks和handlers,那么如何組織playbook才是最好的方式呢?

roles!

 

roles是基於一個已知的文件結構,去自動加載某些vars_file,tasks以及handlers。基於roles對內容進行分組,使得我們可以容易地與其他用戶分享roles。

一個項目的結構如下:

 

一個 playbook 如下:

 

這個 playbook 為一個角色x指定了如下的行為:

  • 如果 roles/x/tasks/main.yml 存在, 其中列出的 tasks 將被添加到 play 中
  • 如果 roles/x/handlers/main.yml 存在, 其中列出的 handlers 將被添加到 play 中
  • 如果 roles/x/vars/main.yml 存在, 其中列出的 variables 將被添加到 play 中
  • 如果 roles/x/meta/main.yml 存在, 其中列出的 “角色依賴” 將被添加到 roles 列表中 (1.3 and later)
  • 所有 copy tasks 可以引用 roles/x/files/ 中的文件,不需要指明文件的路徑。
  • 所有 script tasks 可以引用 roles/x/files/ 中的腳本,不需要指明文件的路徑。
  • 所有 template tasks 可以引用 roles/x/templates/ 中的文件,不需要指明文件的路徑。
  • 所有 include tasks 可以引用 roles/x/tasks/ 中的文件,不需要指明文件的路徑。

 

如果 roles 目錄下有文件不存在,這些文件將被忽略。比如 roles 目錄下面缺少了 vars/ 目錄,這也沒關系。

如果你在 playbook 中同時使用 roles 和 tasks,vars_files 或者 handlers,roles 將優先執行。如果想在roles前執行一些task,可以這樣:

 

而且,如果你願意,也可以使用參數化的 roles,這種方式通過添加變量來實現,比如:

 

當一些事情不需要頻繁去做時,你也可以為 roles 設置觸發條件,像這樣:

 

它的工作方式是:將條件子句應用到 role 中的每一個 task 上。

 

最后,你可能希望給 roles 分配指定的 tags。比如:

 

9.12.1 roles各目錄含義

  • tasks目錄:角色需要執行的主任務文件放置在此目錄中,默認的主任務文件為main.yml,當調用角色時,默認會執行main.yml文件中的任務。也可以將其他需要執行的任務通過include的方式包含在tasks/main.yml文件中。
  • handlers目錄:當角色需要調用handlers時,默認會在此目錄中的main.yml文件中查找對應的handler
  • defaults目錄:角色會使用到的變量可以寫入到此目錄中的main.yml文件中,通常defaults/main.yml文件中的變量都用於設置默認值,以便在你沒有設置對應變量值時,變量有默認的值可以使用,定義在defaults/main.yml文件中的變量的優先級是最低的。
  • vars目錄:角色會使用到的變量可以寫入到此目錄中的main.yml文件中。與defaults/main.yml的區別在於,defaults/main.yml文件中的變量的優先級是最低的,而vars/main.yml文件中的變量的優先級非常高,如果只是想提供一個默認的配置,可以定義在defaults/main.yml,如果想要確保別人在調用角色時,使用的值就是你指定的值,則可以將變量定義在vars/main.yml中,因為定義在vars/main.yml文件中的變量的優先級非常高,所以其值難以覆蓋。
  • meta目錄:如果想要賦予這個角色一些元數據,則可以將元數據寫入到meta/main.yml文件中,這些元數據用於描述角色的相關屬性,比如作者信息、角色的主要作用等。也可以在meta/main.yml文件中定義這個角色依賴於哪些角色,或者改變角色的默認調用設定。
  • templates目錄:角色相關的模板可以放置在此目錄中。當使用角色相關的模板時,如果沒有指定路徑,會默認從此目錄中查找對應名稱模板文件。
  • files目錄:角色可能會用到的一些其他文件可以放置在此目錄中。

注:上述目錄並不全是必須的,如果你的角色中沒有用到對應這些目錄的模塊,那么對應的目錄就不需要包含。一般情況下,至少要有一個tasks目錄。

 

9.12.2 角色默認變量

角色默認變量允許你為 included roles 或者 dependent roles 設置默認變量。要創建默認變量,只需在 roles 目錄下添加 defaults/main.yml 文件。這些變量在所有可用變量中擁有最低優先級,可能被其他地方定義的變量(包括 inventory 中的變量)所覆蓋。

 

9.12.3 role查找

我們可以把單個role的目錄寫在與入口playbook同級的目錄下,也可以放在同級的roles目錄下,還可以通過/etc/ansible/ansible.cfg中的roles_path(默認為家目錄的.ansible/roles目錄)指定。

role查找優先級:同級roles目錄 > /etc/ansible/ansible.cfg中的roles_path(默認為家目錄的.ansible/roles目錄) > 同級目錄下

即使role目錄不處於上述目錄中的任何一個,也可以使用絕對路徑的方式,調用相應的角色:

 

這種寫法其實不算正規,標准語法應該這樣:

 

在roles關鍵字中使用role關鍵字指定角色對應的絕對路徑,可以直接調用角色。即使不使用絕對路徑,也可以使用同樣的語法指定角色名。如:

 

9.12.4 role變量傳遞

我們可以在調用role的時候傳遞對應的變量。如:

 

默認變量也可以定義在defaults/main.yml中,不過優先級是最低的。role使用的變量的優先級為:vars/main.yml > 調用role時傳遞的vars > defaults/main.yml。

還可以寫成:

 

另外,角色中的變量是全局可訪問的。例如:

 

在調用webserver這個角色時傳遞的變量testvar的值,是可以傳遞給web這個角色的。在兩個角色里面對這個變量進行debug,都可以得到這個值:

 

也可以為role設置觸發條件,如:

 

最后,還可以給role分配指定的tags。如:

 

9.12.5 重復調用

默認情況下,我們無法多次調用同一個角色。也就是說,如下的playbook只會調用一次webserver角色:

 

執行該playbook,可以發現,webserver中的debug模塊只輸出了一次:

 

如果想要多次調用同一個角色,有兩種方法。如下:

  • 方法一:設置角色的allow_duplicates屬性,讓其支持重復調用
  • 方法二:調用角色時,傳入的參數值不同

方法一需要為角色設置allow_duplicates屬性,該屬性需要設置在meta/main.yml中,如:

 

方法二,當調用角色時需要傳入參數,如果傳入參數的值不同,也可以連續調用多次。如:

 

9.12.6 role handler

如果想在角色中使用一些handlers以便進行觸發,則可以直接將對應的handlers任務寫入到handlers/main.yml文件中,示例:

 

9.12.7 角色依賴

角色依賴 使你可以自動地將其他 roles 拉取到現在使用的 role 中。角色依賴保存在 roles 目錄下的 meta/main.yml 文件中。這個文件應包含一列 roles 和 為之指定的參數。

示例:

 

“角色依賴” 可以通過絕對路徑指定,如同頂級角色的設置:

 

“角色依賴” 也可以通過源碼控制倉庫或者 tar 文件指定,使用逗號分隔:路徑、一個可選的版本(tag, commit, branch 等等)、一個可選友好角色名(嘗試從源碼倉庫名或者歸檔文件名中派生出角色名):

 

“角色依賴” 總是在 role (包含”角色依賴”的role)之前執行,並且是遞歸地執行。默認情況下,作為 “角色依賴” 被添加的 role 只能被添加一次,如果另一個 role 將一個相同的角色列為 “角色依賴” 的對象,它不會被重復執行。但這種默認的行為可被修改,通過添加 allow_duplicates: yes 到 meta/main.yml 文件中。

比如,一個 role 名為 ‘car’,它可以添加名為 ‘wheel’ 的 role 到它的 “角色依賴” 中:

 

wheel 角色的 meta/main.yml 文件包含如下內容:

 

 

最終的執行順序是這樣的:

tire(n=1)

brake(n=1)

wheel(n=1)

tire(n=2)

brake(n=2)

wheel(n=2)

...

car

 

9.12.8 在 Roles 中嵌入模塊

如果您編寫一個定制模塊,則可能希望將其作為角色的一部分進行分發。

在角色的tasks和handlers結構旁邊,添加一個名為‘library’的目錄,然后將定制模塊直接包含在其中。

 

在一個role中定義的模塊,可供其他role使用:

 

9.12.9 include_role與import_role

在后來版本(ansible>=2.4)中,ansible引入了 import_role(靜態)和include_role(動態)方法。

---
# playbooks/test.yaml
- hosts: node1
  tasks:
    - include_role:
        name: role_A
      vars:
        name: maurice
        age: 100
    - import_role:
        name: role_B

 

比較於 roles 語句,import_role 和 include_role 的優點如下:

  • 可以在task之間穿插導入某些role,這點是「roles」沒有的特性。
  • 更加靈活,可以使用「when」語句等判斷是否導入。

關於include_role(動態)和import_role(靜態)的區別,可以參考之前的include_tasks和import_tasks。

 

也正是因為 include_task 是動態導入,當我們給 include_role 導入的role打tag時,實際並不會執行該roletask

舉個例子,當我們使用include導入role_A,使用import導入role_B時:

---
# playbooks/test.yaml
- hosts: node1
  tasks:
    - include_role:
        name: role_A
      tags: maurice
    - import_role:
        name: role_B
      tags: maurice

 

role_A內容如下:

---
# tasks file for role_A

- debug:
    msg: "age"

- debug:
    msg: "maurice"

 

執行結果顯示,role_A雖然被引用,但里面的task並沒有執行:

  

(End)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM