Salt States 基本法二

五一小长假,魏泽西事件,谁也没想到这事闹得这么大,惊动了习大大出来亲自做指示:「搜索结果不能以给钱多少作为排序依据」,当社会民生问题上升到国家机器的高度,这事推动起来就好办点了,这是积极的一面。

再说黑暗的一面,在此事件中,百度的竞价排名、医疗广告备受诟病,有部分知乎大V收黑钱,昧着良心给那些为百度洗地的答案「点赞」,结果被人扒出来吊打一顿,个中过程,一波三折,撕逼打脸此起彼伏……

详细报道,请观看明晚 19 点 35 分播出的焦点访谈节目《知乎6大V为百度洗地被永久封号》(链接:http://t.cn/Rq8r9zg)

只不过一不小心点了个赞,瞬间几百万粉丝就没了,大V们的人品、口碑及其附带的一系列营销价值一夜坍塌,被永久地钉在知乎的耻辱柱上,受万人唾骂?请问,这事能怪谁?

人在做天在看,且问苍天绕过谁?

勿以恶小而为之啊!

好啦,继续研究《Salt States 基本法》,本集前情提要:

讨论有关 sls 模版以及 include, extend 等高级配置语法。

sls 模版

当你编写 sls 文件时,可能会用到编程语句,这可以用模版语言 { % % } 表示。默认的模版渲染器是 Jinja2,当然,你也可以换成其他的,修改 master 配置文件的 render 值即可。

你写好的所有 state 模块都会发送给 Jinja2 去渲染、编译。

好!下面,就让我们来往里面加点料:模版标记语句,示例如下:

1
2
3
4
{% for usr in ['moe','larry','curly'] %}
{{ usr }}:
user.present
{% endfor %}

渲染后的 sls 文件将变成这样:

1
2
3
4
5
6
moe:
user.present
larry:
user.present
curly:
user.present

下面是个更复杂的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Comments in yaml start with a hash symbol.
# Since jinja rendering occurs before yaml parsing, if you want to include jinja
# in the comments you may need to escape them using 'jinja' comments to prevent
# jinja from trying to render something which is not well-defined jinja.
# e.g.
# {# iterate over the Three Stooges using a {% for %}..{% endfor %} loop
# with the iterator variable {{ usr }} becoming the state ID. #}
{% for usr in 'moe','larry','curly' %}
{{ usr }}:
group:
- present
user:
- present
- gid_from_name: True
- require:
- group: {{ usr }}
{% endfor %}

在 sls 模块中使用 Grains

通常来说,根据主机操作系统的不同,一个 state 模块需要执行不同的动作。前面我们介绍过了,Apache 服务器在不同操作系统下,它的软件安装包名是不一样的。这时,grains 就派上用场了,比如,下面的例子根据不同的操作系统信息确定 Apache 的安装包名:

1
2
3
4
5
6
7
apache:
pkg.installed:
{% if grains['os'] == 'RedHat' %}
- name: httpd
{% elif grains['os'] == 'Ubuntu' %}
- name: apache2
{% endif %}

在 sls 模块中使用环境变量

你可以在 state 中使用 salt['environ.get']('VARNAME') 来访问某个环境变量。

新建一个 test.sls 文件:

1
2
3
file.managed:
- name: /tmp/hello
- contents: {{ salt['environ.get']('MYENVVAR') }}

然后,命令行运行:

1
MYENVVAR="world" salt-call state.template test.sls

利用环境变量来检查错误信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{% set myenvvar = salt['environ.get']('MYENVVAR') %}
{% if myenvvar %}

file.managed:
- name: /tmp/hello
- contents: {{ salt['environ.get']('MYENVVAR') }}

{% else %}

Fail - no environment passed in:
test:
A. fail_without_changes

{% endif %}

调用其他 sls 模块

sls 模版中可以访问 minion 上面的所有 salt 模块,以及模块内的方法:

下面的例子演示了调用了 file 模块的 group_to_gid 方法,参数为 some_group_that_exists

1
2
3
moe:
user.present:
- gid: {{ salt['file.group_to_gid']('some_group_that_exists') }}

再看另外一个例子,使用 network 模块的 hw_addr 方法来读取 eth0MAC 地址。

1
salt['network.hw_addr']('eth0')

高级 sls 语法

include

State 基本法《一》的例子中展示了如何跨文件引用 sls,下面再举一个例子:

python/python-libs.sls:

1
2
python-dateutil:
pkg.installed

python/django.sls:

1
2
3
4
5
6
7
include:
- python.python-libs

django:
pkg.installed:
- require:
- pkg: python-dateutil

extend

通过 extend 语句,你可以添加某些内容到已有的 sls 中,比如,当发现 vhost 配置文件被修改后,马上重启 Apache 服务器。

apache/apache.sls:

1
2
apache:
pkg.installed

apache/mywebsite.sls:

1
2
3
4
5
6
7
8
9
10
11
12
13
include:
- apache.apache

extend:
apache:
service:
- running
- watch:
- file: /etc/httpd/extra/httpd-vhosts.conf

/etc/httpd/extra/httpd-vhosts.conf:
file.managed:
- source: salt://apache/httpd-vhosts.conf

还是那个注意点:在使用 extend时,会添加 require/watch 的内容,而不是覆盖。

命名空间

你可以设置 statename 属性 (如果没有指定 name 属性,它的默认值就是 ID)。

在大多数情况下,重置 name 属性是一个非常实用的小技巧。

  • 其一,避免 ID 声明冲突。

比如,下面的两个 state 不能都用 /etc/motd 作为 ID,但可以通过将 /etc/motd 设为 name 属性来规避这点。

1
2
3
4
5
6
7
8
9
motd_perms:
file.managed:
- name: /etc/motd
- mode: 644

motd_quote:
file.append:
- name: /etc/motd
- text: "Of all smells, bread; of all tastes, salt."
  • 其二,方便其他 state 引用。

ID 名称太长的话,其他 state 来引用不方便还极易出错,比如,下面的例子,将这串冗长的 /etc/apache2/sites-available/mywebsite.com 设为 name 属性,ID 名用 mywebsite 姿势就优雅得多了,想引用几次就引用几次,简单明了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mywebsite:
file.managed:
- name: /etc/apache2/sites-available/mywebsite.com
- source: salt://mywebsite.com

a2ensite mywebsite.com:
cmd.wait:
- unless: test -L /etc/apache2/sites-enabled/mywebsite.com
- watch:
- file: mywebsite

apache2:
service.running:
- watch:
- file: mywebsite

names 声明

另外一个更牛逼的技巧:使用 names 声明一次声明多个 ID,这样就不必在 sls 文件中使用一堆 ungly 的循环语句了。

比如,本集开头的例子可以重写成这样:

1
2
3
4
5
6
stooges:
user.present:
- names:
- moe
- larry
- curly

下集预告

本集主要讨论了有关 include, extend 以及 sls 模版等高级配置语法,下集将介绍如何使用 file_roots 来建立一套可同时用于研发、测试、生产线的运行环境。

很惭愧,今晚又做了一点微小的贡献,谢谢大家!

hxzqlh wechat