一般,play的結果可能取決於變量的值,facts(有關遠程系統的知識)或先前的任務結果。 在某些狀況下,變量的值可能取決於其餘變量。 此外,能夠建立其餘組,以根據主機是否與其餘條件匹配來管理主機。 在Ansible中有許多控制執行流程的選項。 支持條件的更多示例能夠在這裏找到: http : //jinja.pocoo.org/docs/dev/templates/#comparisonshtml
有時您會想要跳過特定主機上的特定步驟。 若是操做系統是特定版本,這多是一個簡單的方法,若是沒有安裝某個包,或者若是文件系統正在充滿,可能會執行一些清理步驟。web
這在使用when子句時很容易作到,它包含一個沒有雙大括號的原始Jinja2表達式(見變量 )。 其實很簡單: shell
tasks: - name: "shut down Debian flavored systems" command: /sbin/shutdown -t now when: ansible_os_family == "Debian" # note that Ansible facts and vars like ansible_os_family can be used # directly in conditionals without double curly braces
您也能夠使用括號來分組條件:
tasks: - name: "shut down CentOS 6 and Debian 7 systems" command: /sbin/shutdown -t now when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6") or (ansible_distribution == "Debian" and ansible_distribution_major_version == "7")
全部須要爲真的多個條件(邏輯「和」)也能夠指定爲列表:
asks: - name: "shut down CentOS 6 systems" command: /sbin/shutdown -t now when: - ansible_distribution == "CentOS" - ansible_distribution_major_version == "6"
一些Jinja2「過濾器」也能夠在語句中使用,其中一些是惟一的,由Ansible提供。 假設咱們想忽略一個語句的錯誤,而後決定根據成功或失敗有條件地作某些事情:
tasks: - command: /bin/false register: result ignore_errors: True - command: /bin/something when: result|failed # In older versions of ansible use |success, now both are valid but succeeded uses the correct tense. - command: /bin/something_else when: result|succeeded - command: /bin/still/something_else when: result|skipped
請注意,這是「register」聲明的一點點預示。 咱們稍後會在本章中討論。
提醒您,要查看特定系統上有哪些facts,您能夠執行如下操做: apache
ansible hostname.example.com -m setup
提示:有時您會收到一個字符串的變量,您將須要對其進行數學運算比較。 你能夠這樣作:
tasks: - shell: echo "only on Red Hat 6, derivatives, and later" when: ansible_os_family == "RedHat" and ansible_lsb.major_release|int >= 6
也能夠使用在playbooks或inventory中定義的變量。 一個例子多是基於一個變量的布爾值執行一個任務:
vars: epic: true
那麼條件執行可能以下所示:
tasks: - shell: echo "This certainly is epic!" when: epic
要麼:
tasks: - shell: echo "This certainly isn't epic!" when: not epic
若是未設置必需變量,則能夠使用Jinja2 定義的測試來跳過或失敗。 例如:
tasks: - shell: echo "I've got '{{ foo }}' and am not afraid to use it!" when: foo is defined - fail: msg="Bailing out. this play requires 'bar'" when: bar is undefined
這與vars文件的條件導入(見下文)相結合特別有用。 如示例所示,您不須要使用{{}}在條件中使用變量,由於這些變量已經被隱含。
結合with_items (請參閱循環 ),請注意,每一個項目分別處理when語句。 這是設計:json
tasks: - command: echo {{ item }} with_items: [ 0, 2, 4, 6, 8, 10 ] when: item > 5
若是須要根據定義的循環變量跳過整個任務,則使用| default過濾器來提供一個空的迭代器:
- command: echo {{ item }} with_items: "{{ mylist|default([]) }}" when: item > 5
若是使用沒有列表的with_dict :
- command: echo {{ item.key }} with_dict: "{{ mydict|default({}) }}" when: item.value > 5
若是須要,提供本身的facts也很容易,這在開發模塊中有所體現。 要運行它們,只需在您的任務列表頂部調用您本身的自定義facts收集模塊,返回的變量將在之後的任務中訪問:ruby
tasks: - name: gather site specific fact data action: site_facts - command: /usr/bin/thingy when: my_custom_fact_just_retrieved_from_the_remote_system == '1234'
請注意,若是您有多個任務共享相同的條件語句,則能夠將條件附加到以下的任務include語句。 全部的任務獲得評估,但條件應用於每一個任務:app
- include: tasks/sometasks.yml when: "'reticulating splines' in output"
- hosts: webservers roles: - { role: debian_stock_config, when: ansible_os_family == 'Debian' }
在不符合條件的系統上使用此方法時,默認狀況下,您將會注意到不少「跳過」輸出。 在「 關於模塊」文檔中的「group_by」模塊上閱讀,以得到更加精簡的方式來完成相同的操做。
有時你會根據某些標準,在一個playbook裏作一些不一樣的事情。 有一本適用於多個平臺和操做系統版本的playbook就是一個很好的例子。curl
例如,CentOS和Debian之間的Apache軟件包的名稱可能不一樣,但能夠在一個可讀的Playbook中使用最少的語法進行處理:ide
--- - hosts: all remote_user: root vars_files: - "vars/common.yml" - [ "vars/{{ ansible_os_family }}.yml", "vars/os_defaults.yml" ] tasks: - name: make sure apache is started service: name={{ apache }} state=started
做爲提醒,各類YAML文件只包含鍵值和值:
--- # for vars/CentOS.yml apache: httpd somethingelse: 42
這個怎麼用? 若是操做系統是「CentOS」,則第一個能夠導入的文件是「vars / CentOS.yml」,若是該文件不存在,則爲「/vars/os_defaults.yml」。
若是列表中沒有找到任何文件,則會出現錯誤。 在Debian上,它會首先查看'vars / Debian.yml'而不是'vars / CentOS.yml',而後再回到'vars / os_defaults.yml'。 很簡單
要使用這個條件導入功能,您須要在運行該playbook以前安裝facter或ohai,但若是您喜歡,您能夠將其與Ansible一塊兒推出:
# for facter
ansible -m yum -a "pkg=facter state=present" ansible -m yum -a "pkg=ruby-json state=present" # for ohai ansible -m yum -a "pkg=ohai state=present"
可配置的配置方法 - 將變量與任務分離,使您的劇本不會變成具備醜陋的嵌套ifs,條件等的任意代碼,並致使更精簡和可審計的配置規則,特別是由於至少有一個決策點要跟蹤。
有時您要複製的配置文件或您將使用的模板可能取決於變量。 如下構造選擇適合於給定主機的變量的第一個可用文件,這一般比在模板中放入大量條件更爲乾淨。oop
如下示例顯示如何模板化出與CentOS和Debian之間有很大不一樣的配置文件:
- name: template a file template: src={{ item }} dest=/etc/myapp/foo.conf with_first_found: - files: - {{ ansible_distribution }}.conf - default.conf paths: - search_location_one/somedir/ - /opt/other_location/somedir/
一般在playbook中,將給定命令的結果存儲在變量中多是有用的,而後再訪問它。 以這種方式使用命令模塊能夠在不少方面消除編寫站點特定事實的須要,例如,您能夠測試特定程序的存在。
'register'關鍵字決定將結果保存到哪一個變量中。生成的變量能夠在模板,動做行或when語句中使用。 看起來像這樣(顯而易見的例子):
- name: test play hosts: all tasks: - shell: cat /etc/motd register: motd_contents - shell: echo "motd contains the word hi" when: motd_contents.stdout.find('hi') != -1
如前所示,註冊變量的字符串內容可經過'stdout'值訪問。 註冊結果能夠在任務的「with_item」中被使用,若是它被轉換成列表(或已是列表),以下所示。
「stdout_lines」也能夠在對象上使用,可是若是須要也能夠調用「home_dirs.stdout.split()」,而且能夠被其餘字段分割:
- name: registered variable usage as a with_items list hosts: all tasks: - name: retrieve the list of home directories command: ls /home register: home_dirs - name: add home dirs to the backup spooler file: path=/mnt/bkspool/{{ item }} src=/home/{{ item }} state=link with_items: "{{ home_dirs.stdout_lines }}" # same as with_items: "{{ home_dirs.stdout.split() }}"
如前所示,註冊變量的字符串內容可經過'stdout'值訪問。 您能夠檢查註冊變量的字符串內容爲空:
- name: check registered variable for emptiness hosts: all tasks: - name: list contents of directory command: ls mydir register: contents - name: check contents for emptiness debug: msg="Directory is empty" when: contents.stdout == ""