Requisites - 必要條件
您也可以參考在Github上維護的這一份技術資料:Requisites and Other Global State Arguments
Salt requisite 系統用於創建狀態之間的關係。 核心思想是,當一種狀態某種程度上依賴於另一種狀態時,可以輕鬆定義相互依賴。 這些依賴性通過使用狀態名稱和ID或名稱聲明關係來表示。 必需目標的一般形式是<state name> : <ID or name>
。 這種特定形式定義爲 Requisite Reference 。
Requisite 分爲兩種類型:direct requisites(例如require
)和requisite_ins(例如require_in
)。 關係是有方向的:直接的先決條件需要其他狀態的某些條件。 但是,Requisite_in將必需項插入指向目標狀態的目標狀態。 下面的示例演示了直接的必要條件:
vim:
pkg.installed
/etc/vimrc:
file.managed:
- source: salt://edit/vimrc
- require:
- pkg: vim
在上面的示例中,文件/etc/vimrc
的配置取決於vim軟件包是否已安裝。
requisite_in語句則相反。 Requisite_ins不會說“我依賴某事”,而是說“某人依賴我”:
vim:
pkg.installed:
- require_in:
- file: /etc/vimrc
/etc/vimrc:
file.managed:
- source: salt://edit/vimrc
因此,在這裏,使用requisite_in可以完成與第一個示例相同的操作,但反之亦然。 vim軟件包說“/etc/vimrc取決於我”。 這將導致將require
插入到針對vim
狀態的/etc/vimrc
狀態。
最後,將創建一個依賴關係圖,並以有限且可預測的順序執行所有操作。
Requisite matching - 必要性條件的匹配方法
Requisites 需要兩條信息進行匹配:狀態模塊名稱-例如 pkg
和標識符,例如 vim ,可以是ID(節的第一行)或-name
參數。
- require:
- pkg: vim
Omitting state module in requisites - 在必要條件中省略狀態模塊
New in version 2016.3.0.
在版本2016.3.0中,狀態模塊名稱被設置爲可選。 如果省略狀態模塊,則將要求與ID匹配的所有狀態,無論它們使用的是哪個模塊。
- require:
- vim
State target matching - 目標狀態匹配
爲了瞭解如何匹配狀態目標,瞭解狀態編譯器的工作方式將很有幫助。 考慮以下示例:
Deploy server package:
file.managed:
- name: /usr/local/share/myapp.tar.xz
- source: salt://myapp.tar.xz
Extract server package:
archive.extracted:
- name: /usr/local/share/myapp
- source: /usr/local/share/myapp.tar.xz
- archive_format: tar
- onchanges:
- file: Deploy server package
第一個公式將轉換爲字典,如下所示(以YAML表示,爲簡化起見,省略了一些屬性)爲高級數據:
Deploy server package:
file:
- managed
- name: /usr/local/share/myapp.tar.xz
- source: salt://myapp.tar.xz
公式中使用的file.managed
格式本質上是語法糖:最後,目標是file,在上面的Extract server package
狀態中使用了file
。
Identifier matching
ID聲明和name
參數要求都匹配。 這意味着,在上面的“Deploy server package”示例中,require
requisite必須與Deploy server package
或/usr/local/share/myapp.tar.xz
匹配,因此以下兩個版本的“ Extract server package”均可使用 :
# (Archive arguments omitted for simplicity)
# Match by ID declaration
Extract server package:
archive.extracted:
- onchanges:
- file: Deploy server package
# Match by name parameter
Extract server package:
archive.extracted:
- onchanges:
- file: /usr/local/share/myapp.tar.xz
Requisite overview - 必要性條件一覽表
name of requisite | state is only executed if target execution result is | state is only executed if target has changes | order 1.target 2.state (default) | comment or description |
---|---|---|---|---|
require | success | default | state will always execute unless target fails | |
watch | success | default | like require, but adds additional behaviour (mod_watch) | |
prereq | success | has changes (run individually as dry-run) | switched | like onchanges, except order |
onchanges | success | has changes | default | execute state if target execution result is success and target has changes |
onfail | failed | default | Only requisite where state exec. if target fails |
在這個表格中使用了以下簡寫形式:
state (= dependent state): state containing requisite
target (= state target) : state referenced by requisite
Direct Requisite and Requisite_in types
下面列表是可以在 Salt 中使用的直接必要性條件:
- require
- watch
- prereq
- use
- onchanges
- onfail
每一個直接必要性條件都有一個相應的 requisite_in條件:
- require_in
- watch_in
- prereq_in
- use_in
- onchanges_in
- onfail_in
其中有幾個必要條件還支持使用 requisite_any 形式的聲明:
- require_any
- watch_any
- onchanges_any
- onfail_any
所有必要條件都定義了特定的關係,並且始終與上面定義的依賴關係邏輯一起工作。
require
使用require
要求必需狀態在從屬狀態之前執行。 包含需求條件的狀態定義爲從屬狀態。 require
語句中指定的狀態定義爲必需狀態。 如果所需狀態的執行成功,則從屬狀態將執行。 如果所需狀態的執行失敗,則從屬狀態將不會執行。 在上面的第一個示例中,文件/etc/vimrc
僅在成功安裝vim軟件包後才執行。
Require an Entire SLS File - 依賴於一個SLS文件
從Salt 0.16.0開始,可以依賴於一個完整的sls文件。 爲此,首先要include sls文件,然後將狀態設置爲要求依賴於包含的sls文件:
include:
- foo
bar:
pkg.installed:
- require:
- sls: foo
這將添加在給定的sls文件中找到的所有狀態聲明。 這意味着將需要依賴於sls foo中的每個狀態。 這使得在任何必要性定義的語句中輕鬆批處理大批狀態非常容易。
require_any
New in version 2018.3.0.
使用require_any
要求至少有必需狀態之一在從屬狀態之前執行。 包含require_any
必要條件的狀態定義爲從屬狀態。 require_any
語句中指定的狀態定義爲必需狀態。 如果所需狀態的執行至少有一個成功了,則將執行從屬狀態。 如果所有必需狀態的執行均失敗,則從屬狀態將不會執行。
A:
cmd.run:
- name: echo A
- require_any:
- cmd: B
- cmd: C
- cmd: D
B:
cmd.run:
- name: echo B
C:
cmd.run:
- name: /bin/false
D:
cmd.run:
- name: echo D
在此示例中,A將運行,因爲指定的需求B,C或D中的至少一個將成功。
watch
當其他狀態發生變化時,watch
語句用於添加由以上狀態變化可以引發的其他行爲。
注意:如果一個狀態僅在另一個狀態發生更改時才執行,否則什麼也不做,則應使用新的
onchanges
要求而不是watch
。watch
旨在在發生更改時添加其他行爲,否則狀態將正常執行。
包含watch
條件的狀態被定義爲watch狀態
。 watch語句
中指定的狀態被定義爲watched狀態
。 當watch狀態
執行時,它將返回一個包含名爲“ changes
”的鍵的字典。 下面是狀態返回字典的兩個示例,爲清楚起見,顯示在json中:
{
"local": {
"file_|-/tmp/foo_|-/tmp/foo_|-directory": {
"comment": "Directory /tmp/foo updated",
"__run_num__": 0,
"changes": {
"user": "bar"
},
"name": "/tmp/foo",
"result": true
}
}
}
{
"local": {
"pkgrepo_|-salt-minion_|-salt-minion_|-managed": {
"comment": "Package repo 'salt-minion' already configured",
"__run_num__": 0,
"changes": {},
"name": "salt-minion",
"result": true
}
}
}
如果watch
狀態的“result
”爲True
,則watch狀態將正常執行;如果爲False
,則watch狀態將永遠不會運行。watch
語句的此部分是複製了require
組件的功能。
如果watch
狀態的“result
”爲True
,並且“changes
”鍵包含填充的詞典(更改在watched狀態下發生),則watch requisite
可以添加其他行爲。此附加行爲由watch狀態
模塊中的mod_watch
函數定義。如果在watch狀態
模塊中存在mod_watch
函數,則除了正常watch狀態
外還將調用該函數。在這種情況下,從mod_watch
函數返回的數據將被返回給master服務器,而從主監視功能返回的數據將被丟棄。
如果“ changes
”鍵包含一個空字典,則watch
條件的行爲與require
必需的行爲完全相同(watch狀態
將在“result
”爲True
時執行,而在“result
”爲False
時失敗)。
注意:並非所有狀態模塊都包含
mod_watch
。如果watch狀態
模塊中缺少mod_watch
,則watch條件
的行爲與require條件
的行爲完全相同。
使用watch
的一個很好的例子是service.running
狀態。當service
監視一個狀態時,除了Salt確保服務正在運行之外,還會在監視狀態更改時重新加載/重新啓動服務。
ntpd:
service.running:
- watch:
- file: /etc/ntp.conf
file.managed:
- name: /etc/ntp.conf
- source: salt://ntp/files/ntp.conf
watch_any
New in version 2018.3.0.
包含watch_any
必要條件的狀態被定義爲監視狀態。 watch_any
語句中指定的狀態被定義爲watched狀態
。當受監視的狀態執行時,它們將返回包含名爲“changes
”的鍵的字典。
如果任何被監視狀態的“result
”爲True
,則監視狀態將正常執行,如果所有狀態均爲False
,則監視狀態將永遠不會運行。watch的此部分複製了require
組件的功能。
如果任何被監視狀態的“result
”爲True
,並且“changes
”鍵包含填充了數據的詞典(在watched狀態下發生了更改),則watch requisite
條件可以添加其他行爲。此附加行爲由watch狀態
模塊中的mod_watch
函數定義。如果在監視狀態模塊中存在mod_watch
函數,則除了正常監視狀態外還將調用該函數。在這種情況下,從mod_watch
函數返回的數據將被返回給master服務器,而主監視功能的返回數據將被丟棄。
如果“changes
”鍵包含一個空字典,則watch條件
的行爲與require
必需的行爲完全相同(watch狀態
將在“result
”爲True
時執行,而在“result
”爲False
時失敗)。
apache2:
service.running:
- watch_any:
- file: /etc/apache2/sites-available/site1.conf
- file: apache2-site2
file.managed:
- name: /etc/apache2/sites-available/site1.conf
- source: salt://apache2/files/site1.conf
apache2-site2:
file.managed:
- name: /etc/apache2/sites-available/site2.conf
- source: salt://apache2/files/site2.conf
在此示例中,如果兩個file.managed
狀態之一的結果爲True
且已更改,則將重新加載/重新啓動服務。
prereq
New in version 0.16.0.
prereq
允許根據尚未執行的狀態的預期結果採取措施。包含prereq
條件的狀態被定義爲pre-requiring狀態
。 prereq
語句中指定的狀態則被定義爲pre-required
狀態。
評估prereq
條件後,pre-required狀態
會報告是否需要任何更改。通過啓用test = True
,將pre-required
的單個狀態作爲測試運行來完成。該測試運行將返回一個包含名爲“changes
”的鍵的字典。 (有關“changes
”詞典的示例,請參見上面的watch
部分。)
如果“changes
”鍵包含一個已填充數據的字典,則意味着pre-required
的狀態期望在實際執行該狀態時發生更改。pre-requiring
狀態現在將實際運行。如果pre-requiring
狀態成功執行,則將繼續執行pre-required
狀態。如果pre-requiring
狀態失敗,則將不會執行pre-required
狀態。
如果“changes
”鍵包含一個空的詞典,則意味着pre-required
狀態將不會發生更改。此時,既不會執行pre-requiring
狀態,也不會運行pre-required
狀態。
在以下實際示例中顯示了定義prereq
的最佳方式:當由於底層代碼將要更改而應關閉服務時,在進行更新時該服務應脫機。在此示例中,graceful-down
是pre-requiring
的狀態,而site-code
是pre-required
的狀態。
graceful-down:
cmd.run:
- name: service apache graceful
- prereq:
- file: site-code
site-code:
file.recurse:
- name: /opt/site_code
- source: salt://site/code
在這種情況下,僅當site-code
狀態希望通過file.recurse
調用部署新代碼時,纔會關閉apache服務器。 只有正常運行正常完成後,纔會執行site-code
部署。
onfail
New in version 2014.7.0.
onfail
必要條件允許嚴格響應於另一個狀態的失敗而發生反應。 這可以通過多種方式使用,例如由於失敗而執行第二次嘗試來設置服務或開始執行單獨的狀態線程。
onfail
要求的應用方式與watch
的要求相同:
primary_mount:
mount.mounted:
- name: /mnt/share
- device: 10.0.0.45:/share
- fstype: nfs
backup_mount:
mount.mounted:
- name: /mnt/share
- device: 192.168.40.34:/share
- fstype: nfs
- onfail:
- mount: primary_mount
注意:將
failhard
(全局或在某個故障狀態中)設置爲True
將導致忽略onfail
,onfail_in
和onfail_any
需求。 如果要將設置爲True
的全局failhard
與onfail
,onfail_in
或onfail_any
組合在一起,則必須在可能發生失敗的狀態下將failhard
顯式設置爲False
(覆蓋全局設置)。
注意:從Salt的2016.11.0版本開始,
onfail
對多個列出的onfail
要求使用OR
邏輯。 在2016.11.0發行版之前,onfail
使用AND
邏輯。 有關更多信息,請參見問題#22370。
onfail_any
New in version 2018.3.0.
onfail_any
必要條件允許嚴格響應作爲對至少一個其他狀態失敗的響應而發生。 這可以通過多種方式使用,例如由於失敗而執行第二次嘗試來設置服務或開始執行單獨的狀態線程。
onfail_any
必要條件的使用方式與require_any
和watch_any
相同:
primary_mount:
mount.mounted:
- name: /mnt/share
- device: 10.0.0.45:/share
- fstype: nfs
secondary_mount:
mount.mounted:
- name: /mnt/code
- device: 10.0.0.45:/code
- fstype: nfs
backup_mount:
mount.mounted:
- name: /mnt/share
- device: 192.168.40.34:/share
- fstype: nfs
- onfail_any:
- mount: primary_mount
- mount: secondary_mount
在此示例中,如果primary_mount
或secondary_mount
狀態中的任何一個導致失敗,則將裝載backup_mount
。
onchanges
New in version 2014.7.0.
onchanges
必要條件使狀態僅在必需狀態發生更改並且watched狀態
的“result
”爲True
時才適用。 這可能是更改系統後執行一個post hook
操作的有用方法。
如果一個狀態具有多個onchanges
要求,則如果任何watched狀態
發生變化,則該狀態將觸發。
注意:一個容易犯的錯誤是在應該使用
onchanges
時使用onchanges_in
。 例如,以下配置不正確:
myservice:
pkg.installed:
- name: myservice
file.managed:
- name: /etc/myservice/myservice.conf
- source: salt://myservice/files/myservice.conf
- mode: 600
cmd.run:
- name: /usr/libexec/myservice/post-changes-hook.sh
- onchanges_in:
- file: /etc/myservice/myservice.conf
這將建立一個必要性依賴的關係,其中cmd.run
狀態始終執行,而file.managed
狀態僅在cmd.run
狀態發生更改時才執行(因爲cmd.run
狀態將命令結果包括爲 變化)。
從語義上看,cmd.run
狀態應該僅在文件狀態發生更改時才運行,但請記住,必需關係涉及一個狀態監視另一個狀態,而Required_in
則相反:它強制指定狀態監視使用了Required_in
聲明的狀態 。
正確的用法是:
myservice:
pkg.installed:
- name: myservice
file.managed:
- name: /etc/myservice/myservice.conf
- source: salt://myservice/files/myservice.conf
- mode: 600
cmd.run:
- name: /usr/libexec/myservice/post-changes-hook.sh
- onchanges:
- file: /etc/myservice/myservice.conf
onchanges_any
New in version 2018.3.0.
onchanges_any
必需條件使一個狀態僅應用其中一個必需的狀態就能生成更改,如果watched狀態
之一的“結果”爲True。 這可能是更改系統方面後執行post hook
的一個有用方法。
myservice:
pkg.installed:
- name: myservice
- name: yourservice
file.managed:
- name: /etc/myservice/myservice.conf
- source: salt://myservice/files/myservice.conf
- mode: 600
file.managed:
- name: /etc/yourservice/yourservice.conf
- source: salt://yourservice/files/yourservice.conf
- mode: 600
cmd.run:
- name: /usr/libexec/myservice/post-changes-hook.sh
- onchanges_any:
- file: /etc/myservice/myservice.conf
- file: /etc/your_service/yourservice.conf
在此示例中,僅當file.managed
狀態中的任何一個生成更改並且至少一個受監視狀態的“result
”爲True
時,才運行cmd.run
。
use
use
必要條件用於繼承另一個id聲明中傳遞的參數。 當許多文件需要具有相同的默認值時,這很有用。
/etc/foo.conf:
file.managed:
- source: salt://foo.conf
- template: jinja
- mkdirs: True
- user: apache
- group: apache
- mode: 755
/etc/bar.conf:
file.managed:
- source: salt://bar.conf
- use:
- file: /etc/foo.conf
該use
聲明主要是針對networking狀態而開發的,但可以在Salt的任何狀態中使用。 這對於networking狀態很有意義,因爲它可以定義一長列選項,這些選項需要應用於多個網絡接口。
use
語句不繼承目標狀態的必要性條件參數。 這也意味着一系列use
條件不會繼承"繼承的選項"。
runas
New in version 2017.7.0.
runas
全局選項用於設置用戶,該用戶將用於在cmd.run
模塊中運行命令。
django:
pip.installed:
- name: django >= 1.6, <= 1.7
- runas: daniel
- require:
- pkg: python-pip
在上述狀態下,由cmd.run
運行的pip命令將由daniel
用戶運行。
runas_password
New in version 2017.7.2.
runas_password
全局選項用於設置runas
全局選項使用的密碼。 指定runas
時,Windows上的cmd.run
要求使用此命令。 在狀態中定義runas_password
時將設置它。
run_script:
cmd.run:
- name: Powershell -NonInteractive -ExecutionPolicy Bypass -File C:\\Temp\\script.ps1
- runas: frank
- runas_password: supersecret
在上述狀態下,由cmd.run
運行的Powershell腳本將由frank用戶使用supersecret
密碼運行。
The _in
versions of requisites
所有的requisites
組件還具有相應的Requires_in
版本,其版本與常規副本相反。 下面的所有示例均以require_in
爲例,但請注意,所有_in
requisites條件的工作方式均相同:它們在目標狀態下產生正常的必備條件,該目標狀態以定義了Required_in
的狀態爲目標。 因此,require_in
導致target狀態會依賴於targeting狀態。 類似地,watch_in
使target狀態監視targeting狀態。
如果一個狀態聲明需要被另一個狀態聲明所依賴,則require_in
可以實現這一點。 因此,這兩個sls文件最後將是相同的:
Using require
httpd:
pkg.installed: []
service.running:
- require:
- pkg: httpd
Using require_in
httpd:
pkg.installed:
- require_in:
- service: httpd
service.running: []
在單獨的sls文件中分配require時,require_in
語句特別有用。 例如,httpd可能需要用於設置PHP或mod_python的組件,這很常見,但是HTTP狀態不需要在設置時就知道需要它的其他組件:
http.sls
httpd:
pkg.installed: []
service.running:
- require:
- pkg: httpd
php.sls
include:
- http
php:
pkg.installed:
- require_in:
- service: httpd
mod_python.sls
include:
- http
mod_python:
pkg.installed:
- require_in:
- service: httpd
現在,只有首先驗證php
和mod_python
都已安裝,才能啓動httpd
服務器。 因此,這將允許在“事後”定義一個條件。