SaltStack State Requisites - 状态配置中的必要性依赖条件的使用方法介绍

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要求而不是watchwatch旨在在发生更改时添加其他行为,否则状态将正常执行。

包含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-downpre-requiring的状态,而site-codepre-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将导致忽略onfailonfail_inonfail_any需求。 如果要将设置为True的全局failhardonfailonfail_inonfail_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_anywatch_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_mountsecondary_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

现在,只有首先验证phpmod_python都已安装,才能启动httpd服务器。 因此,这将允许在“事后”定义一个条件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章